]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC81X/serial_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC81X / 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 /******************************************************************************
27  * INITIALIZATION
28  ******************************************************************************/
29 #define UART_NUM    3
30
31 static const SWM_Map SWM_UART_TX[] = {
32     {0, 0},
33     {1, 8},
34     {2, 16},
35 };
36
37 static const SWM_Map SWM_UART_RX[] = {
38     {0, 8},
39     {1, 16},
40     {2, 24},
41 };
42
43 static const SWM_Map SWM_UART_RTS[] = {
44     {0, 16},
45     {1, 24},
46     {3, 0},
47 };
48  
49 static const SWM_Map SWM_UART_CTS[] = {
50     {0, 24},
51     {2, 0},
52     {3, 8}
53 };
54
55 // bit flags for used UARTs
56 static unsigned char uart_used = 0;
57 static int get_available_uart(void) {
58     int i;
59     for (i=0; i<3; i++) {
60         if ((uart_used & (1 << i)) == 0)
61             return i;
62     }
63     return -1;
64 }
65
66 #define UART_EN       (0x01<<0)
67
68 #define CTS_DELTA     (0x01<<5)
69 #define RXBRK         (0x01<<10)
70 #define DELTA_RXBRK   (0x01<<11)
71
72 #define RXRDY         (0x01<<0)
73 #define TXRDY         (0x01<<2)
74
75 #define TXBRKEN       (0x01<<1)
76 #define CTSEN         (0x01<<9)
77
78 static uint32_t UARTSysClk;
79
80 static uint32_t serial_irq_ids[UART_NUM] = {0};
81 static uart_irq_handler irq_handler;
82
83 int stdio_uart_inited = 0;
84 serial_t stdio_uart;
85
86 void serial_init(serial_t *obj, PinName tx, PinName rx) {
87     int is_stdio_uart = 0;
88     
89     int uart_n = get_available_uart();
90     if (uart_n == -1) {
91         error("No available UART");
92     }
93     obj->index = uart_n;
94     obj->uart = (LPC_USART_TypeDef *)(LPC_USART0_BASE + (0x4000 * uart_n));
95     uart_used |= (1 << uart_n);
96     
97     const SWM_Map *swm;
98     uint32_t regVal;
99     
100     swm = &SWM_UART_TX[uart_n];
101     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
102     LPC_SWM->PINASSIGN[swm->n] = regVal |  (tx   << swm->offset);
103     
104     swm = &SWM_UART_RX[uart_n];
105     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
106     LPC_SWM->PINASSIGN[swm->n] = regVal |  (rx   << swm->offset);
107     
108     /* uart clock divided by 1 */
109     LPC_SYSCON->UARTCLKDIV = 1;
110     
111     /* disable uart interrupts */
112     NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
113     
114     /* Enable UART clock */
115     LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (14 + uart_n));
116     
117     /* Peripheral reset control to UART, a "1" bring it out of reset. */
118     LPC_SYSCON->PRESETCTRL &= ~(0x1 << (3 + uart_n));
119     LPC_SYSCON->PRESETCTRL |=  (0x1 << (3 + uart_n));
120
121     // Derive UART Clock from MainClock    
122     UARTSysClk = MainClock / LPC_SYSCON->UARTCLKDIV;    
123
124     // set default baud rate and format
125     serial_baud  (obj, 9600);
126     serial_format(obj, 8, ParityNone, 1);
127     
128     /* Clear all status bits. */
129     obj->uart->STAT = CTS_DELTA | DELTA_RXBRK;
130     
131     /* enable uart interrupts */
132     NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
133     
134     /* Enable UART interrupt */
135     // obj->uart->INTENSET = RXRDY | TXRDY | DELTA_RXBRK;
136     
137     /* Enable UART */
138     obj->uart->CFG |= UART_EN;
139     
140     is_stdio_uart = ((tx == USBTX) && (rx == USBRX));
141     
142     if (is_stdio_uart) {
143         stdio_uart_inited = 1;
144         memcpy(&stdio_uart, obj, sizeof(serial_t));
145     }
146 }
147
148 void serial_free(serial_t *obj) {
149     uart_used &= ~(1 << obj->index);
150     serial_irq_ids[obj->index] = 0;
151 }
152
153 // serial_baud
154 // set the baud rate, taking in to account the current SystemFrequency
155 void serial_baud(serial_t *obj, int baudrate) {
156     /* Integer divider:
157          BRG = UARTSysClk/(Baudrate * 16) - 1
158        
159        Frational divider:
160          FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
161        
162        where
163          FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
164        
165        (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
166            register is 0xFF.
167        (2) In ADD register value, depending on the value of UartSysClk,
168            baudrate, BRG register value, and SUB register value, be careful
169            about the order of multiplier and divider and make sure any
170            multiplier doesn't exceed 32-bit boundary and any divider doesn't get
171            down below one(integer 0).
172        (3) ADD should be always less than SUB.
173     */
174     obj->uart->BRG = UARTSysClk / 16 / baudrate - 1;
175     
176     LPC_SYSCON->UARTFRGDIV = 0xFF;
177     LPC_SYSCON->UARTFRGMULT = ( ((UARTSysClk / 16) * (LPC_SYSCON->UARTFRGDIV + 1)) /
178                                 (baudrate * (obj->uart->BRG + 1))
179                               ) - (LPC_SYSCON->UARTFRGDIV + 1);
180
181 }
182
183 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
184     // 0: 1 stop bits, 1: 2 stop bits
185     MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
186     MBED_ASSERT((data_bits > 6) && (data_bits < 10)); // 0: 7 data bits ... 2: 9 data bits
187     MBED_ASSERT((parity == ParityNone) || (parity == ParityEven) || (parity == ParityOdd));
188     stop_bits -= 1;
189     data_bits -= 7;
190     
191     int paritysel;
192     switch (parity) {
193         case ParityNone: paritysel = 0; break;
194         case ParityEven: paritysel = 2; break;
195         case ParityOdd : paritysel = 3; break;
196         default:
197             break;
198     }
199     
200     obj->uart->CFG = (data_bits << 2)
201                    | (paritysel << 4)
202                    | (stop_bits << 6);
203 }
204
205 /******************************************************************************
206  * INTERRUPTS HANDLING
207  ******************************************************************************/
208 static inline void uart_irq(uint32_t iir, uint32_t index) {
209     // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
210     SerialIrq irq_type;
211     switch (iir) {
212         case 1: irq_type = TxIrq; break;
213         case 2: irq_type = RxIrq; break;
214         default: return;
215     }
216     
217     if (serial_irq_ids[index] != 0)
218         irq_handler(serial_irq_ids[index], irq_type);
219 }
220
221 void uart0_irq() {uart_irq((LPC_USART0->STAT & (1 << 2)) ? 2 : 1, 0);}
222 void uart1_irq() {uart_irq((LPC_USART1->STAT & (1 << 2)) ? 2 : 1, 1);}
223 void uart2_irq() {uart_irq((LPC_USART2->STAT & (1 << 2)) ? 2 : 1, 2);}
224
225 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
226     irq_handler = handler;
227     serial_irq_ids[obj->index] = id;
228 }
229
230 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
231     IRQn_Type irq_n = (IRQn_Type)0;
232     uint32_t vector = 0;
233     switch ((int)obj->uart) {
234         case LPC_USART0_BASE: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
235         case LPC_USART1_BASE: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
236         case LPC_USART2_BASE: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
237     }
238     
239     if (enable) {
240         obj->uart->INTENSET = (1 << ((irq == RxIrq) ? 0 : 2));
241         NVIC_SetVector(irq_n, vector);
242         NVIC_EnableIRQ(irq_n);
243     } else { // disable
244         int all_disabled = 0;
245         SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
246         obj->uart->INTENSET &= ~(1 << ((irq == RxIrq) ? 0 : 2));
247         all_disabled = (obj->uart->INTENSET & (1 << ((other_irq == RxIrq) ? 0 : 2))) == 0;
248         if (all_disabled)
249             NVIC_DisableIRQ(irq_n);
250     }
251 }
252
253 /******************************************************************************
254  * READ/WRITE
255  ******************************************************************************/
256 int serial_getc(serial_t *obj) {
257     while (!serial_readable(obj));
258     return obj->uart->RXDATA;
259 }
260
261 void serial_putc(serial_t *obj, int c) {
262     while (!serial_writable(obj));
263     obj->uart->TXDATA = c;
264 }
265
266 int serial_readable(serial_t *obj) {
267     return obj->uart->STAT & RXRDY;
268 }
269
270 int serial_writable(serial_t *obj) {
271     return obj->uart->STAT & TXRDY;
272 }
273
274 void serial_clear(serial_t *obj) {
275     // [TODO]
276 }
277
278 void serial_pinout_tx(PinName tx) {
279     
280 }
281
282 void serial_break_set(serial_t *obj) {
283     obj->uart->CTRL |= TXBRKEN;
284 }
285
286 void serial_break_clear(serial_t *obj) {
287     obj->uart->CTRL &= ~TXBRKEN;
288 }
289
290 void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
291     const SWM_Map *swm_rts, *swm_cts;
292     uint32_t regVal_rts, regVal_cts;
293     
294     swm_rts = &SWM_UART_RTS[obj->index];
295     swm_cts = &SWM_UART_CTS[obj->index];
296     regVal_rts = LPC_SWM->PINASSIGN[swm_rts->n] & ~(0xFF << swm_rts->offset);
297     regVal_cts = LPC_SWM->PINASSIGN[swm_cts->n] & ~(0xFF << swm_cts->offset);
298     
299     if (FlowControlNone == type) {
300         LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset);
301         LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset);
302         obj->uart->CFG &= ~CTSEN;
303         return;
304     }
305     if ((FlowControlRTS == type || FlowControlRTSCTS == type) && (rxflow != NC)) {
306         LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (rxflow << swm_rts->offset);
307         if (FlowControlRTS == type) {
308             LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset);
309             obj->uart->CFG &= ~CTSEN;
310         }
311     }
312     if ((FlowControlCTS == type || FlowControlRTSCTS == type) && (txflow != NC)) {
313         LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (txflow << swm_cts->offset);
314         obj->uart->CFG |= CTSEN;
315         if (FlowControlCTS == type) {
316             LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset);
317         }
318     }
319 }
320