一、问题描述
最近用GD32F303CCT6的ADC采集电压,测试过程中发现ADC存在诡异的问题。调节测量电压,绝大部分情况下均能正确采样电压值,证明软硬件没有问题。但在做精细调节测试时,发现当采样信号大致在0.415V~0.455V之间时,ADC采样值不变。一开始以为硬件问题,经过反复排查,确认引脚上的电压和设定值一致,并且一旦超过该范围,又能采样到正确的值。而且在其他某些电压区间也存在该问题。
原理图如下
配置程序如下
void HAL::adc_init()
{
/* ADC channel length config */
adc_channel_length_config(ADC0, ADC_INSERTED_CHANNEL, 4);
/* ADC regular channel config */
adc_inserted_channel_config(ADC0, 0, ADC_CHANNEL_17, ADC_SAMPLETIME_71POINT5); //VREFINT
adc_inserted_channel_config(ADC0, 1, ADC_CHANNEL_3, ADC_SAMPLETIME_71POINT5); //ISENS
adc_inserted_channel_config(ADC0, 2, ADC_CHANNEL_2, ADC_SAMPLETIME_71POINT5); //VISENS
adc_inserted_channel_config(ADC0, 3, ADC_CHANNEL_1, ADC_SAMPLETIME_71POINT5); //VOSENS
/* ADC external trigger enable */
adc_external_trigger_config(ADC0, ADC_INSERTED_CHANNEL,ENABLE);
/* ADC external trigger source config */
adc_external_trigger_source_config(ADC0, ADC_INSERTED_CHANNEL, ADC0_1_2_EXTTRIG_INSERTED_NONE);
/* ADC data alignment config */
adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
/* ADC SCAN function enable */
adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
/* ADC Vbat and temperature channel enable */
adc_tempsensor_vrefint_enable();
/* ADC resolusion 12B */
adc_resolution_config(ADC0, ADC_RESOLUTION_12B);
/* enable ADC interface */
adc_enable(ADC0);
delay_ms(1);
/* ADC calibration and reset calibration */
adc_calibration_enable(ADC0);
}
二、解决方法
在网上搜索了相关问题,大部分只提到GD32的ADC设计上有缺陷,但并未具体说明问题是什么。最终参考这篇博客“GD32F450单片机ADC采集值不变问题 - - 21ic电子技术开发论坛”提到了同样的问题,博客中提到的解决方法如下图
但经过测试,将rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4)放在adc_calibration_enable(ADC0)后面,问题并未解决。最后怀疑是不是ADC时钟太快,将时钟降低,改位rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6),问题有所好转,出问题的区间电压范围似乎变小了,但并未完全解决。如此来说应该就是ADC的时钟问题,最后把时钟再降低,改为rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8),问题解决!
通过GD官方手册的描述,ADC时钟是可以达到30M的,我的板子APB2时钟为120M,rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4)将ADC时钟分频为30M,理论上是没问题的。通过这次掉坑的经历来看,GD32的ADC时钟还是不能太快。
三、总结
有些坑是自己挖的,还有一些坑是别人为你准备的,但不管什么坑,掉过一次之后都应该长教训。如果还能为别人把坑填平,也算功德一件,共勉!