UART communication between an STM32F401CCU6 microcontroller and an ESP32 development board(bare-metal, no HAL).
- A push button on the STM32 (PA0) is used as input.
- When pressed, the STM32 sends a text message (
BTN: PA0 pressed) over USART2 (115200 baud). - The ESP32 receives this message and toggles its onboard LED (GPIO2).
![]() |
![]() |
UART stands for Universal Asynchronous Receiver/Transmitter.
It is a very common way for two devices to talk to each other using just two wires:
- TX (Transmit): sends data out
- RX (Receive): receives data in
Key facts:
- UART is asynchronous → no clock line is shared. Both devices must agree on the baud rate (bits per second).
- Common baud rates: 9600, 115200, etc.
- Data is sent frame by frame:
- 1 start bit (
0) - 8 data bits (like a character
'A') - 1 stop bit (
1) - Optional parity bit (error check)
- 1 start bit (
For example, at 115200 baud each bit is ~8.68 µs long.
So the STM32 can send "BTN: PA0 pressed\r\n" and the ESP32 reconstructs it on the other side.
- STM32F401CCU6 board (Black Pill)
- ESP32 DevKit (ESP32-WROOM or similar)
- Push button + jumper wires
- USB cables for both boards
- Common ground between STM32 and ESP32
| STM32 Pin | Function | ESP32 Pin | Notes |
|---|---|---|---|
| PA2 | USART2_TX | GPIO16 | STM32 → ESP32 data |
| PA3 | USART2_RX | GPIO17 | ESP32 → STM32 data (optional) |
| GND | Ground | GND | Must be common |
| PA0 | Button input | — | Button between PA0 and GND |
-
Clock Configuration
- Enable clock for GPIOA (
RCC_AHB1ENR) - Enable clock for USART2 (
RCC_APB1ENR)
- Enable clock for GPIOA (
-
GPIO Setup (PA2, PA3 for USART2)
GPIOA_MODER: set PA2 and PA3 to Alternate Function mode (10)GPIOA_AFRL: select AF7 (USART2) for PA2 and PA3GPIOA_OSPEEDR: set PA2, PA3 to high speedGPIOA_PUPDR: enable pull-up on PA3 (RX)
-
GPIO Setup (PA0 as Button)
- Configure PA0 as input
- Enable internal pull-up resistor
- Button connects PA0 → GND → pressed = logic
0
-
USART2 Setup
- Disable USART (
CR1=0) - Configure baud rate via helper function
usart_brr_from()- Formula ensures correct baud at 16 MHz system clock
- Enable Transmitter (TE) and Receiver (RE)
- Enable USART (
UE)
- Disable USART (
-
Main Loop
- Poll PA0 for press (active low).
- On press (with debounce):
- Send string
"BTN: PA0 pressed\r\n"viausart2_write_str()
- Send string
- Wait for button release before next toggle.
-
Setup
- Initialize USB Serial (
Serial) at 115200 baud (debug output to PC). - Initialize
Serial2at 115200 baud, pins RX=16, TX=17 (UART connection to STM32). - Configure LED pin (GPIO2) as output, start LOW.
- Initialize USB Serial (
-
Loop
- handleFromSTM32()
- Reads incoming characters from STM32.
- Builds a line until
\n. - If line is
"BTN: PA0 pressed", toggles LED state. - Prints status to Serial Monitor.
- handleFromPC()
- Forwards any text typed in Serial Monitor to STM32.
- handleFromSTM32()
- Copy the
main.cinto your STM32CubeIDE or bare-metal GCC project. - Make sure system clock is left at 16 MHz HSI (default).
- Compile and flash to STM32F401CCU6.
- Connect UART pins to ESP32 as described.
- Open Arduino IDE.
- Select ESP32 Dev Module.
- Copy the ESP32 sketch (
ESP32-Code/UART-LED-control.ino.ino). - Upload to ESP32.
- Open Serial Monitor @ 115200 baud.
When pressing STM32 button:
[STM32] BTN: PA0 pressed
[ESP32] LED is now ON
[STM32] BTN: PA0 pressed
[ESP32] LED is now OFF
MIT License

