Contiki-NG
uart1.c
1 /*
2  * Copyright (c) 2006, 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 MSP430 UART1 code.
33  */
34 
35 #include "contiki.h"
36 #include "dev/uart1.h"
37 #include "dev/watchdog.h"
38 #include "sys/ctimer.h"
39 #include "lib/ringbuf.h"
40 #include "isr_compat.h"
41 
42 static int (*uart1_input_handler)(unsigned char c);
43 static volatile uint8_t rx_in_progress;
44 
45 static volatile uint8_t transmitting;
46 
47 #ifdef UART1_CONF_TX_WITH_INTERRUPT
48 #define TX_WITH_INTERRUPT UART1_CONF_TX_WITH_INTERRUPT
49 #else /* UART1_CONF_TX_WITH_INTERRUPT */
50 #define TX_WITH_INTERRUPT 0
51 #endif /* UART1_CONF_TX_WITH_INTERRUPT */
52 
53 #ifdef UART1_CONF_RX_WITH_DMA
54 #define RX_WITH_DMA UART1_CONF_RX_WITH_DMA
55 #else /* UART1_CONF_RX_WITH_DMA */
56 #define RX_WITH_DMA 1
57 #endif /* UART1_CONF_RX_WITH_DMA */
58 
59 #if TX_WITH_INTERRUPT
60 #define TXBUFSIZE 128
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 /* printf("read: %c [%d,%d]\n", (unsigned char)rxbuf[RXBUFSIZE - last_size], */
80 /* last_size, size); */
81  uart1_input_handler((unsigned char)rxbuf[RXBUFSIZE - last_size]);
82  last_size--;
83  if(last_size == 0) last_size = RXBUFSIZE;
84  }
85 
86  ctimer_reset(&rxdma_timer);
87 }
88 #endif /* RX_WITH_DMA */
89 
90 /*---------------------------------------------------------------------------*/
91 uint8_t
92 uart1_active(void)
93 {
94  return ((~ UTCTL1) & TXEPT) | rx_in_progress | transmitting;
95 }
96 /*---------------------------------------------------------------------------*/
97 void
98 uart1_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  uart1_input_handler = input;
104 }
105 /*---------------------------------------------------------------------------*/
106 void
107 uart1_writeb(unsigned char c)
108 {
110 #if TX_WITH_INTERRUPT
111 
112  /* Put the outgoing byte on the transmission buffer. If the buffer
113  is full, we just keep on trying to put the byte into the buffer
114  until it is possible to put it there. */
115  while(ringbuf_put(&txbuf, c) == 0);
116 
117  /* If there is no transmission going, we need to start it by putting
118  the first byte into the UART. */
119  if(transmitting == 0) {
120  transmitting = 1;
121 
122  /* Loop until the transmission buffer is available. */
123  /*while((IFG2 & UTXIFG1) == 0);*/
124  TXBUF1 = ringbuf_get(&txbuf);
125  }
126 
127 #else /* TX_WITH_INTERRUPT */
128 
129  /* Loop until the transmission buffer is available. */
130  while((IFG2 & UTXIFG1) == 0);
131 
132  /* Transmit the data. */
133  TXBUF1 = c;
134 #endif /* TX_WITH_INTERRUPT */
135 }
136 /*---------------------------------------------------------------------------*/
137 /**
138  * Initalize the RS232 port.
139  *
140  */
141 void
142 uart1_init(unsigned long ubr)
143 {
144  /* RS232 */
145  P3DIR &= ~0x80; /* Select P37 for input (UART1RX) */
146  P3DIR |= 0x40; /* Select P36 for output (UART1TX) */
147  P3SEL |= 0xC0; /* Select P36,P37 for UART1{TX,RX} */
148 
149  UCTL1 = SWRST | CHAR; /* 8-bit character, UART mode */
150 
151 #if 0
152  U1RCTL &= ~URXEIE; /* even erroneous characters trigger interrupts */
153 #endif
154 
155  UTCTL1 = SSEL1; /* UCLK = MCLK */
156 
157  UBR01 = ubr;
158  UBR11 = ubr >> 8;
159  /*
160  * UMCTL1 values calculated using
161  * http://mspgcc.sourceforge.net/baudrate.html
162  */
163  switch(ubr) {
164 
165 #if F_CPU == 3900000ul
166 
167  case UART1_BAUD2UBR(115200ul):
168  UMCTL1 = 0xF7;
169  break;
170  case UART1_BAUD2UBR(57600ul):
171  UMCTL1 = 0xED;
172  break;
173  case UART1_BAUD2UBR(38400ul):
174  UMCTL1 = 0xD6;
175  break;
176  case UART1_BAUD2UBR(19200ul):
177  UMCTL1 = 0x08;
178  break;
179  case UART1_BAUD2UBR(9600ul):
180  UMCTL1 = 0x22;
181  break;
182 
183 #elif F_CPU == 2457600ul
184 
185  case UART1_BAUD2UBR(115200ul):
186  UMCTL1 = 0x4A;
187  break;
188  case UART1_BAUD2UBR(57600ul):
189  UMCTL1 = 0x5B;
190  break;
191  default:
192  /* 9600, 19200, 38400 don't require any correction */
193  UMCTL1 = 0x00;
194 
195 #else
196 
197 #error Unsupported CPU speed in uart1.c
198 
199 #endif
200  }
201 
202  ME2 &= ~USPIE1; /* USART1 SPI module disable */
203  ME2 |= (UTXE1 | URXE1); /* Enable USART1 TXD/RXD */
204 
205  UCTL1 &= ~SWRST;
206 
207  /* XXX Clear pending interrupts before enable!!! */
208  IFG2 &= ~URXIFG1;
209  U1TCTL |= URXSE;
210 
211  rx_in_progress = 0;
212 
213  transmitting = 0;
214 
215  IE2 |= URXIE1; /* Enable USART1 RX interrupt */
216 #if TX_WITH_INTERRUPT
217  ringbuf_init(&txbuf, txbuf_data, sizeof(txbuf_data));
218  IE2 |= UTXIE1; /* Enable USART1 TX interrupt */
219 #endif /* TX_WITH_INTERRUPT */
220 
221 #if RX_WITH_DMA
222  IE2 &= ~URXIE1; /* disable USART1 RX interrupt */
223  /* UART1_RX trigger */
224  DMACTL0 = DMA0TSEL_9;
225 
226  /* source address = RXBUF1 */
227  DMA0SA = (unsigned int) &RXBUF1;
228  DMA0DA = (unsigned int) &rxbuf;
229  DMA0SZ = RXBUFSIZE;
230  last_size = RXBUFSIZE;
231  DMA0CTL = DMADT_4 + DMASBDB + DMADSTINCR_3 + DMAEN + DMAREQ;// DMAIE;
232 
233  msp430_add_lpm_req(MSP430_REQUIRE_LPM1);
234 #endif /* RX_WITH_DMA */
235 }
236 /*---------------------------------------------------------------------------*/
237 #if !RX_WITH_DMA
238 ISR(UART1RX, uart1_rx_interrupt)
239 {
240  uint8_t c;
241 
242  if(!(URXIFG1 & IFG2)) {
243  /* Edge detect if IFG not set? */
244  U1TCTL &= ~URXSE; /* Clear the URXS signal */
245  U1TCTL |= URXSE; /* Re-enable URXS - needed here?*/
246  rx_in_progress = 1;
247  LPM4_EXIT;
248  } else {
249  rx_in_progress = 0;
250  /* Check status register for receive errors. */
251  if(URCTL1 & RXERR) {
252  c = RXBUF1; /* Clear error flags by forcing a dummy read. */
253  } else {
254  c = RXBUF1;
255  if(uart1_input_handler != NULL) {
256  if(uart1_input_handler(c)) {
257  LPM4_EXIT;
258  }
259  }
260  }
261  }
262 }
263 #endif /* !RX_WITH_DMA */
264 /*---------------------------------------------------------------------------*/
265 #if TX_WITH_INTERRUPT
266 ISR(UART1TX, uart1_tx_interrupt)
267 {
268  if(ringbuf_elements(&txbuf) == 0) {
269  transmitting = 0;
270  } else {
271  TXBUF1 = ringbuf_get(&txbuf);
272  }
273 }
274 #endif /* TX_WITH_INTERRUPT */
275 /*---------------------------------------------------------------------------*/
static uint8_t transmitting(void)
Check the RF's TX status.
Definition: ieee-mode.c:285
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 uart1_init(unsigned long ubr)
Initalize the RS232 port.
Definition: uart1.c:142
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
Header file for the callback timer
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:1813
void ringbuf_init(struct ringbuf *r, uint8_t *dataptr, uint8_t size)
Initialize a ring buffer.
Definition: ringbuf.c:44