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
42static int (*uart1_input_handler)(unsigned char c);
43static volatile uint8_t rx_in_progress;
44
45static 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
62static struct ringbuf txbuf;
63static uint8_t txbuf_data[TXBUFSIZE];
64#endif /* TX_WITH_INTERRUPT */
65
66#if RX_WITH_DMA
67#define RXBUFSIZE 128
68
69static uint8_t rxbuf[RXBUFSIZE];
70static uint16_t last_size;
71static struct ctimer rxdma_timer;
72
73static void
74handle_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/*---------------------------------------------------------------------------*/
91uint8_t
92uart1_active(void)
93{
94 return ((~ UTCTL1) & TXEPT) | rx_in_progress | transmitting;
95}
96/*---------------------------------------------------------------------------*/
97void
98uart1_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/*---------------------------------------------------------------------------*/
106void
107uart1_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 */
141void
142uart1_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
238ISR(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
266ISR(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/*---------------------------------------------------------------------------*/
Header file for the callback timer.
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
Definition: ctimer.c:125
static uint8_t transmitting(void)
Check the RF's TX status.
Definition: ieee-mode.c:285
int ringbuf_get(struct ringbuf *r)
Get a byte from the ring buffer.
Definition: ringbuf.c:80
int ringbuf_put(struct ringbuf *r, uint8_t c)
Insert a byte into the ring buffer.
Definition: ringbuf.c:53
void ringbuf_init(struct ringbuf *r, uint8_t *dataptr, uint8_t size)
Initialize a ring buffer.
Definition: ringbuf.c:44
int ringbuf_elements(struct ringbuf *r)
Get the number of elements currently in the ring buffer.
Definition: ringbuf.c:119
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1833
Header file for the ring buffer library.
Structure that holds the state of a ring buffer.
Definition: ringbuf.h:68
A brief description of what this file is.
void uart1_init(unsigned long ubr)
Initalize the RS232 port.
Definition: uart1.c:142