STM32 ADC single channel updated method

Description

I have already written a tutorial about ADC in STM32 and how to use different methods to get values from sensors using ADC. But the CubeMx is upgrading very often recently and they are changing things a lot. So today I am writing this updated method of reading ADC values using all possible ways using latest CubeMx at the time of writing.

I am going to read single channel first using all three methods i.e. Pollforconversion, interrupt, and DMA and than I will read multiple channels using the possible ways to do so.

Before we start conversions, Let’s introduce you to some of the concepts we are going to use in ADC

Single conversion mode

In Single conversion mode the ADC does one conversion and than stops. You can select single conversion in CubeMx by setting continuousconversionmode as DISABLED.

Continuous conversion mode

In continuous conversion mode ADC starts another conversion as soon as it finishes one. This method is more efficient if you want to convert continuously. You can select continuous conversion by setting continuousconversionmode as ENABLED.

Scan mode

This mode is used to scan a group of analog channels. This mode will be automatically selected if you are doing conversions for more than 1 channel. A single conversion is performed for each channel of the group. After each end of conversion the next channel of the group is converted automatically. If the continuousconversionmode is ENABLED, conversion does not stop at the last selected group channel but continues again from the first selected group channel. When using scan mode, DMA bit must be set and the direct memory access controller is used to transfer the converted data of regular group channels to SRAM after each update of the ADC_DR register.

Conversion time

According to the datasheet, 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 = (14cycles/14MHz) = 1 µs

Single channel using Pollforconversion

Pollforconversion is the easiest way to get the ADC value. We have to keep monitoring for the conversion in the blocking mode using HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout)
Once the conversion is complete, we can read the value using HAL_ADC_GetValue(ADC_HandleTypeDef* hadc)
The setup of CubeMx will be as shown in the picture below. I am using only 1 channel and the continuous conversion is DISABLED. Also the sampling time is 13.5 cycles which is around 1 us, as the ADC clock is 12MHz.

the code is as follows

HAL_ADC_Start(&hadc1); // start the adc 

HAL_ADC_PollForConversion(&hadc1, 100); // poll for conversion 

adc_val = HAL_ADC_GetValue(&hadc1); // get the adc value 

HAL_ADC_Stop(&hadc1); // stop adc 

HAL_Delay (500); // wait for 500ms



Single channel using Interrupt

Pollforconversion uses blocking mode to monitor for the conversion and is not an efficient way to use ADC. Using Interrupt is an alternate way to do so and let’s see How to use it

First we need to enable continuousconversion mode otherwise after single conversion, ADC will stop and we have to restart it. Also make sure you enable the interrupt in the NVIC tab as shown below

First we have to start the ADC in the interrupt mode by using the function below

HAL_ADC_Start_IT (&hadc1);

 

Now whenever the conversion is complete, a callback function is called and we are going to write the rest of the code inside it

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) 
{ 
  adc_val = HAL_ADC_GetValue(&hadc1); 
  /*If continuousconversion mode is DISABLED uncomment below*/ 
  //HAL_ADC_Start_IT (&hadc1); 
}

Here
HAL_ADC_GetValue(ADC_HandleTypeDef* hadc) reads the vaue from ADC and stores it in the variable adc_val.
Also note that if the continuousconversion mode is disabled, ADC will stop here and we have to again start the it in interrupt mode.



Single channel using DMA

DMA is another way of getting data from ADC. Like interrupt mode, DMA method also works in a non-blocking mode. That means we can use the rest of the program while the ADC would work in the background and when needed, we can get the value.

In DMA method, whenever the conversion is complete, the ADC values are written to the buffer which we can read anytime we want. The setup for the DMA is shown below

Circular DMA mode will ensure that the new value will override the old one and this way it can continue to work as a circular buffer.
Make sure the data width is selected as word. Because the resolution is 12 bit and only word can store the value here.

To start the ADC in DMA mode we have to use the function below

HAL_ADC_Start_DMA (&hadc1, &buffer, 1);

This will start the ADC1 in DMA mode and the converted value will be stored in the buffer.
We can read the buffer at any point in the code and get the ADC value

adc_val = buffer;

CODE

#include "main.h"


ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);


uint32_t buffer, adc_val;


/* INTERRUPT callback function */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{

/* for INTERRUPT uncomment the line below */	
//	buffer = HAL_ADC_GetValue(&hadc1);
	
/*If continuousconversion mode is DISABLED uncomment below*/
//HAL_ADC_Start_IT (&hadc1);
	
/* for DMA uncomment the line below */
	adc_val = buffer;
}


int main(void)
{

  HAL_Init();


  SystemClock_Config();


  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
	
	
	/* DMA MODE */
	
	HAL_ADC_Start_DMA (&hadc1, &buffer, 1);

  
	/* INTERRUPT MODE */
	
//	HAL_ADC_Start_IT (&hadc1);


  while (1)
  {

		/* POLLFORCONVERSION MODE */
		
//		HAL_ADC_Start(&hadc1);  // start the adc
//	  HAL_ADC_PollForConversion(&hadc1, 100);  // poll for conversion
//	  adc_val = HAL_ADC_GetValue(&adc1);  // get the adc value
//		HAL_ADC_Stop(&hadc1);  // stop adc
//		HAL_Delay (500);  // wait for 500ms 
		
		
  }
}

Connection

Result

Video

You can buy me a coffee sensor 🙂

Or just Download the code below

Share this POST

, , , , , , , , , ,

6
Leave a Reply

avatar
3 Comment threads
3 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
Abdurrahman YAMANpoojaadminAbdulkadir Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Abdulkadir
Guest
Abdulkadir

What is the resolution for this example since stm32f103 has been used.
İf the reading between 0>>3.3 V what is the range for the adc_val ?

pooja
Guest
pooja

i have been trying to parse GPS value and separately print latitude and longitude. but all i get is a zero.so please can you help me in it

Abdurrahman YAMAN
Guest
Abdurrahman YAMAN

I am trying to produce a oscilloscope-like project. I am curious about that how much sample can i get from 6 channel adcs.

Menu