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