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