38f16e5eb96d8042d17dc02b8e475fdbf4cd67e3
[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.sr & (1 << STM_USART_SR_TXE)));
29         stm_usart1.dr = c;
30 }
31
32 void
33 outbyte(char c)
34 {
35         putchar(c);
36 }
37
38 static __xdata uint8_t ao_serial_tx1_started;
39
40 static void
41 ao_serial_tx1_start(void)
42 {
43         if (!ao_fifo_empty(ao_usart1_tx_fifo) &&
44             !ao_serial_tx1_started)
45         {
46                 ao_serial_tx1_started = 1;
47                 ao_fifo_remove(ao_usart1_tx_fifo, stm_usart1.dr);
48         }
49 }
50
51 void stm_usart1_isr(void)
52 {
53         uint32_t        sr;
54
55         sr = stm_usart1.sr;
56         stm_usart1.sr = 0;
57
58         if (sr & (1 << STM_USART_SR_RXNE)) {
59                 char c = stm_usart1.dr;
60                 if (!ao_fifo_full(ao_usart1_rx_fifo))
61                         ao_fifo_insert(ao_usart1_rx_fifo, c);
62                 ao_wakeup(&ao_usart1_rx_fifo);
63 #if USE_SERIAL_STDIN
64                 ao_wakeup(&ao_stdin_ready);
65 #endif
66         }
67         if (sr & (1 << STM_USART_SR_TC)) {
68                 ao_serial_tx1_started = 0;
69                 ao_serial_tx1_start();
70                 ao_wakeup(&ao_usart1_tx_fifo);
71         }
72 }
73
74 char
75 ao_serial_getchar(void) __critical
76 {
77         char    c;
78         cli();
79         while (ao_fifo_empty(ao_usart1_rx_fifo))
80                 ao_sleep(&ao_usart1_rx_fifo);
81         ao_fifo_remove(ao_usart1_rx_fifo, c);
82         sei();
83         return c;
84 }
85
86 #if USE_SERIAL_STDIN
87 char
88 ao_serial_pollchar(void) __critical
89 {
90         char    c;
91         cli();
92         if (ao_fifo_empty(ao_usart1_rx_fifo)) {
93                 sei();
94                 return AO_READ_AGAIN;
95         }
96         ao_fifo_remove(ao_usart1_rx_fifo,c);
97         sei();
98         return c;
99 }
100 #endif
101
102 void
103 ao_serial_putchar(char c) __critical
104 {
105         cli();
106         while (ao_fifo_full(ao_usart1_tx_fifo))
107                 ao_sleep(&ao_usart1_tx_fifo);
108         ao_fifo_insert(ao_usart1_tx_fifo, c);
109         ao_serial_tx1_start();
110         sei();
111 }
112
113 void
114 ao_serial_drain(void) __critical
115 {
116         cli();
117         while (!ao_fifo_empty(ao_usart1_tx_fifo))
118                 ao_sleep(&ao_usart1_tx_fifo);
119         sei();
120 }
121
122 int _write(int file, char *ptr, int len)
123 {
124         int l = len;
125         while (l--)
126                 ao_debug_out(*ptr++);
127         return len;
128 }
129
130 static const struct {
131         uint32_t brr;
132 } ao_serial_speeds[] = {
133         [AO_SERIAL_SPEED_4800] = {
134                 STM_APB1 / 4800
135         },
136         [AO_SERIAL_SPEED_9600] = {
137                 STM_APB1 / 9600
138         },
139         [AO_SERIAL_SPEED_19200] = {
140                 STM_APB1 / 19200
141         },
142         [AO_SERIAL_SPEED_57600] = {
143                 STM_APB1 / 57600
144         },
145 };
146
147 void
148 ao_serial_set_speed(uint8_t speed)
149 {
150 #if 0
151         ao_serial_drain();
152 #endif
153         if (speed > AO_SERIAL_SPEED_57600)
154                 return;
155         stm_usart1.brr = ao_serial_speeds[speed].brr;
156 }
157
158 void
159 ao_serial_init(void)
160 {
161         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
162
163         stm_moder_set(&stm_gpioa, 9, STM_MODER_ALTERNATE);
164         stm_moder_set(&stm_gpioa, 10, STM_MODER_ALTERNATE);
165         stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
166         stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
167         
168         /* Enable USART1 */
169         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
170
171         stm_usart1.cr1 = ((0 << STM_USART_CR1_OVER8) |
172                           (1 << STM_USART_CR1_UE) |
173                           (0 << STM_USART_CR1_M) |
174                           (0 << STM_USART_CR1_WAKE) |
175                           (0 << STM_USART_CR1_PCE) |
176                           (0 << STM_USART_CR1_PS) |
177                           (0 << STM_USART_CR1_PEIE) |
178                           (0 << STM_USART_CR1_TXEIE) |
179                           (1 << STM_USART_CR1_TCIE) |
180                           (1 << STM_USART_CR1_RXNEIE) |
181                           (0 << STM_USART_CR1_IDLEIE) |
182                           (1 << STM_USART_CR1_TE) |
183                           (1 << STM_USART_CR1_RE) |
184                           (0 << STM_USART_CR1_RWU) |
185                           (0 << STM_USART_CR1_SBK));
186
187         stm_usart1.cr2 = ((0 << STM_USART_CR2_LINEN) |
188                           (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
189                           (0 << STM_USART_CR2_CLKEN) |
190                           (0 << STM_USART_CR2_CPOL) |
191                           (0 << STM_USART_CR2_CPHA) |
192                           (0 << STM_USART_CR2_LBCL) |
193                           (0 << STM_USART_CR2_LBDIE) |
194                           (0 << STM_USART_CR2_LBDL) |
195                           (0 << STM_USART_CR2_ADD));
196
197         stm_usart1.cr3 = ((0 << STM_USART_CR3_ONEBITE) |
198                           (0 << STM_USART_CR3_CTSIE) |
199                           (0 << STM_USART_CR3_CTSE) |
200                           (0 << STM_USART_CR3_RTSE) |
201                           (0 << STM_USART_CR3_DMAT) |
202                           (0 << STM_USART_CR3_DMAR) |
203                           (0 << STM_USART_CR3_SCEN) |
204                           (0 << STM_USART_CR3_NACK) |
205                           (0 << STM_USART_CR3_HDSEL) |
206                           (0 << STM_USART_CR3_IRLP) |
207                           (0 << STM_USART_CR3_IREN) |
208                           (0 << STM_USART_CR3_EIE));
209
210         /* Pick a 9600 baud rate */
211         ao_serial_set_speed(AO_SERIAL_SPEED_9600);
212
213         printf ("serial initialized\n");
214 #if USE_SERIAL_STDIN
215         ao_add_stdio(ao_serial_pollchar,
216                      ao_serial_putchar,
217                      NULL);
218 #endif
219
220         stm_nvic_set_enable(STM_ISR_USART1_POS);
221         stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
222 }