1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
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 are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements the OpenThread platform abstraction for UART communication.
32 *
33 */
34
35 #include <openthread-core-config.h>
36 #include <openthread/config.h>
37
38 #include <stdarg.h>
39 #include <stddef.h>
40 #include <stdio.h>
41
42 #include <openthread/platform/debug_uart.h>
43 #include <openthread/platform/logging.h>
44
45 #include "platform-cc2538.h"
46 #include "utils/code_utils.h"
47 #include "utils/uart.h"
48
49 enum
50 {
51 kPlatformClock = 32000000,
52 kBaudRate = 115200,
53 kReceiveBufferSize = 128,
54 };
55
56 extern void UART0IntHandler(void);
57
58 static void processReceive(void);
59 static void processTransmit(void);
60
61 static const uint8_t *sTransmitBuffer = NULL;
62 static uint16_t sTransmitLength = 0;
63
64 typedef struct RecvBuffer
65 {
66 // The data buffer
67 uint8_t mBuffer[kReceiveBufferSize];
68 // The offset of the first item written to the list.
69 uint16_t mHead;
70 // The offset of the next item to be written to the list.
71 uint16_t mTail;
72 } RecvBuffer;
73
74 static RecvBuffer sReceive;
75
enable_uart_clocks(void)76 static void enable_uart_clocks(void)
77 {
78 static int uart_clocks_done = 0;
79
80 if (uart_clocks_done)
81 {
82 return;
83 }
84
85 uart_clocks_done = 1;
86
87 #if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART
88 HWREG(SYS_CTRL_RCGCUART) = (SYS_CTRL_RCGCUART_UART0 | SYS_CTRL_RCGCUART_UART1);
89 HWREG(SYS_CTRL_SCGCUART) = (SYS_CTRL_SCGCUART_UART0 | SYS_CTRL_SCGCUART_UART1);
90 HWREG(SYS_CTRL_DCGCUART) = (SYS_CTRL_DCGCUART_UART0 | SYS_CTRL_DCGCUART_UART1);
91 #else
92 HWREG(SYS_CTRL_RCGCUART) = SYS_CTRL_RCGCUART_UART0;
93 HWREG(SYS_CTRL_SCGCUART) = SYS_CTRL_SCGCUART_UART0;
94 HWREG(SYS_CTRL_DCGCUART) = SYS_CTRL_DCGCUART_UART0;
95 #endif
96 }
97
otPlatUartEnable(void)98 otError otPlatUartEnable(void)
99 {
100 uint32_t div;
101
102 sReceive.mHead = 0;
103 sReceive.mTail = 0;
104
105 // clock
106 enable_uart_clocks();
107
108 HWREG(UART0_BASE + UART_O_CC) = 0;
109
110 // tx pin
111 HWREG(IOC_PA1_SEL) = IOC_MUX_OUT_SEL_UART0_TXD;
112 HWREG(IOC_PA1_OVER) = IOC_OVERRIDE_OE;
113 HWREG(GPIO_A_BASE + GPIO_O_AFSEL) |= GPIO_PIN_1;
114
115 // rx pin
116 HWREG(IOC_UARTRXD_UART0) = IOC_PAD_IN_SEL_PA0;
117 HWREG(IOC_PA0_OVER) = IOC_OVERRIDE_DIS;
118 HWREG(GPIO_A_BASE + GPIO_O_AFSEL) |= GPIO_PIN_0;
119
120 HWREG(UART0_BASE + UART_O_CTL) = 0;
121
122 // baud rate
123 div = (((kPlatformClock * 8) / kBaudRate) + 1) / 2;
124 HWREG(UART0_BASE + UART_O_IBRD) = div / 64;
125 HWREG(UART0_BASE + UART_O_FBRD) = div % 64;
126 HWREG(UART0_BASE + UART_O_LCRH) = UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE;
127
128 // configure interrupts
129 HWREG(UART0_BASE + UART_O_IM) |= UART_IM_RXIM | UART_IM_RTIM;
130
131 // enable
132 HWREG(UART0_BASE + UART_O_CTL) = UART_CTL_UARTEN | UART_CTL_TXE | UART_CTL_RXE;
133
134 // enable interrupts
135 HWREG(NVIC_EN0) = 1 << ((INT_UART0 - 16) & 31);
136
137 return OT_ERROR_NONE;
138 }
139
otPlatUartDisable(void)140 otError otPlatUartDisable(void)
141 {
142 return OT_ERROR_NONE;
143 }
144
otPlatUartSend(const uint8_t * aBuf,uint16_t aBufLength)145 otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
146 {
147 otError error = OT_ERROR_NONE;
148
149 otEXPECT_ACTION(sTransmitBuffer == NULL, error = OT_ERROR_BUSY);
150
151 sTransmitBuffer = aBuf;
152 sTransmitLength = aBufLength;
153
154 exit:
155 return error;
156 }
157
processReceive(void)158 void processReceive(void)
159 {
160 // Copy tail to prevent multiple reads
161 uint16_t tail = sReceive.mTail;
162
163 // If the data wraps around, process the first part
164 if (sReceive.mHead > tail)
165 {
166 otPlatUartReceived(sReceive.mBuffer + sReceive.mHead, kReceiveBufferSize - sReceive.mHead);
167
168 // Reset the buffer mHead back to zero.
169 sReceive.mHead = 0;
170 }
171
172 // For any data remaining, process it
173 if (sReceive.mHead != tail)
174 {
175 otPlatUartReceived(sReceive.mBuffer + sReceive.mHead, tail - sReceive.mHead);
176
177 // Set mHead to the local tail we have cached
178 sReceive.mHead = tail;
179 }
180 }
181
otPlatUartFlush(void)182 otError otPlatUartFlush(void)
183 {
184 otEXPECT(sTransmitBuffer != NULL);
185
186 for (; sTransmitLength > 0; sTransmitLength--)
187 {
188 while (HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF)
189 ;
190
191 HWREG(UART0_BASE + UART_O_DR) = *sTransmitBuffer++;
192 }
193
194 sTransmitBuffer = NULL;
195 return OT_ERROR_NONE;
196
197 exit:
198 return OT_ERROR_INVALID_STATE;
199 }
200
processTransmit(void)201 void processTransmit(void)
202 {
203 otPlatUartFlush();
204 otPlatUartSendDone();
205 }
206
cc2538UartProcess(void)207 void cc2538UartProcess(void)
208 {
209 processReceive();
210 processTransmit();
211 }
212
UART0IntHandler(void)213 void UART0IntHandler(void)
214 {
215 uint32_t mis;
216 uint8_t byte;
217
218 mis = HWREG(UART0_BASE + UART_O_MIS);
219 HWREG(UART0_BASE + UART_O_ICR) = mis;
220
221 if (mis & (UART_IM_RXIM | UART_IM_RTIM))
222 {
223 while (!(HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE))
224 {
225 byte = HWREG(UART0_BASE + UART_O_DR);
226
227 // We can only write if incrementing mTail doesn't equal mHead
228 if (sReceive.mHead != (sReceive.mTail + 1) % kReceiveBufferSize)
229 {
230 sReceive.mBuffer[sReceive.mTail] = byte;
231 sReceive.mTail = (sReceive.mTail + 1) % kReceiveBufferSize;
232 }
233 }
234 }
235 }
236
237 #if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART
238
otPlatDebugUart_kbhit(void)239 int otPlatDebugUart_kbhit(void)
240 {
241 uint32_t v;
242
243 /* get flags */
244 v = HWREG(UART1_BASE + UART_O_FR);
245
246 /* if FIFO empty we have no data */
247 return !(v & UART_FR_RXFE);
248 }
249
otPlatDebugUart_getc(void)250 int otPlatDebugUart_getc(void)
251 {
252 int v = 1;
253
254 /* if nothing in fifo */
255 if (!otPlatDebugUart_kbhit())
256 {
257 return -1;
258 }
259
260 /* fetch */
261 v = (int)HWREG(UART0_BASE + UART_O_DR);
262 v = (v & 0x0ff);
263 return v;
264 }
265
otPlatDebugUart_putchar_raw(int b)266 void otPlatDebugUart_putchar_raw(int b)
267 {
268 /* wait till not busy */
269 while (HWREG(UART1_BASE + UART_O_FR) & UART_FR_TXFF)
270 ;
271
272 /* write byte */
273 HWREG(UART1_BASE + UART_O_DR) = ((uint32_t)(b & 0x0ff));
274 }
275
cc2538DebugUartInit(void)276 void cc2538DebugUartInit(void)
277 {
278 int32_t a, b;
279
280 // clocks
281 enable_uart_clocks();
282
283 HWREG(UART1_BASE + UART_O_CC) = 0;
284
285 // UART1 - tx pin
286 // Using an RF06 Evaluation board
287 // http://www.ti.com/tool/cc2538dk
288 // PA3 => is jumper position RF1.14
289 // To use these, you will require a "flying-lead" UART adapter
290 HWREG(IOC_PA3_SEL) = IOC_MUX_OUT_SEL_UART1_TXD;
291 HWREG(IOC_PA3_OVER) = IOC_OVERRIDE_OE;
292 HWREG(GPIO_A_BASE + GPIO_O_AFSEL) |= GPIO_PIN_3;
293
294 // UART1 - rx pin we don't really use but we setup anyway
295 // PA2 => is jumper position RF1.16
296 HWREG(IOC_UARTRXD_UART1) = IOC_PAD_IN_SEL_PA2;
297 HWREG(IOC_PA2_OVER) = IOC_OVERRIDE_DIS;
298 HWREG(GPIO_A_BASE + GPIO_O_AFSEL) |= GPIO_PIN_2;
299
300 HWREG(UART1_BASE + UART_O_CC) = 0;
301
302 // baud rate
303 b = (((kPlatformClock * 8) / kBaudRate) + 1) / 2;
304 a = b / 64;
305 b = b % 64;
306
307 HWREG(UART1_BASE + UART_O_IBRD) = a;
308 HWREG(UART1_BASE + UART_O_FBRD) = b;
309 HWREG(UART1_BASE + UART_O_LCRH) = UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE;
310
311 /* NOTE:
312 * uart1 is not using IRQs it is tx only
313 * and we block when writing bytes
314 */
315 HWREG(UART1_BASE + UART_O_CTL) = UART_CTL_UARTEN | UART_CTL_TXE | UART_CTL_RXE;
316 }
317
318 #endif
319