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