Working with ADC and STM32 part3: Single Channel Continuous Conversion with Interrupt

In previous two guides (part one and part 2) we looked at the ADC conversion using two methods, first one was single conversion and seconds was continuous conversion. The two methods proven to be effect in certain area. however, we have to wait for the end of conversion each time we want to read the adc which might effect the performance of the system (like in car).

In this guid will cover the following

  • Difference between polling mode and interrupt mode
  • Extra steps needed
  • Needed Parts and Schematic
  • Code
  • Result

1. Difference between polling mode and interrupt mode

In polling as we saw in previous two guides, we need to wait for end of conversion each time we want to read the adc value as illustrated in figure below.

polling mode

On another hand, in interrupt mode, the adc value can be update in background (no need to wait for EOC) since in handled in the interrupt handler function as illustrated in figure below.

Interrupt adc

2. Extra steps needed to enable interrupt.

The extras steps needed from part 1 and part 2 of this guid as following

  • Declare the adc_value as volatile uint16_t variable as following
volatile uint16_t adc_value;
  • Enable end of conversion interrupt from ADC_CR1 as shown bellow
Enable end of conversion interrupt
ADC1->CR1|=ADC_CR1_EOCIE;
  • Attach the EOC to the NVIC (Nested Vector Interrupt Controller) by using the following command
NVIC_EnableIRQ(ADC_IRQn);
  • Handle the ADC interrupt as follow
void  ADC_IRQHandler(void)
{
adc_value=ADC1->DR;

}

3. Required Parts and Schematics

You will need the following parts:

  • STM32F411 Nucleo-64
  • BreadBoard 
  • 1KOhm Potentiometer 
  • Hookup wires (male-male)

We shall use Keil uVision (MDK-ARM) IDE (Link)

Connection
actual connection

4. Code

//read the analog voltage on PA1
#include "stm32f4xx.h"                  // Device header
#include "stdint.h"
void ADC_init(void);
uint16_t adcValue;

int main(void){
ADC_init();
while(1){
//empty loop
}

}
void ADC_init(void){
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN; //enable gpio a clock
RCC->APB2ENR|=RCC_APB2ENR_ADC1EN; //enable adc clock
GPIOA->MODER|=GPIO_MODER_MODER1;  //set the PA1 to analog mode
ADC1->CR1|=ADC_CR1_EOCIE;
ADC1->CR2=0; //disable the adc
ADC1->CR2|=ADC_CR2_CONT; //enable Continuous conversion  	
ADC1->SQR3|=1; //set the second channel to be converted first 
NVIC_EnableIRQ(ADC_IRQn); //attach the interrupt to NVIC
ADC1->CR2|=1; //enable the adc 
ADC1->CR2|=ADC_CR2_SWSTART; //start adc conversion	
}


void  ADC_IRQHandler(void)
{
//update adc vlaue automatically
adcValue=ADC1->DR;

}

5. Results

After compile, upload, start a debug session and adding adcValue to watch window.

Rotate the pot left and right and the value shall be updated without being called each time

Add Comment

Your email address will not be published. Required fields are marked *