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
The usual path needs no init code. Assign the pads in config.json and coregen emits a ready handle, core_usart<n>, set up inside core_init() at the baud you give (115200 by default). Then write strings, bytes, or formatted output. TX is blocking: the call returns once the bytes are on the wire:
// config.json (Core.ST.L0 pads; each Core's definition lists its own):
// "pads": { "7": "USART2.TX", "2": "USART2.RX" },
// "interfaces": { "USART2": { "baud": 115200, "rx_interrupt": true } }
#include "core.h"
#include "core_serial.h"
core_init(); // brings up core_usart2
core_serial_print(&core_usart2, "boot\r\n");
core_serial_printf(&core_usart2, "adc=%u mv=%lu\r\n", raw, mv);rx_interrupt turns on interrupt-driven receive into a ring buffer (see below). To bring up a USART by hand instead, fill a config and call core_serial_init():
hal_uart_t uart;
hal_uart_config_t cfg = { .baud = 115200, .rx_interrupt = 0 };
core_serial_init(&uart, USART2, &cfg);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);
}*_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
hal_uart_tx_dma exists in the API but returns HAL_ERROR on every Core and never calls its callback: UART DMA needs a DMA channel assignment from coregen and per-family DMA setup that haven’t been written. Transmit is blocking today (core_serial_write / hal_uart_tx); for background receive, use the interrupt-driven ring buffer above.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:
See the implementation status for the full matrix.
Known gaps
What the SDK itself lists as missing from serial, straight from the header:
Tier 2 wraps the write side (print_bus, putc_bus) only. getc_bus, read_bus, available_bus need a Twin input affordance to be meaningful — without one the read functions would just return -1/0 always, defeating the point. Adding a "serial input" pane (analog of the GPIO toggle / ADC slider) closes both ends.
A USART<n>.TX / .RX pad in config.json makes coregen emit the handle (core_usart<n>) and its init in core_init(), with `baud` and `rx_interrupt` from interfaces.USART<n>. LPUART1 pads get no handle or init: call core_serial_init() on it by hand.
TX is polled: core_serial_write() and print return once the last byte is in the data register. RX is interrupt-driven into a ring buffer only when `rx_interrupt` is set (or hal_uart_config_t.rx_interrupt); otherwise reads poll the data register. hal_uart_tx_dma() is a stub that returns HAL_ERROR.
ll_uart_init() sets 8 data bits, no parity, 1 stop bit. hal_uart_config_t carries only `baud` and `rx_interrupt`, so RTS/CTS, parity, other stop bits, 9-bit data and inversion need register writes after init.
SDK roadmap Tier 2: LPUART works in Stop mode for wake-on-serial. Compile-only on every Core today; not surfaced through this header.
From the @studio unsupported notes in core_serial.h — tiles@217a38f.
API reference
int core_serial_print_bus(uint8_t bus, const char * str);int core_serial_putc_bus(uint8_t bus, uint8_t byte);hal_status_t core_serial_init(hal_uart_t * h, USART_TypeDef * instance, const hal_uart_config_t * cfg);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);void core_serial_print(hal_uart_t * h, const char * str);void core_serial_putc(hal_uart_t * h, uint8_t byte);uint16_t core_serial_available(hal_uart_t * h);uint8_t core_serial_getc(hal_uart_t * h);uint16_t core_serial_read(hal_uart_t * h, uint8_t * buf, uint16_t max_len);hal_uart_t * core_serial_handle_for_bus(uint8_t bus);Generated from core_serial.h — tiles@77fd3f3.

