记录ADC采集高频信号的一点坑
背景:
本次测试了ADC采集一个高频的谐振电流信号时遇到的一点问题。
正题
这里先展示以下被测试波形(蓝色)。


这里的蓝色波形为完全谐振和感性谐振时的的波形可能频率在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 */
}

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

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


到这里陷入了比较尴尬的位置,变量有点多。
- 怀疑Time设置有问题导致触发ADC不准确(个人感觉不太可能)。
- 怀疑内部时钟不稳定导致的(主要怀疑方向)。
- 信号质量或者杜邦线传输不太好。这个需要去公司验证。
这里还验证了一下,如果使用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
浙公网安备 33010602011771号