4、串口DMA接收原理:RXNE标志与DMA请求的关系,接收溢出与处理策略

在串口DMA接收系统中,理解硬件层面的标志位与DMA请求之间的协同关系,是设计可靠双缓冲机制的前提。本章深入剖析RXNE(Receive Not Empty)标志如何触发DMA请求、数据如何从移位寄存器搬运到内存,以及当数据到达速度超过DMA处理能力时,如何检测并恢复溢出错误。

4.1 RXNE标志与DMA请求的硬件联动

USART外设内部包含一个接收移位寄存器(RDR)和一个接收数据寄存器(DR)。当一帧数据(通常为8位或9位)在移位寄存器中完成同步采样后,硬件自动将数据并行加载到DR中,同时置位RXNE标志。

RXNE标志的置位会触发两种行为:

  • 中断请求:若USART_CR1寄存器中的RXNEIE位被使能,则产生USART中断,CPU需在中断服务程序中读取DR以清除RXNE。
  • DMA请求:若USART_CR3寄存器中的DMAR(DMA接收使能)位被置1,则RXNE置位会向DMA控制器发送一个单次传输请求。
关键概念:RXNE标志是USART外设向DMA控制器发出的“数据已就绪”信号。DMA控制器在响应此请求后,执行一次从USART_DR寄存器到内存地址的搬运,搬运完成后DMA自动清除RXNE标志(无需软件干预)。

下图展示了从串行数据到达至DMA搬运完成的完整硬件流水线:

RXNE与DMA请求硬件流水线 RXNE → DMA请求 → 内存搬运 硬件流水线 串行数据 RX引脚电平采样 移位寄存器 RDR(数据同步) 数据寄存器 DR RXNE = 1 DMA请求发出 DMA控制器 DR → 内存缓冲区 DMA传输完成 → 自动清除RXNE

4.2 DMA请求的触发条件与传输粒度

DMA请求并非持续有效,而是遵循严格的触发-响应-清除周期:

阶段 USART状态 DMA请求线状态 说明
空闲 RXNE = 0,DR为空 无效(低电平) 无数据到达,DMA不动作
数据到达 RXNE = 1,DR有数据 有效(高电平) DMA控制器检测到请求,准备传输
DMA响应 DMA读取DR,RXNE自动清零 变为无效 单次传输完成,等待下一帧
溢出风险 RXNE仍为1,新数据到达 请求持续有效但数据被覆盖 ORE标志置位,需软件处理
工程经验:DMA传输的粒度是单字节。每收到一个字节,DMA就搬运一个字节。这与DMA的“块传输”或“突发传输”模式不同——串口DMA接收天然是单次请求-单次响应模式,直到DMA传输计数器(CNDTR)递减至0时才会触发传输完成中断。

4.3 接收溢出(ORE)的产生机制

溢出错误(OverRun Error,ORE)是串口DMA接收中最常见且最隐蔽的错误之一。其产生条件为:

  1. RXNE = 1:DR中已有数据等待DMA搬运。
  2. 新帧到达:移位寄存器完成下一帧数据的采样。
  3. 硬件冲突:新数据无法加载到DR(因为DR尚未被读取),导致移位寄存器中的数据被覆盖。

此时,USART_SR寄存器中的ORE标志位被硬件置位。如果ORE中断被使能(USART_CR3中的EIE位),则会触发中断;否则,错误仅体现在标志位上。

注意:ORE标志置位后,USART外设会停止接收后续数据,直到软件清除ORE标志。这意味着如果溢出处理不及时,后续所有数据都将丢失。在DMA模式下,DMA请求也会因RXNE无法被清除而停止。

下图展示了溢出发生的时序:

接收溢出时序图 ORE溢出错误产生时序 T0 T1 T2 T3 帧1到达 帧2到达 RXNE: 1(等待DMA) 1(DMA未响应) 1(ORE置位) ORE: 0(正常) 1(溢出) DMA未及时读取DR 新帧覆盖旧帧 数据丢失!

4.4 溢出处理策略

针对DMA接收中的ORE错误,嵌入式系统通常采用以下三种策略:

