altos/stm32l: Add support for software-driven HW flow control
[fw/altos] / src / stm / ao_serial_stm.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_exti.h>
20
21 void
22 ao_debug_out(char c)
23 {
24         if (c == '\n')
25                 ao_debug_out('\r');
26         while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE)));
27         stm_usart1.dr = c;
28 }
29
30 static int
31 _ao_usart_tx_start(struct ao_stm_usart *usart)
32 {
33         if (!ao_fifo_empty(usart->tx_fifo)) {
34 #if HAS_SERIAL_SW_FLOW
35                 if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts, foo) == 1) {
36                         ao_exti_enable(usart->gpio_cts, usart->pin_cts);
37                         return 0;
38                 }
39 #endif
40                 if (usart->reg->sr & (1 << STM_USART_SR_TXE))
41                 {
42                         usart->tx_running = 1;
43                         usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE);
44                         ao_fifo_remove(usart->tx_fifo, usart->reg->dr);
45                         ao_wakeup(&usart->tx_fifo);
46                         return 1;
47                 }
48         }
49         return 0;
50 }
51
52 #if HAS_SERIAL_SW_FLOW
53 static void
54 _ao_usart_cts(struct ao_stm_usart *usart)
55 {
56         if (_ao_usart_tx_start(usart))
57                 ao_exti_disable(usart->gpio_cts, usart->pin_cts);
58 }
59 #endif
60
61 static void
62 _ao_usart_rx(struct ao_stm_usart *usart, int stdin)
63 {
64         if (usart->reg->sr & (1 << STM_USART_SR_RXNE)) {
65                 if (!ao_fifo_full(usart->rx_fifo)) {
66                         ao_fifo_insert(usart->rx_fifo, usart->reg->dr);
67                         ao_wakeup(&usart->rx_fifo);
68                         if (stdin)
69                                 ao_wakeup(&ao_stdin_ready);
70 #if HAS_SERIAL_SW_FLOW
71                         /* If the fifo is nearly full, turn off RTS and wait
72                          * for it to drain a bunch
73                          */
74                         if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) {
75                                 ao_gpio_set(usart->gpio_rts, usart->pin_rts, usart->pin_rts, 1);
76                                 usart->rts = 0;
77                         }
78 #endif
79                 } else {
80                         usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE);
81                 }
82         }
83 }
84
85 static void
86 ao_usart_isr(struct ao_stm_usart *usart, int stdin)
87 {
88         _ao_usart_rx(usart, stdin);
89
90         if (!_ao_usart_tx_start(usart))
91                 usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE);
92
93         if (usart->reg->sr & (1 << STM_USART_SR_TC)) {
94                 usart->tx_running = 0;
95                 usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE);
96                 if (usart->draining) {
97                         usart->draining = 0;
98                         ao_wakeup(&usart->tx_fifo);
99                 }
100         }
101 }
102
103 static int
104 _ao_usart_pollchar(struct ao_stm_usart *usart)
105 {
106         int     c;
107
108         if (ao_fifo_empty(usart->rx_fifo))
109                 c = AO_READ_AGAIN;
110         else {
111                 uint8_t u;
112                 ao_fifo_remove(usart->rx_fifo,u);
113                 if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) {
114                         if (ao_fifo_barely(usart->rx_fifo))
115                                 usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE);
116                 }
117 #if HAS_SERIAL_SW_FLOW
118                 /* If we've cleared RTS, check if there's space now and turn it back on */
119                 if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) {
120                         ao_gpio_set(usart->gpio_rts, usart->pin_rts, foo, 0);
121                         usart->rts = 1;
122                 }
123 #endif
124                 c = u;
125         }
126         return c;
127 }
128
129 static char
130 ao_usart_getchar(struct ao_stm_usart *usart)
131 {
132         int c;
133         ao_arch_block_interrupts();
134         while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN)
135                 ao_sleep(&usart->rx_fifo);
136         ao_arch_release_interrupts();
137         return (char) c;
138 }
139
140 static inline uint8_t
141 _ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout)
142 {
143         return ao_sleep_for(&usart->rx_fifo, timeout);
144 }
145
146 static void
147 ao_usart_putchar(struct ao_stm_usart *usart, char c)
148 {
149         ao_arch_block_interrupts();
150         while (ao_fifo_full(usart->tx_fifo))
151                 ao_sleep(&usart->tx_fifo);
152         ao_fifo_insert(usart->tx_fifo, c);
153         _ao_usart_tx_start(usart);
154         ao_arch_release_interrupts();
155 }
156
157 static void
158 ao_usart_drain(struct ao_stm_usart *usart)
159 {
160         ao_arch_block_interrupts();
161         while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) {
162                 usart->draining = 1;
163                 ao_sleep(&usart->tx_fifo);
164         }
165         ao_arch_release_interrupts();
166 }
167
168 static const struct {
169         uint32_t brr;
170 } ao_usart_speeds[] = {
171         [AO_SERIAL_SPEED_4800] = {
172                 AO_PCLK1 / 4800
173         },
174         [AO_SERIAL_SPEED_9600] = {
175                 AO_PCLK1 / 9600
176         },
177         [AO_SERIAL_SPEED_19200] = {
178                 AO_PCLK1 / 19200
179         },
180         [AO_SERIAL_SPEED_57600] = {
181                 AO_PCLK1 / 57600
182         },
183         [AO_SERIAL_SPEED_115200] = {
184                 AO_PCLK1 / 115200
185         },
186 };
187
188 static void
189 ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)
190 {
191         if (speed > AO_SERIAL_SPEED_115200)
192                 return;
193         usart->reg->brr = ao_usart_speeds[speed].brr;
194 }
195
196 static void
197 ao_usart_init(struct ao_stm_usart *usart)
198 {
199         usart->reg->cr1 = ((0 << STM_USART_CR1_OVER8) |
200                           (1 << STM_USART_CR1_UE) |
201                           (0 << STM_USART_CR1_M) |
202                           (0 << STM_USART_CR1_WAKE) |
203                           (0 << STM_USART_CR1_PCE) |
204                           (0 << STM_USART_CR1_PS) |
205                           (0 << STM_USART_CR1_PEIE) |
206                           (0 << STM_USART_CR1_TXEIE) |
207                           (0 << STM_USART_CR1_TCIE) |
208                           (1 << STM_USART_CR1_RXNEIE) |
209                           (0 << STM_USART_CR1_IDLEIE) |
210                           (1 << STM_USART_CR1_TE) |
211                           (1 << STM_USART_CR1_RE) |
212                           (0 << STM_USART_CR1_RWU) |
213                           (0 << STM_USART_CR1_SBK));
214
215         usart->reg->cr2 = ((0 << STM_USART_CR2_LINEN) |
216                           (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
217                           (0 << STM_USART_CR2_CLKEN) |
218                           (0 << STM_USART_CR2_CPOL) |
219                           (0 << STM_USART_CR2_CPHA) |
220                           (0 << STM_USART_CR2_LBCL) |
221                           (0 << STM_USART_CR2_LBDIE) |
222                           (0 << STM_USART_CR2_LBDL) |
223                           (0 << STM_USART_CR2_ADD));
224
225         usart->reg->cr3 = ((0 << STM_USART_CR3_ONEBITE) |
226                           (0 << STM_USART_CR3_CTSIE) |
227                           (0 << STM_USART_CR3_CTSE) |
228                           (0 << STM_USART_CR3_RTSE) |
229                           (0 << STM_USART_CR3_DMAT) |
230                           (0 << STM_USART_CR3_DMAR) |
231                           (0 << STM_USART_CR3_SCEN) |
232                           (0 << STM_USART_CR3_NACK) |
233                           (0 << STM_USART_CR3_HDSEL) |
234                           (0 << STM_USART_CR3_IRLP) |
235                           (0 << STM_USART_CR3_IREN) |
236                           (0 << STM_USART_CR3_EIE));
237
238         /* Pick a 9600 baud rate */
239         ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);
240 }
241
242 #if HAS_SERIAL_HW_FLOW
243 static void
244 ao_usart_set_flow(struct ao_stm_usart *usart)
245 {
246         usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) |
247                             (1 << STM_USART_CR3_RTSE));
248 }
249 #endif
250
251 #if HAS_SERIAL_1
252
253 struct ao_stm_usart ao_stm_usart1;
254
255 void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
256
257 char
258 ao_serial1_getchar(void)
259 {
260         return ao_usart_getchar(&ao_stm_usart1);
261 }
262
263 void
264 ao_serial1_putchar(char c)
265 {
266         ao_usart_putchar(&ao_stm_usart1, c);
267 }
268
269 int
270 _ao_serial1_pollchar(void)
271 {
272         return _ao_usart_pollchar(&ao_stm_usart1);
273 }
274
275 uint8_t
276 _ao_serial1_sleep_for(uint16_t timeout)
277 {
278         return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
279 }
280
281 void
282 ao_serial1_drain(void)
283 {
284         ao_usart_drain(&ao_stm_usart1);
285 }
286
287 void
288 ao_serial1_set_speed(uint8_t speed)
289 {
290         ao_usart_drain(&ao_stm_usart1);
291         ao_usart_set_speed(&ao_stm_usart1, speed);
292 }
293 #endif  /* HAS_SERIAL_1 */
294
295 #if HAS_SERIAL_2
296
297 struct ao_stm_usart ao_stm_usart2;
298
299 void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
300
301 char
302 ao_serial2_getchar(void)
303 {
304         return ao_usart_getchar(&ao_stm_usart2);
305 }
306
307 void
308 ao_serial2_putchar(char c)
309 {
310         ao_usart_putchar(&ao_stm_usart2, c);
311 }
312
313 int
314 _ao_serial2_pollchar(void)
315 {
316         return _ao_usart_pollchar(&ao_stm_usart2);
317 }
318
319 uint8_t
320 _ao_serial2_sleep_for(uint16_t timeout)
321 {
322         return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
323 }
324
325 void
326 ao_serial2_drain(void)
327 {
328         ao_usart_drain(&ao_stm_usart2);
329 }
330
331 void
332 ao_serial2_set_speed(uint8_t speed)
333 {
334         ao_usart_drain(&ao_stm_usart2);
335         ao_usart_set_speed(&ao_stm_usart2, speed);
336 }
337
338 #if HAS_SERIAL_SW_FLOW
339 void
340 ao_serial2_cts(void)
341 {
342         _ao_usart_cts(&ao_stm_usart2);
343 }
344 #endif
345
346 #endif  /* HAS_SERIAL_2 */
347
348 #if HAS_SERIAL_3
349
350 struct ao_stm_usart ao_stm_usart3;
351
352 void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); }
353
354 char
355 ao_serial3_getchar(void)
356 {
357         return ao_usart_getchar(&ao_stm_usart3);
358 }
359
360 void
361 ao_serial3_putchar(char c)
362 {
363         ao_usart_putchar(&ao_stm_usart3, c);
364 }
365
366 int
367 _ao_serial3_pollchar(void)
368 {
369         return _ao_usart_pollchar(&ao_stm_usart3);
370 }
371
372 uint8_t
373 _ao_serial3_sleep_for(uint16_t timeout)
374 {
375         return _ao_usart_sleep_for(&ao_stm_usart3, timeout);
376 }
377
378 void
379 ao_serial3_set_speed(uint8_t speed)
380 {
381         ao_usart_drain(&ao_stm_usart3);
382         ao_usart_set_speed(&ao_stm_usart3, speed);
383 }
384
385 void
386 ao_serial3_drain(void)
387 {
388         ao_usart_drain(&ao_stm_usart3);
389 }
390 #endif  /* HAS_SERIAL_3 */
391
392 #if HAS_SERIAL_SW_FLOW
393 static void
394 ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart,
395                          void (*isr)(void),
396                          struct stm_gpio *port_rts,
397                          int pin_rts,
398                          struct stm_gpio *port_cts,
399                          int pin_cts)
400 {
401         /* Pull RTS low to note that there's space in the FIFO
402          */
403         ao_enable_output(port_rts, pin_rts, foo, 0);
404         usart->gpio_rts = port_rts;
405         usart->pin_rts = pin_rts;
406         usart->rts = 1;
407
408         ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
409         usart->gpio_cts = port_cts;
410         usart->pin_cts = pin_cts;
411 }
412 #endif
413
414 void
415 ao_serial_init(void)
416 {
417 #if HAS_SERIAL_1
418         /*
419          *      TX      RX
420          *      PA9     PA10
421          *      PB6     PB7     *
422          */
423
424 #if SERIAL_1_PA9_PA10
425         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
426
427         stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
428         stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
429 #else
430 #if SERIAL_1_PB6_PB7
431         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
432
433         stm_afr_set(&stm_gpiob, 6, STM_AFR_AF7);
434         stm_afr_set(&stm_gpiob, 7, STM_AFR_AF7);
435 #else
436 #error "No SERIAL_1 port configuration specified"
437 #endif
438 #endif
439         /* Enable USART */
440         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
441
442         ao_stm_usart1.reg = &stm_usart1;
443         ao_usart_init(&ao_stm_usart1);
444
445         stm_nvic_set_enable(STM_ISR_USART1_POS);
446         stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
447 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
448         ao_add_stdio(_ao_serial1_pollchar,
449                      ao_serial1_putchar,
450                      NULL);
451 #endif
452 #endif
453
454 #if HAS_SERIAL_2
455         /*
456          *      TX      RX
457          *      PA2     PA3
458          *      PD5     PD6
459          */
460
461 #if SERIAL_2_PA2_PA3
462         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
463
464         stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7);
465         stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7);
466 # if USE_SERIAL_2_FLOW
467 #  if USE_SERIAL_2_SW_FLOW
468         ao_serial_set_sw_rts_cts(&ao_stm_usart2,
469                                  ao_serial2_cts,
470                                  SERIAL_2_PORT_RTS,
471                                  SERIAL_2_PIN_RTS,
472                                  SERIAL_2_PORT_CTS,
473                                  SERIAL_2_PIN_CTS);
474 #  else
475         stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7);
476         stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7);
477 #  endif
478 # endif
479 #else
480 #if SERIAL_2_PD5_PD6
481         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
482
483         stm_afr_set(&stm_gpiod, 5, STM_AFR_AF7);
484         stm_afr_set(&stm_gpiod, 6, STM_AFR_AF7);
485 #if USE_SERIAL_2_FLOW
486 #error "Don't know how to set flowcontrol for serial 2 on PD"
487 #endif
488 #else
489 #error "No SERIAL_2 port configuration specified"
490 #endif
491 #endif
492         /* Enable USART */
493         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
494
495         ao_stm_usart2.reg = &stm_usart2;
496         ao_usart_init(&ao_stm_usart2);
497 #if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW
498         ao_usart_set_flow(&ao_stm_usart2);
499 #endif
500
501         stm_nvic_set_enable(STM_ISR_USART2_POS);
502         stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
503 #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
504         ao_add_stdio(_ao_serial2_pollchar,
505                      ao_serial2_putchar,
506                      NULL);
507 #endif
508 #endif
509
510 #if HAS_SERIAL_3
511         /*
512          *      TX      RX
513          *      PB10    PB11
514          *      PC10    PC11
515          *      PD8     PD9
516          */
517 #if SERIAL_3_PB10_PB11
518         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
519
520         stm_afr_set(&stm_gpiob, 10, STM_AFR_AF7);
521         stm_afr_set(&stm_gpiob, 11, STM_AFR_AF7);
522 #else
523 #if SERIAL_3_PC10_PC11
524         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
525
526         stm_afr_set(&stm_gpioc, 10, STM_AFR_AF7);
527         stm_afr_set(&stm_gpioc, 11, STM_AFR_AF7);
528 #else
529 #if SERIAL_3_PD8_PD9
530         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
531
532         stm_afr_set(&stm_gpiod, 8, STM_AFR_AF7);
533         stm_afr_set(&stm_gpiod, 9, STM_AFR_AF7);
534 #else
535 #error "No SERIAL_3 port configuration specified"
536 #endif
537 #endif
538 #endif
539         /* Enable USART */
540         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN);
541
542         ao_stm_usart3.reg = &stm_usart3;
543         ao_usart_init(&ao_stm_usart3);
544
545         stm_nvic_set_enable(STM_ISR_USART3_POS);
546         stm_nvic_set_priority(STM_ISR_USART3_POS, 4);
547 #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN
548         ao_add_stdio(_ao_serial3_pollchar,
549                      ao_serial3_putchar,
550                      NULL);
551 #endif
552 #endif
553 }