#include #include #include #include #include #include #include /* STM32F0 has slightly different status register #defines */ #ifdef USART_ISR_RXNE #define USART_SR_RXNE USART_ISR_RXNE #define USART_SR_TXE USART_ISR_TXE #define USART_SR(x) USART_ISR(x) #endif /* picolibc iob implementation for non-blocking I/O on USART via ring-buffer */ static uint32_t stdio_usart; static uint8_t outbuf[1024]; static ringbuf_t outring = RINGBUF_VAR_INIT(outbuf, sizeof(outbuf)); static uint8_t inbuf[256]; static ringbuf_t inring = RINGBUF_VAR_INIT(inbuf, sizeof(inbuf)); void iob_init(uint32_t usart) { cm3_assert(usart == USART2); stdio_usart = usart; nvic_enable_irq(NVIC_USART2_IRQ); /* Enable RX non-empty interrupt */ USART_CR1(stdio_usart) |= USART_CR1_RXNEIE; } /* FIXME: this obviously doesn't work with iob_init() getting passed a dynamic UART */ void usart2_isr(void) { if ((USART_CR1(stdio_usart) & USART_CR1_RXNEIE) && (USART_SR(stdio_usart) & USART_SR_RXNE)) { uint16_t c = usart_recv(stdio_usart); ringbuf_put(&inring, c); } if ((USART_CR1(stdio_usart) & USART_CR1_TXEIE) && (USART_SR(stdio_usart) & USART_SR_TXE)) { int data = ringbuf_get(&outring); if (data == -1) { USART_CR1(stdio_usart) &= ~USART_CR1_TXEIE; } else { usart_send(stdio_usart, data); } } } /* buffered output to stdout */ static int my_stdout_putc(char c, FILE *file) { (void) file; cm3_assert(stdio_usart); ringbuf_put(&outring, c); USART_CR1(stdio_usart) |= USART_CR1_TXEIE; return c; } /* unbuffered, blocking output to stderr (e.g. for assert, fault handlers, ...) */ static int my_stderr_putc(char c, FILE *file) { (void) file; cm3_assert(stdio_usart); usart_send_blocking(stdio_usart, c); return c; } static int my_stdin_getc(FILE *file) { (void) file; int data = ringbuf_get(&inring); if (data == -1) return EOF; else return data; } static int my_stdout_flush(FILE *file) { (void) file; do { } while (!ringbuf_empty(&outring)); return 0; } static FILE __stdin = FDEV_SETUP_STREAM(NULL, my_stdin_getc, NULL, _FDEV_SETUP_READ); static FILE __stdout = FDEV_SETUP_STREAM(my_stdout_putc, NULL, my_stdout_flush, _FDEV_SETUP_WRITE); static FILE __stderr = FDEV_SETUP_STREAM(my_stderr_putc, NULL, NULL, _FDEV_SETUP_WRITE); #ifndef PICOLIBC_STDIO_GLOBALS FILE *const __iob[3] = { &__stdin, &__stdout, &__stderr }; #else FILE *const stdin = &__stdin; FILE *const stdout = &__stdout; FILE *const stderr = &__stderr; #endif #include bool microvty_cb_uart_rx_not_empty(void) { return !ringbuf_empty(&inring); }