Skip to content

Commit bd69995

Browse files
committed
fixed dma2d
1 parent 8985a66 commit bd69995

3 files changed

Lines changed: 22 additions & 69 deletions

File tree

DASH/Drivers/hal_stm_lvgl/screen_driver.c

Lines changed: 20 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
#define LCD_SCREEN_WIDTH 800 // Actual screen width in landscape mode
1717
#define LCD_SCREEN_HEIGHT 480 // Actual screen height in landscape mode
1818
#define FRAMEBUFFER_SIZE (uint32_t)(LCD_SCREEN_HEIGHT * LCD_SCREEN_WIDTH)
19-
#define DMA_XFERS_NEEDED \
20-
FRAMEBUFFER_SIZE / 2 // We need half as many transfers because the buffer is an array of
21-
// 16 bits but the transfers are 32 bits.
19+
20+
#define DRAW_BUF_LINES 48
21+
#define DRAW_BUF_SIZE (uint32_t)(LCD_SCREEN_WIDTH * DRAW_BUF_LINES)
2222

2323
/*
2424
* Handles to peripherals
@@ -31,23 +31,19 @@ extern DMA2D_HandleTypeDef hdma2d;
3131
* Global variables
3232
*/
3333
lv_disp_drv_t lv_display_driver;
34-
__attribute__((section(".framebuffer"))) lv_color_t screen_buffer[FRAMEBUFFER_SIZE];
35-
__attribute__((section(".framebuffer"))) lv_color_t framebuffer_1[FRAMEBUFFER_SIZE];
34+
__attribute__((section(".framebuffer"))) lv_color_t screen_buffer[FRAMEBUFFER_SIZE]; // LTDC scans this
35+
__attribute__((section(".framebuffer"))) lv_color_t draw_buf_1[DRAW_BUF_SIZE]; // LVGL render buffer A
36+
__attribute__((section(".framebuffer"))) lv_color_t draw_buf_2[DRAW_BUF_SIZE]; // LVGL render buffer B
3637

3738
#define FRAMEBUFFER_ADDR ((uint32_t)0xC0000000)
3839

40+
// The flush in progress: saved so the DMA2D transfer-complete IRQ can release LVGL.
3941
static lv_disp_drv_t *flush_disp_drv;
40-
static lv_disp_t *flush_disp;
41-
static uint32_t flush_src;
42-
static uint32_t flush_dst;
43-
static uint16_t flush_area_idx;
4442

4543
/*
4644
* Private functions prototypes
4745
*/
4846
void stm32_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
49-
static void dma2d_start_area_it(lv_area_t area, uint32_t src_buffer, uint32_t dst_buffer);
50-
static void dma2d_flush_next_area(void);
5147
static void dma2d_xfer_cplt(DMA2D_HandleTypeDef *h);
5248
static void dma2d_xfer_error(DMA2D_HandleTypeDef *h);
5349

@@ -97,7 +93,7 @@ void screen_driver_init(void)
9793

9894
/* ---- LVGL init ---- */
9995
static lv_disp_draw_buf_t draw_buf;
100-
lv_disp_draw_buf_init(&draw_buf, framebuffer_1, screen_buffer, FRAMEBUFFER_SIZE);
96+
lv_disp_draw_buf_init(&draw_buf, draw_buf_1, draw_buf_2, DRAW_BUF_SIZE);
10197

10298
lv_disp_drv_init(&lv_display_driver);
10399
lv_display_driver.hor_res = LCD_SCREEN_WIDTH;
@@ -113,76 +109,33 @@ void screen_driver_init(void)
113109
*/
114110
void stm32_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
115111
{
116-
lv_disp_t *disp = _lv_refr_get_disp_refreshing();
117-
if (!lv_disp_flush_is_last(disp_drv))
118-
{
119-
lv_disp_flush_ready(disp_drv);
120-
return;
121-
}
122-
123-
// Swap the buffer for the one to display and reload the screen at the next vertical blanking
124-
HAL_LTDC_SetAddress_NoReload(&hltdc, (uint32_t)color_p, 0);
125-
HAL_LTDC_Reload(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING); // VSYNC
126-
127-
// The just-rendered buffer (color_p) is now on screen; sync the dirty areas
128-
// back into the other buffer so it is coherent for the next frame. The copies
129-
// run on DMA2D in the background, chained one per transfer-complete IRQ; the
130-
// final one calls lv_disp_flush_ready() to release LVGL.
131-
flush_disp_drv = disp_drv;
132-
flush_disp = disp;
133-
flush_src = (uint32_t)color_p;
134-
flush_dst = (color_p == screen_buffer) ? (uint32_t)framebuffer_1 : (uint32_t)screen_buffer;
135-
flush_area_idx = 0;
136-
dma2d_flush_next_area();
137-
}
138-
139-
// Start an interrupt-driven DMA2D copy of the next non-joined dirty area. When
140-
// no areas remain, release LVGL. Runs in task context for the first area and in
141-
// DMA2D IRQ context for the rest.
142-
static void dma2d_flush_next_area(void)
143-
{
144-
while (flush_area_idx < flush_disp->inv_p)
145-
{
146-
uint16_t i = flush_area_idx++;
147-
// Skip areas that were joined into another (and thus already copied)
148-
if (!flush_disp->inv_area_joined[i])
149-
{
150-
dma2d_start_area_it(flush_disp->inv_areas[i], flush_src, flush_dst);
151-
return; // wait for the transfer-complete IRQ to advance
152-
}
153-
}
154-
155-
// All dirty areas synced into the back buffer
156-
lv_disp_flush_ready(flush_disp_drv);
157-
}
112+
size_t area_width = 1 + area->x2 - area->x1;
113+
size_t area_height = 1 + area->y2 - area->y1;
114+
size_t dst_offset =
115+
(LCD_SCREEN_WIDTH * area->y1 + area->x1) * 2; // byte offset of the area's top-left in screen_buffer
158116

159-
static void dma2d_start_area_it(lv_area_t area, uint32_t src_buffer, uint32_t dst_buffer)
160-
{
161-
size_t start_offset =
162-
(LCD_SCREEN_WIDTH * (area.y1) + (area.x1)) * 2; // address offset (not pixel offset so it is multiplied by 2)
163-
size_t area_width = 1 + area.x2 - area.x1;
164-
size_t area_height = 1 + area.y2 - area.y1;
165-
size_t in_out_offset = LCD_SCREEN_WIDTH - area_width;
117+
flush_disp_drv = disp_drv;
166118

167-
// Set up DMA2D to transfer parts of picture to part of picture
168119
hdma2d.Init.Mode = DMA2D_M2M; // plain memory to memory
169120
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
170-
hdma2d.Init.OutputOffset = in_out_offset; // nb pixels in buffer between end of area line and start of next area line
121+
hdma2d.Init.OutputOffset = LCD_SCREEN_WIDTH - area_width; // skip to the start of the next screen row
171122
hdma2d.LayerCfg[DMA2D_FOREGROUND_LAYER].InputColorMode = DMA2D_INPUT_RGB565;
172-
hdma2d.LayerCfg[DMA2D_FOREGROUND_LAYER].InputOffset = in_out_offset;
123+
hdma2d.LayerCfg[DMA2D_FOREGROUND_LAYER].InputOffset = 0; // compact source: rows are contiguous
173124
hdma2d.LayerCfg[DMA2D_FOREGROUND_LAYER].AlphaMode = DMA2D_NO_MODIF_ALPHA;
174125
hdma2d.LayerCfg[DMA2D_FOREGROUND_LAYER].InputAlpha = 0;
175126

176127
HAL_DMA2D_Init(&hdma2d);
177128
HAL_DMA2D_ConfigLayer(&hdma2d, DMA2D_FOREGROUND_LAYER);
178-
HAL_DMA2D_Start_IT(&hdma2d, src_buffer + start_offset, dst_buffer + start_offset, area_width, area_height);
129+
// Copy runs on DMA2D in the background; dma2d_xfer_cplt() releases LVGL when done,
130+
// so LVGL can render the next chunk into the other draw buffer meanwhile.
131+
HAL_DMA2D_Start_IT(&hdma2d, (uint32_t)color_p, (uint32_t)screen_buffer + dst_offset, area_width, area_height);
179132
}
180133

181-
// DMA2D transfer-complete IRQ: kick off the next dirty area (or finish).
134+
// DMA2D transfer-complete IRQ: the chunk has been blitted, release the draw buffer.
182135
static void dma2d_xfer_cplt(DMA2D_HandleTypeDef *h)
183136
{
184137
(void)h;
185-
dma2d_flush_next_area();
138+
lv_disp_flush_ready(flush_disp_drv);
186139
}
187140

188141
// DMA2D error IRQ: give up on the remaining areas and release LVGL so the

DASH/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.7.10
1+
1.7.11

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.7.35
1+
1.7.36

0 commit comments

Comments
 (0)