记录ADC采集高频信号的一点坑

背景:
本次测试了ADC采集一个高频的谐振电流信号时遇到的一点问题。

正题
这里先展示以下被测试波形(蓝色)。
3kw8
3kw10
这里的蓝色波形为完全谐振和感性谐振时的的波形可能频率在100Khz~30Khz之间。此外还需要在测得数据后计算RMS。但是遇到的问题为计算出来的RMS不准确,和200Mhz的电流探头测得数据相差较大,并且会有跳变。在不断尝试提高ADC采样率时发现一点问题,并记录如下:
1.
由于很长时间用的都是ADI的ADC芯片,有很多ADC的知识忘记了,ADC的采样率计算公式为 Fadc=ADC_clock/(12.5+SamplingTime);经过CubeMX测试在内部时钟源情况下ADC_clock只能配置为60Mhz,但是代价是主频只有120Mhz。这里使用内部时钟源是因为晶振采购成了12.0844Mhz这么一个十分奇怪的晶振,这里使用内部晶振先验证功能。
2.
一开始使用ADC+DMA循环采集双通道数据时,计算的数据与示波器测得数据基本一致,但是会有频繁波动。经过查询发现ADC+DMA循环模式下,ADC的采样间隔并不是固定的,这就导致可能采集的点并不均匀。从而导致数据不准确。
3.
测试ADC+DMA+TIM定时触发,这里将TIM2配置为 psc=17-1、arr=5-1 Fre_Tim=2Mhz。开启TIM2全局中断,TRGO使用UPDATA事件、关闭主从模式。ADC规则通道下2通道、使用Timer2 Trigger Out event。

Time 2 Init
/* TIM2 init function */
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 17-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 4-1;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}
ADC1 Init
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 2;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

c7d8ff0c457c92b03da388f9df97f7ae

搭配这个时钟树可以将ADC运行速度跑到接近2M。具体实测应该是在1.9M。100Khz正弦波信号一个周期内采集到了19个点,1/(10us/19)=1.9M
aab476b218f4bed60b3301ede697bec9

但是在后续测试时,发现逐步降低正弦波信号频率后,开始出现波形缺失。并且是部分频率区间(在45-29khz时),并且单数频率出问题情况较多。之后更换了900Khz的方波测试,发现波形出现了明显的缺失。
dd76f5bd1f4004535ad1f6d13a2dd2cf
cb29247be25506e5c9bfd79085e248ad

到这里陷入了比较尴尬的位置,变量有点多。

  1. 怀疑Time设置有问题导致触发ADC不准确(个人感觉不太可能)。
  2. 怀疑内部时钟不稳定导致的(主要怀疑方向)。
  3. 信号质量或者杜邦线传输不太好。这个需要去公司验证。

这里还验证了一下,如果使用ADC+DMA+TIME不需要使用HAL_ADC_Start(&hadc1);

这样设置即可
	HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);                //adc单端采样校准
	HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_buff,ADC_BUFF_NUM);         //启动DMA 
	HAL_TIM_Base_Start(&htim2);
	//HAL_ADC_Start(&hadc1);                                              //开启AD
posted @ 2025-07-20 18:24  future0218  阅读(112)  评论(0)    收藏  举报