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