对GD32F450的ADC同步模式的理解

[复制链接]
1297|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同步模式的一点理解,以及代码实现。

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

评论

版权声明:本文为CSDN博主「rrrrrrrrrstart」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_43438751/article/details/122293216  发表于 2023-1-18 23:04
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 | 显示全部楼层
  1.     /* configure the ADC sync mode */
  2.     adc_sync_mode_config(ADC_ALL_REGULAL_PARALLEL);
  3.     adc_sync_dma_config(ADC_SYNC_DMA_MODE0);
  4.     adc_sync_dma_request_after_last_enable();// notations of this func are fault
  5.        
  6.     /* ADC SCAN function enable */
  7.     adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);
  8.     adc_special_function_config(ADC1,ADC_SCAN_MODE,ENABLE);
  9.     adc_special_function_config(ADC2,ADC_SCAN_MODE,ENABLE);
  10.        
  11.           /* ADC data alignment config */
  12.     adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
  13.     adc_data_alignment_config(ADC1,ADC_DATAALIGN_RIGHT);
  14.     adc_data_alignment_config(ADC2,ADC_DATAALIGN_RIGHT);
  15.    
  16.     /* ADC channel length config */
  17.     adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,ADC_CHANNEL_LENGTH);
  18.     adc_channel_length_config(ADC1,ADC_REGULAR_CHANNEL,ADC_CHANNEL_LENGTH);
  19.     adc_channel_length_config(ADC2,ADC_REGULAR_CHANNEL,ADC_CHANNEL_LENGTH);
  20.        
  21.     /* ADC regular channel config */
  22.     adc_regular_channel_config(ADC0,0,ADC_CHANNEL_8, ADC_SAMPLETIME_15);//[AI9 ]PB0(ADC01_IN8)
  23.     adc_regular_channel_config(ADC1,0,ADC_CHANNEL_10,ADC_SAMPLETIME_15);//[AI11]PC0(ADC012_IN10)
  24.     adc_regular_channel_config(ADC2,0,ADC_CHANNEL_12,ADC_SAMPLETIME_15);//[AI13]PC2(ADC012_IN12)

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

  33.     /* ADC external trigger enable */
  34.     adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_RISING);
  35.     adc_external_trigger_config(ADC1,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
  36.     adc_external_trigger_config(ADC2,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
  37.     adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC_EXTTRIG_REGULAR_T1_CH1);
 楼主| 为你转身 发表于 2023-1-18 23:14 | 显示全部楼层
DMA配置
  1.     /* ADC_DMA_channel configuration */
  2.     dma_single_data_parameter_struct dma_single_data_parameter;
  3.    
  4.     /* ADC_DMA_channel configuration */
  5.     dma_deinit(DMA1,DMA_CH0);
  6.    
  7.     /* initialize DMA single data mode */
  8.     dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_SYNCDATA);
  9.     dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  10.     dma_single_data_parameter.memory0_addr = (uint32_t)(adc_value);
  11.     dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  12.     dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
  13.     dma_single_data_parameter.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
  14.     dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;
  15.     dma_single_data_parameter.number = ADC_MODULE_NUM*ADC_CHANNEL_LENGTH;
  16.     dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;
  17.     dma_single_data_mode_init(DMA1,DMA_CH0,&dma_single_data_parameter);
  18.     dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
 楼主| 为你转身 发表于 2023-1-18 23:15 | 显示全部楼层
DMA使能
  1.     /* enable DMA channel */
  2.     dma_channel_enable(DMA1,DMA_CH0);
 楼主| 为你转身 发表于 2023-1-18 23:16 | 显示全部楼层
TIMER配置
  1.     timer_oc_parameter_struct timer_ocintpara;
  2.     timer_parameter_struct timer_initpara;
  3.        
  4.     /* TIMER1 configuration */
  5.     timer_initpara.prescaler         = 199;//200 MHz / (199 + 1) = 1 MHz
  6.     timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
  7.     timer_initpara.counterdirection  = TIMER_COUNTER_UP;
  8.     timer_initpara.period            = 999;//period = 1 ms
  9.     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
  10.     timer_initpara.repetitioncounter = 0;
  11.     timer_init(TIMER1,&timer_initpara);

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

  16.     timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_1,899);
  17.     timer_channel_output_mode_config(TIMER1,TIMER_CH_1,TIMER_OC_MODE_PWM0);
  18.     timer_channel_output_shadow_config(TIMER1,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);
 楼主| 为你转身 发表于 2023-1-18 23:17 | 显示全部楼层
TIMER使能
  1.   /* enable TIMER6 */
  2.     timer_enable(TIMER1);       


 楼主| 为你转身 发表于 2023-1-18 23:17 | 显示全部楼层
读取测试
  1.                         adctest[0] = (uint32_t)adc_value[PB0_AI9] * 3300 / 4095;
  2.                         adctest[1] = (uint32_t)adc_value[PC0_AI11] * 3300 / 4095;
  3.                         adctest[2] = (uint32_t)adc_value[PC2_AI13] * 3300 / 4095;
  4.                         adctest[3] = (uint32_t)adc_value[PB1_AI10] * 3300 / 4095;
  5.                         adctest[4] = (uint32_t)adc_value[PC1_AI12] * 3300 / 4095;
  6.                         adctest[5] = (uint32_t)adc_value[PF7_PTIN5] * 3300 / 4095;
  7.                         adctest[6] = (uint32_t)adc_value[PA0_AI1] * 3300 / 4095;
  8.                         adctest[7] = (uint32_t)adc_value[PA1_AI2] * 3300 / 4095;
  9.                         adctest[8] = (uint32_t)adc_value[PF3_PTIN1] * 3300 / 4095;
 楼主| 为你转身 发表于 2023-1-18 23:19 | 显示全部楼层
总结
上述代码段可以直接放入基于GD32F450项目的函数中去使用,需要配置GPIO和时钟。一点思考是,在使用DMA的时候一定要考虑故障诊断。
我本人也是GD32的初学者,深知驱动的配置和使用只是嵌入式开发的入门和皮毛,希望和各位多交流,共同进步。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

82

主题

741

帖子

0

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