STM32F407通过FSMC连接AD7606采样出现通道数据串扰问题求助
问题排查与解决方案
根因定位
以下是直接导致数据混杂的核心问题,完全匹配你观测到的「发全量数据出错、仅发后半段正常」的测试现象:
- USB发送与采样的缓冲区竞争:STM32的
CDC_Transmit_HS绝大多数实现为非阻塞接口,你调用该函数后仅将缓冲区指针交给USB外设,实际数据传输是USB控制器在后台异步完成的。你在调用发送接口后立刻重置adc_data_idx并启动TIM采样,新的采样数据会直接写入还在被USB读取的缓冲区,导致前半段数据被新采样覆盖,后半段还没被覆盖到所以发送正常。 adc_data_idx操作时序错误:你在EXTI回调中启动DMA后立刻将idx+8,但此时DMA传输还未完成,此时adc_data_idx指向的内存地址还没有写入有效数据。你在DMA完成回调中直接读取adc_data[adc_data_idx]判断数据的逻辑本身就不成立,还可能因为时序错位导致地址越界。- 缺少DMA状态校验:EXTI触发时没有判断当前DMA是否处于忙碌状态,如果前一次DMA还未传输完成就再次启动,会导致传输错位、数据写入地址偏移。
- 潜在的中断优先级配置问题:如果EXTI中断优先级高于DMA完成中断优先级,会出现新的采样中断先响应,DMA完成回调延迟处理,进一步加剧
idx和缓冲区的时序错乱。
修复方案
按优先级依次修改:
- 引入双缓冲(乒乓缓冲)机制:申请两块大小相同的采样缓冲区
buf1、buf2,采样阶段往第一块缓冲区写入,写满后自动切换到第二块缓冲区采样,此时再调用USB接口发送第一块缓冲区的内容,发送完成后等待第二块写满再切回,从根本上避免采样和USB发送抢同一块内存。 - 调整
adc_data_idx更新时机:将idx+8的操作从EXTI回调移到DMA完成回调函数中,确保只有DMA传输完成、数据已经写入内存后,再更新下一次写入的地址。 - 校验
CDC_Transmit_HS传输完成状态:如果不想改双缓冲,就在调用CDC_Transmit_HS后加等待逻辑,轮询USB发送完成标志,确认数据全部发出后再重置idx、启动TIM采样,避免缓冲区被提前覆盖。 - 增加DMA状态判断:在EXTI回调中启动DMA前,先判断DMA句柄的状态是否为
HAL_DMA_STATE_READY,仅当DMA空闲时才启动新的传输,避免重复启动冲突。 - 调整中断优先级:将DMA完成中断的优先级设置为高于EXTI中断优先级,保证DMA传输完成后第一时间处理回调更新索引,再响应新的采样中断。
- 确认DMA配置参数:检查DMA的外设、内存位宽是否配置为16bit,单次传输长度是否匹配8通道的总字节数,避免FSMC读取数据时出现位宽不匹配的错位问题。
内容的提问来源于stack exchange,提问作者Edmond
相关产品推荐
相关产品推荐

