Stm32 Baremetal Embedded-C Programming
ADC configuration in continuous mode for STM32
Interfacing ADC in ARM Cortex M3 controller in continuous mode
In the STM32F103 board, we have a single Successive Approximation type Analog to Digital Converter with a resolution of 12 bits. It has 18 channels which allow us to measure analog voltage from 16 external and 2 internal sources.
The A/D conversion of all channels can be performed in continuous, discontinuous, scan, and single modes. The result can be stored in the data register in both the left and right alignments.
The ADC input clock is generated by PCLK2 divided by a pre scalar and it must not exceed 14 MHz
Functional Description
The ADC can be switched on/off by setting the ADON bit in the CR2 register. When the ADON bit is set for the first time i.e. value changes from 0 to 1, the ADC wakes up from power-down mode. The conversion starts when the ADON bit is set for the second time after the ADC power-up time.
The temperature sensor is connected to channel ADCx_IN16
and the internal reference voltage VREFINT
is connected to ADCx_IN17
. These two internal channels can be selected and converted as injected or regular channels.
Modes
The ADC can be operated in any one of the following modes. In this article, we are going to discuss the continuous operation mode.
Single Conversion Mode
In single conversion mode, the ADC stops after performing only one conversion. The mode can be started by either the external trigger or by setting the ADON
bit while the CONT
bit is 0.
Continuous Mode
In continuous conversion mode, the ADC
starts the next conversion as soon as it finishes one. This mode can be triggered by either the external trigger or by setting the ADON
bit while the CONT
bit is 1.
After each conversion:
Data is stored in the 16-bit ADC_DR
register and the End of Conversion (EOC
) flag is set. An interrupt is generated if the EOCIE
bit is set.
Scan Mode
Scan mode is used to scan a group of analog channels. This mode can be triggered by setting the SCAN
bit in the ADC_CR1
register. The temperature sensor is connected to channel ADCx_IN16
and the internal reference voltage VREFINT
is connected to ADCx_IN17
. These two internal channels can be selected and converted as injected or regular channels.
Discontinuous Mode
This mode is enabled by setting the DISCEN
bit in the ADC_CR1
register. It can convert a short sequence of n conversions (n <=8), a part of the sequence of conversions selected in the ADC_SQRx
registers. The value of n is specified by writing to the DISCNUM[2:0]
bits in the ADC_CR1
register.
Calibration
The ADC has a built-in self-calibration mode. Calibration significantly reduces accuracy errors due to internal capacitor bank variations. During calibration, an error correction code (digital word) is calculated for each capacitor, and during all subsequent conversions, the error contribution of each capacitor is removed using this code.
Calibration is started by setting the CAL
bit in the ADC_CR2
register. Once calibration is over, the CAL
bit is reset by the hardware and normal conversion can be performed. It is recommended to calibrate the ADC
once at power-on. The calibration codes are stored in the ADC_DR
as soon as the calibration phase ends.
It is recommended to perform a calibration after each power-up.
Before starting calibration, the ADC must have been in a power-on state (
ADON
bit = ‘1’) for at least two ADC clock cycles.
Data Alignment
ALIGN bit in the ADC_CR2 register selects the alignment of data stored after conversion. Data can be left or right-aligned as shown in fig
Programmable Sample time
ADC samples the input voltage for a number of ADC_CLK
cycles which can be modified using the SMP[2:0]
bits in the ADC_SMPR1
and ADC_SMPR2
registers. Each channel can be sampled with a different sample time.
The total conversion time is calculated as follows:
Tconv = Sampling time + 12.5 cycles
Example:
With an ADCCLK = 14 MHz and a sampling time of 1.5 cycles: Tconv = 1.5 + 12.5 = 14 cycles = 1 μs
Program
The program initialization the peripherals and then continuously writes the analog reading on the serial console. The clock configuration and the ADC configuration are explained in detail however the USART functions are invoked from the library, explained in the following article
Clock initialization
By default, the controller is using the internal RC oscillator operating at 8MHz as the primary clock. We will be configuring it to use the external resonator as the clock source operating at 72MHz.
To dive deep into the inner working of the clock circuit and its configuration, head over to the following article:
ADC Config & Initialization
As the ADC clock cannot exceed 14MHz, we will select the pre-scalar value accordingly i.e. 6. ADC clock will have a frequency of 72Mhz/6 = 12MHz
. The clock sources of ADC and PORTA are enabled afterward.
Pin PA0 where the analog sensor is connected is reset and configured in analog input mode.
For better accuracy, the sampling time is set as 28.5 cycles as described in the above section. The ADC is woken from the power down state while setting the mode as continuous and right data alignment. The ADC will keep reading the value and updating it in the ADC_DR
register in right-aligned mode.
The conversions are started after the completion of recalibration.
Main function
As the ADC is configured in continuous mode, the value read from the ADC_DR
register is printed on the serial console at every 500ms interval.
Building & Flashing on target
This project is configured using Makefile and does not use any external libraries. The entire project is available in the following repository along with all the instructions for building & flashing.