/* * (C) Copyright 2014 Leo C. * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include "serial.h" #define USART_CONSOLE USART1 int _write(int fd, char *ptr, int len) __attribute__((used)); struct ring { uint8_t *data; int size; volatile int begin; volatile int end; }; #define BUFFER_SIZE 256 struct ring rx_ring; struct ring tx_ring; uint8_t rx_ring_buffer[BUFFER_SIZE]; uint8_t tx_ring_buffer[BUFFER_SIZE]; static void ring_init(struct ring *ring, uint8_t *buf, int size) { ring->data = buf; ring->size = size; ring->begin = 0; ring->end = 0; } static int ring_write_ch(struct ring *ring, uint8_t ch) { int ep = (ring->end + 1) % ring->size; if ((ep) != ring->begin) { ring->data[ring->end] = ch; ring->end = ep; return 1; } return -1; } static int ring_write(struct ring *ring, uint8_t *data, int size) { int i; for (i = 0; i < size; i++) { if (ring_write_ch(ring, data[i]) < 0) return -i; } return i; } static int ring_read_ch(struct ring *ring) { int ret = -1; if (ring->begin != ring->end) { ret = ring->data[ring->begin]; ring->begin = (ring->begin +1) % ring->size; } return ret; } void usart_setup(void) { /* Initialize output ring buffer. */ ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE); ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE); /* Enable the USART1 interrupt. */ nvic_enable_irq(NVIC_USART1_IRQ); /* Setup GPIO pin GPIO_USART1_TX/LED_GREEN_PIN on GPIO port A for transmit. */ /* TODO: USART1 --> USART_CONSOLE */ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); /* Setup GPIO pin GPIO_USART1_RE_RX on GPIO port B for receive. */ gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX); /* Setup UART parameters. */ // usart_set_baudrate(USART_CONSOLE, 38400); usart_set_baudrate(USART_CONSOLE, 115200); usart_set_databits(USART_CONSOLE, 8); usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1); usart_set_parity(USART_CONSOLE, USART_PARITY_NONE); usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE); usart_set_mode(USART_CONSOLE, USART_MODE_TX_RX); /* Enable USART1 Receive interrupt. */ USART_CR1(USART1) |= USART_CR1_RXNEIE; /* Finally enable the USART. */ usart_enable(USART_CONSOLE); } void usart1_isr(void) { /* Check if we were called because of RXNE. */ if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) && ((USART_SR(USART1) & USART_SR_RXNE) != 0)) { /* Retrieve the data from the peripheral. */ ring_write_ch(&rx_ring, usart_recv(USART1)); } /* Check if we were called because of TXE. */ if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) && ((USART_SR(USART1) & USART_SR_TXE) != 0)) { int data; data = ring_read_ch(&tx_ring); if (data == -1) { /* Disable the TXE interrupt, it's no longer needed. */ USART_CR1(USART1) &= ~USART_CR1_TXEIE; } else { /* Put data into the transmit register. */ usart_send(USART1, data); } } } /*--------------------------------------------------------------------------*/ void serial_setup(void) { usart_setup(); } /*--------------------------------------------------------------------------*/ /** * Use USART_CONSOLE as a console. * This is a syscall for newlib * @param fd * @param ptr * @param len * @return */ int _write(int fd, char *ptr, int len) { int i; if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { for (i = 0; i < len; i++) { if (ptr[i] == '\n') { serial_putc('\r'); } serial_putc(ptr[i]); } return i; } errno = EIO; return -1; } int serial_getc(void) { return ring_read_ch(&rx_ring); } void serial_putc(uint8_t data) { while (ring_write_ch(&tx_ring, data) < 0) ; /* Enable the TXE interrupt. */ USART_CR1(USART1) |= USART_CR1_TXEIE; }