STM32
直播中

吕钢格

9年用户 1075经验值
私信 关注
[问答]

stm32F723ZET6使用ADC捕获正弦波,adc采样频率过高导致主函数无法运行,怎么优化?

用定时器tiM2,200khz触发ADC采样,每次采样后进行数据存储,采样1000个后置标志位,在主循环中上报1000个点数据。100khz还是能正常上报的,200khz情况下在主循环打断点一直进不去了,要如何优化我的adc采样?

回帖(1)

郭大

2025-7-15 16:59:19

要解决STM32F723ZET6在200kHz ADC采样时主函数无法运行的问题,需通过DMA优化数据搬运和中断处理。以下是分步优化方案:


1. 启用ADC+DMA传输(核心优化)


// 配置步骤
#define ADC_SAMPLES 1000
volatile uint16_t adcBuffer[ADC_SAMPLES];
volatile uint8_t dataReady = 0;

// ADC+DMA初始化
void ADC_DMA_Init(void) {
  // 启用ADC和DMA时钟
  RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
  __DSB();

  // 配置DMA(以DMA2 Stream0为例)
  DMA2_Stream0->PAR = (uint32_t)&(ADC1->DR);     // 外设地址
  DMA2_Stream0->M0AR = (uint32_t)adcBuffer;     // 内存地址
  DMA2_Stream0->NDTR = ADC_SAMPLES;              // 传输数量
  DMA2_Stream0->CR = DMA_SxCR_CHSEL_0 |          // 通道选择(查手册)
                     DMA_SxCR_MINC |            // 内存增量
                     DMA_SxCR_TCIE |            // 传输完成中断
                     DMA_SxCR_CIRC;             // 循环模式
  DMA2_Stream0->CR |= DMA_SxCR_EN;              // 启用DMA

  // 配置ADC使用TIM2触发
  ADC1->CR2 |= ADC_CR2_DMA | ADC_CR2_DDS;
  ADC1->CR2 |= ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_0; // TIM2 TRGO触发
}

2. 优化DMA中断处理(取代ADC中断)


// DMA中断服务函数
void DMA2_Stream0_IRQHandler(void) {
  if (DMA2->LISR & DMA_LISR_TCIF0) {
    DMA2->LIFCR = DMA_LIFCR_CTCIF0;    // 清除标志
    dataReady = 1;                     // 通知主循环
  }
}

3. 主循环处理逻辑


int main(void) {
  // 初始化TIM2、ADC、DMA等
  TIM2_Init();         // 配置TIM2为200kHz触发频率
  ADC_DMA_Init();

  NVIC_EnableIRQ(DMA2_Stream0_IRQn);

  while (1) {
    if (dataReady) {
      dataReady = 0;
      SendData_UART(adcBuffer); // 上报1000点数据
    }
    // 此处可执行其他任务
  }
}

4. 关键优化点说明




  1. DMA代替CPU搬运数据



    • DMA直接将ADC数据存入内存adcBuffer

    • 传输完成产生单次中断(而非每个采样都中断)




  2. 中断频率计算



    • 原始方案:200kHz采样 → 每秒20万次中断

    • 优化后:每1000点1次中断 → 仅200Hz中断

    • 中断负载降低99.9%




























  3. 资源消耗对比 方式 CPU负载 (200kHz) 中断次数 内存访问
    原始方案 >90% 200,000/s 每次中断
    DMA方案 <5% 200/s 零开销



5. 注意事项




  1. 缓冲区保护


    // 主循环处理时禁用DMA中断
    if (dataReady) {
      NVIC_DisableIRQ(DMA2_Stream0_IRQn);
      // 处理数据...
      NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    }



  2. TIM2配置关键点


    void TIM2_Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    TIM2->PSC = SystemCoreClock / 200000 - 1; // 200kHz更新频率
    TIM2->ARR = 1;
    TIM2->CR2 |= TIM_CR2_MMS_1; // TRGO输出
    TIM2->CR1 |= TIM_CR1_CEN;
    }



  3. ADC配置



    • 使用外部触发模式

    • 采样时间根据信号频率调整(建议3-5个时钟周期)




6. 潜在问题排查




  1. DMA通道冲突



    • 确认DMA2_Stream0对应ADC1(参考STM32F7参考手册)

    • 若冲突改用其他Stream(如Stream4)




  2. 内存对齐


    __attribute__((aligned(4))) uint16_t adcBuffer[ADC_SAMPLES];



  3. 性能监测



    • 检查DMA->LISR寄存器确认中断触发

    • 用GPIO翻转测量中断处理时间:
      // 中断中添加
      GPIOA->ODR ^= GPIO_PIN_0;  // 示波器观察耗时




优化后效果:主循环可正常响应,200kHz采样稳定运行,CPU利用率从100%降至极低水平,空闲资源可用于其他任务。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分