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
43static int (*uart0_input_handler)(unsigned char c);
44
45static 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
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 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/*---------------------------------------------------------------------------*/
91uint8_t
92uart0_active(void)
93{
94 return (UCA0STAT & UCBUSY) | transmitting;
95}
96/*---------------------------------------------------------------------------*/
97void
98uart0_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/*---------------------------------------------------------------------------*/
106void
107uart0_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 */
138void
139uart0_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
184ISR(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
202ISR(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/*---------------------------------------------------------------------------*/
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
void uart0_init(unsigned long ubr)
Initalize the RS232 port.
Definition: uart0.c:85
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