A drop-in solution for STM32F4 + HAL that receives variable-length UART data reliably
Here’s a drop-in solution for STM32F4 + HAL that receives variable-length UART data reliably. I’m giving you two production-proven patterns:
-
Delimiter framing (e.g.,
\n
) using an ISR ring buffer (simple, great for text/AT commands) -
DMA circular + IDLE line (best for bursts/binary streams; minimal CPU)
Both work on F4 (F401/F405/F407/F411, etc.) with CubeMX/HAL.
A) Delimiter framing (\n
) with ISR ring buffer
1) CubeMX setup
-
Enable USARTx (e.g., USART1 @ 115200 8N1)
-
Enable RXNE interrupt
-
Configure GPIO pins (Tx/Rx AF)
-
NVIC: set a sensible priority (e.g., preempt 5, sub 0 if using FreeRTOS)
2) Ring buffer + IRQ handler
3) Delimiter parser (non-blocking)
4) Usage (in main.c
)
Pros: dead simple; ideal for ASCII/AT commands.
Cons: payload can’t contain the delimiter; use escaping if needed.
B) DMA circular + IDLE line (variable length without delimiter)
This is the go-to for binary packets or bursts. The UART sets IDLE when the line is idle for ~1 frame; we then consume the newly arrived DMA bytes as a “frame”. Layer a length/CRC on top if needed.
1) CubeMX setup
-
USARTx enabled
-
DMA for RX:
-
Mode: Circular
-
Memory increment: Enabled
-
Peripheral increment: Disabled
-
Data alignment: Byte
-
-
Enable UART global interrupt and IDLE interrupt:
-
In user code after
MX_USARTx_UART_Init()
:__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
-
-
NVIC priority set appropriately
2) Code
3) Usage
Pros: handles arbitrary lengths and binary safely, minimal CPU, no byte-by-byte ISRs.
Cons: you still need a packet format for integrity (length + CRC) if noise is possible.
Optional: length-prefixed + CRC on top (robust binary)
If your sender uses [SYNC=0xAA][LEN][PAYLOAD...][CRC8]
, replace on_idle_event()
with a small state machine that parses the accumulated frame_acc[0..frame_len-1]
into valid packets (resync on errors). This gives you exact message boundaries even if the line doesn’t idle cleanly.
Practical tips (STM32F4)
-
Clock accuracy: Use HSE (or good HSI trimming) for higher baud rates.
-
Buffers: Size DMA/RB for worst bursts (baud × burst_time / 10 bits).
-
Flow control: If the peer can flood you, enable RTS/CTS in CubeMX.
-
Priorities: If using FreeRTOS, keep UART/DMAs at higher priority than tasks.
-
Latency: With DMA+IDLE, your latency ≈ 1 frame time (e.g., ~1 char).
-
Testing: Fuzz with random lengths/delimiters; inject pauses to ensure IDLE framing works as expected.
评论
发表评论