]> git.gag.com Git - fw/altos/blob - src/stm32f1/ao_serial_stm.c
Merge branch 'master' into branch-1.9
[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 HAS_SERIAL_1
200         if (usart == &ao_stm_usart1)
201                 brr = AO_PCLK2 / ao_usart_speeds[speed].baud;
202         else
203 #endif
204                 brr = AO_PCLK1 / ao_usart_speeds[speed].baud;
205         usart->reg->brr = brr;
206 }
207
208 static void
209 ao_usart_init(struct ao_stm_usart *usart, int hw_flow, uint8_t speed)
210 {
211         usart->reg->cr1 = ((1 << STM_USART_CR1_UE) |
212                           (0 << STM_USART_CR1_M) |
213                           (0 << STM_USART_CR1_WAKE) |
214                           (0 << STM_USART_CR1_PCE) |
215                           (0 << STM_USART_CR1_PS) |
216                           (0 << STM_USART_CR1_PEIE) |
217                           (0 << STM_USART_CR1_TXEIE) |
218                           (0 << STM_USART_CR1_TCIE) |
219                           (1 << STM_USART_CR1_RXNEIE) |
220                           (0 << STM_USART_CR1_IDLEIE) |
221                           (1 << STM_USART_CR1_TE) |
222                           (1 << STM_USART_CR1_RE) |
223                           (0 << STM_USART_CR1_RWU) |
224                           (0 << STM_USART_CR1_SBK));
225
226         usart->reg->cr2 = ((0 << STM_USART_CR2_LINEN) |
227                           (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
228                           (0 << STM_USART_CR2_CLKEN) |
229                           (0 << STM_USART_CR2_CPOL) |
230                           (0 << STM_USART_CR2_CPHA) |
231                           (0 << STM_USART_CR2_LBCL) |
232                           (0 << STM_USART_CR2_LBDIE) |
233                           (0 << STM_USART_CR2_LBDL) |
234                           (0 << STM_USART_CR2_ADD));
235
236         usart->reg->cr3 = ((0 << STM_USART_CR3_CTSIE) |
237                           (0 << STM_USART_CR3_CTSE) |
238                           (0 << STM_USART_CR3_RTSE) |
239                           (0 << STM_USART_CR3_DMAT) |
240                           (0 << STM_USART_CR3_DMAR) |
241                           (0 << STM_USART_CR3_SCEN) |
242                           (0 << STM_USART_CR3_NACK) |
243                           (0 << STM_USART_CR3_HDSEL) |
244                           (0 << STM_USART_CR3_IRLP) |
245                           (0 << STM_USART_CR3_IREN) |
246                           (0 << STM_USART_CR3_EIE));
247
248         if (hw_flow)
249                 usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) |
250                                     (1 << STM_USART_CR3_RTSE));
251
252         ao_usart_set_speed(usart, speed);
253 }
254
255 #if HAS_SERIAL_1
256
257 struct ao_stm_usart ao_stm_usart1;
258
259 void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
260
261 char
262 ao_serial1_getchar(void)
263 {
264         return ao_usart_getchar(&ao_stm_usart1);
265 }
266
267 void
268 ao_serial1_putchar(char c)
269 {
270         ao_usart_putchar(&ao_stm_usart1, c);
271 }
272
273 int
274 _ao_serial1_pollchar(void)
275 {
276         return _ao_usart_pollchar(&ao_stm_usart1);
277 }
278
279 uint8_t
280 _ao_serial1_sleep_for(AO_TICK_TYPE timeout)
281 {
282         return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
283 }
284
285 void
286 ao_serial1_drain(void)
287 {
288         ao_usart_drain(&ao_stm_usart1);
289 }
290
291 void
292 ao_serial1_set_speed(uint8_t speed)
293 {
294         ao_usart_drain(&ao_stm_usart1);
295         ao_usart_set_speed(&ao_stm_usart1, speed);
296 }
297 #endif  /* HAS_SERIAL_1 */
298
299 #if HAS_SERIAL_2
300
301 struct ao_stm_usart ao_stm_usart2;
302
303 void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
304
305 char
306 ao_serial2_getchar(void)
307 {
308         return ao_usart_getchar(&ao_stm_usart2);
309 }
310
311 void
312 ao_serial2_putchar(char c)
313 {
314         ao_usart_putchar(&ao_stm_usart2, c);
315 }
316
317 int
318 _ao_serial2_pollchar(void)
319 {
320         return _ao_usart_pollchar(&ao_stm_usart2);
321 }
322
323 uint8_t
324 _ao_serial2_sleep_for(AO_TICK_TYPE timeout)
325 {
326         return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
327 }
328
329 void
330 ao_serial2_drain(void)
331 {
332         ao_usart_drain(&ao_stm_usart2);
333 }
334
335 void
336 ao_serial2_set_speed(uint8_t speed)
337 {
338         ao_usart_drain(&ao_stm_usart2);
339         ao_usart_set_speed(&ao_stm_usart2, speed);
340 }
341
342 #if HAS_SERIAL_SW_FLOW
343 static void
344 ao_serial2_cts(void)
345 {
346         _ao_usart_cts(&ao_stm_usart2);
347 }
348 #endif
349
350 #endif  /* HAS_SERIAL_2 */
351
352 #if HAS_SERIAL_3
353
354 struct ao_stm_usart ao_stm_usart3;
355
356 void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); }
357
358 char
359 ao_serial3_getchar(void)
360 {
361         return ao_usart_getchar(&ao_stm_usart3);
362 }
363
364 void
365 ao_serial3_putchar(char c)
366 {
367         ao_usart_putchar(&ao_stm_usart3, c);
368 }
369
370 int
371 _ao_serial3_pollchar(void)
372 {
373         return _ao_usart_pollchar(&ao_stm_usart3);
374 }
375
376 uint8_t
377 _ao_serial3_sleep_for(AO_TICK_TYPE timeout)
378 {
379         return _ao_usart_sleep_for(&ao_stm_usart3, timeout);
380 }
381
382 void
383 ao_serial3_set_speed(uint8_t speed)
384 {
385         ao_usart_drain(&ao_stm_usart3);
386         ao_usart_set_speed(&ao_stm_usart3, speed);
387 }
388
389 void
390 ao_serial3_drain(void)
391 {
392         ao_usart_drain(&ao_stm_usart3);
393 }
394 #endif  /* HAS_SERIAL_3 */
395
396 #if HAS_SERIAL_SW_FLOW
397 static void
398 ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart,
399                          void (*isr)(void),
400                          struct stm_gpio *port_rts,
401                          uint8_t pin_rts,
402                          struct stm_gpio *port_cts,
403                          uint8_t pin_cts)
404 {
405         /* Pull RTS low to note that there's space in the FIFO
406          */
407         ao_enable_output(port_rts, pin_rts, 0);
408         usart->gpio_rts = port_rts;
409         usart->pin_rts = pin_rts;
410         usart->rts = 1;
411
412         ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
413         usart->gpio_cts = port_cts;
414         usart->pin_cts = pin_cts;
415 }
416 #endif
417
418 void
419 ao_serial_init(void)
420 {
421 #if HAS_SERIAL_1
422         /*
423          *      TX      RX
424          *      PA9     PA10
425          *      PB6     PB7     *
426          */
427
428 #if SERIAL_1_PA9_PA10
429         ao_enable_port(&stm_gpioa);
430         stm_gpio_conf(&stm_gpioa, 9,
431                       STM_GPIO_CR_MODE_OUTPUT_2MHZ,
432                       STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);
433
434         stm_gpio_conf(&stm_gpioa, 10,
435                       STM_GPIO_CR_MODE_INPUT,
436                       STM_GPIO_CR_CNF_INPUT_FLOATING);
437
438         stm_set_afio_mapr(STM_AFIO_MAPR_USART1_REMAP,
439                           STM_AFIO_MAPR_USART1_REMAP_PA9_PA10,
440                           STM_AFIO_MAPR_USART1_REMAP_MASK);
441 #else
442 #if SERIAL_1_PB6_PB7
443         ao_enable_port(&stm_gpiob);
444         stm_gpio_conf(&stm_gpiob, 6,
445                       STM_GPIO_CR_MODE_OUTPUT_2MHZ,
446                       STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);
447
448         stm_gpio_conf(&stm_gpiob, 7,
449                       STM_GPIO_CR_MODE_INPUT,
450                       STM_GPIO_CR_CNF_INPUT_FLOATING);
451
452         stm_set_afio_mapr(STM_AFIO_MAPR_USART1_REMAP,
453                           STM_AFIO_MAPR_USART1_REMAP_PB6_PB7,
454                           STM_AFIO_MAPR_USART1_REMAP_MASK);
455 #else
456 #error "No SERIAL_1 port configuration specified"
457 #endif
458 #endif
459         /* Enable USART */
460         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
461
462         ao_stm_usart1.reg = &stm_usart1;
463         ao_usart_init(&ao_stm_usart1, 0);
464
465         stm_nvic_set_enable(STM_ISR_USART1_POS);
466         stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY);
467 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
468         ao_add_stdio(_ao_serial1_pollchar,
469                      ao_serial1_putchar,
470                      NULL);
471 #endif
472 #endif
473
474 #if HAS_SERIAL_2
475         /*
476          *      TX      RX
477          *      PA2     PA3
478          *      PD5     PD6
479          */
480
481 #if SERIAL_2_PA2_PA3
482         ao_enable_port(&stm_gpioa);
483         stm_gpio_conf(&stm_gpioa, 2,
484                       STM_GPIO_CR_MODE_OUTPUT_2MHZ,
485                       STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);
486
487         stm_gpio_conf(&stm_gpioa, 3,
488                       STM_GPIO_CR_MODE_INPUT,
489                       STM_GPIO_CR_CNF_INPUT_FLOATING);
490
491 #ifndef USE_SERIAL_2_FLOW
492 #define USE_SERIAL_2_FLOW       0
493 #define USE_SERIAL_2_SW_FLOW    0
494 #endif
495
496 # if USE_SERIAL_2_FLOW
497 #  if USE_SERIAL_2_SW_FLOW
498         ao_serial_set_sw_rts_cts(&ao_stm_usart2,
499                                  ao_serial2_cts,
500                                  SERIAL_2_PORT_RTS,
501                                  SERIAL_2_PIN_RTS,
502                                  SERIAL_2_PORT_CTS,
503                                  SERIAL_2_PIN_CTS);
504 #  else
505         stm_gpio_conf(&stm_gpioa, 0,                    /* CTS */
506                       STM_GPIO_CR_MODE_INPUT,
507                       STM_GPIO_CR_CNF_INPUT_FLOATING);
508         stm_gpio_conf(&stm_gpioa, 1,                    /* RTS */
509                       STM_GPIO_CR_MODE_OUTPUT_2MHZ,
510                       STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);
511
512 #  endif
513 # endif
514         stm_set_afio_mapr(STM_AFIO_MAPR_USART2_REMAP,
515                           STM_AFIO_MAPR_USART2_REMAP_PA0_PA1_PA2_PA3_PA4,
516                           STM_AFIO_MAPR_USART2_REMAP_MASK);
517 #elif SERIAL_2_PD5_PD6
518         ao_enable_port(&stm_gpiod);
519         stm_gpio_conf(&stm_gpiod, 5,
520                       STM_GPIO_CR_MODE_OUTPUT_2MHZ,
521                       STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);
522
523         stm_gpio_conf(&stm_gpiod, 6,
524                       STM_GPIO_CR_MODE_INPUT,
525                       STM_GPIO_CR_CNF_INPUT_FLOATING);
526
527 # if USE_SERIAL_2_FLOW
528 #  if USE_SERIAL_2_SW_FLOW
529         ao_serial_set_sw_rts_cts(&ao_stm_usart2,
530                                  ao_serial2_cts,
531                                  SERIAL_2_PORT_RTS,
532                                  SERIAL_2_PIN_RTS,
533                                  SERIAL_2_PORT_CTS,
534                                  SERIAL_2_PIN_CTS);
535 #  else
536         stm_gpio_conf(&stm_gpiod, 3,                    /* CTS */
537                       STM_GPIO_CR_MODE_INPUT,
538                       STM_GPIO_CR_CNF_INPUT_FLOATING);
539         stm_gpio_conf(&stm_gpiod, 4,                    /* RTS */
540                       STM_GPIO_CR_MODE_OUTPUT_2MHZ,
541                       STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);
542
543 #  endif
544 # endif
545         stm_set_afio_mapr(STM_AFIO_MAPR_USART2_REMAP,
546                           STM_AFIO_MAPR_USART2_REMAP_PD3_PD4_PD5_PD6_PD7,
547                           STM_AFIO_MAPR_USART2_REMAP_MASK);
548 #else
549 #error "No SERIAL_2 port configuration specified"
550 #endif
551         /* Enable USART */
552         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
553
554         ao_stm_usart2.reg = &stm_usart2;
555         ao_usart_init(&ao_stm_usart2, USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW, SERIAL_2_SPEED);
556
557         stm_nvic_set_enable(STM_ISR_USART2_POS);
558         stm_nvic_set_priority(STM_ISR_USART2_POS, AO_STM_NVIC_MED_PRIORITY);
559 #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
560         ao_add_stdio(_ao_serial2_pollchar,
561                      ao_serial2_putchar,
562                      NULL);
563 #endif
564 #endif
565
566 #if HAS_SERIAL_3
567         /*
568          *      TX      RX
569          *      PB10    PB11
570          *      PC10    PC11
571          *      PD8     PD9
572          */
573 #if SERIAL_3_PB10_PB11
574         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
575
576         stm_afr_set(&stm_gpiob, 10, STM_AFR_AF7);
577         stm_afr_set(&stm_gpiob, 11, STM_AFR_AF7);
578 #else
579 #if SERIAL_3_PC10_PC11
580         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
581
582         stm_afr_set(&stm_gpioc, 10, STM_AFR_AF7);
583         stm_afr_set(&stm_gpioc, 11, STM_AFR_AF7);
584 #else
585 #if SERIAL_3_PD8_PD9
586         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
587
588         stm_afr_set(&stm_gpiod, 8, STM_AFR_AF7);
589         stm_afr_set(&stm_gpiod, 9, STM_AFR_AF7);
590 #else
591 #error "No SERIAL_3 port configuration specified"
592 #endif
593 #endif
594 #endif
595         /* Enable USART */
596         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN);
597
598         ao_stm_usart3.reg = &stm_usart3;
599         ao_usart_init(&ao_stm_usart3, 0);
600
601         stm_nvic_set_enable(STM_ISR_USART3_POS);
602         stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY);
603 #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN
604         ao_add_stdio(_ao_serial3_pollchar,
605                      ao_serial3_putchar,
606                      NULL);
607 #endif
608 #endif
609 }