BERGSONNE

UART

A classic asynchronous serial port — the simplest way to talk to a sensor, a host terminal, or another MCU. core_serial gives you blocking printf-style TX and buffered RX over any USART; the hal_uart and ll_uart layers sit underneath. Use the Core / HAL / LL toggle at the top of the sidebar to switch.

Overview

A UART is identified by its USART instance (USART1, USART2, …). You give it a baud rate; everything is 8 data bits, no parity, 1 stop bit (8N1). The peripheral clock is resolved for you, so init is just the instance and a baud rate.

core_serial is handle-based (Tier 1): you hold a hal_uart_t and pass it to each call. There’s also a small Tier 2 *_bus surface (print / putc by config-declared bus id) for Studio.

Transmit

Initialize once, then write strings, bytes, or formatted output. All TX is blocking — the call returns once the bytes are on the wire:

#include "core.h"

hal_uart_t uart;
hal_uart_config_t cfg = { .baud = 115200, .rx_interrupt = 0 };
core_serial_init(&uart, USART2, &cfg);

core_serial_print(&uart, "boot\r\n");
core_serial_printf(&uart, "adc=%u mv=%lu\r\n", raw, mv);

Receive

RX has two modes, chosen at init. With rx_interrupt = 0 you poll; with rx_interrupt = 1 the driver fills a background ring buffer you drain at your own pace:

hal_uart_config_t cfg = { .baud = 115200, .rx_interrupt = 1 };
core_serial_init(&uart, USART2, &cfg);

// later, in your loop:
while (core_serial_available(&uart)) {
    uint8_t b = core_serial_getc(&uart);   // blocking; pair with available()
    handle(b);
}
No Tier 2 read yet
The *_bus Studio surface is TX-only — there’s no default-instance read / available yet (a known coverage gap). Use the handle calls above for RX.

DMA transmit

DMA TX is a HAL call
Non-blocking transmit lives at the HAL layer (hal_uart_tx_dma). Switch to HAL for the API; the buffer must stay valid until the completion callback fires.

Cross-architecture support

Polling TX/RX is the verified baseline; interrupt-driven RX and LPUART are further along on some Cores than others. The same core_serial contract holds across the family:

L0M0+L4M4W5M33H5M33WCH (RISC-V) · Nordic (nRF54) — in development

See the implementation status for the full matrix.

API reference

Default-instance · Tier 2
int core_serial_print_bus(uint8_t bus, const char * str);
Write a null-terminated string to `bus` (blocking). Returns 0 on success or -1 on undeclared bus. The most-common DSL pattern — "drop a debug line on UART2" — is one line: serial.print(2, "ready\\n");
int core_serial_putc_bus(uint8_t bus, uint8_t byte);
Write a single byte to `bus` (blocking). Returns 0 on success or -1 on undeclared bus.
Lower-level · Tier 1
hal_status_t core_serial_init(hal_uart_t * h, USART_TypeDef * instance, const hal_uart_config_t * cfg);
Initialize a UART instance. Clock is auto-resolved from PCLK1_HZ (core_config.h).
hal_status_t core_serial_init_clk(hal_uart_t * h, USART_TypeDef * instance, uint32_t pclk_hz, const hal_uart_config_t * cfg);
void core_serial_write(hal_uart_t * h, const uint8_t * data, uint32_t len);
Transmit a buffer (blocking).
void core_serial_print(hal_uart_t * h, const char * str);
Transmit a null-terminated string (blocking).
void core_serial_putc(hal_uart_t * h, uint8_t byte);
Transmit a single byte (blocking).
uint16_t core_serial_available(hal_uart_t * h);
Number of bytes available in the RX buffer.
uint8_t core_serial_getc(hal_uart_t * h);
Receive a single byte (blocking -- waits for data).
uint16_t core_serial_read(hal_uart_t * h, uint8_t * buf, uint16_t max_len);
Read available bytes from the RX ring buffer (non-blocking). Returns number of bytes read.

Generated from core_serial.htiles@6bbf0d8.