Contiki-Inga 3.x
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 "sys/energest.h"
40 #include "dev/sys-ctrl.h"
41 #include "dev/ioc.h"
42 #include "dev/gpio.h"
43 #include "dev/uart.h"
44 #include "lpm.h"
45 #include "reg.h"
46 
47 #include <stdbool.h>
48 #include <stdint.h>
49 #include <string.h>
50 
51 static int (* input_handler)(unsigned char c);
52 /*---------------------------------------------------------------------------*/
53 #define UART_RX_PORT_BASE GPIO_PORT_TO_BASE(UART_RX_PORT)
54 #define UART_RX_PIN_MASK GPIO_PIN_MASK(UART_RX_PIN)
55 
56 #define UART_TX_PORT_BASE GPIO_PORT_TO_BASE(UART_TX_PORT)
57 #define UART_TX_PIN_MASK GPIO_PIN_MASK(UART_TX_PIN)
58 
59 #define UART_CTS_PORT_BASE GPIO_PORT_TO_BASE(UART_CTS_PORT)
60 #define UART_CTS_PIN_MASK GPIO_PIN_MASK(UART_CTS_PIN)
61 
62 #define UART_RTS_PORT_BASE GPIO_PORT_TO_BASE(UART_RTS_PORT)
63 #define UART_RTS_PIN_MASK GPIO_PIN_MASK(UART_RTS_PIN)
64 /*---------------------------------------------------------------------------*/
65 /*
66  * Once we know what UART we're on, configure correct values to be written to
67  * the correct registers
68  */
69 #if UART_BASE==UART_1_BASE
70 /* Running, in sleep, in deep sleep, enable the clock for the correct UART */
71 #define SYS_CTRL_RCGCUART_UART SYS_CTRL_RCGCUART_UART1
72 #define SYS_CTRL_SCGCUART_UART SYS_CTRL_SCGCUART_UART1
73 #define SYS_CTRL_DCGCUART_UART SYS_CTRL_DCGCUART_UART1
74 
75 #define NVIC_INT_UART NVIC_INT_UART1
76 #define IOC_PXX_SEL_UART_TXD IOC_PXX_SEL_UART1_TXD
77 #define IOC_UARTRXD_UART IOC_UARTRXD_UART1
78 #else /* Defaults for UART0 */
79 #define SYS_CTRL_RCGCUART_UART SYS_CTRL_RCGCUART_UART0
80 #define SYS_CTRL_SCGCUART_UART SYS_CTRL_SCGCUART_UART0
81 #define SYS_CTRL_DCGCUART_UART SYS_CTRL_DCGCUART_UART0
82 
83 #define NVIC_INT_UART NVIC_INT_UART0
84 
85 #define IOC_PXX_SEL_UART_TXD IOC_PXX_SEL_UART0_TXD
86 #define IOC_UARTRXD_UART IOC_UARTRXD_UART0
87 #endif
88 /*---------------------------------------------------------------------------*/
89 static void
90 reset(void)
91 {
92  uint32_t lchr;
93 
94  /* Make sure the UART is disabled before trying to configure it */
95  REG(UART_BASE | UART_CTL) = UART_CTL_TXE | UART_CTL_RXE;
96 
97  /* Clear error status */
98  REG(UART_BASE | UART_ECR) = 0xFF;
99 
100  /* Store LCHR configuration */
101  lchr = REG(UART_BASE | UART_LCRH);
102 
103  /* Flush FIFOs by clearing LCHR.FEN */
104  REG(UART_BASE | UART_LCRH) = 0;
105 
106  /* Restore LCHR configuration */
107  REG(UART_BASE | UART_LCRH) = lchr;
108 
109  /* UART Enable */
110  REG(UART_BASE | UART_CTL) |= UART_CTL_UARTEN;
111 }
112 /*---------------------------------------------------------------------------*/
113 static bool
114 permit_pm1(void)
115 {
116  /* Note: UART_FR.TXFE reads 0 if the UART clock is gated. */
117  return (REG(SYS_CTRL_RCGCUART) & SYS_CTRL_RCGCUART_UART) == 0 ||
118  (REG(UART_BASE | UART_FR) & UART_FR_TXFE) != 0;
119 }
120 /*---------------------------------------------------------------------------*/
121 void
123 {
124  lpm_register_peripheral(permit_pm1);
125 
126  /* Enable clock for the UART while Running, in Sleep and Deep Sleep */
127  REG(SYS_CTRL_RCGCUART) |= SYS_CTRL_RCGCUART_UART;
128  REG(SYS_CTRL_SCGCUART) |= SYS_CTRL_SCGCUART_UART;
129  REG(SYS_CTRL_DCGCUART) |= SYS_CTRL_DCGCUART_UART;
130 
131  /* Run on SYS_DIV */
132  REG(UART_BASE | UART_CC) = 0;
133 
134  /*
135  * Select the UARTx RX pin by writing to the IOC_UARTRXD_UARTn register
136  *
137  * The value to be written will be on of the IOC_INPUT_SEL_Pxn defines from
138  * ioc.h. The value can also be calculated as:
139  *
140  * (port << 3) + pin
141  */
142  REG(IOC_UARTRXD_UART) = (UART_RX_PORT << 3) + UART_RX_PIN;
143 
144  /*
145  * Pad Control for the TX pin:
146  * - Set function to UART0 TX
147  * - Output Enable
148  */
149  ioc_set_sel(UART_TX_PORT, UART_TX_PIN, IOC_PXX_SEL_UART_TXD);
150  ioc_set_over(UART_TX_PORT, UART_TX_PIN, IOC_OVERRIDE_OE);
151 
152  /* Set RX and TX pins to peripheral mode */
153  GPIO_PERIPHERAL_CONTROL(UART_TX_PORT_BASE, UART_TX_PIN_MASK);
154  GPIO_PERIPHERAL_CONTROL(UART_RX_PORT_BASE, UART_RX_PIN_MASK);
155 
156  /*
157  * UART Interrupt Masks:
158  * Acknowledge RX and RX Timeout
159  * Acknowledge Framing, Overrun and Break Errors
160  */
161  REG(UART_BASE | UART_IM) = UART_IM_RXIM | UART_IM_RTIM;
162  REG(UART_BASE | UART_IM) |= UART_IM_OEIM | UART_IM_BEIM | UART_IM_FEIM;
163 
164  REG(UART_BASE | UART_IFLS) =
166 
167  /* Make sure the UART is disabled before trying to configure it */
168  REG(UART_BASE | UART_CTL) = UART_CTL_TXE | UART_CTL_RXE;
169 
170  /* Baud Rate Generation */
171  REG(UART_BASE | UART_IBRD) = UART_CONF_IBRD;
172  REG(UART_BASE | UART_FBRD) = UART_CONF_FBRD;
173 
174  /* UART Control: 8N1 with FIFOs */
175  REG(UART_BASE | UART_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
176 
177  /* UART Enable */
178  REG(UART_BASE | UART_CTL) |= UART_CTL_UARTEN;
179 
180  /* Enable UART0 Interrupts */
181  nvic_interrupt_enable(NVIC_INT_UART);
182 }
183 /*---------------------------------------------------------------------------*/
184 void
185 uart_set_input(int (* input)(unsigned char c))
186 {
187  input_handler = input;
188 }
189 /*---------------------------------------------------------------------------*/
190 void
191 uart_write_byte(uint8_t b)
192 {
193  /* Block if the TX FIFO is full */
194  while(REG(UART_BASE | UART_FR) & UART_FR_TXFF);
195 
196  REG(UART_BASE | UART_DR) = b;
197 }
198 /*---------------------------------------------------------------------------*/
199 void
200 uart_isr(void)
201 {
202  uint16_t mis;
203 
204  ENERGEST_ON(ENERGEST_TYPE_IRQ);
205 
206  /* Store the current MIS and clear all flags early, except the RTM flag.
207  * This will clear itself when we read out the entire FIFO contents */
208  mis = REG(UART_BASE | UART_MIS) & 0x0000FFFF;
209 
210  REG(UART_BASE | UART_ICR) = 0x0000FFBF;
211 
212  if(mis & (UART_MIS_RXMIS | UART_MIS_RTMIS)) {
213  while(!(REG(UART_BASE | UART_FR) & UART_FR_RXFE)) {
214  if(input_handler != NULL) {
215  input_handler((unsigned char)(REG(UART_BASE | UART_DR) & 0xFF));
216  } else {
217  /* To prevent an Overrun Error, we need to flush the FIFO even if we
218  * don't have an input_handler. Use mis as a data trash can */
219  mis = REG(UART_BASE | UART_DR);
220  }
221  }
222  } else if(mis & (UART_MIS_OEMIS | UART_MIS_BEMIS | UART_MIS_FEMIS)) {
223  /* ISR triggered due to some error condition */
224  reset();
225  }
226 
227  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
228 }
229 
230 /** @} */