dc446120e965272761970f3e0cabfd67075821cf
[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 __xdata struct ao_fifo  ao_usart1_rx_fifo;
21 __xdata struct ao_fifo  ao_usart1_tx_fifo;
22
23 void
24 ao_debug_out(char c)
25 {
26         if (c == '\n')
27                 ao_debug_out('\r');
28         while (!(STM_USART1->usart_sr & (1 << STM_USART_SR_TXE)));
29         STM_USART1->usart_dr = c;
30 }
31
32 #if 0
33 static __xdata uint8_t ao_serial_tx1_started;
34
35 static void
36 ao_serial_tx1_start(void)
37 {
38         if (!ao_fifo_empty(ao_usart1_tx_fifo) &&
39             !ao_serial_tx1_started)
40         {
41                 ao_serial_tx1_started = 1;
42                 ao_fifo_remove(ao_usart1_tx_fifo, STM_USART1->usart_dr);
43         }
44 }
45
46 void usart1_isr(void)
47 {
48         if (STM_USART1->usart_sr & (1 << STM_USART_SR_RXNE)) {
49                 if (!ao_fifo_full(ao_usart1_rx_fifo))
50                         ao_fifo_insert(ao_usart1_rx_fifo, STM_USART1->usart_dr);
51                 ao_wakeup(&ao_usart1_rx_fifo);
52 #if USE_SERIAL_STDIN
53                 ao_wakeup(&ao_stdin_ready);
54 #endif
55         }
56         if (STM_USART1->usart_sr & (1 << STM_USART_SR_TXE)) {
57                 ao_serial_tx1_started = 0;
58                 ao_serial_tx1_start();
59                 ao_wakeup(&ao_usart1_tx_fifo);
60         }
61 }
62
63 char
64 ao_serial_getchar(void) __critical
65 {
66         char    c;
67         cli();
68         while (ao_fifo_empty(ao_usart1_rx_fifo))
69                 ao_sleep(&ao_usart1_rx_fifo);
70         ao_fifo_remove(ao_usart1_rx_fifo, c);
71         sei();
72         return c;
73 }
74
75 #if USE_SERIAL_STDIN
76 char
77 ao_serial_pollchar(void) __critical
78 {
79         char    c;
80         cli();
81         if (ao_fifo_empty(ao_usart1_rx_fifo)) {
82                 sei();
83                 return AO_READ_AGAIN;
84         }
85         ao_fifo_remove(ao_usart1_rx_fifo,c);
86         sei();
87         return c;
88 }
89 #endif
90
91 void
92 ao_serial_putchar(char c) __critical
93 {
94         cli();
95         while (ao_fifo_full(ao_usart1_tx_fifo))
96                 ao_sleep(&ao_usart1_tx_fifo);
97         ao_fifo_insert(ao_usart1_tx_fifo, c);
98         ao_serial_tx1_start();
99         sei();
100 }
101
102 void
103 ao_serial_drain(void) __critical
104 {
105         cli();
106         while (!ao_fifo_empty(ao_usart1_tx_fifo))
107                 ao_sleep(&ao_usart1_tx_fifo);
108         sei();
109 }
110
111 #endif
112
113 int _write(int file, char *ptr, int len)
114 {
115         int l = len;
116         while (l--)
117                 ao_debug_out(*ptr++);
118         return len;
119 }
120
121 #define F_CPU   24000000
122
123 static const struct {
124         uint32_t usart_brr;
125 } ao_serial_speeds[] = {
126         [AO_SERIAL_SPEED_4800] = {
127                 (F_CPU * 16) / (16 * 4800) 
128         },
129         [AO_SERIAL_SPEED_9600] = {
130                 (F_CPU * 16) / (16 * 9600) 
131         },
132         [AO_SERIAL_SPEED_19200] = {
133                 (F_CPU * 16) / (16 * 19200) 
134         },
135         [AO_SERIAL_SPEED_57600] = {
136                 (F_CPU * 16) / (16 * 57600) 
137         },
138 };
139
140 void
141 ao_serial_set_speed(uint8_t speed)
142 {
143 #if 0
144         ao_serial_drain();
145 #endif
146         if (speed > AO_SERIAL_SPEED_57600)
147                 return;
148         STM_USART1->usart_brr = ao_serial_speeds[speed].usart_brr;
149 }
150
151 void
152 ao_serial_init(void)
153 {
154         STM_USART1->usart_cr1 = ((0 << STM_USART_CR1_OVER8) |
155                              (1 << STM_USART_CR1_UE) |
156                              (0 << STM_USART_CR1_M) |
157                              (0 << STM_USART_CR1_WAKE) |
158                              (0 << STM_USART_CR1_PCE) |
159                              (0 << STM_USART_CR1_PS) |
160                              (0 << STM_USART_CR1_PEIE) |
161                              (0 << STM_USART_CR1_TXEIE) |       /* XXX enable */
162                              (0 << STM_USART_CR1_TCIE) |
163                              (0 << STM_USART_CR1_RXNEIE) |              /* XXX enable */
164                              (0 << STM_USART_CR1_IDLEIE) |
165                              (1 << STM_USART_CR1_TE) |
166                              (1 << STM_USART_CR1_RE) |
167                              (0 << STM_USART_CR1_RWU) |
168                              (0 << STM_USART_CR1_SBK));
169
170         STM_USART1->usart_cr2 = 0;
171         STM_USART1->usart_cr3 = 0;
172
173         /* Pick a 9600 baud rate */
174         ao_serial_set_speed(AO_SERIAL_SPEED_9600);
175
176         printf ("serial initialized\n");
177 #if 0
178 #if USE_SERIAL_STDIN
179         ao_add_stdio(ao_serial_pollchar,
180                      ao_serial_putchar,
181                      NULL);
182 #endif
183 #endif
184 }