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
相关产品推荐
相关产品推荐

