对GD32F450的ADC同步模式的理解

[复制链接]
415|14
手机看帖
扫描二维码
随时随地手机跟帖
为你转身|  楼主 | 2023-1-18 16:52 | 显示全部楼层 |阅读模式
本文的参考资料主要为《GD32F4xx_User_Manual_CN_V2.2》,《GD32F450xx_Datasheet_Rev1.1》,《STM32库开发实战指南——基于野火挑战者开发板》以及《GD32F4xx_Firmware_Library_V2.1.3》固件库中的示例。

本文的主要内容为我对GD32F450的ADC同步模式的一点理解,以及代码实现。

作为学习的过程产物,错误之处在所难免,希望各位积极指出,多多交流。

使用特权

评论回复
评论
为你转身 2023-1-18 23:04 回复TA
版权声明:本文为CSDN博主「rrrrrrrrrstart」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_43438751/article/details/122293216 
duo点| | 2023-1-18 19:27 | 显示全部楼层
本文讲了啥呀,是我没法看到吗

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 22:59 | 显示全部楼层
duo点 发表于 2023-1-18 19:27
本文讲了啥呀,是我没法看到吗

额,刚开始,就被老婆孩子拽去淘气堡了。。。

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 22:59 | 显示全部楼层
9556763c8095e04a01.png
对ADC同步模式的理解

该图片引自GD32F4xx_User_Manual_CN_V2.2

ADC的同步模式中,通过ADC0的触发器来同步ADC1和ADC2的转换。

该文字引自GD32F4xx_User_Manual_CN_V2.2

我的理解是:在对多路模拟信号进行采样时,同时使用ADC0,1,2三个模块,能够提高程序效率。
如图所示,规则并行模式下,对通道的采集是同时的,因此三个ADC模块不能同时对同一个通道进行采集,并且ADC采集的通道数量是对其的(各ADC模块的采集序列中的通道个数相同)。

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:02 | 显示全部楼层
ADC同步模式中使用DMA模式 0
在 ADC 同步 DMA 模式 0 中,DMA 传输的位宽为 16。一次 DMA 请求传输一个数据,这个数据轮流的从各 ADC的规则转换结果中取出。对于每次 DMA 请求,DMA 通道的源地址固定为ADC_SYNCDATA 寄存器,而这个寄存器的内容会变成 DMA要被传输的数值。
当所有的ADC都工作在同步模式时,DMA的传输序列为:
ADC0_RDATA[15:0] -> ADC1_RDATA[15:0] -> ADC2_RDATA[15:0] -> ADC0_RDATA[15:0] -> ADC1_RDATA[15:0] -> ADC2_RDATA[15:0]。

该文字引自GD32F4xx_User_Manual_CN_V2.2

DMA的数据传输,是通过读取同步规则数据寄存器 (ADC_SYNCDATA)中的数据来的,由上文可知,DMA的传输序列是ADC0~2的采集值轮流传输,因此DMA传输后的数组变量中的值按该顺序排列。

我的理解是:因为是ADC0~2轮流传输,所以最好将各ADC模块的采集序列中的通道个数设置的相同,这样不会出错,可以对同一个通道多次采样进行补齐。
————————————————
4345363c8096905e49.png

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:08 | 显示全部楼层
代码
1.配置思路
嵌入式系统外设驱动的配置思路是通用的:
1使能外设时钟;
2配置对应引脚;
3配置外设;
4启动外设(我认为外设的启动最好与配置分开,配置可以放在系统初始化中,启动可以放在任务程序的初始化中);

note:启动顺序最好是 timer/dma->adc.

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:09 | 显示全部楼层
ADC配置
下面代码主要参考了《GD32F4xx_Firmware_Library_V2.1.3》固件库中的示例。

一些宏定义:

