🛠 Acquisition ADC en DMA circulaire

GD32F103 (GigaDevice) — chip + placas compatibles Blue Pill · avance · Schéma : IMG-gd32f103-avance-2-dma-adc.svg — flux ADC0 vers DMA0 canal 0 vers un tampon en SRAM en mode circulaire, sans intervention CPU, sur GD32F103C8

Objetivos

Descargar la CPU de la adquisición analógica: configurar ADC0 en conversiones continuas gestionadas por DMA0 (7 canales en el GD32F103) en modo circular, para rellenar permanentemente un búfer de 64 muestras de 12 bits sin ninguna interrupción de lectura. Esta es la base de un osciloscopio, un vúmetro o un filtro digital. Manipulará RCU (incluido su divisor de reloj ADC, máx. 14 MHz), GPIO en modo AIN, ADC y DMA mediante SPL.

Material

Código completo

/* dma_adc.c — GD32F103C8, SPL V2.2.x : ADC0 continue + DMA0 CH0 circulaire. */
#include "gd32f10x.h"

#define NSAMPLES 64
static uint16_t echantillons[NSAMPLES];

int main(void)
{
    dma_parameter_struct dp;

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_ADC0);
    rcu_periph_clock_enable(RCU_DMA0);
    /* APB2 = 108 MHz -> /8 = 13,5 MHz <= 14 MHz max (datasheet) */
    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);

    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_1);

    /* ADC0 : canal régulier unique, IN1, conversions continues sans trigger */
    adc_deinit(ADC0);
    adc_mode_config(ADC_MODE_FREE);
    adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);
    adc_regular_channel_config(ADC0, 0, 1, ADC_SAMPLETIME_239POINT5);
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL,
                                       ADC_EXTTRIG_REGULAR_NONE);
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
    adc_dma_mode_enable(ADC0);
    adc_enable(ADC0);
    adc_calibration_enable(ADC0);

    /* DMA0 canal 0 : ADC0_RDATA -> echantillons[], circulaire, 16 bits */
    dma_deinit(DMA0, DMA_CH0);
    dp.peripheral_address = (uint32_t)&ADC_RDATA(ADC0);
    dp.memory_address     = (uint32_t)echantillons;
    dp.transfer_mode      = DMA_MODE_CIRCULAR;
    dp.peripheral_source  = DMA_PERIPHERAL_ADC0;
    dp.peripheral_width   = DMA_PERIPHERAL_WIDTH_16BIT;
    dp.memory_width       = DMA_MEMORY_WIDTH_16BIT;
    dp.number             = NSAMPLES;
    dp.priority           = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH0, &dp);
    dma_flag_clear(DMA0, DMA_CH0, DMA_FLAG_G);
    dma_enable(DMA0, DMA_CH0);

    adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);

    rcu_periph_clock_enable(RCU_USART0);   /* console 115200, voir t. console */

    while (1) {
        /* le DMA remplit le tampon en continu ; le CPU est libre */
        if (dma_flag_get(DMA0, DMA_CH0, DMA_FLAG_HT) == SET) {
            dma_flag_clear(DMA0, DMA_CH0, DMA_FLAG_HT);
            /* première moitié prête : la traiter ou l'imprimer */
        }
    }
}

Verificación esperada

El búfer echantillons[] contiene permanentemente valores de 0-4095 coherentes con la tensión de entrada (0 V da ~0, 3,3 V da ~4095), actualizados sin que el código principal lea el ADC. Al inyectar una señal periódica (salida PWM filtrada, o potenciómetro movido lentamente), se observa la forma de onda en el búfer a través del editor (vista en vivo). La CPU sigue disponible: un LED parpadeante en el bucle principal continúa parpadeando con regularidad.

Errores frecuentes

Otros tutoriales para esta placa

Ejemplos de código para esta placa

← Volver a la ficha 🛠 Todos los tutoriales