STM32F0 ADC - Tutorial 6

It’s been nearly one year since I posted the last tutorial on using STM32F0 UART. Many things have happened during my study that gave me no chance to release any new tutorial. But I finally finished my MSc course and having some free time so I make up my mind to go back and continue with what I am interested here instead of watching cats’ and dogs’ videos on Youtube  :-P. In this post, I’ll talk about STM32F0 ADC.

Specifically, I will cover almost every part of Analog-to-Digital Converter (ADC) module of STM32F051 on STM32F0 Discovery board using HAL library with support from STM32CubeMX. This is applicable for other low level STM32 series as their ADC module are quite similar. I will try to cover: Fundamental knowledge of ADC; Single channel/sequence conversion, continuous and discontinuos ADC conversion with/without interrupt;

Two examples will be given: I will first try to measure the supply voltage for the STM32F0 chip, which is also the reference voltage for ADC module. Then, an example of reading the chip’s temperature using built-in temperature sensor as well as reading external analog voltage applied to analog input pin (PA1) will be made. To view the ADC conversion data and other internal variables, I will use STM Studio which has been introduced in this post.

1. Analog to Digital Converter – Things to notice

STM32F0 ADC resolution

ADC resolution is one of the key factors to determine how precise the conversion can achieve. I still remember the first time I made a circuit to convert analog to digital signal using ADC0804 chip. Such chip has a resolution of 8-bit (0-255), meaning that we can detect 256 different levels of input analog signal. At that time, 12-bit (4096), 16-bit (65536) or higher bit of resolution was something that I always wanted to have for my application because it’s very hard and expensive to find those dedicated ADC chips with that high resolution. Then Atmel and Microchip came out with built-in 10-bit ADC (1024 levels) microcontrollers that shrink both size of pcb and complexity of circuit design.

Fig.: Difference in digital output corresponding to difference resolution. Obviously, higher resolution represents the sampled analog input more precisely. source: ni.com

Now, we have our STM32 chip that supports 12-bit ADC, which increases the resolution of analog conversion to 4096 steps (from 0 to 4095). This resolution is configurable to 12-bit, 10-bit, 8-bit or 6-bit where faster conversion times can be obtained by lowering the resolution. In this tut, I will pay attention to 12-bit resolution only to exploit full potential of STM32 chip.

Reference Voltage of STM32F0

For low level, less number of pins series of STM32 such as STM32F051 in the STM32F0 Discovery Kit, the reference voltage (VREFINT) of ADC module is fixed to internal voltage reference provided by internal power block. This reference voltage is equal to supply voltage to Vdd pin, which is around 3V for this STM32F0 Discovery kit.

On the other hand, the conversion data of VREFINT at precisely 3.3V is individually measured for each chip by ST during production test and stored in the system memory area. This will help us in calculation of ADC value when the supply voltage for the STM32 is different from 3.3V (3V for specific), which will be mentioned later.

Vrefint

Sampling time and Conversion time

The sampling time is the time needed to charge up all the capacitors for sampling purposes inside the ADC module. This sampling time must be enough for the input voltage source to charge the sample and hold capacitor to the input voltage level. Therefore, choosing this sampling time will mostly depend on the input resistance of the input voltage source, the lower the resistance, the lower the sampling time and vice versa.

STM32 ADC sampling time STM32 ADC sampling time

The duration of 1 cycle shown in the figure above depends on the clock frequency of the ADC module. The ADC clock has two options: asynchronous clock (at 14MHz) which is independent with the CPU clock and the synchronous clock which depends on the running frequency of the chip. Option 1 has the advantage of reaching the maximum ADC clock frequency whatever the APB clock scheme selected. Option 2 is useful when the application requires that the ADC is precisely triggered without any uncertainty.

The total conversion time for one channel is calculated as follows (edited):

tCONV = (Sampling time + 12.5) * ADC clock cycles

2. STM32 single channel ADC conversion with interrupt

In this part, I will show how to perform a single channel AD conversion by using the internal reference channel (ADC_IN17). Please take a look at the video below to get a rough idea on how it is done.

STM32F0 uses internal reference voltage (VREFINT). This internal voltage is connected to ADC_IN17 (channel 17) and can be measured. Moreover, the precise voltage of VREFINT is individually measured for each part by ST during production test and stored in the system memory area with respect to supply voltage Vdd = 3.3V.  This means that we can calculate the input analog voltage precisely in spite of not knowing the exact Vdd voltage. This is different from Arduino (Mega328) where we only know the internal reference voltage is 2.5V but cannot measure precisely. The following formula gives the actual Vdd voltage supplying the device:

