$npx -y skills add mohitmishra786/low-level-dev-skills --skill uart-serial-baremetalBare-metal UART skill for serial console and debug. Use when configuring baud rate, polling or IRQ-driven TX/RX, or integrating DMA with UART. Activates on queries about UART bare-metal, baud BRR, serial printf, or USART interrupt.
| 1 | # UART Serial (Bare-Metal) |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Implement UART/USART for debug console and device communication: baud rate calculation, 8N1 framing, polling and interrupt-driven I/O, overrun handling, and optional DMA basics. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - First `printf`/log output on new hardware |
| 10 | - Serial protocol to sensor/module |
| 11 | - Replacing blocking HAL_UART with minimal driver |
| 12 | - Fixing garbled or missing characters |
| 13 | |
| 14 | ## Workflow |
| 15 | |
| 16 | ### 1. Baud rate (STM32) |
| 17 | |
| 18 | ``` |
| 19 | BRR = pclk / (16 * baud) /* oversampling by 16 — check RM for USART */ |
| 20 | ``` |
| 21 | |
| 22 | ```c |
| 23 | void usart2_init(uint32_t pclk, uint32_t baud) { |
| 24 | RCC->APB1ENR |= RCC_APB1ENR_USART2EN; |
| 25 | /* GPIO PA2/PA3 AF — see gpio-baremetal */ |
| 26 | |
| 27 | USART2->BRR = pclk / baud; /* simplified — RM has fractional formula */ |
| 28 | USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; |
| 29 | } |
| 30 | ``` |
| 31 | |
| 32 | Verify `pclk` from actual clock tree (`SystemCoreClock`, APB prescaler). |
| 33 | |
| 34 | ### 2. Polling TX/RX |
| 35 | |
| 36 | ```c |
| 37 | void uart_putc(USART_TypeDef *u, char c) { |
| 38 | while (!(u->SR & USART_SR_TXE)) |
| 39 | ; |
| 40 | u->DR = (uint8_t)c; |
| 41 | } |
| 42 | |
| 43 | char uart_getc(USART_TypeDef *u) { |
| 44 | while (!(u->SR & USART_SR_RXNE)) |
| 45 | ; |
| 46 | return (uint8_t)u->DR; |
| 47 | } |
| 48 | ``` |
| 49 | |
| 50 | ### 3. Interrupt-driven RX ring buffer |
| 51 | |
| 52 | ```c |
| 53 | void USART2_IRQHandler(void) { |
| 54 | if (USART2->SR & USART_SR_RXNE) { |
| 55 | uint8_t b = USART2->DR; |
| 56 | rb_push(&rx_rb, b); |
| 57 | } |
| 58 | if (USART2->SR & USART_SR_ORE) { |
| 59 | (void)USART2->DR; /* clear overrun — required on STM32 */ |
| 60 | } |
| 61 | } |
| 62 | ``` |
| 63 | |
| 64 | ### 4. retarget `printf` (newlib) |
| 65 | |
| 66 | ```c |
| 67 | int _write(int fd, char *ptr, int len) { |
| 68 | (void)fd; |
| 69 | for (int i = 0; i < len; i++) |
| 70 | uart_putc(USART2, ptr[i]); |
| 71 | return len; |
| 72 | } |
| 73 | ``` |
| 74 | |
| 75 | Link with `--specs=nosys.specs` or provide full syscalls. |
| 76 | |
| 77 | ### 5. Agent usage |
| 78 | |
| 79 | ``` |
| 80 | /uart-serial-baremetal Calculate USART BRR for 115200 at 84 MHz PCLK |
| 81 | ``` |
| 82 | |
| 83 | ## Common Problems |
| 84 | |
| 85 | | Symptom | Cause | Fix | |
| 86 | |---------|-------|-----| |
| 87 | | Garbage chars | Wrong baud/PCLK | Recompute BRR; check APB divider | |
| 88 | | Lost bytes | ORE not cleared | Read DR on ORE; use IRQ + ringbuf | |
| 89 | | No output | TX pin not AF | GPIO alternate function | |
| 90 | | `printf` hangs | `_write` missing | Implement retarget | |
| 91 | |
| 92 | ## Related Skills |
| 93 | |
| 94 | - `skills/baremetal/gpio-baremetal` — TX/RX pin mux |
| 95 | - `skills/baremetal/interrupts-and-exceptions-baremetal` — USART IRQ |
| 96 | - `skills/baremetal/dma-baremetal` — UART RX DMA |
| 97 | - `skills/embedded/openocd-jtag` — semihosting alternative |