🛠 ADC 12 bits et PWM sur la Nucleo-F401RE : oversampling, millivolts et LED en fondu
Goals
Use the two analog faces of the F401RE: the 12-bit ADC (16 channels) and timer-driven PWM via analogWrite. You will build a potentiometer-in, brightness-out loop with a proper millivolt conversion, then add oversampling to quiet the last digits.
Hardware
- 1× Nucleo-F401RE + micro-USB cable
- 10 kΩ potentiometer: outer legs to 3.3 V and GND, wiper to A0 (PA0)
- 1 LED + ~330 Ω resistor on D5 (any PWM-capable Arduino-header pin mapped by the core)
The facts
- The F401RE ADC is 12-bit (0–4095) over a 0–3.3 V range — scale millivolts with
raw * 3300 / 4095. - The core implements
analogWriteon hardware timers; no software bit-banging. - >
- The chip also carries I2S and SDIO on-chip for real audio/SD streaming (see the advanced USB/SDIO tutorial).
Code
const int kFadePin = D5; // PWM-capable pin mapped by the core
const int kProbePin = A0; // PA0 on the Arduino connector
void setup {
Serial.begin(115200); // ST-LINK VCP (USART2, PA2/PA3)
analogWrite(kFadePin, 0);
}
void loop {
// oversample: 64 reads averaged to stabilise the low digits
long sum = 0;
for (int i = 0; i < 64; i++) sum += analogRead(kProbePin);
int raw = sum / 64;
unsigned long mv = (unsigned long)(raw * 3300 / 4095); // 12-bit scale
int duty = map(raw, 0, 4095, 0, 255);
analogWrite(kFadePin, duty);
Serial.printf("raw=%4d %4lu mV duty=%3d\n", raw, mv, duty);
delay(100);
}
Steps
- Wire the potentiometer divider and the LED as described.
- Upload with board Nucleo F401RE selected; open the serial monitor at 115200.
- Sweep the potentiometer: LED brightness and the mV column track together.
- Compare a single
analogReadagainst the 64-sample average — the flicker in the last digit disappears.
Expected result
A smooth 0 → 3300 mV sweep with a matching 0–255 PWM duty. The blink + fade + ADC-probe loop shipped in the core's own example set is the same pattern in one sketch: hard blink on PA5, software-visible PWM ramp with analogWrite, and a 12-bit probe printed over the ST-LINK VCP.
Common mistakes
- Scaling with 1023 (10-bit habit) — readings top out at a quarter of the range.
- Feeding a 5 V signal straight into A0: the MCU domain is 3.3 V (VDD 1.7–3.6 V); use a divider.
- Putting the LED directly on a GPIO without a series resistor.
- Searching for a DAC-grade
analogWriteoutput: on this class of part, PWM + RC filter is the honest low-cost answer.
Other tutorials for this board
- Prise en main de la Nucleo-F401RE : ST-LINK, LED LD2 et alimentation
- Premier Blink Arduino sur la Nucleo-F401RE avec le core STM32duino
- Console série sur le ST-LINK VCP : printf, ADC 12 bits et piège du USB
- STM32CubeF4 et HAL : blink + UART printf générés pour la Nucleo-F401RE
- Zephyr RTOS sur la Nucleo-F401RE : west build, devicetree et west flash
- Bare-metal sur le STM32F401 : clignoter LD2 en écrivant les registres GPIO