开工第一天,今天是DMA方式的ADC采样。
ADC即模拟数字转换器,ADC的精度一般用位来表示,位数越多,表示相同模拟量范围内的采样点数越多,那么相应的精度就越高。
比如:12位表示的范围是0 ~ 2^12 (4096),8位表示的范围是0 ~ 2^8 (256),前者的精度是后者的16倍。
ADC一般需要配置的内容包括:
【注】ADC的规则组和注入组的区别可简单理解为:规则组是周期执行的程序,注入组是中断程序。
DMA即直接存储器访问控制器,DMA提供了一种硬件的方式在外设和存储器之间或者存储器和存储器之间传输数据,而无需CPU的介入,避免了CPU多次进入中断进行大规模的数据拷贝,最终提高整体的系统性能。
简单而言,DMA相当于是外请(DMA硬件)的搬运工(数据拷贝),节约宝贵的CPU资源。
DMA一般需要配置的内容包括:
DMA的配置需要注意通道的匹配:
STM32F103 DMA通道配置
GD32F450 DMA通道配置
注意,在GD32L233中新增了一个DMAMUX的设计,即在DMA控制器前一级增加了的多路选择器,相比如上图,它的好处是更灵活,缺点当然也是更灵活了。
GD32L233 DMAMUX结构
从设计的角度来看,这种配置个人觉得固定成一张表更好理解和处理。
先把DMA的概念代入,ADC属于外设,我们一般使用ADC的DMA是把ADC的采样数据传送到内存中供程序使用,那么它的处理数据链是:ADC通道数据地址-DMA缓存数据-滤波-业务层数据,DMA的确是省了很多软件的事。
基本架构:
流程和数据结构:
由于单片机内置了CPU温度值,Vrefint和Vbatt(STM32无Vbatt)的采样通道,这里的示例用这几个通道来做示例。
GD32L233的温度计算公式跟GD32F450不一样,在用户手册中写清楚了:
温度(°C) = ((Dtemperature – D30) / Avg_Slope) + 30
D30在芯片内固定:
#define ADC_TEMP_CALIBRATION_VALUE REG16(0x1FFFF7F8)
adc配置:
void adc1_init(int32_t channel_num)
{
/* enable ADC clock */
rcu_periph_clock_enable(RCU_ADC);
rcu_periph_clock_enable(RCU_GPIOA);
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
/* config ADC clock */
rcu_adc_clock_config(RCU_ADCCK_APB2_DIV16);
/* ADC SCAN function enable */
adc_special_function_config(ADC_SCAN_MODE, ENABLE);
/* conyinuous mode */
adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
adc_channel_length_config(ADC_REGULAR_CHANNEL, channel_num);
/* ADC temperature and Vrefint enable */
adc_channel_16_to_19(ADC_TEMP_CHANNEL_SWITCH, ENABLE);
adc_channel_16_to_19(ADC_INTERNAL_CHANNEL_SWITCH, ENABLE);
adc_channel_16_to_19(ADC_VBAT_CHANNEL_SWITCH, ENABLE);
adc_regular_channel_config(0, ADC_CHANNEL_adc_test, ADC_SAMPLETIME_239POINT5);
adc_regular_channel_config(1, ADC_CHANNEL_cpu_temper, ADC_SAMPLETIME_239POINT5);
adc_regular_channel_config(2, ADC_CHANNEL_cpu_vref, ADC_SAMPLETIME_239POINT5);
adc_regular_channel_config(3, ADC_CHANNEL_vbatt, ADC_SAMPLETIME_239POINT5);
/* enable ADC interface */
adc_enable();
adc_dma_mode_enable();
delay_ms(1U);
/* ADC calibration and reset calibration */
adc_calibration_enable();
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}
DMA配置:
void adc1_dma_init(uint32_t addr, uint32_t number)
{
/* ADC_DMA_channel configuration */
dma_parameter_struct dma_parameter;
/* enable DMA0 clock */
rcu_periph_clock_enable(RCU_DMA);
/* ADC DMA_channel configuration */
dma_deinit(DMA_CH0);
/* initialize DMA data mode */
dma_struct_para_init(&dma_parameter);
dma_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_parameter.periph_addr = (uint32_t)(&ADC_RDATA);
dma_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
dma_parameter.memory_addr = addr;
dma_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT;
dma_parameter.number = number;
dma_parameter.priority = DMA_PRIORITY_HIGH;
dma_parameter.request = DMA_REQUEST_ADC;
dma_init(DMA_CH0, &dma_parameter);
dma_circulation_enable(DMA_CH0);
dma_interrupt_enable(DMA_CH0, DMA_CHXCTL_FTFIE);
nvic_irq_enable(DMA_Channel0_IRQn, 2);
dma_channel_enable(DMA_CH0);
}
头文件:
#define COFF_33_4096_10000000x 8057 ///< 3.3/4096 (10000000)
#if defined(GD32M0)
#define COFF_VBATT 3
#define CPU_TEMP_AD_BASE_1000x 30000 ///< 30度
#define ADC_TEMP_CALIBRATION_VALUE REG16(0x1FFFF7F8)
#define GET_CPU_TEMPERATURE(data) CPU_TEMP_AD_BASE_1000x + (data - (int32_t)ADC_TEMP_CALIBRATION_VALUE) * COFF_1_4096_10000000x / 10
#define GET_CPU_VREF(data) COFF_33_4096_10000000x*data/10000
#define GET_CPU_VBATT(data) COFF_33_4096_10000000x*data*COFF_VBATT/10000
#define ADC_CHANNEL_adc_test ((uint8_t)ADC_CHANNEL_1)
#define ADC_CHANNEL_cpu_temper ((uint8_t)ADC_CHANNEL_16)
#define ADC_CHANNEL_cpu_vref ((uint8_t)ADC_CHANNEL_17)
#define ADC_CHANNEL_vbatt ((uint8_t)ADC_CHANNEL_18)
#endif
DMA中断函数:
略
数据扩大1000倍,其中2~4依次是温度,参考电压和电池电压。
adc = [1143] [23654] [1198] [3304]
adc = [1144] [22677] [1198] [3304]
adc = [1144] [22922] [1198] [3304]
adc = [1144] [23410] [1198] [3304]
adc = [1144] [23654] [1198] [3304]
adc = [1144] [22922] [1198] [3304]