GD32的ADC规则组,ADC采样问题#已解决

[复制链接]
5405|5
 楼主| bogu1992 发表于 2022-4-3 15:10 | 显示全部楼层 |阅读模式
本帖最后由 bogu1992 于 2022-4-7 14:34 编辑

芯片采用GD32F303, ADC采用规则组,单次转换模式,中断获取方式,TIMER触发源。最后能进入ADC中断,但无法获取ADC的值。
代码部分:
76401624d49fa8a03d.png 42373624d4a2b1c0c6.png
38929624d4a8fb8524.png
  1. void Adc_GPIO_Configuration(void)
  2. {
  3.   /* enable GPIOA clock */
  4.   rcu_periph_clock_enable(RCU_GPIOA);
  5. gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_1);
  6. }
  1. void Adc_Configuration(void)
  2. {   
  3.   /* enable ADC0 clock */
  4.   rcu_periph_clock_enable(RCU_ADC0);//
  5.   /* config ADC clock */
  6.   rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4);//
  7.   /* configure ADC resolution */
  8.   adc_resolution_config(ADC0 , ADC_RESOLUTION_12B);//
  9.   /* configure ADC discontinuous mode */
  10. <font color="#000000">  //adc_discontinuous_mode_config(ADC0 , ADC_REGULAR_CHANNEL , 1);</font><font color="#ff0000">//单次模式不需要执行该函数</font>
  11.   /* configure the ADC mode */
  12.   adc_mode_config(ADC_MODE_FREE);//
  13.   /* enable or disable ADC special function */
  14.   adc_special_function_config(ADC0 , ADC_CONTINUOUS_MODE , DISABLE);
  15.   adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
  16.   adc_special_function_config(ADC0, ADC_INSERTED_CHANNEL_AUTO, DISABLE);
  17.   /* configure ADC data alignment */
  18.   adc_data_alignment_config(ADC0 , ADC_DATAALIGN_RIGHT);//
  19.   /* configure the length of regular channel group or inserted channel group */
  20. // <font color="#000000">adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 1);</font><font color="#ff0000">//单次模式不需要执行该函数</font>
  21. <font color="#ff0000">  //如需切换ADC,则执行下述函数一次即可获取对应的ADC的值</font>
  22. <font color="#0000ff">  //  adc_regular_channel_config(ADC0 ,</font><font color="#ff0000"> 0</font><font color="#0000ff"> , ADC_CHANNEL_0 , ADC_SAMPLETIME_7POINT5);
  23.   adc_regular_channel_config(ADC0 ,</font><font color="#ff0000"> 0</font><font color="#0000ff"> , ADC_CHANNEL_1 , ADC_SAMPLETIME_7POINT5);
  24.   //  adc_regular_channel_config(ADC0 , </font><font color="#ff0000">0</font><font color="#0000ff"> , ADC_CHANNEL_2 , ADC_SAMPLETIME_7POINT5);
  25.   //  adc_regular_channel_config(ADC0 , </font><font color="#ff0000">0</font><font color="#0000ff"> , ADC_CHANNEL_3 , ADC_SAMPLETIME_7POINT5);</font>
  26.   /* configure ADC external trigger source */
  27.   adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T2_TRGO);//
  28.   /* enable ADC external trigger */
  29.   adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);//
  30.   /* clear the ADC flag */
  31.   adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC);
  32.   /* enable ADC interrupt */
  33.   adc_interrupt_enable(ADC0, ADC_INT_EOC);//
  34.   //  adc_tempsensor_vrefint_enable();
  35.   /* enable ADC interface */
  36.   adc_enable(ADC0);//
  37.   /* ADC calibration and reset calibration */
  38.   adc_calibration_enable(ADC0);//
  39.   
  40.   /* enable ADC software trigger */
  41.   //  adc_software_trigger_enable(ADC0 , ADC_REGULAR_CHANNEL);
  42. }
  1. void SetSampRate(uint32_t freq)
  2. {
  3. //配置定时器3作为ADC的转换触发源
  4.   uint16_t Period;
  5.   timer_parameter_struct timer_initpara;
  6.   rcu_periph_clock_enable(RCU_TIMER2);
  7.   timer_deinit(TIMER2);
  8. /*
  9.   采样频率计算公式 :
  10.    period = 48000000 / freq ;  
  11.    1200  ==  40KHz 采样频率
  12. */
  13.   Period = FMASTER / freq-1;  
  14.   timer_initpara.prescaler         = 1;
  15.   timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;//????
  16.   timer_initpara.counterdirection  = TIMER_COUNTER_UP;
  17.   timer_initpara.period            = Period;
  18.   timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
  19.   timer_initpara.repetitioncounter = 0;
  20.   timer_init(TIMER2,&timer_initpara);
  21.   
  22.   timer_master_output_trigger_source_select(TIMER2, TIMER_TRI_OUT_SRC_UPDATE);
  23. }
  1. void Adc_Start(void)
  2. {
  3.   timer_counter_value_config(TIMER2 , 0);
  4.   timer_enable(TIMER2);
  5. }

  6. void Adc_Stop(void)
  7. {  
  8.   timer_disable(TIMER2);
  9. }
  1. void ADC0_1_IRQHandler(void){
  2.   if(adc_interrupt_flag_get( ADC0, ADC_INT_FLAG_EOC)){

  3.         u16 Conversion_Value = adc_regular_data_read(ADC0);

  4.     adc_interrupt_flag_clear( ADC0, ADC_INT_FLAG_EOC);
  5.   }
  6. }
  1. SetSampRate(10000);
  2. //系统中断管理
  3. void NVIC_Configuration(void)
  4. {
  5.   rcu_periph_clock_enable(RCU_TIMER1);
  6.   rcu_periph_clock_enable(RCU_TIMER2);
  7.   rcu_periph_clock_enable(RCU_TIMER3);
  8.   rcu_periph_clock_enable(RCU_TIMER4);
  9.   rcu_periph_clock_enable(RCU_ADC0);
  10.   nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
  11.   nvic_irq_enable(TIMER1_IRQn, 0U, 1U);//原timer9
  12.   nvic_irq_enable(TIMER3_IRQn, 0U, 2U);
  13.   nvic_irq_enable(TIMER4_IRQn, 0U, 3U);
  14.   nvic_irq_enable(ADC0_1_IRQn, 0U, 0U);
  15. }
  16. void GPIO_Configuration(void)
  17. {
  18.   rcu_periph_clock_enable(RCU_AF);
  19.   rcu_periph_clock_enable(RCU_GPIOA);
  20.   rcu_periph_clock_enable(RCU_GPIOB);
  21.   rcu_periph_clock_enable(RCU_GPIOC);
  22.   rcu_periph_clock_enable(RCU_GPIOD);
  23.   gpio_deinit(GPIOA);
  24.   gpio_deinit(GPIOB);
  25.   gpio_deinit(GPIOC);
  26.   gpio_deinit(GPIOD);
  27.   gpio_afio_deinit();
  28. }
