January 15, 2026 in Embedded4 minutes
A practical guide to setting up UART on custom pins with Zephyr and testing the communication using HydraBus
In this post, I’ll show you how to set up UART communication on the STM32H573I-DK board using Zephyr RTOS, and how to test it with a HydraBus.
This article is a practical application of the Getting Started with Zephyr documentation. The goal is to get familiar with Zephyr OS and dust off my HydraBus that has been sitting unused for too long.
On the STM32H573I-DK, UART3 is available on the Arduino connector. Connect:
Before creating the project, confirm that USART3 exists in the board’s devicetree:
west build -b stm32h573i_dk samples/hello_world
cat build/zephyr/zephyr.dts | grep -A 10 "usart3: arduino_serial"Output:
usart3: arduino_serial: serial@40004800 {
compatible = "st,stm32-usart",
"st,stm32-uart";
reg = < 0x40004800 0x400 >;
clocks = < &rcc 0x9c 0x40000 >;
resets = < &rctl 0xe92 >;
interrupts = < 0x3c 0x0 >;
pinctrl-0 = < &usart3_tx_pb10 &usart3_rx_pb11 >;
pinctrl-names = "default";
current-speed = < 0x1c200 >;
status = "okay";
};USART3 is already defined with status “okay” and mapped to PB10 (TX) and PB11 (RX), which correspond to the Arduino connector pins D1 and D0.
Create a new project with this structure:
uart_demo/
├── CMakeLists.txt
├── prj.conf
├── boards/
│ └── stm32h573i_dk.overlay
└── src/
└── main.cThe CMake build file integrates your application with the Zephyr build system:
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(uart_demo)
target_sources(app PRIVATE src/main.c)The Kconfig file enables the necessary drivers for UART communication:
CONFIG_SERIAL=yCONFIG_SERIAL=y: Enables the serial driver subsystem, which provides the core UART functionality. Without this, the UART peripheral cannot be used.The devicetree overlay enables USART3, which is routed to the Arduino connector pins (D0/D1) on the STM32H573I-DK board:
&usart3 {
status = "okay";
current-speed = <115200>;
};The application code initializes USART3 and sends “ping” every second. This demonstrates basic UART output using Zephyr’s polling API:
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#define PING_INTERVAL_MS 1000
int main(void)
{
const struct device *uart3 = DEVICE_DT_GET(DT_NODELABEL(usart3));
if (!device_is_ready(uart3)) {
printk("USART3 not ready\n");
return -1;
}
printk("Starting ping on USART3\n");
while (1) {
const char *msg = "ping\r\n";
for (int i = 0; msg[i] != '\0'; i++) {
uart_poll_out(uart3, msg[i]);
}
k_msleep(PING_INTERVAL_MS);
}
return 0;
}This simple program sends “ping” every second over UART3. Key functions and macros used:
DT_NODELABEL(usart3): Returns the devicetree node identifier for the node with the label usart3. Labels are defined in the devicetree and provide a human-readable way to reference nodes.DEVICE_DT_GET(node_id): Retrieves a pointer to the device structure at compile time from a devicetree node identifier. This is the recommended way to get device handles in Zephyr.device_is_ready(dev): Checks if a device has been successfully initialized and is ready for use. Always verify this before using a device.uart_poll_out(dev, c): Sends a single character over UART using polling mode. This function blocks until the character is transmitted.Once the firmware is flashed on the STM32H573I-DK, you can observe the UART communication using HydraBus.
Connect the HydraBus to your computer via USB and identify the serial port:
dmesg | grep ttyLook for a line mentioning ttyACM:
cdc_acm 1-1:1.0: ttyACM0: USB ACM deviceOpen a serial terminal on the identified port:
minicom -D /dev/ttyACM0In the HydraBus terminal, enter UART mode:
> uart
Device: UART1
Speed: 9600 bps
Parity: none
Stop bits: 1
uart1> show pins
TX: PA9
RX: PA10Set the baud rate to 115200 to match our firmware settings:
uart1> speed 115200
Speed: 115200 bpsTo passively monitor the UART communication, enter bridge mode. This connects the HydraBus UART RX directly to your terminal:
uart1> bridgeYou should now see the “ping” messages appearing every second:
ping
ping
ping
...Press any key to exit bridge mode and return to the HydraBus prompt.
Zephyr makes embedded development remarkably straightforward, even for low-level protocols like UART. The ability to configure peripheral settings (baud rate, pins, etc.) directly in the devicetree means firmware can be easily ported between different MCU platforms by simply swapping the overlay file. This hardware abstraction is powerful: write your application logic once, and adapt it to new hardware with minimal code changes.
HydraBus proves to be an invaluable prototyping and testing tool. Its interactive shell makes it easy to quickly validate hardware communication without writing dedicated test code. Combined with pyHydrabus, it opens the door to automated testing scenarios—imagine scripting a full protocol validation suite that sends commands and verifies responses programmatically.