Converting an analog value
This tutorial shows how to convert an analog signal, whose value is between 0V and 3.3V, to a digital signal, whose value is an integer between 0 and 4095.
This operation is ensured by an integrated circuit in the STM32WB55 called Analogue-Digital Converter, abbreviated by ADC.
As the number of ADCs integrated into the STM32WB55 is limited, but also as a result of choices made during the design of the NUCLEO-WB55, not all output pins allow analog-to-digital conversions. If you are interested in Arduino connectors, only pins A0 to A5 are connected to ADC.
ADC Details
An ADC is described by three characteristics:
- Its quantum which is the minimum value of the input voltage it can convert, associated with an increment of the numeric value it returns.
- Its measurement range or reference voltage which is the maximum value of the input voltage it can convert.
- Its resolution, equal to the maximum + 1 of the numeric value it returns when the input voltage is equal to the reference voltage.
The figure below shows how these characteristics are related for an ADC with a range of 3.3V, with a resolution of 3 bits (so 8 values) and a quantum of 3.3/ (8-1) = 0.4715 (the “-1” comes from the fact that the ADC returns values between 0 and 7 to which must correspond voltages in 0 and 3.3V).

The legend in this figure mentions a conversion register (ODR for Output Data Register; registers are small memories that are found at the heart of all programmable electronic components). The value returned by an ADC is written in its ODR register, and the STM32WB55 will read it at this location.
Most ADCs require a clock to function, they are synchronous sequential systems. Currently, the most common type of ADC is based on a dichotomous principle of successive approximations (“Successive Approximations Register” or “SAR ADC”).
The conversion is not immediate, its latency can be broken down into two periods:
- The scan time which is the duration of the voltage sampling before converting it. This time must be configured according to the dynamic behaviour of the signal being measured. Concretely, the input stage of the ADC is a capacitor that must have time to charge until reaching the input voltage value. The charging time of this capacitor depends on the measured source impedance and must be adjusted accordingly.
- The conversion time which is the time required for the circuit to convert the value captured by the input capacitor into a numerical value according to the SAR algorithm.
The minimum time to perform a conversion is therefore the sum of these two durations, but we prefer to communicate on its inverse, designated by the sampling frequency.
The ADC integrated in the ST32WB55 is a ADC SAR with
- A reference voltage of 3.3V
- 12-bit resolution, evening 212 = 4096 possible values, from 0 to 4095
- A quantum of 3.3V / 4096 = 0.0008V (approximately)
- A maximum sampling frequency of 4.26 million samples per second. If a signal changes faster than that, its sampling and therefore its conversion will not be feasible.
Required Hardware
- NUCLEO-WB55 Board
- Any 10 KOhm potentiometer reference, for example PTV09A-4020F-B103 or Grove potentiometer module.
For this demonstration we will therefore use a potentiometer that we connect to A0 like this:

MicroPython code
The following scripts are available in the download area.
The following script updates the read value of the voltage on the potentiometer a little less than twice per second. In fact, we do 500 conversions with the ADC and average it to display a reasonably accurate value about every half-second. Of course, if you manipulate the potentiometer too quickly (more than once per second) the estimated voltage value will never be stable and the result will be difficult to interpret.
Edit the main.py script contained in the NUCLEO-WB55-associated USB disk directory: PYBFLASH.
# Object of the script:
# Example of setting up an ADC to scan a variable input voltage using a potentiometer.
# To increase accuracy, the input voltage is averaged over 500 measurements (1 measurement/millisecond)
# Equipment required: potentiometer (Grove or other), ideally designed to operate between 0 and 3.3V and connected to A0.
import pyb # for managing GPIO
from time import sleep_ms # for timeouts
print( "ADC with MicroPython is easy" )
# ADC Reference Voltage / Measurement Range: +3.3V
varef = 3.3
# 12-bit ADC resolution = 2^12 = 4096 (mini = 0, max = 4095)
RESOLUTION = const(4096)
# ADC quantun
quantum = varef / (RESOLUTION -1)
# ADC Initialization on pin A0
adc_A0 = pyb.ADC(pyb.Pin( 'A0' ))
# Initializations for calculating the average
Nb_Mesures = 500
Inv_Nb_Mesures = 1 / Nb_Mesures
while True: # "Infinite" loop (without output clause)
somme_tension = 0
moyenne_tension = 0
# Calculation of the average voltage at the ends of the potentiometer
for i in range(Nb_Mesures): # We do "Nb_Mesures" conversions of the input voltage
# Reads the ADC conversion (a number between 0 and 4095 proportional to the input voltage)
valeur_numerique = adc_A0.read()
# The voltage (analog value) is now calculated
tension = valeur_numerique * quantum
# Add it to the calculated value from the previous iteration
somme_tension = somme_tension + tension
# 1 ms timeout
sleep_ms(1)
# Divide by Nb_Mesures to calculate the potentiometer voltage average
moyenne_tension = somme_tension * Inv_Nb_Mesures
# Average Voltage Display on USB USER Serial Port
print( "The average voltage value is : %.2f V" %moyenne_tension)
You can launch the PuTTY terminal and observe the volt value that changes when you turn the potentiometer:

To go further
The following scripts are available in the download area.
The MicroPython API allows you to take advantage of the STM32WB55’s ADC by using the functions available in the pyb.ADC
module, specific to the pyboard (which is precisely designed around another microcontroller of the STM32 family). The following example shows how to sample values and save them directly to an array in memory by using Timer to time the operation.
For example, the code below shows how to run 100 conversions and load them into an array of ‘H’ type unsigned integers encoded on two bytes (so 200 bytes in total saved in an array of this size).
# Purpose of the script:
# Example of setting up an ADC to scan a variable input voltage using a potentiometer.
# The measurements are controlled by a timer at a rate of 10 per second.
# Hardware required: potentiometer (Grove or other), ideally designed to operate between 0 and 3.3V and connected to A0.
import pyb # for managing GPIO
import array # to store values in an array
from pyb import Timer # to manage timers
# ADC Initialization on A0
adc = pyb.ADC(pyb.Pin( 'A0' ))
#Timer 1 Initialization at a 10 Hz Frequency
tim = Timer(1, freq=10)
# Initialization of a buffer array containing 200 bytes grouped in unsigned integers ('H', two bytes).
# This table will therefore contain 100 elements of two bytes.
buf = array.array('H', bytearray(200))
# Sampling of 100 analog values, at the frequency of 10 Hz, thus for 100 seconds
adc.read_timed(buf, tim)
# Loop on all 100 elements of buf, and display their values
for val in buf:
print(val)
Further explanations of “advanced” ADC functions in MicroPython for NUCLEO-WB55 can be found in the Pyboard-specific library documentation, here.