APM32E030的ADC驱动(DMA)
APM32E030为12位ADC,同时有16个外部通道和2个内部通道。
同时,ADC支持与DMA的联动,实现更高效的数据采集。
ADC与DMA的驱动代码如下:
/*
*PA0 -> ADC_IN0
*PA1 -> ADC_IN1
*PA2 -> ADC_IN2
*PA3 -> ADC_IN3
*PA4 -> ADC_IN4
*PA5 -> ADC_IN5
*PA6 -> ADC_IN6
*PA7 -> ADC_IN7
*PB0 -> ADC_IN8
*PB1 -> ADC_IN9
*PC0 -> ADC_IN10
*PC1 -> ADC_IN11
*PC2 -> ADC_IN12
*PC3 -> ADC_IN13
*PC4 -> ADC_IN14
*PC5 -> ADC_IN15
*/
typedef struct {
GPIO_T *port;
uint16_t pin;
uint32_t AHBPeriph;
uint32_t adc_channel;
} adc_ch_info_t;
/* ADC信息 */
static adc_ch_info_t adc_ch_info[] = {
{GPIOA, GPIO_PIN_0, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_0 },
{GPIOA, GPIO_PIN_1, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_1 },
{GPIOA, GPIO_PIN_2, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_2 },
{GPIOA, GPIO_PIN_3, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_3 },
{GPIOA, GPIO_PIN_4, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_4 },
{GPIOA, GPIO_PIN_5, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_5 },
{GPIOA, GPIO_PIN_6, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_6 },
{GPIOA, GPIO_PIN_7, RCM_AHB_PERIPH_GPIOA, ADC_CHANNEL_7 },
{GPIOB, GPIO_PIN_0, RCM_AHB_PERIPH_GPIOB, ADC_CHANNEL_8 },
{GPIOB, GPIO_PIN_1, RCM_AHB_PERIPH_GPIOB, ADC_CHANNEL_9 },
{GPIOC, GPIO_PIN_0, RCM_AHB_PERIPH_GPIOC, ADC_CHANNEL_10 },
{GPIOC, GPIO_PIN_1, RCM_AHB_PERIPH_GPIOC, ADC_CHANNEL_11 },
{GPIOC, GPIO_PIN_2, RCM_AHB_PERIPH_GPIOC, ADC_CHANNEL_12 },
{GPIOC, GPIO_PIN_3, RCM_AHB_PERIPH_GPIOC, ADC_CHANNEL_13 },
{GPIOC, GPIO_PIN_4, RCM_AHB_PERIPH_GPIOC, ADC_CHANNEL_14 },
{GPIOC, GPIO_PIN_5, RCM_AHB_PERIPH_GPIOC, ADC_CHANNEL_15 },
{NULL, 0, 0, ADC_CHANNEL_16 },
{NULL, 0, 0, ADC_CHANNEL_17 },
};/*
* @brief 引脚初始化
*
* @param None
*
* @retval None
*
*/
void bsp_adc_gpio_init(void)
{
GPIO_Config_T gpioConfig;
uint8_t ch = 0;
for (ch = 0; ch < (sizeof(adc_ch_info) / sizeof(adc_ch_info)); ch++) {
RCM_EnableAHBPeriphClock(adc_ch_info.AHBPeriph);
GPIO_ConfigStructInit(&gpioConfig);
gpioConfig.pin = adc_ch_info.pin;
gpioConfig.mode = GPIO_MODE_AN;
gpioConfig.outtype = GPIO_OUT_TYPE_PP;
gpioConfig.speed = GPIO_SPEED_50MHz;
gpioConfig.pupd = GPIO_PUPD_NO;
GPIO_Config(adc_ch_info.port, &gpioConfig);
}
}/*
* @brief ADC初始化
*
* @param membuf: 存储地址
*
* @retval None
*
*/
void bsp_adc_init(uint16_t *membuf)
{
ADC_Config_T adcConfig;
DMA_Config_T dmaConfig;
uint32_t ch = ADC_CHANNEL_0 | ADC_CHANNEL_1 | ADC_CHANNEL_2 | ADC_CHANNEL_3 | ADC_CHANNEL_4 | \
ADC_CHANNEL_5 | ADC_CHANNEL_6 | ADC_CHANNEL_7 | ADC_CHANNEL_8 | ADC_CHANNEL_9 | \
ADC_CHANNEL_10 | ADC_CHANNEL_11 | ADC_CHANNEL_12 | ADC_CHANNEL_13 | ADC_CHANNEL_14 | \
ADC_CHANNEL_15 | ADC_CHANNEL_16 | ADC_CHANNEL_17;
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
/* DMA配置 */
DMA_ConfigStructInit(&dmaConfig);
dmaConfig.direction = DMA_DIR_PERIPHERAL;
dmaConfig.circular = DMA_CIRCULAR_DISABLE;
dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
dmaConfig.priority = DMA_PRIORITY_LEVEL_LOW;
dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_HALFWORD;
dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD;
dmaConfig.bufferSize = ADC_CH_NUM;
dmaConfig.memoryAddress = (uint32_t)membuf;
dmaConfig.peripheralAddress = (uint32_t)&ADC->DATA;
DMA_Config(DMA1_CHANNEL_1, &dmaConfig);
DMA_Enable(DMA1_CHANNEL_1);
/* ADC Configuration */
ADC_Reset();
ADC_ConfigStructInit(&adcConfig);
/* Set resolution*/
adcConfig.resolution = ADC_RESOLUTION_12B;
/* Set dataAlign*/
adcConfig.dataAlign= ADC_DATA_ALIGN_RIGHT;
/* Set scanDir*/
adcConfig.scanDir = ADC_SCAN_DIR_UPWARD;
/* Set single */
adcConfig.convMode = ADC_CONVERSION_SINGLE;
/* Set extTrigConv*/
adcConfig.extTrigConv= ADC_EXT_TRIG_CONV_TRG0;
/* Set TrigEdge*/
adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;
ADC_Config(&adcConfig);
ADC_EnableTempSensor();
ADC_EnableVrefint();
ADC_ConfigChannel(ch, ADC_SAMPLE_TIME_41_5);
/* Calibration*/
ADC_ReadCalibrationFactor();
/* Enable ADC*/
ADC_Enable();
ADC_EnableDMA();
}/*
* @brief ADC启动
*
* @param None
*
* @retval None
*
*/
void bsp_adc_start(void)
{
DMA_Disable(DMA1_CHANNEL_1);
DMA_SetDataNumber(DMA1_CHANNEL_1, ADC_CH_NUM);
DMA_Enable(DMA1_CHANNEL_1);
/* Wait until ADC is ready */
while (!ADC_ReadStatusFlag(ADC_FLAG_ADRDY));
ADC_StartConversion();
}/*
* @brief ADC停止
*
* @param None
*
* @retval None
*
*/
void bsp_adc_stop(void)
{
ADC_StopConversion();
}/*
* @brief ADC完成
*
* @param None
*
* @retval 完成结果
*
*/
uint8_t bsp_adc_complete(void)
{
uint8_t ret = 0;
if (DMA_ReadStatusFlag(DMA1_FLAG_TF1) != RESET) {
DMA_ClearStatusFlag(DMA1_FLAG_TF1);
ret = 1;
}
return ret;
}enum ADC_CH {
ADC_CH0,
ADC_CH1,
ADC_CH2,
ADC_CH3,
ADC_CH4,
ADC_CH5,
ADC_CH6,
ADC_CH7,
ADC_CH8,
ADC_CH9,
ADC_CH10,
ADC_CH11,
ADC_CH12,
ADC_CH13,
ADC_CH14,
ADC_CH15,
ADC_CH16,
ADC_CH17,
ADC_CH_NUM
};
测试代码如下:
uint16_t adc_ch_value;
float adc_ch_voltage;
// 应用初始化
void app_init(void)
{
bsp_adc_gpio_init();
bsp_adc_init(adc_ch_value);
bsp_adc_start();
}
// 应用任务
void app_task(void)
{
if (bsp_adc_complete() != 0) {
for (uint8_t i = 0; i < ADC_CH_NUM; i++) {
adc_ch_voltage = ((float)adc_ch_value) / 4095 * 3.3f;
}
bsp_adc_start();
}
}
详细代码,请查看附件!
代码中使用了DMA来提高ADC的数据采集效率,这是一个很好的做法
启动一次,ADC通道转换与剩下的操作就都由DMA来实现了。
比一次一次读取方便多了
页:
[1]