如何利用DMAMUX生成事件触发另一DMA请求?STM32L4配置排查
STM32L4 DMAMUX配置排查:UART DMA触发定时器CNT传输失效
需求说明
通过DMA向LPUART发送数据,每完成3次传输后,无需CPU参与,自动触发另一DMA请求,将TIM15的CNT寄存器数据传输至内存。
问题描述
LPUART的DMA数据传输正常,但DMAMUX通道1未接收到触发事件,无法启动定时器CNT到内存的DMA传输。
代码示例(原配置)
DMA1_Channel2 -> CNDTR = 10; DMA1_Channel2 -> CPAR = (uint32_t)&TIM15 -> CNT; DMA1_Channel2 -> CMAR = (uint32_t)data16; DMA1_Channel1 -> CNDTR = 6; DMA1_Channel1 -> CMAR = (uint32_t)data; DMA1_Channel1 -> CPAR = (uint32_t)&LPUART1 -> TDR; DMAMUX1_Channel0 -> CCR = DMA_REQUEST_LPUART1_TX | DMAMUX_CxCR_EGE | (2 << DMAMUX_CxCR_NBREQ_Pos); DMAMUX1_Channel1 -> CCR = DMA_REQUEST_GENERATOR0; DMAMUX1_RequestGenerator0 -> RGCR = DMAMUX_RGxCR_GPOL_Msk | (0 << DMAMUX_RGxCR_GNBREQ_Pos); DMAMUX1_RequestGenerator0 -> RGCR |= DMAMUX_RGxCR_GE; DMA1_Channel1 -> CCR |= DMA_CCR_EN; DMA1_Channel2 -> CCR |= DMA_CCR_EN; LPUART1 -> CR3 |= USART_CR3_DMAT;
方案可行性确认
该方案完全可行。STM32L4的DMAMUX支持通道事件触发请求发生器的功能:当UART的DMA通道完成指定次数传输后,DMAMUX通道生成事件,触发请求发生器输出DMA请求,进而启动定时器CNT到内存的DMA传输,全程无需CPU介入,符合需求。
配置错误排查与修正
1. 请求发生器未关联通道0的触发事件
原代码中,DMAMUX通道0已开启事件生成(DMAMUX_CxCR_EGE),但未配置请求发生器0的触发源为通道0的事件。需在DMAMUX1_RequestGenerator0->RGCR中添加GSEL字段配置,指定触发源为DMAMUX通道0的事件(GSEL=0x0对应通道0事件)。
2. DMA通道2传输方向错误
定时器CNT到内存的传输属于外设到内存,但DMA通道2的DIR位默认是0(内存到外设),需手动置位DMA_CCR_DIR修正方向。
3. 缺失必要的DMA地址递增与数据宽度配置
若需要连续存储TIM15_CNT数据到内存,需开启DMA通道2的内存地址递增(DMA_CCR_MINC);同时TIM_CNT为16位寄存器,需匹配DMA的外设/内存数据宽度。UART_TX的DMA通道1也需开启内存地址递增,确保每次传输下一个字节。
修正后的代码
// 配置DMA通道2:TIM15_CNT -> 内存(外设到内存) DMA1_Channel2->CNDTR = 10; DMA1_Channel2->CPAR = (uint32_t)&TIM15->CNT; DMA1_Channel2->CMAR = (uint32_t)data16; DMA1_Channel2->CCR |= DMA_CCR_DIR; // 设置外设到内存方向 DMA1_Channel2->CCR |= DMA_CCR_MINC; // 内存地址递增(连续存储时启用) DMA1_Channel2->CCR |= DMA_CCR_PSIZE_0; // 外设数据宽度16位(匹配TIM_CNT) DMA1_Channel2->CCR |= DMA_CCR_MSIZE_0; // 内存数据宽度16位 // 配置DMA通道1:内存 -> LPUART1_TDR(内存到外设) DMA1_Channel1->CNDTR = 6; DMA1_Channel1->CMAR = (uint32_t)data; DMA1_Channel1->CPAR = (uint32_t)&LPUART1->TDR; DMA1_Channel1->CCR |= DMA_CCR_DIR; // 设置内存到外设方向 DMA1_Channel1->CCR |= DMA_CCR_MINC; // 内存地址递增 // 配置DMAMUX通道0:LPUART1_TX请求,完成3次传输后生成事件 DMAMUX1_Channel0->CCR = DMA_REQUEST_LPUART1_TX | DMAMUX_CxCR_EGE | (2 << DMAMUX_CxCR_NBREQ_Pos); // NBREQ=2 → 3次请求后生成事件 // 配置DMAMUX请求发生器0:触发源为通道0事件,每次触发生成1次DMA请求 DMAMUX1_RequestGenerator0->RGCR = (0x0 << DMAMUX_RGxCR_GSEL_Pos) // 选择通道0事件为触发源 | DMAMUX_RGxCR_GPOL_Msk // 事件极性(根据需求调整) | (0 << DMAMUX_RGxCR_GNBREQ_Pos) // 每次触发生成1次请求 | DMAMUX_RGxCR_GE; // 使能请求发生器 // 配置DMAMUX通道1:请求源为请求发生器0 DMAMUX1_Channel1->CCR = DMA_REQUEST_GENERATOR0; // 使能DMA通道与UART DMA功能 DMA1_Channel1->CCR |= DMA_CCR_EN; DMA1_Channel2->CCR |= DMA_CCR_EN; LPUART1->CR3 |= USART_CR3_DMAT;
参考手册核心要点(RM0432第396页起)
DMAMUX(DMA多路复用器)负责将外设/软件请求路由到DMA通道,同时提供请求发生器模块,支持通过内部/外部事件触发生成DMA请求:
- 通道事件生成:当通道的
EGE位置1时,每完成NBREQ+1次DMA请求后,通道会生成一个事件信号。- 请求发生器配置:通过
RGCR寄存器选择触发源(如DMAMUX通道事件)、设置触发极性(GPOL)、指定单次触发生成的请求次数(GNBREQ+1),并通过GE位使能。- DMA通道请求源:DMAMUX通道的
CCR寄存器通过DMA_REQUEST_x字段选择请求源,可指定外设请求或请求发生器输出。
内容的提问来源于stack exchange,提问作者gulpr
相关产品推荐
相关产品推荐

