Label not displayed when y > 67

Hello everyone,
I’m moving first steps to port littlevgl to my monochrome display. I’m trying to move a simple text label around but it seems something is not working whenever the y value exceeds 67: the previous label is not cleared and no next position is set. I can see the buffer does not change so it’s not a flushing problem.

I’m posting my main code in hopes someone can see a glaring error that escaped me.

extern unsigned char gbuf[GBUFSIZE];

static void InitializeSystem(void)
    Init_Display(ROTATE_0, FALSE);

void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
    // durata 0,39ms
    int row = area->y1, col;
    unsigned int address = (unsigned int)row * HW_COLUMNS;
    for (row = area->y1; row <= area->y2; row++) {
        for (col = 0; col < HW_COLUMNS; col++)
            vram_data_write(gbuf[(unsigned int) row * HW_COLUMNS + (unsigned int) col], TRUE);
    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/

 void set_px_cb(struct _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) {
     int column = x/8;
     int shift = 7 - (x % 8);
     int row = y;
     int index = row * 30 + column;
     if (color.full) {
         buf[index] |= 1 << shift;
     } else {
        buf[index] &= ~(1 << shift);

void rounder(struct _disp_drv_t * disp_drv, lv_area_t *a)
	//a->x1 -= a->x1%8;
    //a->x2 -= a->x2%8;
    //a->x2 += 8;
    a->x1 = 0;
    a->x2 = 240-1;

int main (void)
    int counter = 0, position = 0;
    static lv_disp_buf_t disp_buf;
    //static lv_color_t buffer[GBUFSIZE];
    lv_disp_buf_init(&disp_buf, gbuf, NULL, 128*240);
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);            /*Basic initialization*/
    disp_drv.buffer = &disp_buf;            /*Set an initialized buffer*/
    disp_drv.flush_cb = my_flush_cb;        /*Set a flush callback to draw to the display*/
    disp_drv.set_px_cb = set_px_cb;
    disp_drv.rounder_cb = rounder;
    lv_disp_t * disp;
    disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created display objects*/ 
    lv_obj_t * scr = lv_disp_get_scr_act(NULL);     /*Get the current screen*/

    /*Create a Label on the currently active screen*/
    lv_obj_t * label1 =  lv_label_create(scr, NULL);
    /*Modify the Label's text*/
    lv_label_set_text(label1, "Hello world!");
    lv_obj_set_pos(label1, 50, 40);
    while (1) {
        if (counter++ > 500) {
            position = (position + 1)%5;
            label1 =  lv_label_create(scr, NULL);
            lv_label_set_text(label1, "Hello my world!");
            lv_obj_set_pos(label1,90, 65 + position);// position, position);
            counter = 0;

My display is 240x128; GBUFSIZE is defined as (240x128/8).

It seems correct at first look.

Could you try without rounder and set_px_cb even with an empty flush function just to see the drawing happens?

Don’t forget to change:

lv_color_t gbuf[GBUFSIZE];

I’m not sure I follow your suggestions. Since I am using a monochrome display my framebuffer is just one eighth of the actual pixel number; thus I cannot remove set_px_cb because that leads to referencing memory outside of gbuf (as lvgl by default assumes at least one byte per pixel). In the same way using lv_color_t does not work, I don’t have enough memory for 128x240 bytes.

I did remove rounder and confirmed that even without it set_px_cb is never called with y > 67. I also found out that the region below 67 is not updated anymore after the first call to lv_task_handler(); any label that is set before that will appear anywhere.

I’ll try to find out exactly what is changed after the first call.

@kisvegabor wants you to remove all of the code that actually draws to the display. Therefore you don’t need set_px_cb. Basically you are temporarily making a dummy driver.

@kisvegabor wants you to remove all of the code that actually draws to the display. Therefore you don’t need set_px_cb . Basically you are temporarily making a dummy driver.

Ok, but if I do that I will need a buffer 128x240 bytes wide as opposed to the current (128x240)/8, and unfortunately my device (PIC24EP512GP206) doesn’t have enough memory.

A buffer even with one line is enough.
So #define GBUFSIZE 240 should work too.

Ok, I have tried with a smaller buffer and an empty flush_cb and I can confirm nothing is written on it below y=67 after the first lv_task_handler has been called.

Very strange.
What is LV_HOR_RES_MAX and LV_VER_RES_MAX in lv_conf.h?

#define LV_HOR_RES_MAX          (240)
#define LV_VER_RES_MAX          (128)

It’s fine.

I suppose it could be because of the 16 bit architecture. I haven’t tested LittlevGL on 16 bit MCU-s for a while. Maybe there is an integer overflow somewhere.
Can you debug if all the variables have a correct value here?
This part breaks up the large areas into smaller chunks.

I believe I found a behavior worth investigating (although I’m not confident yet in my understanding of the library so it might be perfectly normal).
When drawing one label at position (0, 70) continuously (e.g. delete and recreate every second) I reach the point in the code you highlighted with two possible values for area_p:

area_p->x1 = 0;
area_p->y1 = 70;
area_p->x2 = 239;
area_p->y2 = 77;


area_p->x1 = 0;
area_p->y1 = 0;
area_p->x2 = 239;
area_p->y2 = 66;

If I only draw labels above the y = 67 mark I only see the second occurrence. Since the latter values seem to refresh the whole display above y = 67 I suspect that might have something to do with the issue; still, even when drawing a label below 70 a refresh for what seem to be the correct area is invoked…

Edit: I can confirm that adding the line if (disp_refr->inv_areas[i].y2 == 66) disp_refr->inv_areas[i].y2 = 127; here or in the rounder_cb solves the problem.

Hmm, getting even stranger.

Could you check what’s happening lv_inv_area?
You can use your previous test with the label.

scr_area contains the correct data (x from 0 to 239 and y from 0 to 127); both area_p and com_area have the following values:

area_p->x1 = 0;
area_p->y1 = 70;
area_p->x2 = 119;
area_p->y2 = 77;

Which mark the correct drawing area for the label.
com_area is then slightly changed by the rounder function (x2 becomes 135) and is saved in the inv_areas field. Despite that nothing changes in the framebuffer.

The best solution I’ve found so far is to extend the y range from 0 to 127 in the rounder function; I’m not sure why but everything works this way. The x range is correctly limited to the sole drawing area.

So this part still seems working.

There are only a few places left to check so we should find it soon! :slight_smile:

Let’s check lv_refr_area.
If there are intersecting areas to refresh LittlevGL will join them in lv_refr_join_area.

Could you verify these parts too?

I’ll try to recap what happens after lv_refr_areas. The field disp_refr->inv_areas contains 3 areas to invalidate:

  • x = 0-135 and y = 70-77
  • x = 0-135 and y = 0-66
  • x = 0-135 and y = 0-7

the second and third areas are joined together as one and are passed correctly to lv_refr_area.
Beside that, I have noticed something that I can’t explain further into the drawing process. When the function lv_draw_fill is called on the label’s area (0-135, 70-77) it ultimately calls sw_color_fill here on vdb_rel_a; that area is calculated relatively to the origin point of the object but seems to be treated as absolute by sw_color_fill, so it ends up refreshing the area with size 135,7 on the top left corner of the screen… Am I missing something?

Also, if you feel like checking yourself (I’m more than happy to follow your directions but I have little understanding of how the internal code works) I’ve created a minimal project that reproduces the issue :
It can be opened with the official PIC IDE, MPLABX and you will need xc16 compiler to compile it. You can then run it in the internal simulator (project properties should be already set up, so simply running the debug command - the button with the breakpoint and play button on the top bar - should work). Then you can break and inspect gbuf to see whether something is written on it.

I’ve checked you project in MPLABX’s simulator and all seems correct to me. In disp_flush I got:

  1. x: 0;135 y: 70;77 the desired position of the label
  2. x: 0;135 y: 0;66: Some garbage because of creating objects. Doesn’t really matter.

So the key think I see the y:70;77 are in disp_flush. Can you confirm it?

Yes, I can confirm this. The problem is not in the buffer flushing (even if I manage it externally and flush all of the screen the issue persists) but the drawing itself; in the main cycle I create a new label and place it in (0,70), but that is never drawn on the buffer and you can see it by inspecting the variable in the IDE: every row is 30 bytes so the label should be drawn starting at index 70*30 = 2100, but it’s just 0xff there.

I see this disp_flush

It seems gbuf is mainly 0xff (the background) and some other values (probably the label)

If I change the text to “|” I got 0xEF for every 30th byte of gbuf. So the every first pixel is black as expected. (349 Bytes)

Yes, I can see the same flushing values; the problem is that there should be a label (e.g. any value different from 0xff) in gbuf at index 2100 because of the label I’m drawing in (0,70). The garbled values at the beginning are the label created initially (before the first lv_task_handler call)

I would expect to see the same values at index 2100 in gbuf, but instead it’s empty (background 0xff)