diff options
Diffstat (limited to 'stm32/serial.c')
-rw-r--r-- | stm32/serial.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/stm32/serial.c b/stm32/serial.c new file mode 100644 index 0000000..9193005 --- /dev/null +++ b/stm32/serial.c @@ -0,0 +1,194 @@ +/* + * serial.c + * + * Created on: 04.05.2014 + * Author: leo + */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +#include <libopencm3/stm32/gpio.h> +#include <libopencm3/stm32/usart.h> +#include <libopencm3/cm3/nvic.h> +#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; +} |