Contiki-NG
Loading...
Searching...
No Matches
uart.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012, Texas Instruments Incorporated - http://www.ti.com/
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 *
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31/**
32 * \addtogroup cc2538-uart
33 * @{
34 *
35 * \file
36 * Implementation of the cc2538 UART driver
37 */
38#include "contiki.h"
39#include "dev/sys-ctrl.h"
40#include "dev/ioc.h"
41#include "dev/gpio.h"
42#include "dev/uart.h"
43#include "lpm.h"
44#include "reg.h"
45
46#include <stdbool.h>
47#include <stdint.h>
48#include <string.h>
49
50#ifndef UART0_RX_PORT
51#define UART0_RX_PORT (-1)
52#endif
53#ifndef UART0_RX_PIN
54#define UART0_RX_PIN (-1)
55#endif
56#if UART0_RX_PORT >= 0 && UART0_RX_PIN < 0 || \
57 UART0_RX_PORT < 0 && UART0_RX_PIN >= 0
58#error Both UART0_RX_PORT and UART0_RX_PIN must be valid or invalid
59#endif
60
61#ifndef UART0_TX_PORT
62#define UART0_TX_PORT (-1)
63#endif
64#ifndef UART0_TX_PIN
65#define UART0_TX_PIN (-1)
66#endif
67#if UART0_TX_PORT >= 0 && UART0_TX_PIN < 0 || \
68 UART0_TX_PORT < 0 && UART0_TX_PIN >= 0
69#error Both UART0_TX_PORT and UART0_TX_PIN must be valid or invalid
70#endif
71
72#if UART0_RX_PORT >= 0 && UART0_TX_PORT < 0 || \
73 UART0_RX_PORT < 0 && UART0_TX_PORT >= 0
74#error Both UART0_RX and UART0_TX pads must be valid or invalid
75#endif
76
77#if UART_IN_USE(0) && UART0_RX_PORT < 0
78#error Contiki is configured to use UART0, but its pads are not valid
79#endif
80
81#ifndef UART1_RX_PORT
82#define UART1_RX_PORT (-1)
83#endif
84#ifndef UART1_RX_PIN
85#define UART1_RX_PIN (-1)
86#endif
87#if UART1_RX_PORT >= 0 && UART1_RX_PIN < 0 || \
88 UART1_RX_PORT < 0 && UART1_RX_PIN >= 0
89#error Both UART1_RX_PORT and UART1_RX_PIN must be valid or invalid
90#endif
91
92#ifndef UART1_TX_PORT
93#define UART1_TX_PORT (-1)
94#endif
95#ifndef UART1_TX_PIN
96#define UART1_TX_PIN (-1)
97#endif
98#if UART1_TX_PORT >= 0 && UART1_TX_PIN < 0 || \
99 UART1_TX_PORT < 0 && UART1_TX_PIN >= 0
100#error Both UART1_TX_PORT and UART1_TX_PIN must be valid or invalid
101#endif
102
103#if UART1_RX_PORT >= 0 && UART1_TX_PORT < 0 || \
104 UART1_RX_PORT < 0 && UART1_TX_PORT >= 0
105#error Both UART1_RX and UART1_TX pads must be valid or invalid
106#endif
107
108#if UART_IN_USE(1) && UART1_RX_PORT < 0
109#error Contiki is configured to use UART1, but its pads are not valid
110#endif
111
112#ifndef UART1_CTS_PORT
113#define UART1_CTS_PORT (-1)
114#endif
115#ifndef UART1_CTS_PIN
116#define UART1_CTS_PIN (-1)
117#endif
118#if UART1_CTS_PORT >= 0 && UART1_CTS_PIN < 0 || \
119 UART1_CTS_PORT < 0 && UART1_CTS_PIN >= 0
120#error Both UART1_CTS_PORT and UART1_CTS_PIN must be valid or invalid
121#endif
122
123#ifndef UART1_RTS_PORT
124#define UART1_RTS_PORT (-1)
125#endif
126#ifndef UART1_RTS_PIN
127#define UART1_RTS_PIN (-1)
128#endif
129#if UART1_RTS_PORT >= 0 && UART1_RTS_PIN < 0 || \
130 UART1_RTS_PORT < 0 && UART1_RTS_PIN >= 0
131#error Both UART1_RTS_PORT and UART1_RTS_PIN must be valid or invalid
132#endif
133/*---------------------------------------------------------------------------*/
134/*
135 * Baud rate defines used in uart_init() to set the values of UART_IBRD and
136 * UART_FBRD in order to achieve the configured baud rates.
137 */
138#define UART_CLOCK_RATE SYS_CTRL_SYS_CLOCK
139#define UART_CTL_HSE_VALUE 0
140#define UART_CTL_VALUE (UART_CTL_RXE | UART_CTL_TXE | (UART_CTL_HSE_VALUE << 5))
141
142/* DIV_ROUND() divides integers while avoiding a rounding error: */
143#define DIV_ROUND(num, denom) (((num) + (denom) / 2) / (denom))
144
145#define BAUD2BRD(baud) DIV_ROUND(UART_CLOCK_RATE << (UART_CTL_HSE_VALUE + 2), (baud))
146#define BAUD2IBRD(baud) (BAUD2BRD(baud) >> 6)
147#define BAUD2FBRD(baud) (BAUD2BRD(baud) & 0x3f)
148/*---------------------------------------------------------------------------*/
149typedef struct {
150 int8_t port;
151 int8_t pin;
152} uart_pad_t;
153typedef struct {
154 uint32_t sys_ctrl_rcgcuart_uart;
155 uint32_t sys_ctrl_scgcuart_uart;
156 uint32_t sys_ctrl_dcgcuart_uart;
157 uint32_t base;
158 uint32_t ioc_uartrxd_uart;
159 uint32_t ioc_pxx_sel_uart_txd;
160 uint32_t ibrd;
161 uint32_t fbrd;
162 uart_pad_t rx;
163 uart_pad_t tx;
164 uart_pad_t cts;
165 uart_pad_t rts;
166 uint8_t nvic_int;
167} uart_regs_t;
168/*---------------------------------------------------------------------------*/
169static const uart_regs_t uart_regs[UART_INSTANCE_COUNT] = {
170 {
171 .sys_ctrl_rcgcuart_uart = SYS_CTRL_RCGCUART_UART0,
172 .sys_ctrl_scgcuart_uart = SYS_CTRL_SCGCUART_UART0,
173 .sys_ctrl_dcgcuart_uart = SYS_CTRL_DCGCUART_UART0,
174 .base = UART_0_BASE,
175 .ioc_uartrxd_uart = IOC_UARTRXD_UART0,
176 .ioc_pxx_sel_uart_txd = IOC_PXX_SEL_UART0_TXD,
177 .ibrd = BAUD2IBRD(UART0_CONF_BAUD_RATE),
178 .fbrd = BAUD2FBRD(UART0_CONF_BAUD_RATE),
179 .rx = {UART0_RX_PORT, UART0_RX_PIN},
180 .tx = {UART0_TX_PORT, UART0_TX_PIN},
181 .cts = {-1, -1},
182 .rts = {-1, -1},
183 .nvic_int = UART0_IRQn
184 }, {
185 .sys_ctrl_rcgcuart_uart = SYS_CTRL_RCGCUART_UART1,
186 .sys_ctrl_scgcuart_uart = SYS_CTRL_SCGCUART_UART1,
187 .sys_ctrl_dcgcuart_uart = SYS_CTRL_DCGCUART_UART1,
188 .base = UART_1_BASE,
189 .ioc_uartrxd_uart = IOC_UARTRXD_UART1,
190 .ioc_pxx_sel_uart_txd = IOC_PXX_SEL_UART1_TXD,
191 .ibrd = BAUD2IBRD(UART1_CONF_BAUD_RATE),
192 .fbrd = BAUD2FBRD(UART1_CONF_BAUD_RATE),
193 .rx = {UART1_RX_PORT, UART1_RX_PIN},
194 .tx = {UART1_TX_PORT, UART1_TX_PIN},
195 .cts = {UART1_CTS_PORT, UART1_CTS_PIN},
196 .rts = {UART1_RTS_PORT, UART1_RTS_PIN},
197 .nvic_int = UART1_IRQn
198 }
199};
200static int (* input_handler[UART_INSTANCE_COUNT])(unsigned char c);
201/*---------------------------------------------------------------------------*/
202static void
203reset(uint32_t uart_base)
204{
205 uint32_t lchr;
206
207 /* Make sure the UART is disabled before trying to configure it */
208 REG(uart_base + UART_CTL) = UART_CTL_VALUE;
209
210 /* Clear error status */
211 REG(uart_base + UART_ECR) = 0xFF;
212
213 /* Store LCHR configuration */
214 lchr = REG(uart_base + UART_LCRH);
215
216 /* Flush FIFOs by clearing LCHR.FEN */
217 REG(uart_base + UART_LCRH) = 0;
218
219 /* Restore LCHR configuration */
220 REG(uart_base + UART_LCRH) = lchr;
221
222 /* UART Enable */
223 REG(uart_base + UART_CTL) |= UART_CTL_UARTEN;
224}
225/*---------------------------------------------------------------------------*/
226static bool
227permit_pm1(void)
228{
229 const uart_regs_t *regs;
230
231 for(regs = &uart_regs[0]; regs < &uart_regs[UART_INSTANCE_COUNT]; regs++) {
232 if((REG(regs->base + UART_FR) & UART_FR_BUSY) != 0) {
233 return false;
234 }
235 }
236
237 return true;
238}
239/*---------------------------------------------------------------------------*/
240void
241uart_init(uint8_t uart)
242{
243 const uart_regs_t *regs;
244
245 if(uart >= UART_INSTANCE_COUNT) {
246 return;
247 }
248 regs = &uart_regs[uart];
249 if(regs->rx.port < 0 || regs->tx.port < 0) {
250 return;
251 }
252
253 lpm_register_peripheral(permit_pm1);
254
255 /* Enable clock for the UART while Running, in Sleep and Deep Sleep */
256 REG(SYS_CTRL_RCGCUART) |= regs->sys_ctrl_rcgcuart_uart;
257 REG(SYS_CTRL_SCGCUART) |= regs->sys_ctrl_scgcuart_uart;
258 REG(SYS_CTRL_DCGCUART) |= regs->sys_ctrl_dcgcuart_uart;
259
260 /* Run on SYS_DIV */
261 REG(regs->base + UART_CC) = 0;
262
263 /*
264 * Select the UARTx RX pin by writing to the IOC_UARTRXD_UARTn register
265 *
266 * The value to be written will be on of the IOC_INPUT_SEL_Pxn defines from
267 * ioc.h. The value can also be calculated as:
268 *
269 * (port << 3) + pin
270 */
271 REG(regs->ioc_uartrxd_uart) = (regs->rx.port << 3) + regs->rx.pin;
272
273 /*
274 * Pad Control for the TX pin:
275 * - Set function to UARTn TX
276 * - Output Enable
277 */
278 ioc_set_sel(regs->tx.port, regs->tx.pin, regs->ioc_pxx_sel_uart_txd);
279 ioc_set_over(regs->tx.port, regs->tx.pin, IOC_OVERRIDE_OE);
280
281 /* Set RX and TX pins to peripheral mode */
283 GPIO_PIN_MASK(regs->tx.pin));
285 GPIO_PIN_MASK(regs->rx.pin));
286
287 /*
288 * UART Interrupt Masks:
289 * Acknowledge RX and RX Timeout
290 * Acknowledge Framing, Overrun and Break Errors
291 */
292 REG(regs->base + UART_IM) = UART_IM_RXIM | UART_IM_RTIM;
293 REG(regs->base + UART_IM) |= UART_IM_OEIM | UART_IM_BEIM | UART_IM_FEIM;
294
295 REG(regs->base + UART_IFLS) =
297
298 /* Make sure the UART is disabled before trying to configure it */
299 REG(regs->base + UART_CTL) = UART_CTL_VALUE;
300
301 /* Baud Rate Generation */
302 REG(regs->base + UART_IBRD) = regs->ibrd;
303 REG(regs->base + UART_FBRD) = regs->fbrd;
304
305 /* UART Control: 8N1 with FIFOs */
306 REG(regs->base + UART_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
307
308 /*
309 * Enable hardware flow control (RTS/CTS) if requested.
310 * Note that hardware flow control is available only on UART1.
311 */
312 if(regs->cts.port >= 0) {
313 REG(IOC_UARTCTS_UART1) = ioc_input_sel(regs->cts.port, regs->cts.pin);
314 GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->cts.port), GPIO_PIN_MASK(regs->cts.pin));
315 ioc_set_over(regs->cts.port, regs->cts.pin, IOC_OVERRIDE_DIS);
316 REG(UART_1_BASE + UART_CTL) |= UART_CTL_CTSEN;
317 }
318
319 if(regs->rts.port >= 0) {
320 ioc_set_sel(regs->rts.port, regs->rts.pin, IOC_PXX_SEL_UART1_RTS);
321 GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->rts.port), GPIO_PIN_MASK(regs->rts.pin));
322 ioc_set_over(regs->rts.port, regs->rts.pin, IOC_OVERRIDE_OE);
323 REG(UART_1_BASE + UART_CTL) |= UART_CTL_RTSEN;
324 }
325
326 /* UART Enable */
327 REG(regs->base + UART_CTL) |= UART_CTL_UARTEN;
328
329 /* Enable UART0 Interrupts */
330 NVIC_EnableIRQ(regs->nvic_int);
331}
332/*---------------------------------------------------------------------------*/
333void
334uart_set_input(uint8_t uart, int (* input)(unsigned char c))
335{
336 if(uart >= UART_INSTANCE_COUNT) {
337 return;
338 }
339
340 input_handler[uart] = input;
341}
342/*---------------------------------------------------------------------------*/
343void
344uart_write_byte(uint8_t uart, uint8_t b)
345{
346 uint32_t uart_base;
347
348 if(uart >= UART_INSTANCE_COUNT) {
349 return;
350 }
351 uart_base = uart_regs[uart].base;
352
353 /* Block if the TX FIFO is full */
354 while(REG(uart_base + UART_FR) & UART_FR_TXFF);
355
356 REG(uart_base + UART_DR) = b;
357}
358/*---------------------------------------------------------------------------*/
359static void
360uart_isr(uint8_t uart)
361{
362 uint32_t uart_base;
363 uint16_t mis;
364
365 uart_base = uart_regs[uart].base;
366
367 /* Store the current MIS and clear all flags early, except the RTM flag.
368 * This will clear itself when we read out the entire FIFO contents */
369 mis = REG(uart_base + UART_MIS) & 0x0000FFFF;
370
371 REG(uart_base + UART_ICR) = 0x0000FFBF;
372
373 if(mis & (UART_MIS_RXMIS | UART_MIS_RTMIS)) {
374 while(!(REG(uart_base + UART_FR) & UART_FR_RXFE)) {
375 if(input_handler[uart] != NULL) {
376 input_handler[uart]((unsigned char)(REG(uart_base + UART_DR) & 0xFF));
377 } else {
378 /* To prevent an Overrun Error, we need to flush the FIFO even if we
379 * don't have an input_handler. Use mis as a data trash can */
380 mis = REG(uart_base + UART_DR);
381 }
382 }
383 } else if(mis & (UART_MIS_OEMIS | UART_MIS_BEMIS | UART_MIS_FEMIS)) {
384 /* ISR triggered due to some error condition */
385 reset(uart_base);
386 }
387}
388/*---------------------------------------------------------------------------*/
389#define UART_ISR(u) void uart##u##_isr(void) { uart_isr(u); }
390UART_ISR(0)
391UART_ISR(1)
392
393/** @} */
Header file with register and macro declarations for the cc2538 GPIO module.
@ UART1_IRQn
UART1 Interrupt.
Definition cc2538_cm3.h:83
@ UART0_IRQn
UART0 Interrupt.
Definition cc2538_cm3.h:82
#define GPIO_PIN_MASK(PIN)
Converts a pin number to a pin mask.
Definition gpio.h:320
#define GPIO_PERIPHERAL_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be under peripheral control with PIN_MASK of port with PORT_BASE.
Definition gpio.h:250
#define GPIO_PORT_TO_BASE(PORT)
Converts a port number to the port base address.
Definition gpio.h:328
#define ioc_input_sel(port, pin)
Generates an IOC_INPUT_SEL_PXn value from a port/pin number.
Definition ioc.h:286
void ioc_set_sel(uint8_t port, uint8_t pin, uint8_t sel)
Function select for Port:Pin.
Definition ioc.c:66
#define IOC_OVERRIDE_OE
Output Enable.
Definition ioc.h:222
#define IOC_UARTRXD_UART0
UART0 RX.
Definition ioc.h:125
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition ioc.c:54
#define IOC_UARTCTS_UART1
UART1 CTS.
Definition ioc.h:126
#define IOC_OVERRIDE_DIS
Override Disabled.
Definition ioc.h:226
#define IOC_UARTRXD_UART1
UART1 RX.
Definition ioc.h:127
#define SYS_CTRL_DCGCUART_UART1
UART1 Clock, PM0.
Definition sys-ctrl.h:246
#define SYS_CTRL_SCGCUART_UART0
UART0 Clock, CPU IDLE.
Definition sys-ctrl.h:240
#define SYS_CTRL_SCGCUART_UART1
UART1 Clock, CPU IDLE.
Definition sys-ctrl.h:239
#define SYS_CTRL_RCGCUART
UART[1:0] clocks - active mode.
Definition sys-ctrl.h:75
#define SYS_CTRL_DCGCUART_UART0
UART0 Clock, PM0.
Definition sys-ctrl.h:247
#define SYS_CTRL_SCGCUART
UART[1:0] clocks - sleep mode.
Definition sys-ctrl.h:76
#define SYS_CTRL_DCGCUART
UART[1:0] clocks - PM0.
Definition sys-ctrl.h:77
#define SYS_CTRL_RCGCUART_UART0
UART0 Clock, CPU running.
Definition sys-ctrl.h:233
#define SYS_CTRL_RCGCUART_UART1
UART1 Clock, CPU running.
Definition sys-ctrl.h:232
#define UART_CC
UART clock configuration.
Definition uart.h:87
#define UART_MIS_RTMIS
UART RX time-out masked stat.
Definition uart.h:254
#define UART_ICR
UART interrupt clear.
Definition uart.h:79
#define UART_LCRH
UART line control.
Definition uart.h:73
#define UART_CTL_CTSEN
UART CTS flow-control enable (UART1 only)
Definition uart.h:168
#define UART_FR_TXFF
UART transmit FIFO full.
Definition uart.h:120
#define UART_IM_OEIM
UART overrun error mask.
Definition uart.h:216
#define UART_CTL
UART control.
Definition uart.h:74
#define UART_FR_BUSY
UART busy.
Definition uart.h:122
#define UART_CTL_UARTEN
UART enable.
Definition uart.h:179
#define UART_IM_BEIM
UART break error mask.
Definition uart.h:217
#define UART_IFLS_TXIFLSEL_1_2
UART TX FIFO >= 1/2 empty.
Definition uart.h:204
#define UART_MIS_RXMIS
UART RX masked intr stat.
Definition uart.h:256
#define UART_IM_RTIM
UART receive time-out mask.
Definition uart.h:220
#define UART_IFLS
UART interrupt FIFO level.
Definition uart.h:75
#define UART_FR
UART flag.
Definition uart.h:69
#define UART_CTL_RTSEN
UART RTS flow-control enable (UART1 only)
Definition uart.h:169
#define UART_IBRD
UART BAUD divisor: integer.
Definition uart.h:71
#define UART_MIS_FEMIS
UART framing err masked stat.
Definition uart.h:253
void uart_set_input(uint8_t uart, int(*input)(unsigned char c))
Assigns a callback to be called when the UART receives a byte.
Definition uart.c:334
#define UART_IM
UART interrupt mask.
Definition uart.h:76
#define UART_FR_RXFE
UART receive FIFO empty.
Definition uart.h:121
#define UART_ECR
UART RX status and err clear.
Definition uart.h:68
#define UART_IM_FEIM
UART framing error.
Definition uart.h:219
#define UART_MIS_BEMIS
UART break err masked stat.
Definition uart.h:251
#define UART_FBRD
UART BAUD divisor: fractional.
Definition uart.h:72
#define UART_IM_RXIM
UART receive interrupt mask.
Definition uart.h:222
void uart_write_byte(uint8_t uart, uint8_t b)
Sends a single character down the UART.
Definition uart.c:344
#define UART_LCRH_FEN
UART enable FIFOs.
Definition uart.h:149
#define UART_IFLS_RXIFLSEL_1_8
UART RX FIFO >= 1/8 full.
Definition uart.h:196
#define UART_MIS
UART masked interrupt status.
Definition uart.h:78
#define UART_MIS_OEMIS
UART overrun err masked stat.
Definition uart.h:250
#define UART_DR
UART data.
Definition uart.h:66
#define UART0_CONF_BAUD_RATE
Default UART0 baud rate.
#define UART1_CONF_BAUD_RATE
Default UART1 baud rate.
void uart_init(void)
Initializa the UART driver.
Definition uart-arch.c:87
Header file with declarations for the I/O Control module.
Header file with register manipulation macro definitions.
Header file for the cc2538 System Control driver.
Header file for the cc2538 UART driver.