I’m on an ESP32-S3 and I’m using an e-Reader screen. The e-Reader screen I’m using is this one: 10.3inch e-Paper E-Ink Display HAT for Raspberry Pi, 1872×1404 pixels, Black / White, 2-16 Grey Scales, USB/SPI/I80. The resolution of the screen is rather large, 1872x1404 pixels, so I’m trying to be as optimal as possible regarding memory usage.
I’ve set the color depth to 16 bit to support gray scale, and I’ve created a display buffer of 40 lines. I’m currently trying to implement the flush_cb method.
The challenge I’m facing is getting flush_cb play nice with the IT8951 controller. The logic is as follows:
- flush_cb is called.
- If this is the first call to flush_cb, I tell the controller I’m going to send it the whole screen. This assumes the whole screen is being updated every time. On LVGL 8 I had full_refresh set. Right now, on 9.2.2, I’m just invalidating the whole screen whenever I touch part of it.
- I copy a small part of the px_map buffer into a DMA buffer and send it (in the background) to the controller using SPI.
- While that’s going, I fill a second DMA buffer. I wait for the first to be sent through SPI and then start sending the second buffer.
- This keeps going until the whole px_map is sent to the controller.
- If this was the last call to flush_cb, I show the image on the e-Reader screen.
This works fine. However, I would like to support partial updates. The problem I have is that I need to know the whole size of the area that’s being updated when I start uploading the image to the controller. I need to tell the controller the dimensions of the image I’m uploading.
I’ve looked through the code and the best I can come up with is that I re-implement all logic related to inv_areas. I prefer not to do that. There’s complexity around overlapping areas, and I’m aware that a sequence of flush_cb calls can flush unrelated parts of the screen.
Realistically it’s preferable for me that any flush_cb call will only update a single area. One idea I had was to intercept LV_EVENT_INVALIDATE_AREA events and track the area being invalidated that way. Something like this:
lv_display_add_event_cb(
display,
[](lv_event_t* event) {
auto self = (Device*)lv_event_get_user_data(event);
auto com_area = (lv_area_t*)lv_event_get_param(event);
ESP_LOGI(TAG, "Invalidating area %" PRIi32 "x%" PRIi32 " %" PRIi32 "x%" PRIi32, com_area->x1, com_area->y1,
com_area->x2, com_area->y2);
if (self->_invalidated_area.x2) {
com_area->x1 = min(com_area->x1, self->_invalidated_area.x1);
com_area->y1 = min(com_area->y1, self->_invalidated_area.y1);
com_area->x2 = max(com_area->x2, self->_invalidated_area.x2);
com_area->y2 = max(com_area->y2, self->_invalidated_area.y2);
}
lv_area_copy(&self->_invalidated_area, com_area);
ESP_LOGI(TAG, "Whole invalidated area %" PRIi32 "x%" PRIi32 " %" PRIi32 "x%" PRIi32, _invalidated_area.x1,
_invalidated_area.y1, _invalidated_area.x2, _invalidated_area.y2);
},
LV_EVENT_INVALIDATE_AREA, this);
However, this also won’t work because once the display is out of inv_areas, it refreshes the whole screen. Again, I could re-implement this logic, but that’s quite fragile. (Plus I’m pretty sure updating com_area isn’t supported.)
What’s a decent way to accomplish this? Basically what I want is:
- The first call of flush_cb needs to know the complete area size being rendered until the last flush_cb call.
- No disjoint areas. Every run of flush_cb calls will only render one area (i.e. there’s only ever just one inv_areas with inv_area_joined set to 0).