#define ADC_CHANNEL_LENGTH                3U
#define ADCT_EN_TIMEOUT   ((uint32_t)0x1000)
#define ADC_MODULE_NUM                3U

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:12 | 显示全部楼层
    /* configure the ADC sync mode */
    adc_sync_mode_config(ADC_ALL_REGULAL_PARALLEL);
    adc_sync_dma_config(ADC_SYNC_DMA_MODE0);
    adc_sync_dma_request_after_last_enable();// notations of this func are fault
       
    /* ADC SCAN function enable */
    adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);
    adc_special_function_config(ADC1,ADC_SCAN_MODE,ENABLE);
    adc_special_function_config(ADC2,ADC_SCAN_MODE,ENABLE);
       
          /* ADC data alignment config */
    adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
    adc_data_alignment_config(ADC1,ADC_DATAALIGN_RIGHT);
    adc_data_alignment_config(ADC2,ADC_DATAALIGN_RIGHT);
   
    /* ADC channel length config */
    adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,ADC_CHANNEL_LENGTH);
    adc_channel_length_config(ADC1,ADC_REGULAR_CHANNEL,ADC_CHANNEL_LENGTH);
    adc_channel_length_config(ADC2,ADC_REGULAR_CHANNEL,ADC_CHANNEL_LENGTH);
       
    /* ADC regular channel config */
    adc_regular_channel_config(ADC0,0,ADC_CHANNEL_8, ADC_SAMPLETIME_15);//[AI9 ]PB0(ADC01_IN8)
    adc_regular_channel_config(ADC1,0,ADC_CHANNEL_10,ADC_SAMPLETIME_15);//[AI11]PC0(ADC012_IN10)
    adc_regular_channel_config(ADC2,0,ADC_CHANNEL_12,ADC_SAMPLETIME_15);//[AI13]PC2(ADC012_IN12)

        adc_regular_channel_config(ADC0,1,ADC_CHANNEL_9, ADC_SAMPLETIME_15);//[AI10]PB1(ADC01_IN9)
        adc_regular_channel_config(ADC1,1,ADC_CHANNEL_11,ADC_SAMPLETIME_15);//[AI12]PC1(ADC012_IN11)
        adc_regular_channel_config(ADC2,1,ADC_CHANNEL_5, ADC_SAMPLETIME_15);//[PTIN5]PF7(ADC2_IN5)
               
        adc_regular_channel_config(ADC0,2,ADC_CHANNEL_0, ADC_SAMPLETIME_15);//[AI1]PA0(ADC012_IN0)
        adc_regular_channel_config(ADC1,2,ADC_CHANNEL_1, ADC_SAMPLETIME_15);//[AI2]PA1(ADC012_IN1)
        adc_regular_channel_config(ADC2,2,ADC_CHANNEL_9, ADC_SAMPLETIME_15);//[PTIN1]PF3(ADC2_IN9)               
        //sample sequence:B0/C0/C2->B1/C1/F7->PA0/PA1/PF3

    /* ADC external trigger enable */
    adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_RISING);
    adc_external_trigger_config(ADC1,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
    adc_external_trigger_config(ADC2,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
    adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC_EXTTRIG_REGULAR_T1_CH1);

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:14 | 显示全部楼层
DMA配置
    /* ADC_DMA_channel configuration */
    dma_single_data_parameter_struct dma_single_data_parameter;
   
    /* ADC_DMA_channel configuration */
    dma_deinit(DMA1,DMA_CH0);
   
    /* initialize DMA single data mode */
    dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_SYNCDATA);
    dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_single_data_parameter.memory0_addr = (uint32_t)(adc_value);
    dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
    dma_single_data_parameter.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
    dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;
    dma_single_data_parameter.number = ADC_MODULE_NUM*ADC_CHANNEL_LENGTH;
    dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1,DMA_CH0,&dma_single_data_parameter);
    dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:15 | 显示全部楼层
DMA使能
    /* enable DMA channel */
    dma_channel_enable(DMA1,DMA_CH0);

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:16 | 显示全部楼层
TIMER配置
    timer_oc_parameter_struct timer_ocintpara;
    timer_parameter_struct timer_initpara;
       
    /* TIMER1 configuration */
    timer_initpara.prescaler         = 199;//200 MHz / (199 + 1) = 1 MHz
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 999;//period = 1 ms
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1,&timer_initpara);

    /* CH1 configuration in PWM mode0 */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_channel_output_config(TIMER1,TIMER_CH_1,&timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_1,899);
    timer_channel_output_mode_config(TIMER1,TIMER_CH_1,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER1,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:17 | 显示全部楼层
TIMER使能
  /* enable TIMER6 */
    timer_enable(TIMER1);       


使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:17 | 显示全部楼层
读取测试
                        adctest[0] = (uint32_t)adc_value[PB0_AI9] * 3300 / 4095;
                        adctest[1] = (uint32_t)adc_value[PC0_AI11] * 3300 / 4095;
                        adctest[2] = (uint32_t)adc_value[PC2_AI13] * 3300 / 4095;
                        adctest[3] = (uint32_t)adc_value[PB1_AI10] * 3300 / 4095;
                        adctest[4] = (uint32_t)adc_value[PC1_AI12] * 3300 / 4095;
                        adctest[5] = (uint32_t)adc_value[PF7_PTIN5] * 3300 / 4095;
                        adctest[6] = (uint32_t)adc_value[PA0_AI1] * 3300 / 4095;
                        adctest[7] = (uint32_t)adc_value[PA1_AI2] * 3300 / 4095;
                        adctest[8] = (uint32_t)adc_value[PF3_PTIN1] * 3300 / 4095;

使用特权

评论回复
为你转身|  楼主 | 2023-1-18 23:19 | 显示全部楼层
总结
上述代码段可以直接放入基于GD32F450项目的函数中去使用,需要配置GPIO和时钟。一点思考是,在使用DMA的时候一定要考虑故障诊断。
我本人也是GD32的初学者,深知驱动的配置和使用只是嵌入式开发的入门和皮毛,希望和各位多交流,共同进步。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

401

帖子

0

粉丝