GD32F4xx MCU ADC+DMA 多通道采样

1、GD32F4xx ADC

GD32F4xx 的12位ADC是一种采用逐次逼近方式的模拟数字转换器。

1.1 主要特征

  1. 可配置12位、10位、8位、6位分辨率;
  2. ADC采样率:12位分辨率为2.6MSPs,10位分辨率为3.0 MSPs。分辨率越低,转换越快;
    PS: MSPs (模拟混合信号转换速率),是指完成1次从模拟转换到数字的AD转换所需的时间的倒数。常用单位是ksps和Msps,表示每秒采样(千)/(百万)次(kilo / Million Samples per Second)。 1msps=1000 ksps
  3. 自校准时间:131个ADC时钟周期;(如25MHz时钟,校准时间约5.24us
  4. 可编程采样时间、可配置数据对齐方式;
  5. 支持规则通道数据转换的DMA请求;
  6. 模拟输入通道:
    1) 16个外部输入通道;
    2) 1个内部温度传感器通道;
    3) 1个内部参考电压输入通道;
    4) 1个外部监测电池Vbat供电引脚输入通道;
  7. 转换触发: 软件触发 和 硬件触发(硬件中断等

1.2 引脚定义

引脚名称 信号类型 说明
VDDA 输入,模拟供电电源 2.6v ≤ VDDA ≤ 3.6v
VSSA 输入,模拟电源地 等于Vss
VREFP 输入,模拟参考电压正 ADC 正参考电压 2.6v ≤ VREFP ≤ VDDA
VREFN 输入,模拟参考电压负 ADC 负参考电压 VREFN = VSSA
ADCx_IN[15:0] 输入,模拟信号 16路外部通道
VBAT 输入,模拟信号 外部电池电压

PS: VDDA 和 VSSA 必须分别接到VDD 和 Vss

1.3 ADC校准

ADC带有一个前置校准功能。在校准期间,ADC计算一个校准系数,这个系数直到ADC下次掉电才无效。在校准期间,不能使用ADC必须等到校准完成。在AD转换之前应执行校准操作,一般放在初始化里执行。通过软件设置 ADC_CTL1寄存器的RSTCLB位为1来对校准进行初始化,在校准期间RSTCLB位会一直保持1,直到校准完成,该位由硬件清0。

PS: 当ADC运行条件改变(如,VDDA、VREFP、温度等条件变化,建议重新执行一次校准操作。)

1.4 ADC时钟

ADC CLK 与 CK_AHB、PLCK2 时钟保持同步。ADC最大时钟频率为40MHz。
GD32F4xx MCU ADC+DMA 多通道采样_第1张图片

1.5 规则组和注入组

ADC转换可以组织成2组: 一个规则组通道和一个注入组通道。
1)规则组最多16个转换组成。而注入组最多4个转换组成。
2)注入组通道可以打断规则组通道
注入通道有2中模式:
① 触发注入模式: 在规则组通道转换期间如果软件触发或外部触发发生,ADC取消当前转换,启动触发注入转换,注入通道序列被以单次扫描方式进行转换。注入通道转换结束后,规则组转换从上次被取消的转换处重新开始。
② 自动注入模式:在规则通道之后,注入通道被自动转换。

1.6 转换模式

举例说明: 规则组通道序列为 CH_0、CH_1、CH_2。
GD32F4xx MCU ADC+DMA 多通道采样_第2张图片

1.7 其他

  1. 模拟看门狗,可以设置ADC转换电压的低阈值和高阈值,当转换电压 < 低阈值或 >高阈值时,看门狗可以置位标志位或产生中断。可以通过配置看门狗监控单一通道或多通道。
  2. 可编程的采样时间:ADC使用若干个ADCCLK周期对输入电压进行采样。每个通道可以用不同的时间采样。
    12位分辨率的情况下:总转换时间 = 采样时间 + 12个ADCCLK
  3. DMA:ADC在规则组一个通道转换结束后产生一个DMA请求,DMA接收到请求后可以将转换的数据从ADC_RDATA寄存器传输到用户指定的目的地址。
  4. ADC同步模式:待研究…