where:  VREFINTCAL is the VREFINT calibration value, which is stored in the system memory;  VREFINTDATA is the actual VREFINT output value converted by ADC.

VREFINT_CAL memory address VREFINT_CAL memory address

The ADC delivers a digital value corresponding to the ratio between the analog power supply and the voltage applied on the converted channel. For most application use cases, it is necessary to convert this ratio into a voltage independent of Vdd:

The ADC interrupt callback in the video is fairly simple:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)  
{ 
  if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) 
    { 
    ADC_raw = HAL_ADC_GetValue(hadc); 
    Vdd = 3300 * (*VREFINT_CAL_ADDR)/ADC_raw; 
    } 
}

Continuous mode explanation for the single channel conversion:

With continuous mode disabled for single channel conversion, we need to trigger the start of conversion manually by using the HAL function:

HAL_ADC_Start_IT(&hadc);  

An illustration below shows how the process is going when continuous mode is disabled:

https://image.ibb.co/hUu2H5/1.png Illustration of single channel, continuous mode disabled analog to digital conversion process.

With continuous mode enabled for single channel conversion, the ADC module automatically restart the conversion process right after the previous conversion is done. In this way, the interrupt will be triggered continuously with the rate equal to the total conversion time calculated in section above.

https://image.ibb.co/icOJqQ/2.png Illustration of single channel, continuous mode enabled analog to digital conversion process.

3. STM32 sequence ADC conversion with multiple channels (channel scanning) with interrupt

In this part, a demonstration on how to perform ADC on multiple channels will be presented. STM32 has internal temperature sensor so that it can measure temperature of the microcontroller itself. The temperature sensor is connected to ADC_IN16 (channel 16). In this STM32F0 ADC tutorial, I will use this internal temperature sensor as our analog input for all the experiments. We will use one external input (ADC_IN1), the internal temperature as a second channel (ADC_IN16) and Vdd voltage (ADC_IN17) as the third channel. Let’s take a look at the following video first:

For external input channel, we have:

where:

  • ADCData is the digital output from conversion
  • Vref is the reference voltage which is the Vdd
  • Vin is the input analog voltage to convert. This voltage must always be lower or equal to Vref so as to avoid saturation problem
  • Resolution: 4096 for STM32 (we use full 12-bit)

If you need to calculate input voltage from the converted digital output, the equation above can be rewritten as

The code for ADC interrupt callback in the video for ADC_IN1, Temperature and Vdd is as:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)  
{
 if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) 
  {
  ADC_raw[index] = HAL_ADC_GetValue(hadc); 
  index++;
  }
if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS))  
 {
 index=0;
 Vdd = 3300 * (*VREFINT_CAL_ADDR) / ADC_raw[2];
 temperature = (((int32_t)ADC_raw[1] * Vdd/3300)- (int32_t) *TEMP30_CAL_ADDR );
 temperature = temperature * (int32_t)(110 - 30);
 temperature = temperature / (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
 temperature = temperature + 30; Vin = Vdd*ADC_raw[0]/4095;
 }
}

With TEMP110_CAL_ADDR and TEMP30_CAL_ADDR can be found form the datasheet:

https://image.ibb.co/fnnBAQ/8.png STM32F0 Internal temperature calibration addresses

Continuous mode and Discontinuous mode explanation for the sequence conversion:

When we are having multiple channels for our ADC module, the discontinuous mode is needed to be taken into account. The following illustrations present the differences among various configuration for continuous mode and discontinuous mode:

With both modes disabled: the conversion sequence start from the first channel until the last channel and then stop. Each time the channel conversion is done, the End of Conversion (EOC) interrupt flag will be triggered until the last channel, End of sequence (EOS) will be on.

https://image.ibb.co/nGwGc5/3.png Illustration of 2 channels, continuous mode disabled, and discontinuous mode disabled analog to digital conversion process.

With continuous mode enabled, and discontinuous mode disabled: similarly to single channel, the conversion process will be restarted automatically when the last channel is finished.

https://image.ibb.co/fpBhH5/4.png Illustration of 2 channels, continuous mode enabled, and discontinuous mode disabled analog to digital conversion process.

With continuous mode disabled, and discontinuous mode enabled: Everytime the channel conversion is done, we need to trigger the start of ADC module again to move on to the next channel in the sequence.

https://image.ibb.co/hYSBAQ/5.png Illustration of 2 channels, continuous mode disabled, and discontinuous mode enabled analog to digital conversion process.

I hope you like it and stay tuned for the next tutorial, which will be about I2C.