Fading Coder

An Old Coder’s Final Dance

Home > Tech > Content

STM32 HAL ADC: configuration, sampling strategies, and data movement with polling, interrupts, and DMA

Tech 2

1. Fundamentals

  • ADC converts an analog voltage into a digital code.
  • Resolution defines the number of quantization steps:
    • 8-bit: 0–255
    • 12-bit: 0–4095 (2^12 − 1)
  • A single ADC controller typicallly multiplexes multiple input channels. When reading more than one channel, enable scanning or explicitly select each channel.
  • DMA can transfer ADC results directly into memory without CPU involvement, improving throughput and reducing latency.
  • Reference voltages (Vref+ and Vref−) define the conversion range. Many STM32 designs use Vref+ = VCC and Vref− = GND. Some devices support an external reference pin.
  • Internal channels are available for on-chip temperature sensor and VBAT/RTC supply measurement.
  • Sampling time affects accuracy and source loading. Longer sampling times improve acquisition for high-impedance sources. The total time per conversion is a function of the ADC clock and the selected sampling cycles.
    • Example: with ADC clock = 12 MHz and sampling time = 239.5 cycles, one conversion duration ≈ (SamplingCycles + ConversionCycles)/Fadc.

Conversion modes

  • Single conversion: performs one conversion for the current channel/rank.
  • Continuous conversion: repeats conversions without software re-trigger.
  • Scan mode: steps through a configured sequence of ranks (multiple channels).

Operation strategies

  • Polling (blocking): CPU waits for completion via HAL_ADC_PollForConversion.
  • Interrupt-driven: conversion-complete (EOC) triggers HAL callback.
  • DMA-driven: hardware fills a memory buffer automatically.

2. CubeMX essentials

  • System clock: configure an external crystal if required and set SWD for debugging.
  • ADC prescaler and clock: target 12 MHz ADC clock (device-dependent; ensure within datasheet limits).
  • Enable the desired ADC instance (e.g., ADC1) and set:
    • Resolution (e.g., 12-bit)
    • Data alignment (left or right; right-aligned is typical)
    • Scan mode if sampling multiple channels
    • Continuous vs. discontinuous mode
    • Number of conversions (ranks) when scanning
    • External trigger (software, timer, etc.)
    • Sampling time for each channel (e.g., 239.5 cycles)
    • Optional: Analog Watchdog thresholds for out-of-range detection

Configure pins for anallog mode for the selected channels. If using internal channels (temperature sensor, VBAT), enable them where applicable.

3. Single-channel acquisition using polling (blocking)

Use when CPU time is available and sample rate is low.

  • Steps:
    1. Start conversion
    2. Poll for completion
    3. Read the result

Example (assuming ADC1 and one configured regular channel):

#include "main.h"

extern ADC_HandleTypeDef hadc1;

static uint16_t adc_read_once(void) {
    uint16_t result = 0;

    if (HAL_ADC_Start(&hadc1) != HAL_OK) {
        return 0;
    }

    if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) {
        result = (uint16_t)HAL_ADC_GetValue(&hadc1);
    }

    HAL_ADC_Stop(&hadc1);
    return result;
}

// Usage
volatile uint16_t adc_sample = 0;
void app_single_read(void) {
    adc_sample = adc_read_once();
    // For 12-bit and Vref+ = 3.3V: Vin ≈ (adc_sample / 4095.0f) * 3.3f
}

4. Multi-channel acquisition using polling (scan + discontinuous)

When multiple channels are configured as a scan sequence, enabling discontinuous mode with a count of 1 allows one rank per software start. Each start-convert-read advances to the next rank.

  • CubeMX:
    • Enable Scan Conversion Mode
    • Enable Discontinuous Mode; set count = 1
    • Number of Conversions = 3 (example)
    • Trigger = Software start
    • Right alignmant

Example to read three ranks into an array:

#include "main.h"

extern ADC_HandleTypeDef hadc1;

