You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32 UART RX采用DMA模式:DMA未处理接收数据问题求助

STM32F030K6 UART DMA接收异常修复方案

问题背景

原有中断式UART接收代码正常运行,切换为DMA模式后,UART可接收字符(RDR寄存器存有效数据且RXNE位置位),但DMA未处理接收数据,CNDTR寄存器值无递减。使用硬件为STM32F030K6,UART1搭配DMA1_CHANNEL5,当前DMA配置代码如下:

__HAL_RCC_DMA1_CLK_ENABLE();

DMA_CHANNEL->CCR &= ~(1 << DMA_CCR_EN_Pos);

// Set up the DMA configuration
// MEM2MEM 0 - disabled
// PINC = disabled
// TC interrupt disabled
// TE interrupt disbled
DMA_CHANNEL->CCR =
         (1 << DMA_CCR_PL_Pos)          // Medium priority
        | (0 << DMA_CCR_MSIZE_Pos)      // 8 bits
        | (0 << DMA_CCR_PSIZE_Pos)      // 8 bits
        | (1 << DMA_CCR_MINC_Pos)       // Memory increment
        | (0 << DMA_CCR_DIR_Pos)        // Peripheral to memory
        | (1 << DMA_CCR_CIRC_Pos);      // Circular buffer

  // Start the DMA
  DMA_CHANNEL->CCR &= ~(1 << DMA_CCR_EN_Pos); 
  DMA_CHANNEL->CPAR = (uint32_t) (&USART1->RDR);
  DMA_CHANNEL->CMAR = (uint32_t) (ring);
  DMA_CHANNEL->CNDTR = RING_BUFFER_SIZE;
  DMA_CHANNEL->CCR |= (1 << DMA_CCR_EN_Pos);

  // Route UART receive to DMA
  USART1->CR3 |= USART_CR3_DMAR;

必要修改与检查项

  • 配置DMA通道请求映射:STM32F030的DMA请求映射由DMA1->CSELR寄存器控制,DMA1_CHANNEL5需映射到UART1_RX请求源,添加以下代码:
    DMA1->CSELR &= ~DMA_CSELR_C5S_Msk; // 清除通道5原有请求映射
    DMA1->CSELR |= DMA_CSELR_C5S_0;    // 将通道5映射到UART1_RX(请求源编码001)
    
  • 清除UART RXNE标志:当前RXNE已置位,DMA不会触发新传输,需手动清除该标志后再启动DMA,在启用DMA通道前添加:
    (void)USART1->RDR; // 读取RDR寄存器清除RXNE标志
    
  • 优化DMA配置顺序:移除重复的通道关闭操作,保持"关闭通道→配置参数→设置地址与长度→清除UART标志→启用通道"的顺序
  • 确认UART接收使能:确保UART1的接收功能已开启(冗余但避免误操作),添加:
    USART1->CR1 |= USART_CR1_RE;
    

修正后的完整配置代码

__HAL_RCC_DMA1_CLK_ENABLE();

// 配置DMA通道请求映射(关键步骤)
DMA1->CSELR &= ~DMA_CSELR_C5S_Msk;
DMA1->CSELR |= DMA_CSELR_C5S_0;

// 关闭DMA通道以配置参数
DMA_CHANNEL->CCR &= ~(1 << DMA_CCR_EN_Pos);

// 设置DMA核心参数
DMA_CHANNEL->CCR =
         (1 << DMA_CCR_PL_Pos)          // 中等优先级
        | (0 << DMA_CCR_MSIZE_Pos)      // 内存数据宽度8位
        | (0 << DMA_CCR_PSIZE_Pos)      // 外设数据宽度8位
        | (1 << DMA_CCR_MINC_Pos)       // 内存地址自增
        | (0 << DMA_CCR_DIR_Pos)        // 外设到内存方向
        | (1 << DMA_CCR_CIRC_Pos);      // 循环模式开启

// 设置外设、内存地址及传输长度
DMA_CHANNEL->CPAR = (uint32_t)(&USART1->RDR);
DMA_CHANNEL->CMAR = (uint32_t)(ring);
DMA_CHANNEL->CNDTR = RING_BUFFER_SIZE;

// 清除UART RXNE标志,避免阻塞DMA触发
(void)USART1->RDR;

// 启用DMA通道
DMA_CHANNEL->CCR |= (1 << DMA_CCR_EN_Pos);

// 开启UART DMA接收模式
USART1->CR3 |= USART_CR3_DMAR;

// 确保UART接收功能开启
USART1->CR1 |= USART_CR1_RE;

内容的提问来源于stack exchange,提问作者JavaLatte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:45:20