2、ADC + DMA 测试代码

ADC_DMA_Init

// ADC Init
void ADC_DMA_Init(void)
{
	/* enable GPIOC clock */
    rcu_periph_clock_enable(RCU_GPIOC);		// enable GPIOC clk
	/* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC0);		// enable ADC clk
    /* config ADC clock */ 
    adc_clock_config(ADC_ADCCK_PCLK2_DIV4);	// config ADC clk: PCLK2/4 = 25MHz  (PCLK2=100MHz)
	
	rcu_periph_clock_enable(RCU_DMA1);		// enable DMA1 clk

	/* config the GPIO as analog mode */
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0); // PC0 : ADC012_IN10 
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1); // PC1 : ADC012_IN11 
	ADC_Config();	// ADC init
	DMA_config();	// DMA init
	Log_printf("ADC_DMA_Init\r\n");
}

ADC_Config

void ADC_Config(void)
{
	// ADC 独立模式
    adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
    // 连续转换模式使能
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
    // Scan mode enable
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    // ADC data右对齐
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    
    // 规则通道数量
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 2);
    // ADC规则通道配置:Rank优先级排序(0~15),采样时间:15个周期
    adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_10, ADC_SAMPLETIME_15);
    adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_11, ADC_SAMPLETIME_15);

	adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 12位分辨率
	// ADC外部触发禁用, 即只能使用软件触发
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
    
    // ADC DMA function enable
    adc_dma_request_after_last_enable(ADC0);  // 每个规则组通道转换完成后发送一个DMA请求
    adc_dma_mode_enable(ADC0);
    
    adc_enable(ADC0);
    // wait for ADC stability 
	osDelay(1);
    // ADC自校准
    adc_calibration_enable(ADC0); 
}

DMA_config

#define ADC_CH_CNT 2  //ADC通道数
#define ADC_VALUE_CNT 30  //每通道保存值个数
#define ADC_BUF_LEN (ADC_CH_CNT * ADC_VALUE_CNT)  //DMA缓冲区数据长度
uint16_t gt_adc_val[ADC_BUF_LEN];  //DMA缓冲区

void DMA_config(void)
{
	// ADC0 DMA
    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_RDATA(ADC0));	// peripheral address
    dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_single_data_parameter.memory0_addr = (uint32_t)(gt_adc_val);		// memory address
    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.direction = DMA_PERIPH_TO_MEMORY;				// transfer direction
    dma_single_data_parameter.number = ADC_BUF_LEN;							// transfer 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);

    // 使能循环模式
    dma_circulation_enable(DMA1, DMA_CH0);
}

ADC_Conv_Start

// 启动ADC转换
void ADC_Conv_Start(void)
{
	dma_channel_enable(DMA1, DMA_CH0); // 启动DMA
	adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL); // 开启软件触发ADC转换
}

PS:
1.开启转换后,ADC采样值通过DMA直接传送到了gt_adc_val[ADC_BUF_LEN] 中。由于规则通道组是2个通道(ADC_CHANNEL_10,ADC_CHANNEL_11)。gt_adc_val[ADC_BUF_LEN] 中的存储形式如下:

gt_adc_val[0] = ADC_CHANNEL_10的值;
gt_adc_val[1] = ADC_CHANNEL_11的值;
gt_adc_val[2] = ADC_CHANNEL_10的值;
gt_adc_val[3] = ADC_CHANNEL_11的值;

2.采样值转换12位分辨率: Value = Vadc * VREFP / 4096


以上是近期使用的一些总结,后续如有需要会继续补充!

To Be Continue …

你可能感兴趣的:(GD32,MCU,GD32,ADC,DMA)