Contiki-NG
uart0.c
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 /*
32  * Machine dependent MSP430X UART0 code.
33  */
34 
35 #include <stdlib.h>
36 
37 #include "contiki.h"
38 #include "dev/uart0.h"
39 #include "dev/watchdog.h"
40 #include "lib/ringbuf.h"
41 #include "isr_compat.h"
42 
43 static int (*uart0_input_handler)(unsigned char c);
44 
45 static volatile uint8_t transmitting;
46 
47 #ifdef UART0_CONF_TX_WITH_INTERRUPT
48 #define TX_WITH_INTERRUPT UART0_CONF_TX_WITH_INTERRUPT
49 #else /* UART0_CONF_TX_WITH_INTERRUPT */
50 #define TX_WITH_INTERRUPT 1
51 #endif /* UART0_CONF_TX_WITH_INTERRUPT */
52 
53 #ifdef UART0_CONF_RX_WITH_DMA
54 #define RX_WITH_DMA UART0_CONF_RX_WITH_DMA
55 #else /* UART0_CONF_RX_WITH_DMA */
56 #define RX_WITH_DMA 1
57 #endif /* UART0_CONF_RX_WITH_DMA */
58 
59 #if TX_WITH_INTERRUPT
60 #define TXBUFSIZE 64
61 
62 static struct ringbuf txbuf;
63 static uint8_t txbuf_data[TXBUFSIZE];
64 #endif /* TX_WITH_INTERRUPT */
65 
66 #if RX_WITH_DMA
67 #define RXBUFSIZE 128
68 
69 static uint8_t rxbuf[RXBUFSIZE];
70 static uint16_t last_size;
71 static struct ctimer rxdma_timer;
72 
73 static void
74 handle_rxdma_timer(void *ptr)
75 {
76  uint16_t size;
77  size = DMA0SZ; /* Note: loop requires that size is less or eq to RXBUFSIZE */
78  while(last_size != size) {
79  uart0_input_handler((unsigned char)rxbuf[RXBUFSIZE - last_size]);
80  last_size--;
81  if(last_size == 0) {
82  last_size = RXBUFSIZE;
83  }
84  }
85 
86  ctimer_reset(&rxdma_timer);
87 }
88 #endif /* RX_WITH_DMA */
89 
90 /*---------------------------------------------------------------------------*/
91 uint8_t
92 uart0_active(void)
93 {
94  return (UCA0STAT & UCBUSY) | transmitting;
95 }
96 /*---------------------------------------------------------------------------*/
97 void
98 uart0_set_input(int (*input)(unsigned char c))
99 {
100 #if RX_WITH_DMA /* This needs to be called after ctimer process is started */
101  ctimer_set(&rxdma_timer, CLOCK_SECOND / 64, handle_rxdma_timer, NULL);
102 #endif
103  uart0_input_handler = input;
104 }
105 /*---------------------------------------------------------------------------*/
106 void
107 uart0_writeb(unsigned char c)
108 {
110 #if TX_WITH_INTERRUPT
111  /* Put the outgoing byte on the transmission buffer. If the buffer
112  is full, we just keep on trying to put the byte into the buffer
113  until it is possible to put it there. */
114  while(ringbuf_put(&txbuf, c) == 0);
115 
116  /* If there is no transmission going, we need to start it by putting
117  the first byte into the UART. */
118  if(transmitting == 0) {
119  transmitting = 1;
120  UCA0TXBUF = ringbuf_get(&txbuf);
121  }
122 
123 #else /* TX_WITH_INTERRUPT */
124 
125  /* Loop until the transmission buffer is available. */
126  /*Enric while((IFG2 & UCA0TXIFG) == 0); */
127  while((UCA0STAT & UCBUSY));
128 
129  /* Transmit the data. */
130  UCA0TXBUF = c;
131 #endif /* TX_WITH_INTERRUPT */
132 }
133 /*---------------------------------------------------------------------------*/
134 /**
135  * Initalize the RS232 port.
136  *
137  */
138 void
139 uart0_init(unsigned long ubr)
140 {
141  /* RS232 */
142  UCA0CTL1 |= UCSWRST; /* Hold peripheral in reset state */
143  UCA0CTL1 |= UCSSEL_2; /* CLK = SMCLK */
144 
145  UCA0BR0 = ((uint8_t *)&ubr)[0]; /* 8MHz/115200 = 69 = 0x45 */
146  UCA0BR1 = ((uint8_t *)&ubr)[1];
147  UCA0MCTL = UCBRS_3; /* Modulation UCBRSx = 3 */
148 
149  P3DIR &= ~0x20; /* P3.5 = USCI_A0 RXD as input */
150  P3DIR |= 0x10; /* P3.4 = USCI_A0 TXD as output */
151  P3SEL |= 0x30; /* P3.4,5 = USCI_A0 TXD/RXD */
152  /*UCA0CTL1 &= ~UCSWRST;*/ /* Initialize USCI state machine */
153 
154  transmitting = 0;
155 
156  /* XXX Clear pending interrupts before enable */
157  IFG2 &= ~UCA0RXIFG;
158  IFG2 &= ~UCA0TXIFG;
159  UCA0CTL1 &= ~UCSWRST; /* Initialize USCI state machine **before** enabling interrupts */
160  IE2 |= UCA0RXIE; /* Enable UCA0 RX interrupt */
161  /* Enable USCI_A0 TX interrupts (if TX_WITH_INTERRUPT enabled) */
162 #if TX_WITH_INTERRUPT
163  ringbuf_init(&txbuf, txbuf_data, sizeof(txbuf_data));
164  IE2 |= UCA0TXIE; /* Enable UCA0 TX interrupt */
165 #endif /* TX_WITH_INTERRUPT */
166 
167 #if RX_WITH_DMA
168  IE2 &= ~UCA0RXIE; /* disable USART0 RX interrupt */
169  /* UART0_RX trigger */
170  DMACTL0 = DMA0TSEL_3;
171 
172  /* source address = UCA0RXBUF */
173  DMA0SA = (unsigned int)&UCA0RXBUF;
174  DMA0DA = (unsigned int)&rxbuf;
175  DMA0SZ = RXBUFSIZE;
176  last_size = RXBUFSIZE;
177  DMA0CTL = DMADT_4 + DMASBDB + DMADSTINCR_3 + DMAEN + DMAREQ;
178 
179  msp430_add_lpm_req(MSP430_REQUIRE_LPM1);
180 #endif /* RX_WITH_DMA */
181 }
182 /*---------------------------------------------------------------------------*/
183 #if !RX_WITH_DMA
184 ISR(USCIAB0RX, uart0_rx_interrupt)
185 {
186  uint8_t c;
187 
188  if(UCA0STAT & UCRXERR) {
189  c = UCA0RXBUF; /* Clear error flags by forcing a dummy read. */
190  } else {
191  c = UCA0RXBUF;
192  if(uart0_input_handler != NULL) {
193  if(uart0_input_handler(c)) {
194  LPM4_EXIT;
195  }
196  }
197  }
198 }
199 #endif /* !RX_WITH_DMA */
200 /*---------------------------------------------------------------------------*/
201 #if TX_WITH_INTERRUPT
202 ISR(USCIAB0TX, uart0_tx_interrupt)
203 {
204  if((IFG2 & UCA0TXIFG)) {
205 
206  if(ringbuf_elements(&txbuf) == 0) {
207  transmitting = 0;
208  } else {
209  UCA0TXBUF = ringbuf_get(&txbuf);
210  }
211  }
212 
213  /* In a stand-alone app won't work without this. Is the UG misleading? */
214  IFG2 &= ~UCA0TXIFG;
215 }
216 #endif /* TX_WITH_INTERRUPT */
217 /*---------------------------------------------------------------------------*/
static uint8_t transmitting(void)
Check the RF&#39;s TX status.
Definition: ieee-mode.c:272
int ringbuf_elements(struct ringbuf *r)
Get the number of elements currently in the ring buffer.
Definition: ringbuf.c:119
int ringbuf_get(struct ringbuf *r)
Get a byte from the ring buffer.
Definition: ringbuf.c:80
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
Definition: ctimer.c:125
Header file for the ring buffer library
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void uart0_init(unsigned long ubr)
Initialize the RS232 port.
Definition: uart0.c:100
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
Structure that holds the state of a ring buffer.
Definition: ringbuf.h:68
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
int ringbuf_put(struct ringbuf *r, uint8_t c)
Insert a byte into the ring buffer.
Definition: ringbuf.c:53
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1777
void ringbuf_init(struct ringbuf *r, uint8_t *dataptr, uint8_t size)
Initialize a ring buffer.
Definition: ringbuf.c:44