STM32F407如何配置DMA在外部信号每个下降沿触发?
问题:STM32F407 外部信号每个下降沿触发DMA读取GPIO
需求与异常现象
- 需求:在外部信号的每个下降沿通过DMA读取GPIO引脚
- 当前配置思路:将外部下降沿作为TIMER时钟源,设置PSC=0、ARR=0,通过定时器更新事件触发DMA请求
- 异常:
- PSC=0、ARR=0时,DMA无触发
- ARR=1时,每2个下降沿触发一次DMA
当前配置代码
DMA2_Stream5->NDTR = 20; DMA2_Stream5->M0AR = (uint32_t) &buffer[0]; DMA2_Stream5->PAR = (uint32_t) &GPIOB->IDR; DMA2_Stream5->CR = (6u << DMA_SxCR_CHSEL_Pos) | // 选择通道6(对应TIM1_UP请求) DMA_SxCR_MSIZE_1 | // 内存数据宽度32位 DMA_SxCR_PSIZE_1 | // 外设数据宽度32位 DMA_SxCR_MINC | // 内存地址递增 DMA_SxCR_EN | // 使能DMA流 DMA_SxCR_TCIE_Msk | // 开启传输完成中断 0; TIM1->DIER = TIM_DIER_UDE; // 使能更新事件DMA请求 TIM1->SMCR |= 1 << 15; // ETR信号极性反转(下降沿有效) TIM1->CR1 = TIM_CR1_CEN; // 使能TIM1
解决方案
问题核心是定时器未正确配置为外部时钟模式,导致计数器无法响应外部下降沿产生更新事件。需修改以下配置:
1. 正确配置定时器外部时钟源模式
将TIM1配置为外部时钟模式2,直接使用ETR引脚的外部信号作为时钟源,同时保留下降沿触发的极性设置:
// 配置SMCR:外部时钟模式2(SMS=011)+ ETR极性反转(下降沿有效) TIM1->SMCR = (3 << TIM_SMCR_SMS_Pos) | (1 << TIM_SMCR_ETRP_Pos);
2. 显式设置PSC和ARR为0
确保计数器在每个外部时钟沿都能溢出产生更新事件:
TIM1->PSC = 0; // 预分频器设为0 TIM1->ARR = 0; // 自动重装载值设为0
3. 可选:触发初始更新事件(确保计数器初始状态正确)
若首次触发存在问题,可手动触发一次更新事件,初始化计数器:
TIM1->EGR |= TIM_EGR_UG; // 生成更新事件,初始化计数器和预分频器
修改后的完整关键代码片段
// 定时器配置 TIM1->PSC = 0; TIM1->ARR = 0; TIM1->DIER = TIM_DIER_UDE; // 使能更新事件DMA请求 TIM1->SMCR = (3 << TIM_SMCR_SMS_Pos) | (1 << TIM_SMCR_ETRP_Pos); // 外部时钟模式2 + 下降沿有效 TIM1->EGR |= TIM_EGR_UG; // 初始化计数器 TIM1->CR1 = TIM_CR1_CEN; // 使能TIM1 // DMA配置(保持原配置不变) DMA2_Stream5->NDTR = 20; DMA2_Stream5->M0AR = (uint32_t) &buffer[0]; DMA2_Stream5->PAR = (uint32_t) &GPIOB->IDR; DMA2_Stream5->CR = (6u << DMA_SxCR_CHSEL_Pos) | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MINC | DMA_SxCR_EN | DMA_SxCR_TCIE_Msk | 0;
原理说明
当TIM1配置为外部时钟模式2时,ETRP引脚的下降沿会直接驱动计数器递增:
- ARR=0时,计数器从0开始,每收到一个外部下降沿,计数器加1并立即溢出到0,同时产生更新事件,触发DMA请求
- 该配置保证每个外部下降沿都会对应一次DMA读取操作
内容的提问来源于stack exchange,提问作者mesutdr
相关产品推荐
相关产品推荐

