chore(color): reduce busy wait time on LCD refresh#7483
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughLTDC LCD refresh synchronization is split by build mode across all hardware targets: the ChangesLCD Flush Synchronization Refactor
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
tested on h7 hardware without issue I could spot |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
radio/src/targets/horus/lcd_driver.cpp (1)
169-193: 🩺 Stability & Availability | 🔴 CriticalDMA operations are asynchronous; data race when
lvglFlushed()is signaled mid-copy.
DMACopyBitmap()callsLL_DMA2D_Start()and returns immediately without waiting for the transfer to complete. In non-BOOT builds,_update_frame_buffer_addr()enablesLTDC_IT_LIbut skips the busy-wait, soLTDC_IRQHandlerfires at the next vertical blank—potentially while DMA2D is still writing to_back_buffer. When the IRQ callslvglFlushed(), it signals to LVGL that the refresh is complete before the DMA copy operations have actually finished, creating a data race on the buffer contents.Add
DMAWait()after the invalidation area loop (after line 192) to ensure all pending DMA transfers complete before the IRQ can fire.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@radio/src/targets/horus/lcd_driver.cpp` around lines 169 - 193, The issue is that `DMACopyBitmap()` initiates asynchronous DMA transfers but returns immediately, while the loop iterates through multiple invalidation areas and queues multiple DMA operations. The LTDC IRQ can fire before all DMA operations complete, causing `lvglFlushed()` to signal refresh completion while DMA is still writing to `_back_buffer`, creating a data race. After the for loop that processes `disp->inv_p` invalidation areas and calls `DMACopyBitmap()`, add a call to `DMAWait()` to ensure all pending DMA transfers finish before the IRQ handler fires and signals the buffer is ready.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@radio/src/targets/horus/lcd_driver.cpp`:
- Around line 169-193: The issue is that `DMACopyBitmap()` initiates
asynchronous DMA transfers but returns immediately, while the loop iterates
through multiple invalidation areas and queues multiple DMA operations. The LTDC
IRQ can fire before all DMA operations complete, causing `lvglFlushed()` to
signal refresh completion while DMA is still writing to `_back_buffer`, creating
a data race. After the for loop that processes `disp->inv_p` invalidation areas
and calls `DMACopyBitmap()`, add a call to `DMAWait()` to ensure all pending DMA
transfers finish before the IRQ handler fires and signals the buffer is ready.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 505ba5a8-533c-4f46-9efa-aa96027da32b
📒 Files selected for processing (18)
radio/src/boards/jumper-h750/lcd_driver.cppradio/src/boards/jumper-h750/lcd_driver.hradio/src/boards/rm-h750/lcd_driver_480.cppradio/src/boards/rm-h750/lcd_driver_480.hradio/src/boards/rm-h750/lcd_driver_800.cppradio/src/boards/rm-h750/lcd_driver_800.hradio/src/gui/colorlcd/lcd.cppradio/src/gui/colorlcd/lcd.hradio/src/gui/common/stdlcd/lcd_common.cppradio/src/gui/common/stdlcd/lcd_common.hradio/src/targets/horus/lcd_driver.cppradio/src/targets/horus/lcd_st7796s_driver.cppradio/src/targets/pa01/lcd_driver.cppradio/src/targets/pl18/lcd_driver.cppradio/src/targets/simu/simulib.cppradio/src/targets/st16/lcd_driver.cppradio/src/targets/stm32h7s78-dk/lcd_driver.cppradio/src/targets/taranis/board.h
💤 Files with no reviewable changes (2)
- radio/src/boards/rm-h750/lcd_driver_800.h
- radio/src/targets/taranis/board.h
|
Reverted to using busy wait loop for radios with inverted LCD. While the interrupt driven version works - it can result in some screen tearing while the inverted front buffer contents are being DMA copied to the back buffer. Interrupt version works on F4 radios with non-inverted LCD and H7 radios (except PA01). |
Version 2 - replacement for #7448.
Moved the call to tell LVGL that it can swap buffers and continue into the LDTC vertical refresh interrupt.
Seems to solves all the issues.
Tested widgets using lcd and lvgl API's with no issues.
This removes the busy wait loop completely in the firmware (still used in bootloader).
Note: PA01 does not have a vertical refresh interrupt so still uses a busy wait loop.
Summary by CodeRabbit