forked from electronics/osmo-opencm3-projects
112 lines
2.7 KiB
C
112 lines
2.7 KiB
C
#include <stdio.h>
|
|
#include <sys/cdefs.h>
|
|
#include <libopencm3/cm3/assert.h>
|
|
#include <libopencm3/cm3/nvic.h>
|
|
#include <libopencm3/stm32/usart.h>
|
|
|
|
#include <libcommon/iob.h>
|
|
|
|
#include <librfn/ringbuf.h>
|
|
|
|
/* 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 <libcommon/microvty.h>
|
|
|
|
bool microvty_cb_uart_rx_not_empty(void)
|
|
{
|
|
return !ringbuf_empty(&inring);
|
|
}
|