Switch from GPLv2 to GPLv2+
[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)
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         /* Pick a 9600 baud rate */
240         ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);
241 }
242
243 #if HAS_SERIAL_HW_FLOW
244 static void
245 ao_usart_set_flow(struct ao_stm_usart *usart)
246 {
247         usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) |
248                             (1 << STM_USART_CR3_RTSE));
249 }
250 #endif
251
252 #if HAS_SERIAL_1
253
254 struct ao_stm_usart ao_stm_usart1;
255
256 void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
257
258 char
259 ao_serial1_getchar(void)
260 {
261         return ao_usart_getchar(&ao_stm_usart1);
262 }
263
264 void
265 ao_serial1_putchar(char c)
266 {
267         ao_usart_putchar(&ao_stm_usart1, c);
268 }
269
270 int
271 _ao_serial1_pollchar(void)
272 {
273         return _ao_usart_pollchar(&ao_stm_usart1);
274 }
275
276 uint8_t
277 _ao_serial1_sleep_for(uint16_t timeout)
278 {
279         return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
280 }
281
282 void
283 ao_serial1_drain(void)
284 {
285         ao_usart_drain(&ao_stm_usart1);
286 }
287
288 void
289 ao_serial1_set_speed(uint8_t speed)
290 {
291         ao_usart_drain(&ao_stm_usart1);
292         ao_usart_set_speed(&ao_stm_usart1, speed);
293 }
294 #endif  /* HAS_SERIAL_1 */
295
296 #if HAS_SERIAL_2
297
298 struct ao_stm_usart ao_stm_usart2;
299
300 void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
301
302 char
303 ao_serial2_getchar(void)
304 {
305         return ao_usart_getchar(&ao_stm_usart2);
306 }
307
308 void
309 ao_serial2_putchar(char c)
310 {
311         ao_usart_putchar(&ao_stm_usart2, c);
312 }
313
314 int
315 _ao_serial2_pollchar(void)
316 {
317         return _ao_usart_pollchar(&ao_stm_usart2);
318 }
319
320 uint8_t
321 _ao_serial2_sleep_for(uint16_t timeout)
322 {
323         return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
324 }
325
326 void
327 ao_serial2_drain(void)
328 {
329         ao_usart_drain(&ao_stm_usart2);
330 }
331
332 void
333 ao_serial2_set_speed(uint8_t speed)
334 {
335         ao_usart_drain(&ao_stm_usart2);
336         ao_usart_set_speed(&ao_stm_usart2, speed);
337 }
338
339 #if HAS_SERIAL_SW_FLOW
340 void
341 ao_serial2_cts(void)
342 {
343         _ao_usart_cts(&ao_stm_usart2);
344 }
345 #endif
346
347 #endif  /* HAS_SERIAL_2 */
348
349 #if HAS_SERIAL_3
350
351 struct ao_stm_usart ao_stm_usart3;
352
353 void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); }
354
355 char
356 ao_serial3_getchar(void)
357 {
358         return ao_usart_getchar(&ao_stm_usart3);
359 }
360
361 void
362 ao_serial3_putchar(char c)
363 {
364         ao_usart_putchar(&ao_stm_usart3, c);
365 }
366
367 int
368 _ao_serial3_pollchar(void)
369 {
370         return _ao_usart_pollchar(&ao_stm_usart3);
371 }
372
373 uint8_t
374 _ao_serial3_sleep_for(uint16_t timeout)
375 {
376         return _ao_usart_sleep_for(&ao_stm_usart3, timeout);
377 }
378
379 void
380 ao_serial3_set_speed(uint8_t speed)
381 {
382         ao_usart_drain(&ao_stm_usart3);
383         ao_usart_set_speed(&ao_stm_usart3, speed);
384 }
385
386 void
387 ao_serial3_drain(void)
388 {
389         ao_usart_drain(&ao_stm_usart3);
390 }
391 #endif  /* HAS_SERIAL_3 */
392
393 #if HAS_SERIAL_SW_FLOW
394 static void
395 ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart,
396                          void (*isr)(void),
397                          struct stm_gpio *port_rts,
398                          int pin_rts,
399                          struct stm_gpio *port_cts,
400                          int pin_cts)
401 {
402         /* Pull RTS low to note that there's space in the FIFO
403          */
404         ao_enable_output(port_rts, pin_rts, foo, 0);
405         usart->gpio_rts = port_rts;
406         usart->pin_rts = pin_rts;
407         usart->rts = 1;
408
409         ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
410         usart->gpio_cts = port_cts;
411         usart->pin_cts = pin_cts;
412 }
413 #endif
414
415 void
416 ao_serial_init(void)
417 {
418 #if HAS_SERIAL_1
419         /*
420          *      TX      RX
421          *      PA9     PA10
422          *      PB6     PB7     *
423          */
424
425 #if SERIAL_1_PA9_PA10
426         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
427
428         stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
429         stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
430 #else
431 #if SERIAL_1_PB6_PB7
432         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
433
434         stm_afr_set(&stm_gpiob, 6, STM_AFR_AF7);
435         stm_afr_set(&stm_gpiob, 7, STM_AFR_AF7);
436 #else
437 #error "No SERIAL_1 port configuration specified"
438 #endif
439 #endif
440         /* Enable USART */
441         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
442
443         ao_stm_usart1.reg = &stm_usart1;
444         ao_usart_init(&ao_stm_usart1);
445
446         stm_nvic_set_enable(STM_ISR_USART1_POS);
447         stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
448 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
449         ao_add_stdio(_ao_serial1_pollchar,
450                      ao_serial1_putchar,
451                      NULL);
452 #endif
453 #endif
454
455 #if HAS_SERIAL_2
456         /*
457          *      TX      RX
458          *      PA2     PA3
459          *      PD5     PD6
460          */
461
462 #if SERIAL_2_PA2_PA3
463         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
464
465         stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7);
466         stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7);
467 # if USE_SERIAL_2_FLOW
468 #  if USE_SERIAL_2_SW_FLOW
469         ao_serial_set_sw_rts_cts(&ao_stm_usart2,
470                                  ao_serial2_cts,
471                                  SERIAL_2_PORT_RTS,
472                                  SERIAL_2_PIN_RTS,
473                                  SERIAL_2_PORT_CTS,
474                                  SERIAL_2_PIN_CTS);
475 #  else
476         stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7);
477         stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7);
478 #  endif
479 # endif
480 #else
481 #if SERIAL_2_PD5_PD6
482         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
483
484         stm_afr_set(&stm_gpiod, 5, STM_AFR_AF7);
485         stm_afr_set(&stm_gpiod, 6, STM_AFR_AF7);
486 #if USE_SERIAL_2_FLOW
487 #error "Don't know how to set flowcontrol for serial 2 on PD"
488 #endif
489 #else
490 #error "No SERIAL_2 port configuration specified"
491 #endif
492 #endif
493         /* Enable USART */
494         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
495
496         ao_stm_usart2.reg = &stm_usart2;
497         ao_usart_init(&ao_stm_usart2);
498 #if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW
499         ao_usart_set_flow(&ao_stm_usart2);
500 #endif
501
502         stm_nvic_set_enable(STM_ISR_USART2_POS);
503         stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
504 #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
505         ao_add_stdio(_ao_serial2_pollchar,
506                      ao_serial2_putchar,
507                      NULL);
508 #endif
509 #endif
510
511 #if HAS_SERIAL_3
512         /*
513          *      TX      RX
514          *      PB10    PB11
515          *      PC10    PC11
516          *      PD8     PD9
517          */
518 #if SERIAL_3_PB10_PB11
519         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
520
521         stm_afr_set(&stm_gpiob, 10, STM_AFR_AF7);
522         stm_afr_set(&stm_gpiob, 11, STM_AFR_AF7);
523 #else
524 #if SERIAL_3_PC10_PC11
525         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
526
527         stm_afr_set(&stm_gpioc, 10, STM_AFR_AF7);
528         stm_afr_set(&stm_gpioc, 11, STM_AFR_AF7);
529 #else
530 #if SERIAL_3_PD8_PD9
531         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
532
533         stm_afr_set(&stm_gpiod, 8, STM_AFR_AF7);
534         stm_afr_set(&stm_gpiod, 9, STM_AFR_AF7);
535 #else
536 #error "No SERIAL_3 port configuration specified"
537 #endif
538 #endif
539 #endif
540         /* Enable USART */
541         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN);
542
543         ao_stm_usart3.reg = &stm_usart3;
544         ao_usart_init(&ao_stm_usart3);
545
546         stm_nvic_set_enable(STM_ISR_USART3_POS);
547         stm_nvic_set_priority(STM_ISR_USART3_POS, 4);
548 #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN
549         ao_add_stdio(_ao_serial3_pollchar,
550                      ao_serial3_putchar,
551                      NULL);
552 #endif
553 #endif
554 }