Bug when aligning an object

MCU: ESP32-WROOM-32, RTOS: Mongoose OS, Display: SSD1309

Hi,
I have a problem with alignment of a label. If I set a text for the first time it is drawn correctly on the display. When I align the label e.g. to the right top corner, it is aligned correctly as well. But the problem occures when I want to change the aligned text later. If I rewrite the text then it spills (the characters go to pieces) and the text is no more readable. When I rewrite the text again I can see some changes but the text remains spilled. However, if I don´t align the text it is always rewritten correctly and is always readable.

What I want to reach is just to create a text, align it and later when an event is received I want to rewrite this text.

Here is my simplified code

static lv_obj_t* lv_Screen;
static lv_obj_t* lv_Label;

void TextCreate (void)
{
    lv_Screen = lv_obj_create(NULL, NULL);
    lv_scr_load (lv_Screen);
    
    lv_Label = lv_label_create (lv_Screen, NULL);

    lv_label_set_text(lv_Label, "123");      
    lv_obj_align (lv_Label, lv_Screen, LV_ALIGN_CENTER, 0, 0);
}

void TextRewrite (void)
{
    lv_label_set_text(lv_Label, "456");
}

Updated text

Created text

Have you tried this in the PC simulator? Does it work there? If so, it’s probably an issue with your display driver.

No, I haven’t. I try it and I let you know.

Well, I realized that I don’t need to test it on the simulator. I have read the data which are sent in the Display_flush_cb callback to the display driver. And all data are correct. That means the display driver renders the data correctly on the display. So either there is a bug in the lv_obj_align function or there is something wrong in my library initialization. I suppose the bug is on my side :slightly_smiling_face:

So, here’s my code:


#define DISPLAY_BUFFER_SIZE ( LV_HOR_RES_MAX * 64)
static lv_disp_buf_t disp_buf;
// Declare a size of buffer - only one buffer will be created
static lv_color_t buf[DISPLAY_BUFFER_SIZE];

static lv_obj_t *lv_Screen;

static void Display_Flush_cb (lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{    
    uint8_t u8_Height, u8_Width, u8_BlockHeight;
    uint8_t* pu8_Buffer = (uint8_t*) color_p;

    u8_Width = area->x2 + 1;
    u8_Height = area->y2 - area->y1 + 1;
    u8_BlockHeight = area->y1/u8_Height;

    ssd1306_drawBuffer (area->x1, u8_BlockHeight, u8_Width, u8_Height, (uint8_t*) color_p);

    //Indicate you are ready with the flushing
    lv_disp_flush_ready(disp);
}

static void Display_Rounder_cb (lv_disp_drv_t * disp_drv, lv_area_t * area)
{
    area->x1 = area->x1 & ~(0x7);
    area->x2 = area->x2 |  (0x7);

    area->y1 = area->y1 & ~(0x7);
    area->y2 = (area->y2 | (0x7)) + 8;
}

static void Display_Set_Px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
{
    buf += buf_w * (y >> 3) + x;
    if (lv_color_brightness(color) <= 128)
    {
        (*buf) |= (1 << (y % 8));
    }
    else
    {
        (*buf) &= ~(1 << (y % 8));
    }
}

void Display_Init (void)
{
    lv_disp_drv_t disp_drv;

    // Initialize the library
    lv_init();
    // Initialize display buffer
    lv_disp_buf_init(&disp_buf, buf, NULL, DISPLAY_BUFFER_SIZE);
    // Initialize display driver
    lv_disp_drv_init(&disp_drv);    
    // Set the driver callback function
    disp_drv.flush_cb = Display_Flush_cb;
    // Set the rounder callback function
    disp_drv.rounder_cb = Display_Rounder_cb;

    disp_drv.set_px_cb = Display_Set_Px_cb;
    // Assign the buffer to the display
    disp_drv.buffer = &disp_buf;
    // Register the driver
    lv_disp_drv_register(&disp_drv);
}

void v_Display_PowerUp (void)
{
    // Initialize SSD driver
    ssd1309_Init();
    // Start tick handler timer
    mgos_set_timer(TICK_DELAY_MS, MGOS_TIMER_REPEAT, tick_handler_cb, NULL);
    // Start task handler timer
    mgos_set_timer(TASK_DELAY_MS, MGOS_TIMER_REPEAT, task_handler_cb, NULL);

    lv_Screen = lv_obj_create(NULL, NULL);
    lv_scr_load (lv_Screen);
}

Note that I use monochromatic display with resolution 128 x 64. The lv_tick_inc() and lv_task_handler() are called every 10 ms.

I would be very happy If someone found the reason why the text spills.

And there two interesting things. If I align the label to LV_ALIGN_IN_TOP_LEFT then everything is OK and I can rewrite the text later. But any other align position fails. And if I change the size of the buffer to e.g. 128 x 8 the display shows nothing - remains empty.

The easiest way to find if it’s a LittlevGL bug or not is to try it in the simulator and see if you get the same behavior.

It looks like a driver issue. I suggest using you driver without LittlevGL to set only one pixel on the screen and see if really to correct pixel is set or not.

Hi, I tried to set one pixel without using the LvGL and the driver displays it exactly on the position. Code is here (together with description of the ssd driver function). Note that the pixel is shown on position (10,0).

void Test_DrawPixel (void)
{
    uint8_t Buffer[1] = {0x01};

    ssd1306_drawBuffer (10, 0, 1, 8, Buffer);

    /**
 * Draws bitmap, located in SRAM, on the display
 * Each byte represents 8 vertical pixels.
 *
 * ~~~~~~~~~~~~~~~{.c}
 * // Draw small rectangle 3x8 at position 10,8
 * uint8_t buffer[3] = { 0xFF, 0x81, 0xFF };
 * ssd1306_drawBuffer(10, 1, 3, 8, buffer);
 * ~~~~~~~~~~~~~~~
 *
 * @param x - horizontal position in pixels
 * @param y - vertical position in blocks (pixels/8)
 * @param w - width of bitmap in pixels
 * @param h - height of bitmap in pixels (must be divided by 8)
 * @param buf - pointer to data, located in SRAM: each byte represents 8 vertical pixels.
 void         ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
 */
}

Changing the labels text is very commonly used so I doubt that it’s an issue in the library.

Can you debug your project and examine the buffer’s content manually inflush_cb?

Hi,
so finally I have found the bug. I have found it during preparing the data for you. I noticed that the problem is really in the Display_Flush_cb callback. The width must be u8_Width = area->x2 - area->x1 +1;. When the label was aligned to the left, everything was ok. But when x1 was greater than 0 the problem occured. And my second problem with changing the buffer size is also resolved: the y1 coordinate must be as following: u8_BlockHeight = area->y1/8;
So I would like to apologize you for losing your time and thank you for your support. Please consider this issue as closed.

No problem :slight_smile:
Glad to hear that you have found the issue.