I was adding some navigation features to a series that I had designed with LVGL 9 using Arduino_H7_Video (which has its own code for the display buffers that I tried to code into my code because I didn't know better and caused issues when I did this, but that's a different discussion). I was consistently getting a really strange freeze (solid red LED, so not an Mbed OS crash) that I could not trace to any particular issue in my code, so I asked ChatGPT for help. For reference, I'm working with an Arduino Giga Display on this project.
With ChatGPT, "we" were able to trace the issue to Arduino_H7_Video.cpp. It turns out that the issue was a repeated realloc()for the rotated buffer in that file, overwriting the allocated memory. ChatGPT suggested a patch to require Arduino_H7_Video.cpp to reuse the same buffer and resize it if there is a need for a larger buffer. This solved my issue, so I thought that I would share it in case anyone else is having the same issues.
In Arduino_H7_Video.cpp, (found at C:\Users\(your user profile)\AppData\Local\Arduino15\packages\arduino\hardware\mbed_giga\4.6.0\libraries\Arduino_H7_Video\src), near the bottom, there is a section that goes
#if __has_include("lvgl.h")
#if (LVGL_VERSION_MAJOR == 9)
static uint8_t* rotated_buf = nullptr;
void lvgl_displayFlushing(lv_display_t * disp, const lv_area_t * area, unsigned char * px_map) {
uint32_t w = lv_area_get_width(area);
uint32_t h = lv_area_get_height(area);
lv_area_t* area_in_use = (lv_area_t *)area;
// TODO: find a smart way to tackle sw rotation
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
lv_area_t rotated_area;
if (rotation != LV_DISPLAY_ROTATION_0) {
rotated_buf = (uint8_t*)realloc(rotated_buf, w * h * 4);
lv_color_format_t cf = lv_display_get_color_format(disp);
#if (LVGL_VERSION_MINOR < 2)
rotation = LV_DISPLAY_ROTATION_90; // bugfix: force 90 degree rotation for lvgl 9.1 end earlier
#endif
lv_draw_sw_rotate(px_map, rotated_buf,
w, h, lv_draw_buf_width_to_stride(w, cf),
lv_draw_buf_width_to_stride(h, cf),
rotation, cf);
rotated_area.x1 = lv_display_get_vertical_resolution(disp) - area->y2 - 1;
rotated_area.y1 = area->x1;
//rotated_area.y2 = dsi_getDisplayYSize() - area->x1 - 1;
rotated_area.x2 = rotated_area.x1 + h - 1;
rotated_area.y2 = rotated_area.y1 + w + 1;
area_in_use = &rotated_area;
px_map = rotated_buf;
auto temp = w;
w = h;
h = temp;
}
uint32_t offsetPos = (area_in_use->x1 + (dsi_getDisplayXSize() * area_in_use->y1)) * sizeof(uint16_t);
dsi_lcdDrawImage((void *) px_map, (void *)(dsi_getActiveFrameBuffer() + offsetPos), w, h, DMA2D_INPUT_RGB565);
lv_display_flush_ready(disp); /* Indicate you are ready with the flushing*/
}
#else
void lvgl_displayFlushing(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) {
uint32_t width = lv_area_get_width(area);
uint32_t height = lv_area_get_height(area);
uint32_t offsetPos = (area->x1 + (dsi_getDisplayXSize() * area->y1)) * sizeof(uint16_t);
dsi_lcdDrawImage((void *) color_p, (void *)(dsi_getActiveFrameBuffer() + offsetPos), width, height, DMA2D_INPUT_RGB565);
lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
}
The problem seems to come from rotated_buf = (uint8_t*)realloc(rotated_buf, w * h * 4);
I replaced that section with this:
#if __has_include("lvgl.h")
#if (LVGL_VERSION_MAJOR == 9)
static uint8_t* rotated_buf = nullptr;
static size_t rotated_buf_size = 0;
void lvgl_displayFlushing(
lv_display_t * disp,
const lv_area_t * area,
unsigned char * px_map)
{
uint32_t w = lv_area_get_width(area);
uint32_t h = lv_area_get_height(area);
lv_area_t* area_in_use = (lv_area_t *)area;
// TODO: find a smart way to tackle sw rotation
lv_display_rotation_t rotation =
lv_display_get_rotation(disp);
lv_area_t rotated_area;
if (rotation != LV_DISPLAY_ROTATION_0) {
size_t requiredSize =
(size_t)w * (size_t)h * 4;
if (requiredSize > rotated_buf_size) {
uint8_t *newBuf =
(uint8_t *)realloc(
rotated_buf,
requiredSize);
if (newBuf == nullptr) {
lv_display_flush_ready(disp);
return;
}
rotated_buf = newBuf;
rotated_buf_size = requiredSize;
}
lv_color_format_t cf =
lv_display_get_color_format(disp);
#if (LVGL_VERSION_MINOR < 2)
rotation = LV_DISPLAY_ROTATION_90;
#endif
lv_draw_sw_rotate(
px_map,
rotated_buf,
w,
h,
lv_draw_buf_width_to_stride(w, cf),
lv_draw_buf_width_to_stride(h, cf),
rotation,
cf);
rotated_area.x1 =
lv_display_get_vertical_resolution(disp)
- area->y2 - 1;
rotated_area.y1 = area->x1;
rotated_area.x2 =
rotated_area.x1 + h - 1;
rotated_area.y2 =
rotated_area.y1 + w + 1;
area_in_use = &rotated_area;
px_map = rotated_buf;
auto temp = w;
w = h;
h = temp;
}
uint32_t offsetPos =
(area_in_use->x1 +
(dsi_getDisplayXSize() *
area_in_use->y1))
* sizeof(uint16_t);
dsi_lcdDrawImage(
(void *)px_map,
(void *)(dsi_getActiveFrameBuffer()
+ offsetPos),
w,
h,
DMA2D_INPUT_RGB565);
lv_display_flush_ready(disp);
}
The major change is adding static size_t rotated_buf_size = 0; and replacing rotated_buf = (uint8_t*)realloc(rotated_buf, w * h * 4); with this:
size_t requiredSize =
(size_t)w * (size_t)h * 4;
if (requiredSize > rotated_buf_size) {
uint8_t *newBuf =
(uint8_t *)realloc(
rotated_buf,
requiredSize);
if (newBuf == nullptr) {
lv_display_flush_ready(disp);
return;
}
rotated_buf = newBuf;
rotated_buf_size = requiredSize;
}
I will caution everyone about potentially using this patch, as there is code in there that I don't understand, but it solve the issues that I was having. I've attached the patched file in case anyone wants to use it (again, use it at your own risk).
Arduino_H7_Video.cpp (8.8 KB)