程序函数有一个巨坑:
    adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 1);//
void adc_channel_length_config(uint32_t adc_periph, uint8_t adc_channel_group, uint32_t length)的描述:
/*!
    \brief      configure the length of regular channel group or inserted channel group
    \param[in]  adc_periph: ADCx,x=0,1,2
                only one among these parameters can be selected
    \param[in]  adc_channel_group: select the channel group
                only one parameter can be selected
      \arg        ADC_REGULAR_CHANNEL: regular channel group
      \arg        ADC_INSERTED_CHANNEL: inserted channel group
    \param[in]  length: the length of the channel
                        regular channel 1-16
                        inserted channel 1-4
    \param[out] none
    \retval     none
*/
规则通道的 length 为1-16,而ADC是从0开始,函数里也已经(length-1U),但不知道为什么PA1口
函数adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 2);就能用了adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 2);不需要该函数。


如需更改或切换其他ADC口则执行一遍下述函数进行刷新:
  adc_regular_channel_config(uint32_t adc_periph , uint8_t rank , uint8_t adc_channel , uint32_t sample_time)
其中 固定参数 rank = 0;即可






 楼主| bogu1992 发表于 2022-4-6 15:40 | 显示全部楼层
Green_Apple 发表于 2022-4-6 10:11
官网有对应的DEMO的,GD芯片销售 MCU10000(WX)

