]> git.gir.st - tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC82X/serial_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC82X / serial_api.c
1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 ARM Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 // math.h required for floating point operations for baud rate calculation
17 #include "mbed_assert.h"
18 #include <math.h>
19 #include <string.h>
20
21 #include "serial_api.h"
22 #include "cmsis.h"
23 #include "pinmap.h"
24 #include "mbed_error.h"
25
26 #if DEVICE_SERIAL
27
28 /******************************************************************************
29 * INITIALIZATION
30 ******************************************************************************/
31 #define UART_NUM 3
32
33 static const SWM_Map SWM_UART_TX[] = {
34 {0, 0},
35 {1, 8},
36 {2, 16},
37 };
38
39 static const SWM_Map SWM_UART_RX[] = {
40 {0, 8},
41 {1, 16},
42 {2, 24},
43 };
44
45 static const SWM_Map SWM_UART_RTS[] = {
46 {0, 16},
47 {1, 24},
48 {3, 0},
49 };
50
51 static const SWM_Map SWM_UART_CTS[] = {
52 {0, 24},
53 {2, 0},
54 {3, 8}
55 };
56
57 // bit flags for used UARTs
58 static unsigned char uart_used = 0;
59
60 static int get_available_uart(void)
61 {
62 int i;
63 for (i=0; i<UART_NUM; i++) {
64 if ((uart_used & (1 << i)) == 0)
65 return i;
66 }
67 return -1;
68 }
69
70 #define UART_EN (0x01<<0)
71
72 #define CTS_DELTA (0x01<<5)
73 #define RXBRK (0x01<<10)
74 #define DELTA_RXBRK (0x01<<11)
75
76 #define RXRDY (0x01<<0)
77 #define TXRDY (0x01<<2)
78
79 #define RXRDYEN RXRDY
80 #define TXRDYEN TXRDY
81
82 #define TXBRKEN (0x01<<1)
83 #define CTSEN (0x01<<9)
84
85 static uint32_t UARTSysClk;
86
87 static uint32_t serial_irq_ids[UART_NUM] = {0};
88 static uart_irq_handler irq_handler;
89
90 int stdio_uart_inited = 0;
91 serial_t stdio_uart;
92
93 static int check_duplication(serial_t *obj, PinName tx, PinName rx)
94 {
95 if (uart_used == 0)
96 return 0;
97
98 const SWM_Map *swm;
99 uint32_t assigned_tx, assigned_rx;
100 int ch;
101 for (ch=0; ch<UART_NUM; ch++) {
102 // read assigned TX in the UART channel of switch matrix
103 swm = &SWM_UART_TX[ch];
104 assigned_tx = LPC_SWM->PINASSIGN[swm->n] & (0xFF << swm->offset);
105 assigned_tx = assigned_tx >> swm->offset;
106 // read assigned RX in the UART channel of switch matrix
107 swm = &SWM_UART_RX[ch];
108 assigned_rx = LPC_SWM->PINASSIGN[swm->n] & (0xFF << swm->offset);
109 assigned_rx = assigned_rx >> swm->offset;
110 if ((assigned_tx == (uint32_t)(tx >> PIN_SHIFT)) && (assigned_rx == (uint32_t)(rx >> PIN_SHIFT))) {
111 obj->index = ch;
112 obj->uart = (LPC_USART0_Type *)(LPC_USART0_BASE + (0x4000 * ch));
113 return 1;
114 }
115 }
116 return 0;
117 }
118
119 void serial_init(serial_t *obj, PinName tx, PinName rx)
120 {
121 int is_stdio_uart = 0;
122
123 if (check_duplication(obj, tx, rx) == 1)
124 return;
125
126 int uart_n = get_available_uart();
127 if (uart_n == -1) {
128 error("No available UART");
129 }
130 obj->index = uart_n;
131 obj->uart = (LPC_USART0_Type *)(LPC_USART0_BASE + (0x4000 * uart_n));
132 uart_used |= (1 << uart_n);
133
134 const SWM_Map *swm;
135 uint32_t regVal;
136
137 swm = &SWM_UART_TX[uart_n];
138 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
139 LPC_SWM->PINASSIGN[swm->n] = regVal | ((tx >> PIN_SHIFT) << swm->offset);
140
141 swm = &SWM_UART_RX[uart_n];
142 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
143 LPC_SWM->PINASSIGN[swm->n] = regVal | ((rx >> PIN_SHIFT) << swm->offset);
144
145 /* uart clock divided by 1 */
146 LPC_SYSCON->UARTCLKDIV = 1;
147
148 /* disable uart interrupts */
149 NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
150
151 /* Enable UART clock */
152 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (14 + uart_n));
153
154 /* Peripheral reset control to UART, a "1" bring it out of reset. */
155 LPC_SYSCON->PRESETCTRL &= ~(0x1 << (3 + uart_n));
156 LPC_SYSCON->PRESETCTRL |= (0x1 << (3 + uart_n));
157
158 UARTSysClk = MainClock / LPC_SYSCON->UARTCLKDIV;
159
160 // set default baud rate and format
161 serial_baud (obj, 9600);
162 serial_format(obj, 8, ParityNone, 1);
163
164 /* Clear all status bits. */
165 obj->uart->STAT = CTS_DELTA | DELTA_RXBRK;
166
167 /* enable uart interrupts */
168 NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
169
170 /* Enable UART */
171 obj->uart->CFG |= UART_EN;
172
173 is_stdio_uart = ((tx == USBTX) && (rx == USBRX));
174
175 if (is_stdio_uart) {
176 stdio_uart_inited = 1;
177 memcpy(&stdio_uart, obj, sizeof(serial_t));
178 }
179 }
180
181 void serial_free(serial_t *obj)
182 {
183 uart_used &= ~(1 << obj->index);
184 serial_irq_ids[obj->index] = 0;
185 }
186
187 void serial_baud(serial_t *obj, int baudrate)
188 {
189 /* Integer divider:
190 BRG = UARTSysClk/(Baudrate * 16) - 1
191
192 Frational divider:
193 FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
194
195 where
196 FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
197
198 (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
199 register is 0xFF.
200 (2) In ADD register value, depending on the value of UartSysClk,
201 baudrate, BRG register value, and SUB register value, be careful
202 about the order of multiplier and divider and make sure any
203 multiplier doesn't exceed 32-bit boundary and any divider doesn't get
204 down below one(integer 0).
205 (3) ADD should be always less than SUB.
206 */
207 obj->uart->BRG = UARTSysClk / 16 / baudrate - 1;
208
209 LPC_SYSCON->UARTFRGDIV = 0xFF;
210 LPC_SYSCON->UARTFRGMULT = ( ((UARTSysClk / 16) * (LPC_SYSCON->UARTFRGDIV + 1)) /
211 (baudrate * (obj->uart->BRG + 1))
212 ) - (LPC_SYSCON->UARTFRGDIV + 1);
213 }
214
215 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
216 {
217 // 0: 1 stop bits, 1: 2 stop bits
218 MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
219 MBED_ASSERT((data_bits > 6) && (data_bits < 10)); // 0: 7 data bits ... 2: 9 data bits
220 MBED_ASSERT((parity == ParityNone) || (parity == ParityEven) || (parity == ParityOdd));
221 stop_bits -= 1;
222 data_bits -= 7;
223
224 int paritysel = 0;
225 switch (parity) {
226 case ParityNone: paritysel = 0; break;
227 case ParityEven: paritysel = 2; break;
228 case ParityOdd : paritysel = 3; break;
229 default:
230 break;
231 }
232
233 obj->uart->CFG = (data_bits << 2)
234 | (paritysel << 4)
235 | (stop_bits << 6);
236 }
237
238 /******************************************************************************
239 * INTERRUPTS HANDLING
240 ******************************************************************************/
241 static inline void uart_irq(SerialIrq irq_type, uint32_t index)
242 {
243 if (serial_irq_ids[index] != 0)
244 irq_handler(serial_irq_ids[index], irq_type);
245 }
246
247 void uart0_irq() {uart_irq((LPC_USART0->INTSTAT & RXRDY) ? RxIrq : TxIrq, 0);}
248 void uart1_irq() {uart_irq((LPC_USART1->INTSTAT & RXRDY) ? RxIrq : TxIrq, 1);}
249 void uart2_irq() {uart_irq((LPC_USART2->INTSTAT & RXRDY) ? RxIrq : TxIrq, 2);}
250
251 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
252 {
253 irq_handler = handler;
254 serial_irq_ids[obj->index] = id;
255 }
256
257 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
258 {
259 IRQn_Type irq_n = (IRQn_Type)0;
260 uint32_t vector = 0;
261 switch ((int)obj->uart) {
262 case LPC_USART0_BASE: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
263 case LPC_USART1_BASE: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
264 case LPC_USART2_BASE: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
265 }
266
267 if (enable) {
268 NVIC_DisableIRQ(irq_n);
269 obj->uart->INTENSET |= (1 << ((irq == RxIrq) ? 0 : 2));
270 NVIC_SetVector(irq_n, vector);
271 NVIC_EnableIRQ(irq_n);
272 } else { // disable
273 obj->uart->INTENCLR |= (1 << ((irq == RxIrq) ? 0 : 2));
274 if ( (obj->uart->INTENSET & (RXRDYEN | TXRDYEN)) == 0) {
275 NVIC_DisableIRQ(irq_n);
276 }
277 }
278 }
279
280 /******************************************************************************
281 * READ/WRITE
282 ******************************************************************************/
283 int serial_getc(serial_t *obj)
284 {
285 while (!serial_readable(obj));
286 return obj->uart->RXDAT;
287 }
288
289 void serial_putc(serial_t *obj, int c)
290 {
291 while (!serial_writable(obj));
292 obj->uart->TXDAT = c;
293 }
294
295 int serial_readable(serial_t *obj)
296 {
297 return obj->uart->STAT & RXRDY;
298 }
299
300 int serial_writable(serial_t *obj)
301 {
302 return obj->uart->STAT & TXRDY;
303 }
304
305 void serial_clear(serial_t *obj)
306 {
307 // [TODO]
308 }
309
310 void serial_pinout_tx(PinName tx)
311 {
312
313 }
314
315 void serial_break_set(serial_t *obj)
316 {
317 obj->uart->CTL |= TXBRKEN;
318 }
319
320 void serial_break_clear(serial_t *obj)
321 {
322 obj->uart->CTL &= ~TXBRKEN;
323 }
324
325 void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
326 {
327 const SWM_Map *swm_rts, *swm_cts;
328 uint32_t regVal_rts, regVal_cts;
329
330 swm_rts = &SWM_UART_RTS[obj->index];
331 swm_cts = &SWM_UART_CTS[obj->index];
332 regVal_rts = LPC_SWM->PINASSIGN[swm_rts->n] & ~(0xFF << swm_rts->offset);
333 regVal_cts = LPC_SWM->PINASSIGN[swm_cts->n] & ~(0xFF << swm_cts->offset);
334
335 if (FlowControlNone == type) {
336 LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset);
337 LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset);
338 obj->uart->CFG &= ~CTSEN;
339 return;
340 }
341 if ((FlowControlRTS == type || FlowControlRTSCTS == type) && (rxflow != NC)) {
342 LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | ((rxflow >> PIN_SHIFT) << swm_rts->offset);
343 if (FlowControlRTS == type) {
344 LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset);
345 obj->uart->CFG &= ~CTSEN;
346 }
347 }
348 if ((FlowControlCTS == type || FlowControlRTSCTS == type) && (txflow != NC)) {
349 LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | ((txflow >> PIN_SHIFT) << swm_cts->offset);
350 obj->uart->CFG |= CTSEN;
351 if (FlowControlCTS == type) {
352 LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset);
353 }
354 }
355 }
356
357 #endif
Imprint / Impressum