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