口天土立口 发表于 2025-9-15 17:28

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();
    }
}

详细代码,请查看附件!







复古留声机 发表于 2025-9-27 09:55

代码中使用了DMA来提高ADC的数据采集效率,这是一个很好的做法

夜幕叙事曲 发表于 2025-10-4 10:07

启动一次,ADC通道转换与剩下的操作就都由DMA来实现了。
比一次一次读取方便多了
页: [1]
查看完整版本: APM32E030的ADC驱动(DMA)