DEMO都看过了,恰巧没有规则的独立触发DEMO
sonicll 发表于 2022-4-7 09:13 | 显示全部楼层
你只采样一个通道的话,需要把长度设置为1,通道的rank设置为0。你现在设置长度为2,实际上ADC采样了两个通道,第2个通道的数据把第1个通道的数据覆盖了
 楼主| bogu1992 发表于 2022-4-7 10:56 | 显示全部楼层
本帖最后由 bogu1992 于 2022-4-7 11:28 编辑
sonicll 发表于 2022-4-7 09:13
你只采样一个通道的话,需要把长度设置为1,通道的rank设置为0。你现在设置长度为2,实际上ADC采样了两个通 ...

rank的具体值0,1都是用的是rsq2寄存器,但是我配置的是PA1口,但是为什么length配置为2却能采集到值,这是我很奇怪的地方。length我尝试配置为1看看结果    经过测试length = 1 为PA0的ADC值
  1. if(rank < 6U){
  2.         rsq = ADC_RSQ2(adc_periph);
  3.         rsq &=  ~((uint32_t)(ADC_RSQX_RSQN << (5U*rank)));
  4.         rsq |= ((uint32_t)adc_channel << (5U*rank));
  5.         ADC_RSQ2(adc_periph) = rsq;
  6.     }else if(rank < 12U){
  7.         rsq = ADC_RSQ1(adc_periph);
  8.         rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*(rank-6U))));
  9.         rsq |= ((uint32_t)adc_channel << (5U*(rank-6U)));
  10.         ADC_RSQ1(adc_periph) = rsq;
  11.     }else if(rank < 16U){
  12.         rsq = ADC_RSQ0(adc_periph);
  13.         rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*(rank-12U))));
  14.         rsq |= ((uint32_t)adc_channel << (5U*(rank-12U)));
  15.         ADC_RSQ0(adc_periph) = rsq;
  16.     }else{
  17.     }

sonicll 发表于 2022-4-7 14:19 | 显示全部楼层
本帖最后由 sonicll 于 2022-4-7 14:26 编辑
bogu1992 发表于 2022-4-7 10:56
rank的具体值0,1都是用的是rsq2寄存器,但是我配置的是PA1口,但是为什么length配置为2却能采集到值,这 ...

配置规则长度为2,ADC会先采样ADC_RSQ2寄存器里RSQ0位域里写入的通道,然后再采样RSQ1位域里写入的通道,第二次采样值会把前一次覆盖掉。
配置规则长度为1,那就只会采样ADC_RSQ2寄存器里RSQ0位域里写入的通道。

你的这个写法 adc_regular_channel_config(ADC0 , 1 , ADC_CHANNEL_1 , ADC_SAMPLETIME_7POINT5); 实际只给RSQ1里写了个1,而RSQ0里还是0,所以你如果设置长度为1,就只采样了通道0,如果设置长度为2,其实是先采样了通道0,然后又采样了通道1,通道1的数据把通道0的覆盖了

正确的用法就是我前面说的,你只采样1个通道,那就要把长度设置为1,然后通道的rank设置为0,rank值必须要小于长度值


 楼主| bogu1992 发表于 2022-4-7 14:41 | 显示全部楼层
sonicll 发表于 2022-4-7 14:19
配置规则长度为2,ADC会先采样ADC_RSQ2寄存器里RSQ0位域里写入的通道,然后再采样RSQ1位域里写入的通道, ...

谢谢你,已经解决了,分析了一下寄存器,单次模式rank 只能为零,其他的不行 20697624e8709dd88d.jpg
因为是单次,可以不需要执行adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 1);函数
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

6

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部