215a301d0f32e25ef3163894a54b9253423cb1f3
[fw/altos] / ao_serial.c
1 /*
2  * Copyright © 2009 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 #define SERIAL_FIFO     32
21
22 struct ao_fifo {
23         uint8_t insert;
24         uint8_t remove;
25         uint8_t fifo[SERIAL_FIFO];
26 };
27
28 volatile __xdata struct ao_fifo ao_usart1_rx_fifo;
29 volatile __xdata struct ao_fifo ao_usart1_tx_fifo;
30
31 #define ao_fifo_insert(f,c) do { \
32         (f).fifo[(f).insert] = (c); \
33         (f).insert = ((f).insert + 1) & (SERIAL_FIFO-1); \
34 } while(0)
35
36 #define ao_fifo_remove(f,c) do {\
37         c = (f).fifo[(f).remove]; \
38         (f).remove = ((f).remove + 1) & (SERIAL_FIFO-1); \
39 } while(0)
40
41 #define ao_fifo_full(f) ((((f).insert + 1) & (SERIAL_FIFO-1)) == (f).remove)
42 #define ao_fifo_empty(f)        ((f).insert == (f).remove)
43
44 void
45 ao_serial_rx1_isr(void) interrupt 3
46 {
47         if (!ao_fifo_full(ao_usart1_rx_fifo))
48                 ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF);
49         ao_wakeup(&ao_usart1_rx_fifo);
50 }
51
52 static __xdata uint8_t ao_serial_tx1_started;
53
54 static void
55 ao_serial_tx1_start(void)
56 {
57         if (!ao_fifo_empty(ao_usart1_tx_fifo) &&
58             !ao_serial_tx1_started)
59         {
60                 ao_serial_tx1_started = 1;
61                 ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF);
62         }
63 }
64
65 void
66 ao_serial_tx1_isr(void) interrupt 14
67 {
68         UTX1IF = 0;
69         ao_serial_tx1_started = 0;
70         ao_serial_tx1_start();
71         ao_wakeup(&ao_usart1_tx_fifo);
72 }
73
74 uint8_t
75 ao_serial_getchar(void) __critical
76 {
77         uint8_t c;
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         return c;
82 }
83
84 void
85 ao_serial_putchar(uint8_t c) __critical
86 {
87         while (ao_fifo_full(ao_usart1_tx_fifo))
88                 ao_sleep(&ao_usart1_tx_fifo);
89         ao_fifo_insert(ao_usart1_tx_fifo, c);
90         ao_serial_tx1_start();
91 }
92
93 void
94 ao_serial_init(void)
95 {
96         /* Set up the USART pin assignment */
97         PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
98
99         /* ee has already set the P2SEL bits */
100
101         /* Make the USART pins be controlled by the USART */
102         P1SEL |= (1 << 6) | (1 << 7);
103
104         /* UART mode with receiver enabled */
105         U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
106
107         /* Pick a 4800 baud rate */
108         U1BAUD = 163;                           /* 4800 */
109         U1GCR = 7 << UxGCR_BAUD_E_SHIFT;        /* 4800 */
110
111         /* Reasonable serial parameters */
112         U1UCR = (UxUCR_FLUSH |
113                  UxUCR_FLOW_DISABLE |
114                  UxUCR_D9_ODD_PARITY |
115                  UxUCR_BIT9_8_BITS |
116                  UxUCR_PARITY_DISABLE |
117                  UxUCR_SPB_1_STOP_BIT |
118                  UxUCR_STOP_HIGH |
119                  UxUCR_START_LOW);
120
121         IEN0 |= IEN0_URX1IE;
122         IEN2 |= IEN2_UTX1IE;
123 }