• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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