9a9885d4d452ece834480acc94aa79510be854e6
[goodfet] / firmware / lib / msp430_serial.c
1 /* Name: serial_io.c
2  * Tabsize: 8
3  * Copyright: (c) 2011 by Peter@Lorenzen.us
4  * License: [BSD]eerware 
5  * serput{c,s} sergetc functionality as on UNIX
6  */
7
8 #include "platform.h"
9 #include <signal.h>
10 #include <io.h>
11 #include <iomacros.h>
12 #include "msp430_serial.h"
13
14 #if (DEBUG_LEVEL > 0)
15 #ifdef DEBUG_START
16 char dlevel = DEBUG_START;
17 #else
18 char dlevel = DEBUG_LEVEL;
19 #endif
20 #ifdef  INBAND_DEBUG
21 #include "command.h"
22 #endif
23 #endif
24
25 fifo_t fiforx0, fifotx0;
26 fifo_t fiforx1, fifotx1;
27 fifo_t *rxfp0;                  // NULL not in use
28 fifo_t *txfp0;                  // NULL not in use
29 fifo_t *rxfp1;                  // NULL not in use
30 fifo_t *txfp1;                  // NULL not in use
31
32 void fifo_init(fifo_t * fp)
33 {
34         fp->i = 0;
35         fp->o = 0;
36         fp->count = 0;
37         fp->empty = 1;
38 }
39
40 static void fifo_advance(uint8_t * ptr)
41 {
42         if (*ptr == (FIFO_SZ - 1)) {
43                 *ptr = 0;
44         } else {
45                 (*ptr)++;
46         }
47 }
48
49 static void fifo_wr(fifo_t * fp, char c)
50 {
51         fp->b[fp->i] = c;
52         _DINT();                // only need to disable tx irq for this stream
53         fifo_advance(&fp->i);
54         fp->count++;
55         _EINT();
56 }
57
58 static uint8_t fifo_rd(fifo_t * fp)     // only called if count>0
59 {
60         uint8_t c = fp->b[fp->o];
61         _DINT();                // only need to disable tx irq for this stream
62         fifo_advance(&fp->o);
63         fp->count--;
64         _EINT();
65         return c;
66 }
67
68 //http://mspgcc.sourceforge.net/baudrate.html
69 /** TI lauchpad and  EZ430/FETUIF with 12MHz crystal */
70 #if (platform == tilaunchpad)
71 uint8_t bauds[6][3] = {
72         {0x68, 0x00, 0x04}      // 0 - 12000000Hz 115273bps
73         , {0xE2, 0x04, 0x00}    // 1 - 12000000Hz 9600bps
74         , {0x71, 0x02, 0x00}    // 2 - 12000000Hz 19200bps
75         , {0x38, 0x01, 0x55}    // 3 - 12000000Hz 38400bps
76         , {0xD0, 0x00, 0x4A}    // 4 - 12000000Hz 57581bps
77         , {0x68, 0x00, 0x04}    // 5 - 12000000Hz 115273bps
78 };
79 #else
80 uint8_t bauds[6][3] = {
81         {0x20, 0x00, 0x00}      // 0 - 3683400Hz 115106bps
82         , {0x7F, 0x01, 0x5B}    // 1 - 3683400Hz 9599bps
83         , {0xBF, 0x00, 0xF7}    // 2 - 3683400Hz 19194bps
84         , {0x5F, 0x00, 0xBF}    // 3 - 3683400Hz 38408bps
85         , {0x40, 0x00, 0x00}    // 4 - 3683400Hz 57553bps
86         , {0x20, 0x00, 0x00}    // 5 - 3683400Hz 115106bps
87 };
88 #endif
89
90 void setbaud0(uint8_t rate)
91 {
92         UBR00 = bauds[rate][0];
93         UBR10 = bauds[rate][1];
94         UMCTL0 = bauds[rate][2];
95 }
96
97 void setbaud1(uint8_t rate)
98 {
99         UBR01 = bauds[rate][0];
100         UBR11 = bauds[rate][1];
101         UMCTL1 = bauds[rate][2];
102 }
103
104 // we assume rx and tx is always supplied, so no check
105 void ser0_init(int baud, fifo_t * rx, fifo_t * tx)
106 {
107         rxfp0 = rx;
108         txfp0 = tx;
109         P3DIR &= ~BIT5;         // Select P35 for input (UART0RX)
110         P3SEL |= BIT4 | BIT5;   // P3.4,5 = USART0 TXD/RXD
111         P3DIR |= BIT4;
112
113         UCTL0 = SWRST | CHAR;   /* 8-bit character, UART mode */
114         ME1 &= ~USPIE0;         // USART1 SPI module disable
115         UTCTL0 = SSEL1;         /* UCLK = MCLK */
116
117         setbaud0(baud);
118
119         ME1 &= ~USPIE0;         /* USART1 SPI module disable */
120         ME1 |= (UTXE0 | URXE0); /* Enable USART1 TXD/RXD */
121
122         UCTL0 &= ~SWRST;
123
124         //U0TCTL |= URXSE;      // XXX Clear pending interrupts before enable!!!
125         fifo_init(rx);
126         fifo_init(tx);
127
128         IE1 |= UTXIE0;          // Enable USART0 TX interrupt
129         IE1 |= URXIE0;          // Enable USART0 RX interrupt
130
131         P1DIR |= DSR | CTS;
132         P1OUT &= ~(DSR | CTS);  // We are On and we are ready
133 }
134
135 // we can use uart1 tx for debug messages, using rx bit for something else
136 // or we can use full uart1 for pass through
137 // or not uart1 functions at all,
138 void ser1_init(int baud, fifo_t * rx, fifo_t * tx)
139 {
140         rxfp1 = rx;
141         txfp1 = tx;
142         if (rx) {               // RX enabled
143                 P3SEL |= BIT7;  // Select P37 for UART1 RX function
144                 P3DIR &= ~BIT7; // P37 is input
145         } else {
146                 P3SEL &= ~BIT7; // No UART1 RX, can be used as a bit port
147         }
148         if (tx) {               // TX enabled
149                 P3SEL |= BIT6;  // Select P36 for UART1 TX function
150                 P3DIR |= BIT6;  // P36 is output UART1 TX
151         } else {
152                 P3SEL &= ~BIT6; // No UART1 TX, can be used as a bit port
153         }
154         UCTL1 = SWRST | CHAR;   // 8-bit character, UART mode  stop UART state machine
155         if (rx || tx) {         // RX or TX enabled
156                 ME2 &= ~USPIE1; // USART1 SPI module disable
157         }
158         UTCTL1 = SSEL1;         // UCLK = MCLK
159
160         //U1TCTL |= URXSE;      // XXX Clear pending interrupts before enable!!!
161         if (rx) {               // RX enabled
162                 ME2 |= URXE1;   // Enable USART1 RX
163                 fifo_init(rx);
164         }
165         if (tx) {               // TX enabled
166                 ME2 |= UTXE1;   // Enable USART1 TXD
167                 fifo_init(tx);
168         }
169
170         setbaud1(baud);         // we set it even when disabling uart1 - who cares
171
172         UCTL1 &= ~SWRST;        // enable UART state machine
173         if (tx) {               // TX enabled
174                 IE2 |= UTXIE1;  // Enable USART1 TX interrupt
175         } else {
176                 IE2 &= ~UTXIE1; // Disable USART1 TX interrupt
177         }
178         if (rx) {               // RX enabled
179                 IE2 |= URXIE1;  // Enable USART1 RX interrupt
180         } else {
181                 IE2 &= ~URXIE1; // Disable USART1 TX interrupt
182         }
183 }
184
185
186 int seravailable(fifo_t * fp)
187 {
188         return fp->count;
189 }
190
191 void serflush(fifo_t * fp)
192 {
193         while (seravailable(fp) > 0) {
194                 delay_ms(1);
195         }
196 }
197
198 int sergetc(fifo_t * fp)
199 {
200         int c;
201         if (fp == NULL)
202                 return -1;
203         if (fp->count) {
204                 c = fifo_rd(fp);
205         } else {
206                 fp->empty = TRUE;
207                 c = -1;
208         }
209         return c;
210 }
211
212 void serclear(fifo_t *fp)
213 {
214         while (seravailable(fp) > 0) {
215                 sergetc(fp);
216         }
217 }
218
219 #ifdef  INBAND_DEBUG
220 // send debug messages over USB-serial link encapsulated in the goodfet protocol
221 void dputc(char c)
222 {
223         char two[2];
224         two[0]=c;
225         two[1]=0;
226         debugstr(two);
227 }
228
229 void dputs(char *str)
230 {
231         debugstr(str);
232 }
233 void dputb(char c)
234 {
235         debugbytes(&c,1);
236 }
237
238 void dputw(int w)
239 {
240         debugbytes((char *)&w,2);
241 }
242 #else
243 // defines in msp430_serial.h resolves to the functions below on txfp1
244 #endif
245
246 void serputc(char c, fifo_t * fp)
247 {
248         if (fp == NULL)
249                 return;
250         while (seravailable(fp) == FIFO_SZ) {
251         }
252         fifo_wr(fp, c);         // magic is in count-- indivisible, do not optimize
253         if (fp->empty && fp->count) {   // buffer had been empty
254                 fp->empty = FALSE;
255                 c = fifo_rd(fp);
256                 if (fp == txfp0) {
257                         TXBUF0 = c;
258                 } else {
259                         TXBUF1 = c;
260                 }
261         }
262 }
263
264 void serputs(char *cpt, fifo_t * fp)
265 {
266         while (*cpt) {
267                 serputc(*cpt++, fp);
268         }
269 }
270
271 char hex2c(char i)
272 {
273         i &=0x0f;
274         return i > 9 ? 'a' + i - 10 : '0' + i;
275 }
276
277 void serputb(char c, fifo_t * fp)
278 {
279         serputc(hex2c(c>>4), fp);
280         serputc(hex2c(c), fp);
281 }
282
283 void serputw(int w, fifo_t * fp)
284 {
285         serputb(w >> 8, fp);
286         serputb(w & 0xff, fp);
287 }
288
289 #if (DEBUG_LEVEL>2)
290 char *dddlog_input(char c)
291 {
292         static char buf[7];
293         int n = rxfp0->o;
294         buf[0]='<';
295         buf[1]=hex2c(c>>4);
296         buf[2]=hex2c(c);
297         buf[3]='>';
298         buf[4]=hex2c(n>>4);
299         buf[5]=hex2c(n);
300         buf[6]=0;
301         return buf;
302 }
303 #endif
304 //  These is what goodfet uses
305 uint8_t serial0_rx()
306 {
307         uint8_t c;
308         while (seravailable(rxfp0) == 0) {      // wait for data to be available
309                 // FIXME we should sleep
310         }
311         c = sergetc(rxfp0);
312         dddputs(dddlog_input(c));
313         return c;
314 }
315
316 uint8_t serial1_rx()
317 {
318         uint8_t c;
319         while ((seravailable(rxfp1)) == 0) {    // wait for data to be available
320                 // FIXME we should sleep
321         }
322         c = sergetc(rxfp1);
323         return c;
324 }
325
326 void serial0_tx(uint8_t x)
327 {
328         serputc(x, txfp0);
329 }
330
331 void serial1_tx(uint8_t x)
332 {
333         serputc(x, txfp1);
334 }
335
336 //Interrupt routines
337
338 interrupt(UART0RX_VECTOR) UART0_RX_ISR(void)
339 {
340         led_toggle();
341         rxfp0->b[rxfp0->i] = RXBUF0;
342         fifo_advance(&rxfp0->i);
343         rxfp0->count++;
344 }
345
346 interrupt(UART1RX_VECTOR) UART1_RX_ISR(void)
347 {
348         led_toggle();
349         rxfp1->b[rxfp1->i] = RXBUF1;
350         fifo_advance(&rxfp1->i);
351         rxfp1->count++;
352 }
353
354 interrupt(UART0TX_VECTOR) UART0_TX_ISR(void)
355 {
356         if (txfp0->count) {
357                 TXBUF0 = txfp0->b[txfp0->o];
358                 fifo_advance(&txfp0->o);
359                 txfp0->count--;
360         } else {
361                 txfp0->empty = TRUE;
362         }
363 }
364
365 interrupt(UART1TX_VECTOR) UART1_TX_ISR(void)
366 {
367         if (txfp1->count) {
368                 TXBUF1 = txfp1->b[txfp1->o];
369                 fifo_advance(&txfp1->o);
370                 txfp1->count--;
371         } else {
372                 txfp1->empty = TRUE;
373         }
374 }