arduino / arduino/ArduinoCore-mbed

Solving a weird freeze up with LVGL v9 in Arduino_H7_Video using Giga Display Shield

Open
#1,119 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
411
Forks
225
PR merge metrics
No merged PRs in 30d

Description

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](https://github.com/user-attachments/files/31337014/Arduino_H7_Video.cpp)

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with Arduino_H7_Video.cpp and the LVGL 9 path around rotated_buf in lvgl_displayFlushing. Reproduce the freeze on an Arduino Giga Display Shield with rotation and compare behavior when buffer sizes vary. Done means rotated display updates no longer freeze and allocation failures are handled safely.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics, embedded-iot
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.