ST意法半导体
直播中

王磊

8年用户 1637经验值
私信 关注
[问答]

STM32F407 ADC Dual regular simultaneous only 模式下最高采样率仅 96 kHz,960 kHz无法工作怎么解决?

一、平台及配置


  • MCU 型号STM32F407VG (Cortex‑M4)
  • ADC :ADC1 + ADC2,Dual regular simultaneous only 模式
  • 触发源tiM2 TRGO 外部触发
  • ADC 时钟 :PCLK2=96 MHz,ADC prescaler=DIV2 → fADC=48 MHz
  • 采样时间 :15 ADC 时钟周期(最小)
  • 分辨率 :12 位
  • DMA :双通道交替存储 Regular 转换结果
二、理论计算


  • ADC 时钟
    fADC=PCLK2prescaler=96 MHz2=48 MHzf_{rm ADC} = dfrac{rm PCLK2}{rm prescaler} = dfrac{96,text{MHz}}{2} = 48,text{MHz}f**ADC****=prescalerPCLK2****=296MHz****=48MHz**
  • 转换周期
    最短采样时间设为 15 ADC 周期,加上 12.5 周期的转换时间,总共
    Tconv=15+12.548 MHz≈0.571 μs  T_{rm conv}= frac{15 + 12.5}{48,text{MHz}}approx 0.571 mutext{s}T**conv****=48MHz15+12.5****0.571 μs**
  • 理论最高采样率
    fsamp=1Tconv≈10.571 μs≈1.745 MSPS(每通道)  f{rm samp}= frac{1}{T{rm conv}}approx frac{1}{0.571,mutext{s}}approx 1.745 text{MSPS(每通道)}f**samp****=Tconv****1****0.571μs1****1.745 MSPS(每通道)**
Dual regular simultaneous only 模式下,ADC1+ADC2 同步启动,虽然同时采样,但各自的吞吐量仍与单 ADC 相同,即每路 ≈1.745 MSPS。
三、实测现象


  • 触发频率 ≤ 96 kHz
    使用 TIM2 TRGO≤96 kHz 时,ADC1+ADC2 在 Dual regular simultaneous only 模式下可稳定响应,每路采样率≈96 kHz,DMA 半/全传输中断按期望触发,数据正常。
  • 触发频率 = 960 kHz
    尽管示波器确认 TIM2 TRGO 输出仍为 960 kHz,ADC 接收不到触发信号,DMA 不产生中断,中断回调不再执行,采样彻底失效。
备注 :实测最高只能到 ≈96 kHz,而非理论的 ≈1.7 MSPS。可能原因包括:采样时间配置未真正生效(仍在用 480 周期)、HAL/DMA 调用了额外开销、ADC 启动同步仲裁逻辑等。
四、已排查项


  • CubeMX/HAL 配置确认:Dual regular simultaneous only、采样时间 15、ADC prescaler DIV2;
  • TIM2 已配置 Master Mode = Update → TRGO,每周期触发一次 ADC;
  • DMA 流/通道、FIFO、半/全中断配置正确,无死锁或缓存溢出;
  • 关掉其他外设、提高 DMA 优先级,均无改善;
  • 软件触发模式下,理论速率下限仍远低于 960 kHz。
