]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC82X/serial_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.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