fix(UART_ReceptionToIdle_CircularDMA): wrap old_pos to fix silent data loss#204
fix(UART_ReceptionToIdle_CircularDMA): wrap old_pos to fix silent data loss#20494xhn wants to merge 1 commit into
Conversation
…a loss HAL_UARTEx_RxEventCallback() tracks the last-processed position in the circular DMA Rx buffer via old_pos, and compares it against Size to detect whether new data has arrived (`if (Size != old_pos)`). On a Transfer Complete event (a full circular buffer), the HAL reports Size == huart->RxXferSize == RX_BUFFER_SIZE, not a wrapped 0 (confirmed in stm32f4xx_hal_uart.c's UART_DMAReceiveCplt(), which calls HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize) for HAL_UART_RECEPTION_TOIDLE mode). Since old_pos was previously set to `old_pos = Size;` unwrapped, after one full-buffer cycle old_pos is left at RX_BUFFER_SIZE. On every subsequent full-buffer Transfer Complete event, Size == old_pos == RX_BUFFER_SIZE, so the `Size != old_pos` check spuriously evaluates false and the entire buffer's worth of newly received data is silently dropped without calling UserDataTreatment(). Wrap old_pos with `% RX_BUFFER_SIZE` so it stays a valid index into aRXBufferUser, matching the actual wrapped position. Fixes STMicroelectronics#196 Signed-off-by: 94xhn <87560781+94xhn@users.noreply.github.com>
|
Hello @94xhn, Thank you for the report. After checking the example behavior against the readme and running a few tests, the current implementation is aligned with the intended use case of this example. As described in the readme, the example handles received data through these notifications. For instance, with a 20-byte buffer and 22 received bytes, the documented callback sequence is: Therefore, in the intended configuration of this example, repeated full-buffer The case described in the PR corresponds to a customized event sequence compared to the one documented and demonstrated by this example. For the example as provided, with HT, TC, and IDLE notifications enabled as described in the readme, no change is required. Please allow me to close the PR. Thank you for your understanding. With regards, |
Relates to #196 (closed for inactivity, but the underlying issue is still present in current
main.c).Problem
In
HAL_UARTEx_RxEventCallback(),old_postracks the last-processed position in the circular DMA Rx buffer, compared against the HAL-reportedSizeto detect new data:On a Transfer Complete event (buffer fills up exactly to
RX_BUFFER_SIZE), the HAL reportsSize == huart->RxXferSize == RX_BUFFER_SIZE, not a wrapped0. This is confirmed inDrivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c'sUART_DMAReceiveCplt():Since
old_pos = Size;stores this unwrapped, after one full-buffer cycleold_posis left atRX_BUFFER_SIZE. On every subsequent full-buffer Transfer Complete event,Size == old_pos == RX_BUFFER_SIZE, soSize != old_posspuriously evaluates false and an entire buffer's worth of newly received UART data is silently dropped —UserDataTreatment()is never called for it.This matches the original report in #196: "old_pos==RX_BUFFER_SIZE Size==RX_BUFFER_SIZE ... will break condition."
Fix
Wrap
old_poswith% RX_BUFFER_SIZEso it stays a valid index intoaRXBufferUser, matching the actual wrapped position (this is also the fix originally suggested in #196).Test plan
No hardware on hand to reproduce end-to-end, so I verified with a standalone C reproduction of the callback's exact state-machine logic (comparing before/after over 3 consecutive full-buffer Transfer Complete events, each reporting
Size == RX_BUFFER_SIZE):UserDataTreatment()is called only once (10/30 bytes processed) — cycles 2 and 3 are silently dropped, exactly reproducing the reported bug.UserDataTreatment()is called on all 3 cycles (30/30 bytes processed).Size % RX_BUFFER_SIZE == SizewhenSize < RX_BUFFER_SIZE.Disclosure
Generative AI (Claude) was used to help investigate this issue, implement, and verify this fix. All changes were reviewed by me before submission.