策略 实现方式 优点 缺点
中断轮询清除 使能USART错误中断(EIE),在中断中读取SR和DR清除ORE 响应快,错误恢复及时 增加中断开销,可能嵌套
DMA循环模式+软件检测 DMA配置为循环模式,软件通过比较缓冲区写入位置检测溢出 无需中断,CPU负载低 无法检测单次溢出,仅能发现连续丢失
双缓冲乒乓切换 两个缓冲区交替使用,DMA传输完成中断中切换目标地址 从根本上避免溢出(缓冲区始终有空位) 需要合理配置缓冲区大小和切换频率
推荐做法:在乒乓操作设计中,建议同时使能USART的错误中断(EIE)作为安全网。即使双缓冲机制因突发大数据量而出现短暂的DMA响应延迟,ORE中断也能及时介入,清除错误并重新同步,避免数据流永久中断。

4.5 ORE清除的软件流程

当检测到ORE标志时,正确的清除序列为:

  1. 读取USART_SR寄存器:获取当前状态,确认ORE位为1。
  2. 读取USART_DR寄存器:读取DR中的数据(即使已无效),此操作会硬件清除ORE标志。
  3. 重新使能DMA:如果DMA通道因溢出而暂停,需重新配置DMA的CNDTR寄存器并重新使能通道。
  4. 重置缓冲区指针:根据设计,可能需要丢弃当前缓冲区中的部分数据,重置写入索引。
// HAL库中ORE中断处理示例
void USART1_IRQHandler(void)
{
    uint32_t isrflags = READ_REG(huart1.Instance->SR);
    
    // 检查溢出错误
    if ((isrflags & USART_SR_ORE) != RESET)
    {
        // 步骤1:读取SR(已读取)
        // 步骤2:读取DR以清除ORE
        volatile uint32_t tmp = READ_REG(huart1.Instance->DR);
        (void)tmp;  // 防止编译器警告
        
        // 步骤3:重新启动DMA接收
        HAL_UART_AbortReceive(&huart1);
        HAL_UART_Receive_DMA(&huart1, g_dma_rx_buf, BUF_SIZE);
        
        // 步骤4:记录错误计数
        g_overflow_count++;
        
        // 可选:通知上层协议栈
        // protocol_notify_overflow();
    }
    
    // 其他中断处理...
}
优化技巧:在高速通信(如1Mbps以上)中,建议将ORE中断优先级设置为高于DMA传输完成中断。这样即使DMA正在处理传输完成回调,ORE中断也能立即抢占并清除错误,防止连续溢出导致数据雪崩。

4.6 乒乓操作中的溢出防护设计

在双缓冲乒乓架构中,溢出防护的核心思想是:确保DMA始终有一个空的缓冲区可供写入。具体措施包括:

  • 缓冲区大小匹配:单个缓冲区容量应大于最大预期帧长,通常设置为最大帧长的2倍。
  • 切换时机优化:在DMA传输完成一半(HT)和完全完成(TC)时均触发中断,实现更细粒度的切换控制。
  • 看门狗计数器:在DMA传输完成中断中检查时间戳,若两次中断间隔超过阈值,则认为可能发生溢出,主动复位DMA通道。

下图展示了乒乓操作中防止溢出的缓冲区切换逻辑:

乒乓操作溢出防护切换逻辑 乒乓双缓冲溢出防护切换逻辑 缓冲区 A DMA当前写入目标 写入指针持续递增 缓冲区 B 应用程序处理中 读取指针追赶写入 TC中断触发 状态:写入中(未满) 状态:处理中(已腾空) 关键:切换前确保目标缓冲区已处理完毕 若B未处理完,则等待或丢弃旧数据,防止DMA写入冲突
常见陷阱:不要依赖DMA的“自动循环模式”来防止溢出。循环模式虽然会自动重置地址,但如果应用程序处理速度跟不上DMA写入速度,旧数据会被新数据覆盖,且没有任何错误标志。乒乓操作配合显式的缓冲区切换和状态检查,才是可靠的溢出防护方案。