1. Introduction
The ADC (Analog-to-Digital Converter) on STM32 microcontrollers is a crucial peripheral for converting analog signals into digital values, enabling applications such as DC measurements (e.g., temperature sensing, battery monitoring) and AC measurements (e.g., audio signal acquisition, waveform analysis). Proper ADC configuration is essential to ensure accurate and reliable results.
This wiki provides an overview of the key parameters and the features required for ADC configuration in each type of measurement. It also covers post-processing techniques like normalization, filtering, and averaging to enhance signal quality and reduce noise. Additionally, evaluation methods for analyzing conversion errors are discussed to help users assess and optimize ADC performance.
To bridge theory and practice, practical examples are provided for DC, AC, Phase and Rise time measurements, demonstrating how to configure the ADC for various use cases. By following this guide, readers will gain the knowledge needed to configure, optimize, and evaluate ADC performance on STM32 boards effectively.
2. ADC features overview
The ADC features are generally related to specific ADC functionalities that we want to enable or disable. These features determine how the ADC will operate in terms of behavior and system interactions. Some of them are listed below.
| ADC Features Overview | |||
|---|---|---|---|
| General | I/O | Core | Power |
|
|
|
|
3. ADC parameters overview
ADC parameters define the technical and numerical settings of the peripheral. They determine the performance and accuracy of the ADC, as well as how the converted data will be handled. Some of them are listed below.
| ADC Parameters Overview | |||
|---|---|---|---|
| Range | Frequency | DC Accuracy | AC Accuracy |
|
|
|
|
4. ADC post-processing methods overview
Post-processing methods refer to a set of techniques or operations applied to data, images, signals, or results after the primary processing or analysis has been completed. These methods are commonly used to refine, enhance, or interpret the output, making it more useful, accurate, or visually appealing.
Among the methods, there are those performed in hardware and those implemented in software - the latter offering greater flexibility but requiring more of CPU usage and processing time. Some of them are listed below.
| Post-Processing methods | |
|---|---|
| Hardware - Based methods | Software - Based methods |
|
|
5. ADC measurement recommendations details
6. Constant voltage or DC voltage measurement
The following table presents recommendations on the configuration of the ADC for the DC measurement context. Before following the recommendations, check the product datasheet and reference manual to ensure compatibility with our recommendations.
| ADC measurement configuration - DC voltage measurement | |||
| ADC
Features |
Mandatory | Recommended | Optional |
|
|
| |
| ADC
Parameters |
|
||
| Post Processing |
|
|
|
| Application design |
|
|
|
| Verification
Methods |
|
|
|
6.1. Example of measurement - Static or DC voltage
To illustrate constant voltage measurements using an ADC, measurements were taken using a DAC as the voltage generator being internally connected (on-chip analog peripheral) to the ADC.
As illustrated in the schematic above, a multimeter was used to verify the voltage applied to the ADC input. Therefore, for this analysis, errors or noise originating from the DAC were not considered; only the DAC output voltage itself was taken into account.
The primary objective of this experiment is to evaluate the accuracy of DC voltage measurements using the STM32H7A3ZI-Q ADC. The ADC was properly configured by following the previously outlined recommendations. Subsequently, measurement errors were calculated, and verification methods were applied to ensure reliable results.
To thoroughly assess the ADC’s good configuration across its input range, measurements were performed at three distinct voltage levels—low, medium, and high. In the following section, the ADC configuration, the experimental code developed using STM32CubeMX and STM32CubeIDE, and a step-by-step procedure for data acquisition are detailed.
6.1.1. Acquired raw data - Low, Medium, High voltage measurements
Following the guidelines provided on the Wiki page, the table below provides the configurations used in the experiment.
| Board Nucleo | Package | Power supply (VDDA) | VREF voltage | ADC frequency | Sampling Time | ADC Features | Post Processing method | Verification Method |
|---|---|---|---|---|---|---|---|---|
| H7A3ZI - Q | QFP | 3.3 V | 3.302 V | 5 MHz | 810.5 cycles |
• Single ended channel • Slow channel • 12-bits resolution • Continuous Mode • Offset Calibration • Linearity Calibration |
• Averaging |
• Total Unadjusted Error (TUE) • Statistic histogram |
Next, for the first analysis, a buffer adc_dma_buffer[16] was created to store the values of each ADC conversion; in this case, it was collected 16 values for each measurement.
For the second analysis, the histogram data was stored in "full_adc_histogram[4096]. In the last mentioned case, for each code value (represented by the buffer position number), the number of times it appears. The code below shows the lines of code that were added. Note that calibration and load calibration were performed before the conversion.
#include <stdio.h>
#include <string.h>
#define NUM_CODE 4096
#define ADC_BUFFER_SIZE 16
#define NUM_SAMPLES 1
volatile uint32_t samples_collected = 0;
uint16_t full_adc_histogram[NUM_CODE];
uint16_t adc_dma_buffer[ADC_BUFFER_SIZE];
volatile uint8_t conversion_complete = 0;
/* Main program entry point */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_DAC1_Init();
MX_OPAMP1_Init();
MX_USART3_UART_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
// Histogram initialization
for (uint16_t i=0; i <ADC_BUFFER_SIZE;i++)
{
full_adc_histogram[i]=0;
}
samples_collected =0;
<!-- ------------------------------------------------------------------
Perform raw data acquisition for specific DAC codes
Low voltage - dac_code = 90, Medium voltage - dac_code = 2000 and
High voltage - dac_code = 4000
-------------------------------------------------------------------->
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_2, DAC_ALIGN_12B_R, 2000);
HAL_Delay(100);
if (HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc_dma_buffer, ADC_BUFFER_SIZE);
while(samples_collected ==0){
//Wait buffer complete
}
samples_collected =0;
HAL_ADC_Stop_DMA(&hadc2);
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); //to indicate that the conversion finished
for (uint16_t i = 0; i< ADC_BUFFER_SIZE; i++)
{
uint16_t adc_value = adc_dma_buffer[i];
if (adc_value < NUM_CODE)
{
full_adc_histogram[adc_value]++;
}
samples_collected++;
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
/* Function to indicate that the conversion is finished and the histogram can be collected*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
samples_collected = 1;
}
/* USER CODE END 4 */
To collect the histogram data, we directly access the microprocessor's memory. For this, it is first necessary to know the address where the "full_adc_histogram" buffer is located (use the file shown below).
Then, the STM32Programmer software is used to transfer the memory data (in binary) to a binary file so that the data can be processed. In this way, the following commands are used in the command prompt.
#1 Open "Command Prompt" and past the STM32_CubeProgrammer_CLI.exe PATH:
ex: cd "C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin"
#2 Run the update of the embedded ST-Link debugger (optional)
STM32_Programmer_CLI.exe -stlink_fwupdate
#3 Save firmware variable to file: STM32_Programmer_CLI --connect port=<PORT_TYPE> -u <ADDRESS> <SIZE> <FILE_PATH>
ex: STM32_Programmer_CLI --connect port=SWD -u 0x240002ac 0x2000 c:\Temp\fw_variable_content_file.bin
#Attention: before executing command 3, stop the debugger.
Once the data was collected, an error analysis was conducted to quantify the measurement accuracy using Octave software for example.
6.1.2. Measurement accuracy analysis methodology
Total Unadjusted Error Analysis
For a first analysis of the error under the measurements performed (low, medium, and high voltage), a standard average of the acquired codes is performed and compared with the theoretical value. These are calculated as follows:
Finally, for the calculation of the error:
Histogram and normal distribution noise analysis
For the second analysis, the process begins with standard averaging, where multiple ADC samples are collected and averaged to calculate a stable mean value. This averaging reduces random noise and transient fluctuations inherent in individual readings, resulting in a more reliable representation of the true DC voltage.
Following the calculation of the average, a histogram of the sampled data is constructed. This histogram visually represents the distribution of ADC codes, highlighting the frequency of each code acquired. Analyzing this distribution provides insight into the noise characteristics and stability of the measurement system.
A crucial step in this methodology is the comparison of the histogram with a Gaussian (normal) distribution. This comparison is justified because the predominant noise sources in electronic measurements—such as thermal noise and quantization noise—typically follow a normal distribution due to the central limit theorem. Confirming that the ADC sample distribution approximates a Gaussian shape validates the assumption of random, unbiased noise and indicates proper ADC configuration.
6.1.3. Results - DC voltage measurement
The results of the first TUE analysis are shown in the following figure.
As a first DC measure, a low voltage of 0.07422V was applied and a TUE = -5.04 LSB was obtained, as indicated in "Error (AVG)".
Such measurement will be compared with the value from the data sheet at the end of this section.As a second DC measure, a medium ADC input voltage of 1.65131 V was applied and a TUE = -0.31 LSB was obtained, as indicated in "Error (AVG)".
Such measurement will be compared with the value from the data sheet at the end of this section.As the last DC measure, a high ADC input voltage of 3.2247 V was applied and a TUE = 4.68 LSB was obtained, as indicated in "Error (AVG)".
![]()
Analyzing the results obtained and comparing them with the product’s data sheet (slow channel -> single ended), it can be stated that the accuracy is within the expected error value:
- Low voltage: -10 LSB < -5.04 LSB < 10 LSB
- Medium voltage: -10 LSB < -0.31 LSB < 10 LSB
- High voltage: -10 LSB < 4.68 LSB < 10 LSB
For the histogram analysis, we consider an error of±2% as good, meaning the measurement is highly accurate with minimal deviation from the expected value, ±5% as moderate, meaning the measurement has some noticeable deviation but is still acceptable for many practical purposes and ±10% as poor, meaning the measurement shows significant deviation and is generally not reliable.
The following graphs show 3 types of analysis:
- Error between the mean value of the distribution (dark blue dashed line) and the theoretical expected value for the input voltage applied (pink dashed line).
- Comparison between the normal (Gaussian) distribution (yellow curve) and the obtained distribution (bar graph), highlighted by black crosses.
- Comparison between the mean value of the Gaussian (green line) and the mean value of the obtained distribution (dark blue dashed line).
Thus, it was obtained the results below:
For the first measurement at low voltage (0.07422 V), we obtained the following result (TUE=-4.05 LSB):
In figure, we follow the methodology explained previously. The yellow curve shows the normal distribution of the obtained codes, taking into account the expected noise. As can be seen, it deviates only slightly from the measured distribution (black marks indicate the values crossing the Gaussian curve). Thus, the mean of the 4096 values obtained was calculated and compared with the theoretical mean (input value to the ADC in LSB).
The error percentage remains within ±2%, which classifies it as a good result.For the measurement at medium voltage (1.65131 V), we obtained the following result (TUE=0.61 LSB):
As can be seen, it also deviates only slightly from the measured distribution (black marks indicate the values crossing the Gaussian curve). Thus, the mean of the 4096 values obtained was calculated and compared with the theoretical mean (input value to the ADC in LSB).
The error percentage remains within ±2%, which classifies it as a good result in medium voltage.For the measurement at medium voltage (3.2247 V), we obtained the following result (TUE=1.03 LSB):
As can be seen, it also deviates only slightly from the measured distribution. Thus, the mean of the 4096 values obtained was calculated and compared with the theoretical mean.
The error percentage remains within ±5%, which classifies it as a moderate result in high voltage.6.1.4. Conclusion - DC voltage measurement
In conclusion, the experiment shows that for all three measurements, the obtained real distributions are similar to the expected normal distributions. Furthermore, as observed in the first analysis, the error values are within the established tolerance and comply with the specifications set by the datasheet. This indicates a good ADC configuration and, consequently, an efficient measurement of DC voltage.
The advantages of this approach are multifold:
- It enables the identification of systematic errors or anomalies that deviate from expected noise behavior.
- It provides a quantitative basis for estimating measurement uncertainty and ADC resolution effectiveness.
- It supports the optimization of ADC configuration and signal conditioning by revealing noise patterns and potential distortions.
By combining averaging, histogram analysis, and Gaussian comparison, this methodology offers a robust framework for evaluating and improving the accuracy of DC voltage measurements using ADCs.
7. Dynamic or AC voltage measurement
The following table presents recommendations on the configuration of the ADC for the AC measurement context. Before following the recommendations, check the product datasheet and reference manual to ensure compatibility with our recommendations.
| ADC measurement configuration - AC voltage measurement | |||
| ADC
Features |
Mandatory | Recommended | Optional |
|
|
| |
| ADC
Parameters |
|
|
|
| Post Processing |
|
|
|
| Application design |
|
|
|
| Verification
Methods |
|
|
|
7.1. Example of measurement - Dynamic or AC voltage
To illustrate AC measurements using an ADC, measurements were taken using a wave generator to generate a sine wave as shown below. As in the previous example, we can use an external multimeter to measure the external RMS signal voltage and compare it with the acquired adc_dma_buffer.
At the embedded code level, a buffer "adc_dma_buffer" with a size of 1024 was declared (slightly over 10 cycles of a sine wave at 4 kHz frequency). The buffer stores the resulting code value for each voltage value.
In the following points, the methodology for analyzing the accuracy of the AC measurement performed will be explained.
The step-by-step procedure for data acquisition is detailed below.
Following the guidelines provided on the Wiki page, the table below provide the configurations used in the experiment.
| Board Nucleo | Package | Power supply (VDDA) | VREF voltage | ADC frequency | Sampling Time | ADC Features | Post Processing method | Verification Method |
|---|---|---|---|---|---|---|---|---|
| H7A3ZI - Q | QFP | 3.302 V | 3.302 V | 18 MHz | 64.5 cycles |
• Single ended channel • Fast channel • 16-bits resolution • Continuous Mode • DMA circular • Offset Calibration • Linearity Calibration |
• Zero Crossing Detection • AC RMS measurement |
• Validation with known signal • SNR and THD |
Next, a buffer adc_dma_buffer[16] was created to store the values of each ADC conversion; in this case, it was collected 16 values for each measurement. Note that calibration and load calibration were performed before the conversion. The code used shows the lines of code that were added.
#include <stdio.h>
#include <string.h>
#define ADC_BUFFER_SIZE 1024 //dma buffer size
uint16_t adc_dma_buffer[ADC_BUFFER_SIZE];
volatile uint32_t samples_collected = 0;
/* Main program entry point */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_DAC1_Init();
MX_OPAMP1_Init();
MX_USART3_UART_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
if(HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK)
Error_Handler();
if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_buffer, ADC_BUFFER_SIZE) != HAL_OK)
Error_Handler();
samples_collected =0;
while(samples_collected ==0){
//Wait buffer complete
}
samples_collected =0;
HAL_ADC_Stop_DMA(&hadc1);
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
/* Function to indicate that the conversion is finished and the histogram can be collected*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
samples_collected = 1;
HAL_GPIO_WritePin(GPIOB, LD1_Pin, GPIO_PIN_RESET);
}
/* USER CODE END 4 */
To collect the raw data, we directly access the microprocessor's memory. For this, the data acquisition ("adc_dma_buffer" data) followed the same methodology as described in the DC voltage measurement section. </syntaxhighlight>
7.1.1. Measurement accuracy analysis methodology
A pure sine wave is commonly used as an input signal for ADC testing because it is a simple, well-defined waveform with a single frequency. This allows precise evaluation of the ADC’s behavior, including the noise and distortion introduced during conversion.
Validating an ADC often involves comparing its output to known theoretical signals like sine waves. This section outlines the key principles and practical steps for performing such validation.
Following this, the analysis extends to evaluating SNR (Signal-to-Noise Ratio) and THD (Total Harmonic Distortion), which are critical metrics for assessing the accuracy and fidelity of the ADC conversion.
Validation with a known signal
Understanding the validation methodology starts with the use of known reference signals. These signals serve as precise benchmarks for comparing ADC outputs, allowing accurate assessment of key performance metrics such as linearity, noise, distortion, resolution, and frequency response. They also help identify issues like offset, gain errors, non-linearity, and saturation, ensuring the integrity of the entire signal processing chain.
This section presents an experimental AC measurement test applying the validation method through the following steps:
1. Plotting the ADC Output Curve;
2. Zero Crossing Detection;
3. Theoretical Signal Reconstruction;
4. Error Analysis;
5. RMS and Peak-to-Peak (Vpp) Calculation;
6. Signal with Saturation Analysis.
Signal - to - Noise Ratio (SNR) and Total Harmonic Distortion (THD)
SNR quantifies the ratio between the power of the desired signal and the power of background noise present in the output. It is expressed in decibels (dB) and defined as:
where:
- is the power of the fundamental sine wave component.
- is the power of all noise components excluding the fundamental frequency.
A higher SNR indicates that the ADC output is dominated by the true signal with minimal noise interference, reflecting better conversion accuracy and resolution. In practical terms, SNR helps assess the ADC’s ability to distinguish the input signal from noise sources such as thermal noise, quantization noise, and other electronic interferences.
THD measures the distortion introduced by the ADC by quantifying the presence of harmonic frequencies generated during the conversion process. It is the ratio of the sum of powers of all harmonic components (integer multiples of the fundamental frequency) to the power of the fundamental frequency itself:
where:
- is the power of the fundamental frequency.
- is the power of the power of the n-th harmonic frequency.
Lower THD values indicate that the ADC introduces minimal nonlinear distortion, preserving the purity of the input sine wave.
7.1.2. Results - AC voltage measurement
The first step is data acquisition. Raw ADC data were acquired and processed in Octave, as shown in the previous section. The digital codes were converted into voltage values using the known sampling frequency, allowing the reconstruction of the analog input waveform for visualization and analysis.
After centering the signal, we can already observe that the signal amplitude is consistent with the expected results (shown in the figure of the AC measurement setup - Vpp = 1V).Next, to facilitate the calculation of RMS and Vpp (calculation shown in step 4), it is necessary to perform a zero-crossing method by analyzing 10 periods. Additionally, the sine waveform generated by the Hilbert transform (shifted by 90°) was compared with the signal waveform (comparison analysis in step 3).
![]()
By comparing the resulting waves — the ideal sine wave (in dark blue) and the obtained sine wave (in light blue)— analyzing the graph below, we found a maximum error of approximately 3.47% .
The figure above shows the graph of the percentage error. By analyzing the second figure, we can confirm the accuracy of the measurement performed, knowing that most of the time the percentage error stays below 2%. Even when it exceeds this limit, it remains between 2% and 5%, which may still be acceptable for some applications. The error is also within the specifications outlined in the datasheet.The Root Mean Square (RMS) value of the segmented 10-period signal was calculated to quantify its effective amplitude. From the RMS, the peak-to-peak voltage (Vpp) was derived using the appropriate mathematical relationship for sinusoidal signals.
Calculating the RMS value and Vpp using the Octave software, we obtained the following results:
The graph below presents an analysis of signal distortion using FFT (Fast Fourier Transform) on the ADC output. The FFT reveals the frequency spectrum of the input signal, clearly highlighting the fundamental frequency as the dominant peak, confirming accurate signal capture. In the graph, the fundamental frequency appears at 4093.61 Hz with a magnitude of -13.85 dB, indicating its predominance.
Harmonic peaks at integer multiples of the fundamental frequency represent nonlinear distortion introduced during conversion. Quantifying these harmonics allows calculation of the Total Harmonic Distortion (THD), a direct measure of signal purity. A low THD value indicates minimal distortion and high linearity of the ADC. The noise level observed in the FFT spectrum enables calculation of the Signal-to-Noise Ratio (SNR), reflecting the ADC’s ability to distinguish the input signal from background noise.
Together, the FFT, THD, and SNR metrics provide a comprehensive evaluation of ADC performance, confirming its suitability for high-fidelity signal acquisition. In this case, the ADC achieved a THD of 0.09% and an SNR of 62.70 dB.
Since the acquisition was performed using the DMA One-shot mode (single acquisition), the FFT results are notably affected by noise, as indicated by the SNR. To improve measurement quality, the FFT Video Averaging method was employed. This technique averages multiple acquisitions point-by-point, enhancing the harmonic components while reducing noise, as noise averages toward zero and periodic signals remain stable.
The figure below illustrates the improved spectrum obtained using this averaging technique.
7.1.3. Example of an anomaly case in the input signal
To analyze non-ideal conditions, the same analysis workflow was applied to a signal intentionally saturated over a specific time interval. This allowed evaluation of the impact of saturation on measurement accuracy and error characteristics.
Next, the high THD indicates the presence of nonlinearity and distortion, with a THD of 4.77% and an SNR of 32.35 dB (always consult the product datasheet to compare and validate the results).
This result is significantly below the expected values indicated in the datasheet, confirming the presence of anomalies at the input.
7.1.4. Conclusion - AC voltage measurement
To conclude, following the Wiki recommendations for AC measurements, efficient data acquisition was achieved. Using zero crossing for data selection and RMS calculation for Vpp determination proved effective. Validation of raw data via Hilbert transform, along with SNR and THD calculations, enabled a precise analysis of measurement accuracy. This approach allows consistent verification of ADC noise performance and linearity, identification of distortion sources, and ensures compliance with design and quality standards.
It is worth noting that, in FFT analysis of a signal acquired in DMA one-shot mode, it becomes necessary to perform software-based oversampling methods followed by averaging to highlight the signal harmonics, preventing them from being mistaken for noise.
This methodology provides a quantitative and repeatable way to:
- Verify the ADC’s noise performance and linearity.
- Identify potential sources of distortion or interference.
- Ensure compliance with design specifications and quality standards.
8. Phase (or delay) and Rise time measurement
The following table presents recommendations on the configuration of the ADC for the phase measurement context. Before following the recommendations, check the product datasheet and reference manual to ensure compatibility with our recommendations.
| ADC measurement configuration - Phase measurement | |||
| ADC
Features |
Mandatory | Recommended | Optional |
|
|
| |
| ADC
Parameters |
|
|
|
| Post Processing |
|
|
|
| Application design |
|
|
|
| Verification
Methods |
|
|
|
8.1. Example of measurement - Phase (or delay) and Rise time
As an example of a phase measurement, the following experiment was conducted by applying two out-of-phase trapezoidal signals at the ADC input, with different amplitudes and offsets relative to each other.
For data acquisition, a comparator was added to one of the ADC inputs so that it triggers a flag (COMP_IT) when the input voltage equals Vref/4. At the beginning of the process, the ADC will be initialized and will start converting the input signals continuously, and the dma_buffer data will be saved in the data_buffer_0 and data_buffer_1 registers (each stores information for half of the DMA buffer). The data will be written and rewritten until an interrupt occurs.
When the comparator interrupt is triggered, the ADC will stop the conversion, and the data stored in data_buffer_0 and data_buffer_1 will be stored in a new register called data_complete, where the order in which they are concatenated will depend on the moment the interrupt occurred, that is, the position in the DMA buffer where the conversion data was being saved when the interrupt happened.
As a form of validation, the rise times of the two output signals were compared with the input signals, as well as the phase shift, among other verification methods that will be detailed in the following sections.
The step-by-step procedure for data acquisition is detailed.
The first step for data acquisition was setting up the ADC, as specified in the table below, using CubeMX.
| Board Nucleo | Package | Power supply (VDDA) | VREF voltage | ADC frequency | Sampling Time | ADC Features | Post Processing method | Verification Method |
|---|---|---|---|---|---|---|---|---|
| H7A3ZI - Q | QFP | 3.302 V | 3.302 V | 25 MHz with prescaler of 64 | 1.5 cycles |
• Single ended channel • Fast channel • 12-bits resolution • Continuous Mode • Scan Mode • DMA conversion - Circular Mode • DMA circular • Offset Calibration • Linearity Calibration • Number of conversion = 2 • Conversion launched by software |
• Signal normalization • Signal synchronization |
• Rise time comparison • Validation with known signals |
Next, a buffer adc_dma_buffer[1024] was created to store the values of each ADC conversion. Note that calibration and load calibration were performed before the conversion. The code used shows the lines of code that were added.
#include <stdio.h>
#include <string.h>
#define TAILLE_BUFFER 512
#define TAILLE_TOTAL 1024
uint16_t dma_buffer[TAILLE_BUFFER];
uint16_t data_buffer_0[TAILLE_BUFFER];
uint16_t data_buffer_1[TAILLE_BUFFER];
uint16_t data_complete[TAILLE_TOTAL];
volatile uint32_t comp_IT = 0;
volatile uint32_t dest_buffer = 0;
volatile uint32_t half_complete = 0;
volatile uint32_t full_complete = 0;
volatile uint32_t COMP1_IT_unmask=0;
volatile uint32_t COMP_IT_during_halftransfer=0;
volatile uint32_t COMP_IT_during_fulltransfer=0;
volatile uint32_t buffer_recording=1;
void HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp);
void copy_half_buffer(uint16_t* dest, uint16_t* src, uint16_t start, uint16_t end);
void copy_full_buffer(uint16_t* dest, uint16_t* src, uint16_t offset);
/* Main program entry point */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_COMP1_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
HAL_COMP_Start_IT(&hcomp1);
HAL_Delay(10);
COMP1_IT_unmask=1;
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)dma_buffer, TAILLE_BUFFER);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (buffer_recording)
{
uint16_t* target_buffer = (dest_buffer == 1) ? data_buffer_1 : data_buffer_0;
uint16_t half_size = TAILLE_BUFFER / 2;
if (half_complete)
{
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
copy_half_buffer(target_buffer, dma_buffer, 0, half_size);
if (comp_IT == 1)
{
COMP_IT_during_halftransfer = 1;
comp_IT = 0;
COMP1_IT_unmask = 0;
}
half_complete = 0;
}
if (full_complete)
{
copy_half_buffer(target_buffer, dma_buffer, half_size, TAILLE_BUFFER);
if (COMP_IT_during_halftransfer || COMP_IT_during_fulltransfer)
{
buffer_recording = 0;
}
else if (comp_IT == 1)
{
COMP_IT_during_fulltransfer = 1;
comp_IT = 0;
COMP1_IT_unmask = 0;
}
dest_buffer = !dest_buffer; // Toggle buffer
full_complete = 0;
}
}
else // buffer_recording == 0
{
// Copy first half from current destination buffer
if (dest_buffer)
{
copy_full_buffer(data_complete, data_buffer_1, 0);
copy_full_buffer(data_complete, data_buffer_0, TAILLE_BUFFER);
}
else
{
copy_full_buffer(data_complete, data_buffer_0, 0);
copy_full_buffer(data_complete, data_buffer_1, TAILLE_BUFFER);
}
while (1)
{
HAL_Delay(150);
// HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
}
}
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
/* USER CODE BEGIN 4 */
void HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp)
{
if (hcomp->Instance == COMP1)
{
if(COMP1_IT_unmask)
{
comp_IT = 1;
}
}
}
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
{
half_complete = 1;
;
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
full_complete = 1;
}
void copy_half_buffer(uint16_t* dest, uint16_t* src, uint16_t start, uint16_t end)
{
for (uint16_t i = start; i < end; i++)
{
dest[i] = src[i];
}
}
void copy_full_buffer(uint16_t* dest, uint16_t* src, uint16_t offset)
{
for (uint16_t i = 0; i < TAILLE_BUFFER; i++)
{
dest[i + offset] = src[i];
}
}
/* USER CODE END 4 */
To collect the raw data ("data_complete"), we directly access the microprocessor's memory.
When the comparator interrupt is triggered (as mentioned at the Setup of Phase measurement), the data recording process in the buffers is halted, and the data is retrieved. However, since the ADC conversion runs continuously in scan mode, the exact moment when data capture occurs is unpredictable. Therefore, the data may be fully captured during the complete filling of the DMA buffer, but two other scenarios can also occur:
- Interrupt occurs in the first half of the buffer: In this case, data prior to the comparator interrupt may be lost.
- Interrupt occurs in the second half of the buffer: Here, data after the comparator interrupt may be lost once the DMA buffer is completely filled.
To address this, two buffers (data_buffer_0 and data_buffer_1) are used alternately to store the ADC conversion data. The diagram below summarizes this data acquisition methodology.
For case 1, the two buffers are concatenated to recover data from conversions (n-1) and n. For case 2, the buffers are concatenated to recover data from conversions n and (n+1).
This approach ensures complete acquisition of the signals and enables accurate reconstruction of the acquired data.The diagram below shows in detail the operations performed in the embedded code.
![]()
8.1.1. Measurement accuracy analysis methodology
To ensure precise and reliable phase measurement using the ADC of the STM32H7A3ZI-Q, a systematic methodology combining experimental acquisition and data processing was implemented.
First, the input signals were simultaneously applied to both the device under test and a reference oscilloscope, allowing direct capture of the original waveform. ADC data was collected and stored for subsequent analysis.
Before calculating the rise time and applying the threshold crossing method, the signals were normalized to a common scale. This normalization step ensures that amplitude variations do not affect the timing measurements, providing a consistent basis for comparison. Then, using the threshold crossing method, the rising points at 10% and 90% of the maximum value of the trapezoidal signal were collected. With this data, it is possible to calculate the rise time (the same method used by the oscilloscope employed as a reference).
The phase difference between signals was then calculated using the threshold crossing method at 50% of the total amplitude. This approach defines a consistent and stable reference point on the signal’s rising edge, minimizing errors caused by noise or amplitude fluctuations.
The same threshold crossing calculation was applied to both the oscilloscope data and the ADC output data, enabling a direct comparison between the two measurement sources. This process validated the ADC’s ability to accurately capture both the phase shift and the rise time of the input signals, confirming that the digital acquisition system faithfully reproduces the temporal characteristics of the analog signals.
8.1.2. Results - Phase (or delay) and Rise time measurements
The first step was setting up the ADC and acquiring raw data, as specified in the previous section. Post-processing was then performed using Octave software.
Since the ADC was configured in Scan Mode to sequentially acquire data from multiple input channels, the complete data vector (data_complete) was divided into two separate vectors to separate the signals from each channel: one containing the samples at odd indices and the other containing the samples at even indices. The resulting waveforms for each channel are shown in the graphs below.
An initial analysis of the input signals was performed using an oscilloscope to obtain a direct visualization of the waveform characteristics. Subsequently, a more precise analysis was conducted using Octave software. For improved signal quality and accurate measurement, the signals were filtered in Octave using a 4th-order Butterworth filter, followed by a moving average filter. The filtered signals are presented in the following graph.
We can already observe that the signal amplitude is consistent with the expected result, comparing the data acquired and the oscilloscope data. To analyze and compare the original input signal and the signal resulting from the ADC conversion, it was necessary to resample the raw data so that they had the same time scale. Additionally, the oscilloscope signals were shifted to have the same origin (0.0).Before further processing, the signals were normalized to a common amplitude scale to ensure the threshold points corresponded in both signals. To calculate the rise time, the time interval between the points where the input voltage reaches 10% and 90% of its maximum value was measured. This metric provides a robust characterization of the signal’s transition speed.
Extracting the points where the dashed line crosses and performing the calculations via Octave, for the raw extracted data (converted and resampled signals from collected raw data) we have:
Signal 1: Rise time = 0.827 ms and Signal 2: Rise time = 0.832 ms. For the data extracted from the oscilloscope (normalized filtered entry signals) we have: Signal 1: Rise time = 0.838 ms and Signal 2: Rise time = 0.839 ms. The percentage error between the rise times calculated from the raw data and the oscilloscope data is approximately 1.3% for Signal 1 and 0.8% for Signal 2.For the delay calculation, the threshold crossing method was performed at 50% of the signal amplitude, ensuring consistent and accurate estimation of the relative timing between the two signals.
Extracting the points where the dashed line crosses and performing the calculations via Octave the following values are obtained for the raw extracted data delay = 1.9802 ms. For the data extracted from the oscilloscope we have delay = 2.0052 ms. The percentage error between these two delay measurements is approximately 1.25%.
For a period of 20 ms, these delays correspond to phase shifts of approximately 35.64° (raw data) and 36.47° (oscilloscope data). The percentage error between these phase shift values is approximately 1.25%.
8.1.3. Conclusions - Phase (or delay) and Rise time measurements
For phase and rise time measurements, also following the recommendations, successful data acquisition was achieved. The post-processing methodology and verification methods provide a means to directly compare ADC measurements with a trusted reference instrument (oscilloscope), identify and minimize errors caused by noise and signal amplitude variations through normalization and threshold crossing at 50% of rise time, validate the ADC’s capability to accurately capture phase shift (in our case, the lag time) and rise time consistently, and ensure that the digital acquisition system reliably reflects the temporal characteristics of the analog input signals.
By combining experimental verification with a clear and robust signal processing technique, this approach delivers confidence and precision in phase measurement using the STM32 ADC.
9. Conclusion
This wiki has provided a comprehensive guide to understanding and configuring the ADC peripheral on STM32 microcontrollers for various measurement types. By detailing key ADC parameters, ADC features, post-processing techniques, and evaluation methods, it offers a solid foundation for achieving accurate and reliable analog-to-digital conversions.
The practical examples and tailored recommendations for DC voltage, AC voltage, rise time, and phase measurements demonstrate how to apply these concepts effectively in real-world applications. Following these guidelines will help users optimize ADC performance, minimize errors, and enhance signal quality.
We encourage users to leverage this resource as a reference throughout their development process, adapting the recommendations to their specific application requirements. Continuous experimentation and validation remain essential to fully exploit the capabilities of the STM32 ADC and achieve optimal measurement results.
10. References
- ↑ 1.0 1.1 How to optimize the ADC accuracy in the STM32 MCUs - Application note
- ↑ 2.0 2.1 Getting started with the STM32H7 Series MCU 16-bit ADC - Application note
- ↑ 3.0 3.1 Getting started with the STM32H7 Series MCU 16-bit ADC - Application note
- ↑ How to optimize the ADC accuracy in the STM32 MCUs - Application note