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

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)

Thanks for taking the time to share your findings @littlejohn657!

In order to make relevant information available to any who are interested in this subject, I'll share a link to the formal report you submitted to the developers of the "Arduino Mbed OS GIGA Boards" platform: