ILI9341: 刷新改为 DMA+任务内同步等待,消除移动残留竞态
- 中断只置完成标志,等待/收尾/回调全部移到任务上下文 - 去掉 ISR 内 lv_disp_flush_ready、ISR 内 Abort、双重收尾等竞态 - flush 返回时该块像素必已完整写入,LVGL 不会提前复用缓冲 - 拉高 CS 前等待 SPI 移位排空,避免尾部像素被截断 - 传输 50ms 超时后重建 SPI 自恢复
This commit is contained in:
@@ -12,8 +12,8 @@ STM32H750 · SPI1 · DMA1_Stream2 · LVGL v8
|
||||
| 旧版问题 | 根因 | 新版做法 |
|
||||
|---|---|---|
|
||||
| 移动方块留下残影/线条 | `disp_flush()` 里做软件 90° 转置,坐标/尺寸与 LVGL 失效区域不严格一致,且多一层 `rot_buf→dma_buf` 拷贝 | **硬件旋转**:面板 MADCTL 直接设横屏,LVGL 坐标 = 面板坐标,刷新区与失效区严格 1:1,转置整段删除 |
|
||||
| 长时间运行白屏 | ① DMA 源缓冲可能被链接器放进 **DTCM**,而 DMA1 无法访问 DTCM;② 阻塞式信号量 + 出错 `Abort`,SPI 状态一乱就级联白屏 | ① 缓冲用 `.lcd_ram` 段**强制放入 AXI SRAM**;② 全异步 DMA,去掉信号量;出错回调 + 看门狗自恢复,单次异常不级联 |
|
||||
| 刷新与 CPU 抢时间 | flush_cb 阻塞等待传输完成 | flush_cb 启动 DMA 后**立即返回**,双缓冲边渲染边传,完成中断里 `lv_disp_flush_ready()` |
|
||||
| 长时间运行白屏 | ① DMA 源缓冲可能被链接器放进 **DTCM**,而 DMA1 无法访问 DTCM;② 阻塞式信号量 + 出错 `Abort`,SPI 状态一乱就级联白屏 | ① 缓冲用 `.lcd_ram` 段**强制放入 AXI SRAM**;② 传输超时后重建 SPI 自恢复,单次异常不级联 |
|
||||
| 刷新时序/竞态 | 中断里 `lv_disp_flush_ready`、ISR 内 `Abort`、完成被收尾两次等竞态,会丢失“擦除”写入 → 移动物体残留 | **DMA 加速 + 任务内同步等待**:中断只置完成标志,等待/收尾/回调全在任务里做;flush 返回时该块像素一定已完整写入,杜绝提前复用缓冲/擦除未写完 |
|
||||
| 字节序靠 CPU 逐像素交换 | `LV_COLOR_16_SWAP=0`,驱动里手工打包 | `LV_COLOR_16_SWAP=1`,LVGL 直接产出面板字节序,DMA 直接搬运 |
|
||||
|
||||
> 备注:旧 `ILI9341.h` 里关于 “CS=PB12 未配置为输出” 的警告是**过时的**——
|
||||
@@ -26,15 +26,17 @@ STM32H750 · SPI1 · DMA1_Stream2 · LVGL v8
|
||||
```
|
||||
LVGL 渲染 → buf_1/buf_2 (.lcd_ram, AXI SRAM, 32B 对齐)
|
||||
→ disp_flush() : 裁剪坐标,直接调 ILI9341_FlushArea_DMA()
|
||||
→ FlushArea_DMA : 设窗口(2A/2B/2C) → clean D-Cache → CS 低 → 启动 SPI DMA,立即返回
|
||||
→ [DMA 完成] SPI1 中断 → HAL_SPI_TxCpltCallback → CS 高 → lv_disp_flush_ready()
|
||||
→ [出错] HAL_SPI_ErrorCallback → Abort → 收尾 → flush_ready(不卡死)
|
||||
→ [兜底] 任务里 ILI9341_ServiceWatchdog(180) 超时中止+重建 SPI
|
||||
→ FlushArea_DMA : 设窗口(2A/2B/2C) → clean D-Cache → CS 低 → 启动 SPI DMA
|
||||
→ 任务内轮询等待 lcd_xfer_done(1~2ms,50ms 超时兜底)
|
||||
→ 等 SPI 移位排空 → CS 高 → done_cb(=lv_disp_flush_ready)
|
||||
→ [DMA 完成] SPI1 中断 → HAL_SPI_TxCpltCallback → 仅置 lcd_xfer_done=1
|
||||
→ [出错] HAL_SPI_ErrorCallback → 记录错误 + 置 lcd_xfer_done=1,任务侧恢复
|
||||
→ [兜底] 超时(或 ServiceWatchdog) → Abort + 重建 SPI
|
||||
```
|
||||
|
||||
关键不变量:任意时刻**至多一次 DMA 在途**(LVGL 在 `flush_ready` 前不会再次
|
||||
调用 `flush_cb`)。收尾函数 `LCD_FinishTransfer()` 在关中断临界区内“取回调+复位
|
||||
状态”,保证 `done_cb` 只被调用一次,杜绝 ISR 与看门狗竞争。
|
||||
关键不变量:`flush_cb` **返回时该块像素一定已完整写入面板**,LVGL 不会提前复用
|
||||
缓冲,“擦除”写入不会丢失。中断只做“置标志”一件事,不在中断里调用 LVGL、不在
|
||||
中断里 `Abort`,从根上消除竞态。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user