]> cloudbase.mooo.com Git - z180-stamp.git/blob - stm32/serial.c
Interrupt driven Serial I/O, msg-fifo, do_msg..., debug msgs
[z180-stamp.git] / stm32 / serial.c
1 /*
2 * serial.c
3 *
4 * Created on: 04.05.2014
5 * Author: leo
6 */
7
8 #include <errno.h>
9 #include <stdio.h>
10 #include <unistd.h>
11
12 #include <libopencm3/stm32/gpio.h>
13 #include <libopencm3/stm32/usart.h>
14 #include <libopencm3/cm3/nvic.h>
15 #include "serial.h"
16
17
18 #define USART_CONSOLE USART1
19
20 int _write(int fd, char *ptr, int len) __attribute__((used));
21
22
23 struct ring {
24 uint8_t *data;
25 int size;
26 volatile int begin;
27 volatile int end;
28 };
29
30
31 #define BUFFER_SIZE 256
32
33 struct ring rx_ring;
34 struct ring tx_ring;
35 uint8_t rx_ring_buffer[BUFFER_SIZE];
36 uint8_t tx_ring_buffer[BUFFER_SIZE];
37
38
39 static void ring_init(struct ring *ring, uint8_t *buf, int size)
40 {
41 ring->data = buf;
42 ring->size = size;
43 ring->begin = 0;
44 ring->end = 0;
45 }
46
47 static int ring_write_ch(struct ring *ring, uint8_t ch)
48 {
49 int ep = (ring->end + 1) % ring->size;
50
51 if ((ep) != ring->begin) {
52 ring->data[ring->end] = ch;
53 ring->end = ep;
54 return 1;
55 }
56
57 return -1;
58 }
59
60 static int ring_write(struct ring *ring, uint8_t *data, int size)
61 {
62 int i;
63
64 for (i = 0; i < size; i++) {
65 if (ring_write_ch(ring, data[i]) < 0)
66 return -i;
67 }
68
69 return i;
70 }
71
72 static int ring_read_ch(struct ring *ring)
73 {
74 int ret = -1;
75
76 if (ring->begin != ring->end) {
77 ret = ring->data[ring->begin];
78 ring->begin = (ring->begin +1) % ring->size;
79 }
80
81 return ret;
82 }
83
84 void usart_setup(void)
85 {
86 /* Initialize output ring buffer. */
87 ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE);
88 ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE);
89
90 /* Enable the USART1 interrupt. */
91 nvic_enable_irq(NVIC_USART1_IRQ);
92
93 /* Setup GPIO pin GPIO_USART1_TX/LED_GREEN_PIN on GPIO port A for transmit. */
94 /* TODO: USART1 --> USART_CONSOLE */
95
96 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
97 GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
98
99 /* Setup GPIO pin GPIO_USART1_RE_RX on GPIO port B for receive. */
100 gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
101 GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);
102
103 /* Setup UART parameters. */
104 // usart_set_baudrate(USART_CONSOLE, 38400);
105 usart_set_baudrate(USART_CONSOLE, 115200);
106 usart_set_databits(USART_CONSOLE, 8);
107 usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1);
108 usart_set_parity(USART_CONSOLE, USART_PARITY_NONE);
109 usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE);
110 usart_set_mode(USART_CONSOLE, USART_MODE_TX_RX);
111
112 /* Enable USART1 Receive interrupt. */
113 USART_CR1(USART1) |= USART_CR1_RXNEIE;
114
115 /* Finally enable the USART. */
116 usart_enable(USART_CONSOLE);
117 }
118
119 void usart1_isr(void)
120 {
121 /* Check if we were called because of RXNE. */
122 if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) &&
123 ((USART_SR(USART1) & USART_SR_RXNE) != 0)) {
124
125 /* Retrieve the data from the peripheral. */
126 ring_write_ch(&rx_ring, usart_recv(USART1));
127
128 }
129
130 /* Check if we were called because of TXE. */
131 if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) &&
132 ((USART_SR(USART1) & USART_SR_TXE) != 0)) {
133
134 int data;
135
136 data = ring_read_ch(&tx_ring);
137
138 if (data == -1) {
139 /* Disable the TXE interrupt, it's no longer needed. */
140 USART_CR1(USART1) &= ~USART_CR1_TXEIE;
141 } else {
142 /* Put data into the transmit register. */
143 usart_send(USART1, data);
144 }
145 }
146 }
147
148 /*--------------------------------------------------------------------------*/
149
150 void serial_setup(void)
151 {
152 usart_setup();
153 }
154
155 /*--------------------------------------------------------------------------*/
156
157 /**
158 * Use USART_CONSOLE as a console.
159 * This is a syscall for newlib
160 * @param fd
161 * @param ptr
162 * @param len
163 * @return
164 */
165 int _write(int fd, char *ptr, int len)
166 {
167 int i;
168
169 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
170 for (i = 0; i < len; i++) {
171 if (ptr[i] == '\n') {
172 serial_putc('\r');
173 }
174 serial_putc(ptr[i]);
175 }
176 return i;
177 }
178 errno = EIO;
179 return -1;
180 }
181
182 int serial_getc(void)
183 {
184 return ring_read_ch(&rx_ring);
185 }
186
187 void serial_putc(uint8_t data)
188 {
189 while (ring_write_ch(&tx_ring, data) < 0)
190 ;
191
192 /* Enable the TXE interrupt. */
193 USART_CR1(USART1) |= USART_CR1_TXEIE;
194 }