九、UART 错误恢复流程
CommTask 的 app_main_consume_uart_recovery_flags() 消费来自 ISR 的位图(HAL_UART_ErrorCallback 在中断中设置 s_uart_recovery_needed)。三种错误类型:overrun error(溢出)、noise error(噪声)、framing error(帧错误)。
flowchart TB
subgraph ISR[ISR 中断]
I1[UART RX]
I2[设置任务通知位图]
end
subgraph COMM[CommTask]
C1[等待通知]
C2[解析帧]
C3[分发到 ProtoTask]
end
subgraph PROTO[ProtoTask]
P1[协议处理]
P2[响应发送]
end
ISR -->|通知| COMM --> PROTO
style ISR fill:transparent,stroke:#8dc7ff,color:#eaf4ff
style COMM fill:transparent,stroke:#8dc7ff,color:#eaf4ff
style PROTO fill:transparent,stroke:#8dc7ff,color:#eaf4ff恢复调用链:HAL_UART_ErrorCallback (ISR) → set bit in s_uart_recovery_needed → CommTask → app_main_consume_uart_recovery_flags() → bsp_uart_port_rx_restart()。
bsp_uart_port_rx_restart() 执行:tail=0, started=0, 清零 DMA 缓冲 → HAL_UART_Receive_DMA() 重新启动。注意:正在进行的 TX DMA 不受影响,只重启 RX。
| 错误码 | 类型 | 恢复动作 |
|---|---|---|
| HAL_UART_ERROR_ORE | Overrun (溢出) | 重启 RX DMA,丢弃溢出字节 |
| HAL_UART_ERROR_NE | Noise (噪声) | 重启 RX DMA |
| HAL_UART_ERROR_FE | Framing (帧错误) | 重启 RX DMA |
十、TX DMA 续传机制
bsp_uart_start_tx_dma() 每端口检查:busy==0 && 队列非空 → 最多复制 64 字节到线性 dma_buf → HAL_UART_Transmit_DMA()。
DMA 完成回调(ISR)只做两件事:busy=0, kick_pending=1。下一周期 bsp_uart_task_once() 在任务上下文中启动下一段 DMA。这避免了 HAL_UART_Transmit_DMA() 的重入问题(嵌套调用返回 HAL_BUSY)。
完整的发送生命周期 ASCII 图:
Task 写队列 → DMA 发送第一段 → ISR 清标志 → bsp_uart_task_once 启动下一段 → ... → 队列空
TX 队列 (RingBuf)
│
▼ (bsp_uart_port_transmit 写入)
┌─────────────┐
│ 队列非空? │ ← bsp_uart_start_tx_dma 检查
└──────┬──────┘
│ yes
▼
┌─────────────────────┐
│ 复制 ≤64B → dma_buf │
│ HAL_UART_Transmit_DMA│
└──────────┬──────────┘
│
▼ (DMA 传输完成)
┌─────────────────────┐
│ ISR: busy=0 │
│ kick_pending=1 │
└──────────┬──────────┘
│
▼ (下一周期 bsp_uart_task_once)
┌─────────────────────┐
│ 队列空? → 结束 │
│ 非空 → 启动下一段 │
└─────────────────────┘
十一、整包入队原子性保证
bsp_uart_port_transmit() 在入队任何字节前等待直到整个数据包能放进 TX 队列。防止半帧交织。
// 等待直到队列有足够空间容纳整包
while (ringbuf_available(tx_queue) < len) {
// 让出 CPU,等待 DMA 消费
taskYIELD();
}
// 整包一次性入队
ringbuf_write(tx_queue, data, len);
// 触发发送
bsp_uart_start_tx_dma(port);
Comments NOTHING