bogu1992 发表于 2022-4-3 15:10

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

本帖最后由 bogu1992 于 2022-4-7 14:34 编辑

芯片采用GD32F303, ADC采用规则组,单次转换模式,中断获取方式,TIMER触发源。最后能进入ADC中断,但无法获取ADC的值。
代码部分:


void Adc_GPIO_Configuration(void)
{
/* enable GPIOA clock */
rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_1);
}void Adc_Configuration(void)
{   
/* enable ADC0 clock */
rcu_periph_clock_enable(RCU_ADC0);//
/* config ADC clock */
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4);//
/* configure ADC resolution */
adc_resolution_config(ADC0 , ADC_RESOLUTION_12B);//
/* configure ADC discontinuous mode */
<font color="#000000">//adc_discontinuous_mode_config(ADC0 , ADC_REGULAR_CHANNEL , 1);</font><font color="#ff0000">//单次模式不需要执行该函数</font>
/* configure the ADC mode */
adc_mode_config(ADC_MODE_FREE);//
/* enable or disable ADC special function */
adc_special_function_config(ADC0 , ADC_CONTINUOUS_MODE , DISABLE);
adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
adc_special_function_config(ADC0, ADC_INSERTED_CHANNEL_AUTO, DISABLE);
/* configure ADC data alignment */
adc_data_alignment_config(ADC0 , ADC_DATAALIGN_RIGHT);//
/* configure the length of regular channel group or inserted channel group */
// <font color="#000000">adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 1);</font><font color="#ff0000">//单次模式不需要执行该函数</font>
<font color="#ff0000">//如需切换ADC,则执行下述函数一次即可获取对应的ADC的值</font>
<font color="#0000ff">//adc_regular_channel_config(ADC0 ,</font><font color="#ff0000"> 0</font><font color="#0000ff"> , ADC_CHANNEL_0 , ADC_SAMPLETIME_7POINT5);
adc_regular_channel_config(ADC0 ,</font><font color="#ff0000"> 0</font><font color="#0000ff"> , ADC_CHANNEL_1 , ADC_SAMPLETIME_7POINT5);
//adc_regular_channel_config(ADC0 , </font><font color="#ff0000">0</font><font color="#0000ff"> , ADC_CHANNEL_2 , ADC_SAMPLETIME_7POINT5);
//adc_regular_channel_config(ADC0 , </font><font color="#ff0000">0</font><font color="#0000ff"> , ADC_CHANNEL_3 , ADC_SAMPLETIME_7POINT5);</font>
/* configure ADC external trigger source */
adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T2_TRGO);//
/* enable ADC external trigger */
adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);//
/* clear the ADC flag */
adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC);
/* enable ADC interrupt */
adc_interrupt_enable(ADC0, ADC_INT_EOC);//
//adc_tempsensor_vrefint_enable();
/* enable ADC interface */
adc_enable(ADC0);//
/* ADC calibration and reset calibration */
adc_calibration_enable(ADC0);//

/* enable ADC software trigger */
//adc_software_trigger_enable(ADC0 , ADC_REGULAR_CHANNEL);
}void SetSampRate(uint32_t freq)
{
//配置定时器3作为ADC的转换触发源
uint16_t Period;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER2);
timer_deinit(TIMER2);
/*
采样频率计算公式 :
   period = 48000000 / freq ;
   1200==40KHz 采样频率
*/
Period = FMASTER / freq-1;
timer_initpara.prescaler         = 1;
timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;//????
timer_initpara.counterdirection= TIMER_COUNTER_UP;
timer_initpara.period            = Period;
timer_initpara.clockdivision   = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2,&timer_initpara);

timer_master_output_trigger_source_select(TIMER2, TIMER_TRI_OUT_SRC_UPDATE);
}void Adc_Start(void)
{
timer_counter_value_config(TIMER2 , 0);
timer_enable(TIMER2);
}

void Adc_Stop(void)
{
timer_disable(TIMER2);
}void ADC0_1_IRQHandler(void){
if(adc_interrupt_flag_get( ADC0, ADC_INT_FLAG_EOC)){

      u16 Conversion_Value = adc_regular_data_read(ADC0);

    adc_interrupt_flag_clear( ADC0, ADC_INT_FLAG_EOC);
}
}SetSampRate(10000);
//系统中断管理
void NVIC_Configuration(void)
{
rcu_periph_clock_enable(RCU_TIMER1);
rcu_periph_clock_enable(RCU_TIMER2);
rcu_periph_clock_enable(RCU_TIMER3);
rcu_periph_clock_enable(RCU_TIMER4);
rcu_periph_clock_enable(RCU_ADC0);
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
nvic_irq_enable(TIMER1_IRQn, 0U, 1U);//原timer9
nvic_irq_enable(TIMER3_IRQn, 0U, 2U);
nvic_irq_enable(TIMER4_IRQn, 0U, 3U);
nvic_irq_enable(ADC0_1_IRQn, 0U, 0U);
}
void GPIO_Configuration(void)
{
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
gpio_deinit(GPIOA);
gpio_deinit(GPIOB);
gpio_deinit(GPIOC);
gpio_deinit(GPIOD);
gpio_afio_deinit();
}程序函数有一个巨坑:
    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
    \paramadc_periph: ADCx,x=0,1,2
                only one among these parameters can be selected
    \paramadc_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
    \paramlength: the length of the channel
                        regular channel 1-16
                        inserted channel 1-4
    \param none
    \retval   none
*/
规则通道的 length 为1-16,而ADC是从0开始,函数里也已经(length-1U),但不知道为什么PA1口
函数adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 2);就能用了{:dizzy:}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值
if(rank < 6U){
      rsq = ADC_RSQ2(adc_periph);
      rsq &=~((uint32_t)(ADC_RSQX_RSQN << (5U*rank)));
      rsq |= ((uint32_t)adc_channel << (5U*rank));
      ADC_RSQ2(adc_periph) = rsq;
    }else if(rank < 12U){
      rsq = ADC_RSQ1(adc_periph);
      rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*(rank-6U))));
      rsq |= ((uint32_t)adc_channel << (5U*(rank-6U)));
      ADC_RSQ1(adc_periph) = rsq;
    }else if(rank < 16U){
      rsq = ADC_RSQ0(adc_periph);
      rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U*(rank-12U))));
      rsq |= ((uint32_t)adc_channel << (5U*(rank-12U)));
      ADC_RSQ0(adc_periph) = rsq;
    }else{
    }

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 只能为零,其他的不行
因为是单次,可以不需要执行adc_channel_length_config(ADC0 , ADC_REGULAR_CHANNEL , 1);函数
页: [1]
查看完整版本: GD32的ADC规则组,ADC采样问题#已解决