fix(LTDC): add cache cleaning (#9192)

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Liam Howatt
2025-11-04 14:24:48 +01:00
committed by GitHub
parent a221927e10
commit 66dcd2335b
2 changed files with 46 additions and 3 deletions
@@ -65,8 +65,9 @@ LTDC layer to create the display for.
For the best visial results, ``optional_other_full_size_buffer`` should be used
if enough memory is available. Single-buffered mode is what you should use
if memory is very scarce. If there is almost enough memory for double-buffered
direct mode, but not quite, then use partial render mode.
if memory is very scarce. Chips with a CPU data cache have unavoidable visual
artifacts when using single-buffered direct mode. If there is almost enough
memory for double-buffered direct mode, but not quite, then use partial render mode.
To clarify what ``my_ltdc_framebuffer_address`` exactly is, it's the value of
``pLayerCfg.FBStartAdress`` when the LTDC layer is configured using the STM32 HAL,
@@ -118,6 +119,26 @@ the display width is 800, the display height is 480, and ``1K`` means 1024 bytes
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 4096K
}
If the framebuffer is not reserved in the linker script or the framebuffer is not set during
board initialization, you may absolutely set it at runtime before creating the LVGL display.
.. code-block:: c
/* like this */
HAL_LTDC_SetAddress(&hltdc, (uint32_t)my_ltdc_framebuffer_address, my_ltdc_layer_index);
/* and then... */
lv_display_t * disp;
disp = lv_st_ltdc_create_direct(my_ltdc_framebuffer_address,
optional_other_full_size_buffer,
my_ltdc_layer_index);
/* or */
disp = lv_st_ltdc_create_partial(partial_buf1,
optional_partial_buf2,
partial_buf_size,
my_ltdc_layer_index);
Display Rotation
****************
+23 -1
View File
@@ -49,6 +49,7 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m
static void flush_wait_cb(lv_display_t * disp);
static lv_color_format_t get_lv_cf_from_layer_cf(uint32_t cf);
static void reload_event_callback(LTDC_HandleTypeDef * hltdc);
static void clean_dcache(void);
#if LV_ST_LTDC_USE_DMA2D_FLUSH
static void transfer_complete_callback(DMA2D_HandleTypeDef * hdma2d);
@@ -144,7 +145,15 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m
g_data.disp_flushed_in_flush_cb[layer_idx] = false;
if(disp->render_mode == LV_DISPLAY_RENDER_MODE_DIRECT) {
if(lv_display_is_double_buffered(disp) && lv_display_flush_is_last(disp)) {
bool flush_is_last = lv_display_flush_is_last(disp);
if(flush_is_last) {
/* there is no ideal time to clean the cache (if present)
for **single-buffered** direct mode because the active buffer is drawn to
while LTDC is scanning it. Clean it in the last flush, at least,
but not every flush because it's expensive for not much visual improvement. */
clean_dcache();
}
if(flush_is_last && lv_display_is_double_buffered(disp)) {
HAL_LTDC_SetAddress_NoReload(&hltdc, (uint32_t)px_map, layer_idx);
g_data.layer_interrupt_is_owned[layer_idx] = true;
HAL_LTDC_Reload(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING);
@@ -172,6 +181,8 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
if(rotation == LV_DISPLAY_ROTATION_0) {
#if LV_ST_LTDC_USE_DMA2D_FLUSH
clean_dcache();
uint32_t dma2d_input_cf = get_dma2d_input_cf_from_lv_cf(cf);
uint32_t dma2d_output_cf = get_dma2d_output_cf_from_layer_cf(layer_cfg->PixelFormat);
@@ -194,12 +205,14 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m
fb_p += fb_stride;
px_map_p += area_stride;
}
clean_dcache();
g_data.disp_flushed_in_flush_cb[layer_idx] = true;
#endif
}
else {
uint32_t area_stride = px_size * area_width;
lv_draw_sw_rotate(px_map, first_pixel, area_width, area_height, area_stride, fb_stride, rotation, cf);
clean_dcache();
g_data.disp_flushed_in_flush_cb[layer_idx] = true;
}
}
@@ -242,6 +255,15 @@ static void reload_event_callback(LTDC_HandleTypeDef * hltdc)
}
}
static void clean_dcache(void)
{
#if defined(__CORTEX_M) && __CORTEX_M == 7
SCB_CleanDCache();
#elif defined(__CORTEX_A) && __CORTEX_A == 7
L1C_CleanDCacheAll();
#endif
}
#if LV_ST_LTDC_USE_DMA2D_FLUSH
static void transfer_complete_callback(DMA2D_HandleTypeDef * hdma2d)
{