altos: Use TXE instead of TC for serial on STM32l
[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
20 void
21 ao_debug_out(char c)
22 {
23         if (c == '\n')
24                 ao_debug_out('\r');
25         while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE)));
26         stm_usart1.dr = c;
27 }
28
29 static int
30 _ao_usart_tx_start(struct ao_stm_usart *usart)
31 {
32         if (!ao_fifo_empty(usart->tx_fifo) && !usart->tx_started)
33         {
34                 usart->tx_started = 1;
35                 usart->tx_running = 1;
36                 usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE);
37                 ao_fifo_remove(usart->tx_fifo, usart->reg->dr);
38                 ao_wakeup(&usart->tx_fifo);
39                 return 1;
40         }
41         return 0;
42 }
43
44 static void
45 ao_usart_isr(struct ao_stm_usart *usart, int stdin)
46 {
47         uint32_t        sr;
48
49         sr = usart->reg->sr;
50         usart->reg->sr = 0;
51
52         if (sr & (1 << STM_USART_SR_RXNE)) {
53                 char c = usart->reg->dr;
54                 if (!ao_fifo_full(usart->rx_fifo))
55                         ao_fifo_insert(usart->rx_fifo, c);
56                 ao_wakeup(&usart->rx_fifo);
57                 if (stdin)
58                         ao_wakeup(&ao_stdin_ready);
59         }
60         if (sr & (1 << STM_USART_SR_TXE)) {
61                 usart->tx_started = 0;
62                 if (!_ao_usart_tx_start(usart))
63                         usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE);
64         }
65         if (sr & (1 << STM_USART_SR_TC)) {
66                 usart->tx_running = 0;
67                 usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE);
68                 if (usart->draining) {
69                         usart->draining = 0;
70                         ao_wakeup(&usart->tx_fifo);
71                 }
72         }
73 }
74
75 int
76 _ao_usart_pollchar(struct ao_stm_usart *usart)
77 {
78         int     c;
79
80         if (ao_fifo_empty(usart->rx_fifo))
81                 c = AO_READ_AGAIN;
82         else {
83                 uint8_t u;
84                 ao_fifo_remove(usart->rx_fifo,u);
85                 c = u;
86                 ao_usb_putchar(c); ao_usb_flush();
87         }
88         return c;
89 }
90
91 char
92 ao_usart_getchar(struct ao_stm_usart *usart)
93 {
94         int c;
95         ao_arch_block_interrupts();
96         while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN)
97                 ao_sleep(&usart->rx_fifo);
98         ao_arch_release_interrupts();
99         ao_usb_putchar(c); ao_usb_flush();
100         return (char) c;
101 }
102
103 static inline uint8_t
104 _ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout)
105 {
106         return ao_sleep_for(&usart->rx_fifo, timeout);
107 }
108
109 void
110 ao_usart_putchar(struct ao_stm_usart *usart, char c)
111 {
112         ao_usb_putchar(c); ao_usb_flush();
113         ao_arch_block_interrupts();
114         while (ao_fifo_full(usart->tx_fifo))
115                 ao_sleep(&usart->tx_fifo);
116         ao_fifo_insert(usart->tx_fifo, c);
117         _ao_usart_tx_start(usart);
118         ao_arch_release_interrupts();
119 }
120
121 static void
122 ao_usart_drain(struct ao_stm_usart *usart)
123 {
124         ao_arch_block_interrupts();
125         while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) {
126                 usart->draining = 1;
127                 ao_sleep(&usart->tx_fifo);
128         }
129         ao_arch_release_interrupts();
130 }
131
132 static const struct {
133         uint32_t brr;
134 } ao_usart_speeds[] = {
135         [AO_SERIAL_SPEED_4800] = {
136                 AO_PCLK1 / 4800
137         },
138         [AO_SERIAL_SPEED_9600] = {
139                 AO_PCLK1 / 9600
140         },
141         [AO_SERIAL_SPEED_19200] = {
142                 AO_PCLK1 / 19200
143         },
144         [AO_SERIAL_SPEED_57600] = {
145                 AO_PCLK1 / 57600
146         },
147         [AO_SERIAL_SPEED_115200] = {
148                 AO_PCLK1 / 115200
149         },
150 };
151
152 void
153 ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)
154 {
155         if (speed > AO_SERIAL_SPEED_115200)
156                 return;
157         usart->reg->brr = ao_usart_speeds[speed].brr;
158 }
159
160 void
161 ao_usart_init(struct ao_stm_usart *usart)
162 {
163         usart->reg->cr1 = ((0 << STM_USART_CR1_OVER8) |
164                           (1 << STM_USART_CR1_UE) |
165                           (0 << STM_USART_CR1_M) |
166                           (0 << STM_USART_CR1_WAKE) |
167                           (0 << STM_USART_CR1_PCE) |
168                           (0 << STM_USART_CR1_PS) |
169                           (0 << STM_USART_CR1_PEIE) |
170                           (0 << STM_USART_CR1_TXEIE) |
171                           (0 << STM_USART_CR1_TCIE) |
172                           (1 << STM_USART_CR1_RXNEIE) |
173                           (0 << STM_USART_CR1_IDLEIE) |
174                           (1 << STM_USART_CR1_TE) |
175                           (1 << STM_USART_CR1_RE) |
176                           (0 << STM_USART_CR1_RWU) |
177                           (0 << STM_USART_CR1_SBK));
178
179         usart->reg->cr2 = ((0 << STM_USART_CR2_LINEN) |
180                           (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
181                           (0 << STM_USART_CR2_CLKEN) |
182                           (0 << STM_USART_CR2_CPOL) |
183                           (0 << STM_USART_CR2_CPHA) |
184                           (0 << STM_USART_CR2_LBCL) |
185                           (0 << STM_USART_CR2_LBDIE) |
186                           (0 << STM_USART_CR2_LBDL) |
187                           (0 << STM_USART_CR2_ADD));
188
189         usart->reg->cr3 = ((0 << STM_USART_CR3_ONEBITE) |
190                           (0 << STM_USART_CR3_CTSIE) |
191                           (0 << STM_USART_CR3_CTSE) |
192                           (0 << STM_USART_CR3_RTSE) |
193                           (0 << STM_USART_CR3_DMAT) |
194                           (0 << STM_USART_CR3_DMAR) |
195                           (0 << STM_USART_CR3_SCEN) |
196                           (0 << STM_USART_CR3_NACK) |
197                           (0 << STM_USART_CR3_HDSEL) |
198                           (0 << STM_USART_CR3_IRLP) |
199                           (0 << STM_USART_CR3_IREN) |
200                           (0 << STM_USART_CR3_EIE));
201
202         /* Pick a 9600 baud rate */
203         ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);
204 }
205
206 void
207 ao_usart_set_flow(struct ao_stm_usart *usart)
208 {
209         usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) |
210                             (1 << STM_USART_CR3_RTSE));
211 }
212
213 #if HAS_SERIAL_1
214
215 struct ao_stm_usart ao_stm_usart1;
216
217 void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
218
219 char
220 ao_serial1_getchar(void)
221 {
222         return ao_usart_getchar(&ao_stm_usart1);
223 }
224
225 void
226 ao_serial1_putchar(char c)
227 {
228         ao_usart_putchar(&ao_stm_usart1, c);
229 }
230
231 int
232 _ao_serial1_pollchar(void)
233 {
234         return _ao_usart_pollchar(&ao_stm_usart1);
235 }
236
237 uint8_t
238 _ao_serial1_sleep_for(uint16_t timeout)
239 {
240         return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
241 }
242
243 void
244 ao_serial1_drain(void)
245 {
246         ao_usart_drain(&ao_stm_usart1);
247 }
248
249 void
250 ao_serial1_set_speed(uint8_t speed)
251 {
252         ao_usart_drain(&ao_stm_usart1);
253         ao_usart_set_speed(&ao_stm_usart1, speed);
254 }
255 #endif  /* HAS_SERIAL_1 */
256
257 #if HAS_SERIAL_2
258
259 struct ao_stm_usart ao_stm_usart2;
260
261 void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
262
263 char
264 ao_serial2_getchar(void)
265 {
266         return ao_usart_getchar(&ao_stm_usart2);
267 }
268
269 void
270 ao_serial2_putchar(char c)
271 {
272         ao_usart_putchar(&ao_stm_usart2, c);
273 }
274
275 int
276 _ao_serial2_pollchar(void)
277 {
278         return _ao_usart_pollchar(&ao_stm_usart2);
279 }
280
281 uint8_t
282 _ao_serial2_sleep_for(uint16_t timeout)
283 {
284         return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
285 }
286
287 void
288 ao_serial2_drain(void)
289 {
290         ao_usart_drain(&ao_stm_usart2);
291 }
292
293 void
294 ao_serial2_set_speed(uint8_t speed)
295 {
296         ao_usart_drain(&ao_stm_usart2);
297         ao_usart_set_speed(&ao_stm_usart2, speed);
298 }
299 #endif  /* HAS_SERIAL_2 */
300
301 #if HAS_SERIAL_3
302
303 struct ao_stm_usart ao_stm_usart3;
304
305 void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_2_STDIN); }
306
307 char
308 ao_serial3_getchar(void)
309 {
310         return ao_usart_getchar(&ao_stm_usart3);
311 }
312
313 void
314 ao_serial3_putchar(char c)
315 {
316         ao_usart_putchar(&ao_stm_usart3, c);
317 }
318
319 int
320 _ao_serial3_pollchar(void)
321 {
322         return _ao_usart_pollchar(&ao_stm_usart3);
323 }
324
325 uint8_t
326 _ao_serial3_sleep_for(uint16_t timeout)
327 {
328         return _ao_usart_sleep_for(&ao_stm_usart3, timeout);
329 }
330
331 void
332 ao_serial3_set_speed(uint8_t speed)
333 {
334         ao_usart_drain(&ao_stm_usart3);
335         ao_usart_set_speed(&ao_stm_usart3, speed);
336 }
337
338 void
339 ao_serial3_drain(void)
340 {
341         ao_usart_drain(&ao_stm_usart3);
342 }
343 #endif  /* HAS_SERIAL_3 */
344
345 void
346 ao_serial_init(void)
347 {
348 #if HAS_SERIAL_1
349         /*
350          *      TX      RX
351          *      PA9     PA10
352          *      PB6     PB7     *
353          */
354
355 #if SERIAL_1_PA9_PA10
356         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
357
358         stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
359         stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
360 #else
361 #if SERIAL_1_PB6_PB7
362         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
363
364         stm_afr_set(&stm_gpiob, 6, STM_AFR_AF7);
365         stm_afr_set(&stm_gpiob, 7, STM_AFR_AF7);
366 #else
367 #error "No SERIAL_1 port configuration specified"
368 #endif
369 #endif
370         /* Enable USART */
371         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
372
373         ao_stm_usart1.reg = &stm_usart1;
374         ao_usart_init(&ao_stm_usart1);
375
376         stm_nvic_set_enable(STM_ISR_USART1_POS);
377         stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
378 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
379         ao_add_stdio(_ao_serial1_pollchar,
380                      ao_serial1_putchar,
381                      NULL);
382 #endif
383 #endif
384
385 #if HAS_SERIAL_2
386         /*
387          *      TX      RX
388          *      PA2     PA3
389          *      PD5     PD6
390          */
391
392 #if SERIAL_2_PA2_PA3
393         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
394
395         stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7);
396         stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7);
397 #if USE_SERIAL_2_FLOW
398         stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7);
399         stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7);
400 #endif
401 #else
402 #if SERIAL_2_PD5_PD6
403         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
404
405         stm_afr_set(&stm_gpiod, 5, STM_AFR_AF7);
406         stm_afr_set(&stm_gpiod, 6, STM_AFR_AF7);
407 #if USE_SERIAL_2_FLOW
408 #error "Don't know how to set flowcontrol for serial 2 on PD"
409 #endif
410 #else
411 #error "No SERIAL_2 port configuration specified"
412 #endif
413 #endif
414         /* Enable USART */
415         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
416
417         ao_stm_usart2.reg = &stm_usart2;
418         ao_usart_init(&ao_stm_usart2);
419 #if USE_SERIAL_2_FLOW
420         ao_usart_set_flow(&ao_stm_usart2);
421 #endif
422
423         stm_nvic_set_enable(STM_ISR_USART2_POS);
424         stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
425 #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
426         ao_add_stdio(_ao_serial2_pollchar,
427                      ao_serial2_putchar,
428                      NULL);
429 #endif
430 #endif
431
432 #if HAS_SERIAL_3
433         /*
434          *      TX      RX
435          *      PB10    PB11
436          *      PC10    PC11
437          *      PD8     PD9
438          */
439 #if SERIAL_3_PB10_PB11
440         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
441
442         stm_afr_set(&stm_gpiob, 10, STM_AFR_AF7);
443         stm_afr_set(&stm_gpiob, 11, STM_AFR_AF7);
444 #else
445 #if SERIAL_3_PC10_PC11
446         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
447
448         stm_afr_set(&stm_gpioc, 10, STM_AFR_AF7);
449         stm_afr_set(&stm_gpioc, 11, STM_AFR_AF7);
450 #else
451 #if SERIAL_3_PD8_PD9
452         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
453
454         stm_afr_set(&stm_gpiod, 8, STM_AFR_AF7);
455         stm_afr_set(&stm_gpiod, 9, STM_AFR_AF7);
456 #else
457 #error "No SERIAL_3 port configuration specified"
458 #endif
459 #endif
460 #endif
461         /* Enable USART */
462         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN);
463
464         ao_stm_usart3.reg = &stm_usart3;
465         ao_usart_init(&ao_stm_usart3);
466
467         stm_nvic_set_enable(STM_ISR_USART3_POS);
468         stm_nvic_set_priority(STM_ISR_USART3_POS, 4);
469 #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN
470         ao_add_stdio(_ao_serial3_pollchar,
471                      ao_serial3_putchar,
472                      NULL);
473 #endif
474 #endif
475 }