Mono display refresh a label on portion of screen shows garbage

Lvgl Version
v8.01

Initial Question
Before I get into a long discussion I would like to ask is it allowable to refresh only a portion of the screen on a mono display or must one always refresh the whole screen?

Problem
I have a SSD1306 display which is 128 columns by 64 rows (8 pages). I have created a driver for this display and I have implemented rounder_cb and set_px_cb. I have a couple dynamic labels on the screen. When the screen is first displayed I place dummy text ("—") for the labels. The screen is properly displayed when first drawn with the dummy text. For testing I only updated one of the labels and when I do the refresh this label includes some garbage.

Details
I have a section on the screen which has a label. The label section is y1=40, y2=49, x1=56, x2=95.
The y axis is the has 2 pages one full page (y=40 to y=47) and one partial page (y=48 to y=49). When I do the refresh of the label the display_flush_cb correctly identifies y1, y2, x1, x2.
When I examine set_px_cb on the refresh of the label it is using a draw area based on y=0, x=0 and not the display area of y=40, x=56. So set_px_cb is updating display_buffer at location y=0, x=0 and not y=40, x=56. Now the old remaining pixels in display (y=10 to y=15) will be used to update the label not y=50 to y=55. These pixels are causing the garbage on the updated label because the display can only be updated using full page boundaries.

Question
Is there a way the modify set_px_cb to write to the correct pixel location of the display buffer.

set_px_cb

// in buf (video display buffer) from supplied x,y coordinates
    void IRAM_ATTR DisplayDriver::set_px_cb(struct _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)
    {
        uint16_t buf_index;
        uint8_t bit_index;

        
        // landscape
        buf_index = x + (buf_w * (y >> 3));
        bit_index = y & 0x07;

        if ((color.full == 0) && (LV_OPA_TRANSP != opa))
        {
            // clear the bit
            buf[buf_index] &= static_cast<uint8_t>(~(1 << bit_index));
        }
        else
        {
            // set the bit
            buf[buf_index] |= static_cast<uint8_t>(1 << bit_index);
        }

        

        // Debug code
        if((x==0) & (y==0))
        {
            Log::warning(TAG, "set px cb   x={}, y={}", x, y);
            //Log::warning(TAG, "set px cb   buf_addr={:#04x}", buf);
            std::cout << reinterpret_cast<void *>(buf) << std::endl;
        }

        
    }

rounder_cb

void IRAM_ATTR DisplayDriver::rounder_cb(struct _lv_disp_drv_t* disp_drv, lv_area_t* area)
    {
        //Log::info(TAG, "rounder");
        area->x1 = area->x1 & (~0x7);  // round down to page byte bounder
        area->x2 = area->x2 | 0x07;    // round up to page byte bounder
    }

I’m not familiar enough with set_px_cb to be helpful so I’ll ping @kisvegabor to take a look.

I have added some pictures and some more info.

Picture of initial screen with dummy labels

Picture of bad screen - Good count has garbage that overwrites Bad Count

Picture of data inside display_flush_cb
display_flush_cb_data

In theory I need to send the display 80 bytes since I cannot send a partial page.
bytes to send = (end_page - start_page +1) * (end_col - start_col +1) = 80.
Picture of screen when sending only 40 bytes

For some reason the rest of the bits in end_page (page 6) contain garbage data (looks like some parts of the title of screen “Statistics”)

Ok found the problem. I was using the wrong axis in rounder_cb it should have been the y-axis and not the x-axis. The y-axis uses page boundaries.
so should look like the following.

void IRAM_ATTR DisplayDriver::rounder_cb(struct _lv_disp_drv_t* disp_drv, lv_area_t* area)
    {
        area->y1 = area->y1 & (~0x07);
        area->y2 = area->y2 | 0x07;
    }
1 Like