summaryrefslogtreecommitdiff
path: root/stm32/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm32/serial.c')
-rw-r--r--stm32/serial.c194
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;
+}