In this guide, we shall learn how to use the ADC of the STM32 for single channel Single Conversion mode using only registers.
The ADC is commonly used to measure the voltage from a sensor for example temperature sensor such as LM35 which can provide voltage proportional to the temperature.
This guide will cover the following
- What is the ADC
- Required Parts
- Schematic
- Code
- Results
1.1 What is the ADC
In electronics, an analog-to-digital converter (ADC, A/D, or A-to-D) is a system that converts an analog signal, such as a sound picked up by a microphone or light entering a digital camera, into a digital signal that can be read by STM32.
ADCs can vary greatly between microcontroller. The ADC on the STM32F411 is a 12-bit ADC meaning it has the ability to detect 4096(2^12) discrete analog levels (which is also called Resolution). Some microcontrollers have 8-bit ADCs (2^8 = 256 discrete levels) and some have 16-bit ADCs (2^16 = 65,536 discrete levels).
The way an ADC works is fairly complex. There are a few different ways to achieve this feat (see Wikipedia for a list), but one of the most common technique uses the analog voltage to charge up an internal capacitor and then measure the time it takes to discharge across an internal resistor. The microcontroller monitors the number of clock cycles that pass before the capacitor is discharged. This number of cycles is the number that is returned once the ADC is complete. Other methods used called Successive-approximation ADC which you can read about it in details from this wikipedia page (Link).
1.2 Relating ADC Value to Voltage
The ADC reports a ratio metric value. This means that the ADC assumes 3.3V is 4095 and anything less than 3.3V will be a ratio between 3.3V and 4095.
For example if the sensor has output voltage of 1.66V hence the ADC output will be (4095/3.3)*1.66=2059.
2 Required Parts
You will need the following parts:
- STM32L053 Nucleo-64.
- BreadBoard.
- 1KOhm Potentiometer.
- Hookup wires (male-male).
3. Code:
According to the STM32 Nucloe-64 user manual, the A1 of Arduino pinout is connected to PA1, hence we need to enable clock access to GPIOA as following:
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
Then set PA1 as analog mode:
/*Set pa4 mode to analog mode*/ GPIOA->MODER |=GPIO_MODER_MODE1;
Now, the configuration of the ADC.
To start with the configuration of the ADC, we need to know to which bus is the ADC connected to:
From the datasheet of stm32l053:
Hence, the ADC1 is connected to APB2, we can enable clock access as following:
/*Enable clock access to ADC*/ RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
Then we need to set the sampling time to max:
#define MaxClockCycle 0x07 /*Set sampling time TO 160.5 ADC clock cycles*/ ADC1->SMPR |=(MaxClockCycle<<ADC_SMPR_SMP_Pos);
Then set the conversion type to single conversion:
/*Set single conversion mode*/ ADC1->CFGR1 &= ~ADC_CFGR1_CONT;
Select channel 1 as input source:
/*Set sequencer channel*/ ADC1->CHSELR |=ADC_CHSELR_CHSEL1;
Then set the clock to be clock/4:
ADC1->CFGR2|=ADC_CFGR2_CKMODE_0;
Then start the calibration:
/*Start ADC calibration*/ ADC1->CR |= ADC_CR_ADCAL;
Then start the ADC:
/*Enable ADC*/ ADC1->CR |= ADC_CR_ADEN;
For start the conversion and read the adc:
void start_conversion(void) { /*Start conversion*/ ADC1->CR |= ADC_CR_ADSTART; /*Clear End-of-Conversion flag*/ ADC1->ISR &= ~ADC_ISR_EOC; } uint32_t adc_read(void) { /*Wait for conversion completion*/ while(!(ADC1->ISR & (ADC_ISR_EOC))){} /*Read result*/ return (ADC1->DR); }
You may download the code from here:
Results:
Open a serial terminal and set the baud rate at 9600 and you will get the following:
Happy coding 🙂
Add Comment