1、GD32F4xx ADC
GD32F4xx 的12位ADC是一种采用逐次逼近方式的模拟数字转换器。
1.1 主要特征
- 可配置12位、10位、8位、6位分辨率;
- ADC采样率:12位分辨率为2.6MSPs,10位分辨率为3.0 MSPs。分辨率越低,转换越快;
PS: MSPs (模拟混合信号转换速率),是指完成1次从模拟转换到数字的AD转换所需的时间的倒数。常用单位是ksps和Msps,表示每秒采样(千)/(百万)次(kilo / Million Samples per Second)。 1msps=1000 ksps
- 自校准时间:131个ADC时钟周期;(如25MHz时钟,校准时间约5.24us)
- 可编程采样时间、可配置数据对齐方式;
- 支持规则通道数据转换的DMA请求;
- 模拟输入通道:
1) 16个外部输入通道;
2) 1个内部温度传感器通道;
3) 1个内部参考电压输入通道;
4) 1个外部监测电池Vbat供电引脚输入通道;
- 转换触发: 软件触发 和 硬件触发(硬件中断等)
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。
1.5 规则组和注入组
ADC转换可以组织成2组: 一个规则组通道和一个注入组通道。
1)规则组最多16个转换组成。而注入组最多4个转换组成。
2)注入组通道可以打断规则组通道
注入通道有2中模式:
① 触发注入模式: 在规则组通道转换期间如果软件触发或外部触发发生,ADC取消当前转换,启动触发注入转换,注入通道序列被以单次扫描方式进行转换。注入通道转换结束后,规则组转换从上次被取消的转换处重新开始。
② 自动注入模式:在规则通道之后,注入通道被自动转换。
1.6 转换模式
举例说明: 规则组通道序列为 CH_0、CH_1、CH_2。
1.7 其他
- 模拟看门狗,可以设置ADC转换电压的低阈值和高阈值,当转换电压 < 低阈值或 >高阈值时,看门狗可以置位标志位或产生中断。可以通过配置看门狗监控单一通道或多通道。
- 可编程的采样时间:ADC使用若干个ADCCLK周期对输入电压进行采样。每个通道可以用不同的时间采样。
12位分辨率的情况下:总转换时间 = 采样时间 + 12个ADCCLK
- DMA:ADC在规则组一个通道转换结束后产生一个DMA请求,DMA接收到请求后可以将转换的数据从ADC_RDATA寄存器传输到用户指定的目的地址。
- 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 …