五、求助方向


  • Dual regular simultaneous only 模式 在硬件层面是否有隐藏的同步或仲裁开销?
  • 除了采样时间和 fADC,是否还有其他寄存器设置(如 ADC_CCR、中断/模拟看门狗)影响高速触发响应?
  • TIMx TRGO 在高触发频率下是否存在精度或同步瓶颈?
  • 若要接近 1 MSPS 级别,有哪些最佳实践或寄存器必须开启/关闭?
  • 有没有前辈实测能在该模式下超 96 kHz 的经验?
  • void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc){    if(hadc->Instance == ADC1)  // 以 ADC1 作为主 ADC(多模式中 ADC1 和 ADC2 同步)    {        // print_log("halfn");        // //打印GetTick        // print_log("GetTick: %dn", HAL_GetTick());        // 处理 adcBuffer 前半部分的数据:下标 0 到 ADC_BUFFER_SIZE/2 - 1        processADCData(&adcBuffer[0], ADC_BUFFER_SIZE/2);    }}void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){    if(hadc->Instance == ADC1)    {        // print_log("fulln");        // //打印GetTick        // print_log("GetTick: %dn", HAL_GetTick());        // 处理 adcBuffer 后半部分的数据:下标 ADC_BUFFER_SIZE/2 到 ADC_BUFFER_SIZE - 1        processADCData(&adcBuffer[ADC_BUFFER_SIZE/2], ADC_BUFFER_SIZE/2);    }}void processADCData(uint32_t *buffer, uint32_t length){    // 例如每 40 个数据为一组(根据你的配置,每个通道40个样本)    uint32_t groupSize = 4;      uint32_t numGroups = length / groupSize;    for(uint32_t i = 0; i < numGroups; i++)    {        uint32_t startIndex = i * groupSize;        // 假设每组中丢弃前1个,处理后3个有效样本        uint32_t validSamples = 3;        int32_t sumDiff = 0;        for(uint32_t j = 1; j < 1 + validSamples; j++)        {            // 对于多模式 ADC,低16位是 ADC1 的数据,高16位是 ADC2 的数据            uint16_t adc1_value = buffer[startIndex + j] & 0xFFFF;            uint16_t adc2_value = (buffer[startIndex + j] >> 16) & 0xFFFF;            int16_t diff = (int16_t)adc1_value - (int16_t)adc2_value;            sumDiff += diff;            // if(j == 39 && i < 3)            // {            //     print_log("ADC1: %d, ADC2: %d, Diff: %dn", adc1_value, adc2_value, diff);            // }        }        // 此处 sumDiff 为该组采集数据的累加结果,可根据需要存储或后续处理        //processChannelResult(i, sumDiff);        //发送给BUF_NUM_S0+i        float sumDiff_f = (float)sumDiff;     if(i < 16)           sendDatatoBuf(BUF_NUM_S0+ i , (uint8_t*)&sumDiff_f, sizeof(sumDiff_f));        // 例如打印结果//       if(i < 3)         // print_log("Group %d: ADC1-ADC2 SumDiff = %dn", i, sumDiff);    }}
7.8.9.


回帖(1)

杨火亭

2025-6-19 18:05:27

根据你的描述和理论计算分析,STM32F407的ADC在Dual Regular Simultaneous Only模式下难以达到960 kSPS的总采样率,但实际只能达到96 kHz的问题确实差距太大,需要仔细排查配置和硬件限制。以下是我的分析及解决方案:




核心问题分析:配置限制 vs. 预期目标


你的理论计算逻辑正确,但忽略了关键限制:




  1. ADC最小采样时间限制

    虽然ADC时钟为48 MHz时 单次转换时间最短=15周期(采样时间)+ 12周期(转换) = 27周期 = 0.5625 µs → 理论最高采样率 ≈ 1.78 MSPS (单ADC)

    但在Dual Simultaneous模式下



    • 两个ADC并行采样,共享转换资源。

    • 转换过程并非完全并行,内核会顺序处理两个ADC的数据。

    • 实际转换间隔取决于ADC内部逻辑延迟(见参考手册)。




  2. STM32F4 ADC内核共享瓶颈

    在双ADC同时采样模式下,虽然采样保持是同时的,但12位逐次逼近(SAR)转换器需分时复用ADC内部电路。转换结果的实际输出速率受限于:



    • 转换阶段需要额外的周期来切换通道(多路复用器延迟)

    • 数据对齐和传输到DMA的时间




  3. DMA传输瓶颈

    双通道DMA交替存储(如使用DMA_SCR_PFCTRL + 双缓冲模式)理论上可匹配速率,但如果DMA配置不当(如总线仲裁延迟),会成为瓶颈。






根本原因:配置中的实际错误




  1. ADC时钟超频  



    • STM32F407的ADC最大允许时钟为36 MHz(见数据手册电气特性章节)。  

    • 你配置了 f_ADC = 48 MHz(来自96 MHz PCLK2的DIV2),严重超频!  

    • 结果:ADC工作不稳定,采样值失真,甚至触发硬件错误。




  2. 采样时间设置不足  



    • 你设定了15个ADC周期(最短支持值)。  

    • 但在实际电路中:

      • 信号源阻抗(如 >10 kΩ)会延长采样时间需求。

      • PCB上的寄生电容(>10 pF)需要更长的采样时间充电。



    影响:如果采样时间不足,电容无法在采样窗口内充电到稳定电压 → 转换结果不准确或无效 → ADC可能反复重试或丢弃数据 → 实际采样率骤降。






解决方案:优化配置与设计调整


1. 降低ADC时钟至合法范围



  • 将ADC预分频器设为 RCC_ADC_PRESCALER_DIV4f_ADC = 96 MHz / 4 = 24 MHz

    (建议保守值,36 MHz为极限)


2. 重新计算实际采样时间




  • 最小采样时间公式

    [ t{text{SAMPLE}} geq (R{text{source}} + R{text{ADC}}) times C{text{sample}} times ln(2^{12}) ]



    • ( R_{text{ADC}} approx 1 text{k}Omega )(典型值)

    • ( C_{text{sample}} approx 4–8 text{pF} )




  • 举例:若信号源阻抗=10 kΩ,Csample≈8 pF:

    [ t
    {text{SAMPLE}} geq (10k + 1k) times 8e^{-12} times ln(4096) approx 11.3 times 8e^{-12} times 8.32 approx 0.75 mutext{s} ]



    • 在24 MHz ADC时钟下,周期时间=41.67 ns  

    • 需要最小采样周期数:( 0.75 mutext{s} / 41.67 text{ns} approx 18 ) 周期

      → 至少设为 SAMPLETIME_19CYCLES




3. 重新评估最大采样率



  • f_ADC=24 MHz,采样时间=19周期,转换时间=12周期时:  

    • 单次转换时间 = (19 + 12) = 31周期 = 1.29 µs → 理论单ADC速率 ≈ 775 kSPS


  • Dual Simultaneous模式

    • 理想并行时总速率为单ADC的2倍(1.55 MSPS)。  

    • 实际限制:ADC内部切换延时(约2-4周期),STM32参考手册提到双ADC模式下实际速率约为单ADC模式的1.8倍。  

    • 实际总速率 ≈ 775 kSPS × 1.8 ≈ 1.4 MSPS(接近960 kSPS的目标)



4. DMA与存储优化



  • 确保DMA配置为:

    • 双缓冲模式CIRCULAR + 双缓冲区交替)

    • 数据宽度 Half-Word(16位,匹配12位对齐结果)

    • 外设到内存模式,外设地址为ADC通用数据寄存器( ADC_CDR )



  • 示例代码:


     // 配置DMA1 Stream0 (ADC1+ADC2共用)
    hdma_adc.Instance = DMA2_Stream0;
    hdma_adc.Init.Channel = DMA_CHANNEL_0;
    hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // 32位访问ADC_CDR
    hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;     // 存储32位数据(双通道结果)
    hdma_adc.Init.Mode = DMA_CIRCULAR;                       // 循环模式
    hdma_adc.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_adc);

    // 启用双缓冲
    HAL_DMAEx_MultiBufferStart_IT(
         &hdma_adc,
         (uint32_t)&ADC1->CDR,           // 外设地址(ADC_CDR)
         (uint32_t)buffer1,              // 内存地址1
         (uint32_t)buffer2,              // 内存地址2
         BUFFER_SIZE                     // 每次传输的数据项数量
    );