static void adc_read_sequence_blocking(uint16_t *dst, uint8_t count) {
    for (uint8_t i = 0; i < count; ++i) {
        if (HAL_ADC_Start(&hadc1) != HAL_OK) {
            dst[i] = 0;
            continue;
        }
        if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) {
            dst[i] = (uint16_t)HAL_ADC_GetValue(&hadc1);
        } else {
            dst[i] = 0;
        }
        HAL_ADC_Stop(&hadc1);
    }
}

#define ADC_CHANS 3
static uint16_t seq_values[ADC_CHANS] = {0};

void app_multi_read_polling(void) {
    adc_read_sequence_blocking(seq_values, ADC_CHANS);
    // seq_values[0..2] correspond to ranks 1..3
}

5. Multi-channel acquisition with interrupts

With continuous conversion and scan enabled, HAL_ADC_Start_IT will repeatedly trigger EOC interrupts. Buffer the data in the conversion-complete callback. Note that with scanning, the callback fires for each rank in sequence; if you only store raw samples, the order reflects the rank order but may appear interleaved with continuous operation.

  • CubeMX:
    • Scan mode: enabled
    • Continuous conversion: enabled
    • EOC interrupt: enabled
    • Configure NVIC priority as needed

Example ring buffer:

#include "main.h"

extern ADC_HandleTypeDef hadc1;

#define ADC_RANKS        3
#define SAMPLES_PER_RANK 5
#define ADC_BUF_LEN      (ADC_RANKS * SAMPLES_PER_RANK)

static volatile uint16_t adc_ring[ADC_BUF_LEN] = {0};
static volatile uint16_t adc_w = 0;

void adc_start_it(void) {
    HAL_ADC_Start_IT(&hadc1);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
    if (hadc->Instance != ADC1) {
        return;
    }
    adc_ring[adc_w++] = (uint16_t)HAL_ADC_GetValue(hadc);
    if (adc_w >= ADC_BUF_LEN) {
        adc_w = 0;
    }
}

If channel-to-rank association is required, map indices by rank (e.g., index % ADC_RANKS indicates rank position within the scan).

6. Multi-channel acquisition with DMA

DMA provides the highest efficiency for periodic sampling of multiple channels. In circular mode, the ADC continuously fills the buffer and wraps around, optionally generating half/full transfer callbacks.

  • CubeMX:
    • Scan mode: enabled; set Number of Conversions to total channels
    • Continuous conversion: enabled
    • EOC interrupt: disabled (DMA will handle transfers)
    • ADC DMA: enabled on the ADC regular conversion
    • DMA mode:
      • Circular for continuous streaming; Normal for one-shot
    • Data width: Half Word (16-bit) for 12-bit ADC data
    • Memory increment: enabled

Example startup code:

#include "main.h"

extern ADC_HandleTypeDef hadc1;

#define ADC_RANKS        3
#define SAMPLES_PER_RANK 5
#define ADC_DMA_LEN      (ADC_RANKS * SAMPLES_PER_RANK)

static uint16_t adc_dma_buf[ADC_DMA_LEN] = {0};

void adc_start_dma(void) {
    // For circular streaming, ensure DMA channel/stream is configured in circular mode in CubeMX
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_dma_buf, ADC_DMA_LEN);
}
  • In circular mode, the buffer layout is typically rank-major on most STM32 HAL configurations: [R1,R2,R3,R1,R2,R3,...]. Verify on your device and HAL version.
  • Convert to voltage with Vin ≈ (sample / 4095.0f) * Vref+, or use Vrefint calibration for better accuracy if supported.

7. Notes on configuration parameters

  • Data Alignment: Right alignment is common; left alignment can simplify scaling by shifting.
  • External Trigger: Use software trigger for manual acquisision or a timer trigger for periodic sampling.
  • Analog Watchdog: Configure thresholds to generate an interrupt when a reading goes outside [low, high]. Useful for fault detection without constant polling.
  • Source impedance: For accurate results, insure the signal source impedance and sampling time satisfy datasheet requirements (settling within 1 LSB).
Tags: STM32haladc

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.