打印

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

[复制链接]
3046|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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
    \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值
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{
    }

使用特权

评论回复
5
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值必须要小于长度值


使用特权

评论回复
6
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

主题

5

帖子

0

粉丝