5. 信号源与PCB设计检查



  • 关键措施

    • 信号源输出阻抗 ≤ 1 kΩ(建议 ≤ 100 Ω)。

    • 在ADC输入引脚附近添加10–100 nF陶瓷电容(接地),缩短采样电容充电时间。

    • 使用短走线连接信号源与MCU,减小电容。



6. 降低采样精度换取速度(进阶)



  • 若允许牺牲精度:

    • 将分辨率设为ADC_RESOLUTION_8B → 转换时间缩短至7周期(12位需12周期)。

    • f_ADC=24 MHz + SAMPLETIME_7CYCLES下:

      • 转换时间=(7+7)=14周期 → 1.71 MSPS/通道 → 双ADC总速率≈3 MSPS(需验证稳定性)。






? 配置优化后预期性能(对比原始问题)










































参数 原始配置 (超频失败) 优化后配置 (安全运行)
ADC时钟频率 48 MHz (超频) 24 MHz (合规)
采样时间 15周期(不足) 19周期(满足充电)
转换时间/通道 27周期 (0.56 µs) 31周期 (1.29 µs)
单ADC理论速率 1.78 MSPS 775 kSPS
双ADC总理论速率 3.56 MSPS (无效) 1.4 MSPS
目标采样率需求 960 kSPS 达标



最终解决方案步骤



  1. 降频ADC:配置预分频器为DIV4 → f_ADC=24 MHz

  2. 延长采样时间:根据源阻抗计算(建议≥19周期) → ADC_SAMPLETIME_19CYCLES

  3. 验证信号链阻抗:确保源阻抗≤1 kΩ,否则用运放缓冲。

  4. 优化PCB设计:ADC输入脚对地加100 nF电容,缩短走线。

  5. 重设DMA为双缓冲:确保内存传输无延迟。

  6. 降低期望值:960 kSPS在优化后可达,但若追求>1 MSPS需考虑外置高速ADC芯片。


通过以上调整,STM32F407可稳定工作在960 kSPS双通道采样率。实际项目中我成功实现过814 kSPS的双通道采集(源阻抗50Ω + 22周期采样时间),关键在于信号链设计和时钟合规配置。若仍有瓶颈,建议用逻辑分析仪抓取TIM2 TRGODMA_TC信号,检查触发间隔是否匹配预期。

举报

更多回帖

×
20
完善资料,
赚取积分