Contiki-NG
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 /*---------------------------------------------------------------------------*/
149 typedef struct {
150  int8_t port;
151  int8_t pin;
152 } uart_pad_t;
153 typedef 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 /*---------------------------------------------------------------------------*/
169 static 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 };
200 static int (* input_handler[UART_INSTANCE_COUNT])(unsigned char c);
201 /*---------------------------------------------------------------------------*/
202 static void
203 reset(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 /*---------------------------------------------------------------------------*/
226 static bool
227 permit_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 /*---------------------------------------------------------------------------*/
240 void
241 uart_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 /*---------------------------------------------------------------------------*/
333 void
334 uart_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 /*---------------------------------------------------------------------------*/
343 void
344 uart_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 /*---------------------------------------------------------------------------*/
359 static void
360 uart_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); }
390 UART_ISR(0)
391 UART_ISR(1)
392 
393 /** @} */
#define UART_FR_TXFF
UART transmit FIFO full.
Definition: uart.h:120
Header file for the cc2538 UART driver.
#define UART_FBRD
UART BAUD divisor: fractional.
Definition: uart.h:72
#define UART_IM_RXIM
UART receive interrupt mask.
Definition: uart.h:222
#define UART_IFLS
UART interrupt FIFO level.
Definition: uart.h:75
#define SYS_CTRL_RCGCUART_UART0
UART0 Clock, CPU running.
Definition: sys-ctrl.h:233
Header file for the cc2538 System Control driver.
#define UART_LCRH
UART line control.
Definition: uart.h:73
#define SYS_CTRL_RCGCUART
UART[1:0] clocks - active mode.
Definition: sys-ctrl.h:75
Header file with register and macro declarations for the cc2538 GPIO module.
#define UART_IFLS_RXIFLSEL_1_8
UART RX FIFO >= 1/8 full.
Definition: uart.h:196
#define UART_MIS_BEMIS
UART break err masked stat.
Definition: uart.h:251
void uart_init(uint8_t uart)
Initialises the UART controller, configures I/O control and interrupts.
Definition: uart.c:241
#define UART_FR
UART flag.
Definition: uart.h:69
#define UART_IFLS_TXIFLSEL_1_2
UART TX FIFO >= 1/2 empty.
Definition: uart.h:204
Header file with declarations for the I/O Control module.
void uart_write_byte(uint8_t uart, uint8_t b)
Sends a single character down the UART.
Definition: uart.c:344
#define UART_FR_BUSY
UART busy.
Definition: uart.h:122
#define SYS_CTRL_DCGCUART_UART1
UART1 Clock, PM0.
Definition: sys-ctrl.h:246
Header file with register manipulation macro definitions.
UART0 Interrupt.
Definition: cc2538_cm3.h:82
#define UART_LCRH_FEN
UART enable FIFOs.
Definition: uart.h:149
#define IOC_OVERRIDE_DIS
Override Disabled.
Definition: ioc.h:226
#define UART_IM_OEIM
UART overrun error mask.
Definition: uart.h:216
#define GPIO_PIN_MASK(PIN)
Converts a pin number to a pin mask.
Definition: gpio.h:320
#define UART_CTL_UARTEN
UART enable.
Definition: uart.h:179
#define IOC_UARTRXD_UART1
UART1 RX.
Definition: ioc.h:127
#define UART_CC
UART clock configuration.
Definition: uart.h:87
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
Enable External Interrupt.
Definition: core_cm0.h:642
#define UART_CTL_CTSEN
UART CTS flow-control enable (UART1 only)
Definition: uart.h:168
#define UART_FR_RXFE
UART receive FIFO empty.
Definition: uart.h:121
#define IOC_UARTCTS_UART1
UART1 CTS.
Definition: ioc.h:126
#define UART_MIS_FEMIS
UART framing err masked stat.
Definition: uart.h:253
#define UART_ECR
UART RX status and err clear.
Definition: uart.h:68
#define SYS_CTRL_DCGCUART
UART[1:0] clocks - PM0.
Definition: sys-ctrl.h:77
#define UART_ICR
UART interrupt clear.
Definition: uart.h:79
#define UART_MIS_RTMIS
UART RX time-out masked stat.
Definition: uart.h:254
#define UART_IM_FEIM
UART framing error.
Definition: uart.h:219
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
UART1 Interrupt.
Definition: cc2538_cm3.h:83
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
#define UART1_CONF_BAUD_RATE
Default UART1 baud rate.
Definition: cc2538-conf.h:114
#define SYS_CTRL_DCGCUART_UART0
UART0 Clock, PM0.
Definition: sys-ctrl.h:247
#define UART_MIS_OEMIS
UART overrun err masked stat.
Definition: uart.h:250
#define SYS_CTRL_SCGCUART_UART1
UART1 Clock, CPU IDLE.
Definition: sys-ctrl.h:239
#define IOC_OVERRIDE_OE
Output Enable.
Definition: ioc.h:222
#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 UART_IBRD
UART BAUD divisor: integer.
Definition: uart.h:71
#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 UART_CTL_RTSEN
UART RTS flow-control enable (UART1 only)
Definition: uart.h:169
#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_CTL
UART control.
Definition: uart.h:74
#define SYS_CTRL_SCGCUART_UART0
UART0 Clock, CPU IDLE.
Definition: sys-ctrl.h:240
#define GPIO_PORT_TO_BASE(PORT)
Converts a port number to the port base address.
Definition: gpio.h:328
#define SYS_CTRL_RCGCUART_UART1
UART1 Clock, CPU running.
Definition: sys-ctrl.h:232
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1777
#define UART_IM
UART interrupt mask.
Definition: uart.h:76
#define IOC_UARTRXD_UART0
UART0 RX.
Definition: ioc.h:125
#define SYS_CTRL_SCGCUART
UART[1:0] clocks - sleep mode.
Definition: sys-ctrl.h:76
#define UART_MIS
UART masked interrupt status.
Definition: uart.h:78
#define UART_DR
UART data.
Definition: uart.h:66
#define UART_IM_BEIM
UART break error mask.
Definition: uart.h:217
#define UART0_CONF_BAUD_RATE
Default UART0 baud rate.
Definition: cc2538-conf.h:110