]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC15XX/serial_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC15XX / 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},  // Pin assign register0, 7:0bit
33     {1, 8},  // Pin assign register1, 15:8bit
34     {2, 16}, // Pin assign register2, 23:16bit
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}, // not available
47 };
48  
49 static const SWM_Map SWM_UART_CTS[] = {
50     {0, 24},
51     {2, 0},
52     {3, 8} // not available
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 static void switch_pin(const SWM_Map *swm, PinName pn)
87 {
88     uint32_t regVal;
89     if (pn != NC)
90     {
91         // check if we have any function mapped to this pin already and remove it
92         for (uint32_t n = 0; n < sizeof(LPC_SWM->PINASSIGN)/sizeof(*LPC_SWM->PINASSIGN); n ++) {
93             regVal = LPC_SWM->PINASSIGN[n];
94             for (uint32_t j = 0; j <= 24; j += 8) {
95                 if (((regVal >> j) & 0xFF) == (uint32_t)pn)
96                     regVal |= (0xFF << j);
97             }
98             LPC_SWM->PINASSIGN[n] = regVal;
99         }
100     }
101     // now map it
102     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
103     LPC_SWM->PINASSIGN[swm->n] = regVal |  (pn  << swm->offset);
104 }
105
106 void serial_init(serial_t *obj, PinName tx, PinName rx) {
107     int is_stdio_uart = 0;
108     
109     int uart_n = get_available_uart();
110     if (uart_n == -1) {
111         error("No available UART");
112     }
113     obj->index = uart_n;
114     switch (uart_n) {
115         case 0: obj->uart = (LPC_USART0_Type *)LPC_USART0_BASE; break;
116         case 1: obj->uart = (LPC_USART0_Type *)LPC_USART1_BASE; break;
117         case 2: obj->uart = (LPC_USART0_Type *)LPC_USART2_BASE; break;
118     }
119     uart_used |= (1 << uart_n);
120     
121     switch_pin(&SWM_UART_TX[uart_n], tx);
122     switch_pin(&SWM_UART_RX[uart_n], rx);
123     
124     /* uart clock divided by 6 */
125     LPC_SYSCON->UARTCLKDIV =6;
126     
127     /* disable uart interrupts */
128     NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
129     
130     /* Enable UART clock */
131     LPC_SYSCON->SYSAHBCLKCTRL1 |= (1 << (17 + uart_n));
132     
133     /* Peripheral reset control to UART, a "1" bring it out of reset. */
134     LPC_SYSCON->PRESETCTRL1 |=  (0x1 << (17 + uart_n));
135     LPC_SYSCON->PRESETCTRL1 &= ~(0x1 << (17 + uart_n));
136     
137     UARTSysClk = SystemCoreClock / LPC_SYSCON->UARTCLKDIV;
138     
139     // set default baud rate and format
140     serial_baud  (obj, 9600);
141     serial_format(obj, 8, ParityNone, 1);
142     
143     /* Clear all status bits. */
144     obj->uart->STAT = CTS_DELTA | DELTA_RXBRK;
145     
146     /* enable uart interrupts */
147     NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
148     
149     /* Enable UART */
150     obj->uart->CFG |= UART_EN;
151     
152     is_stdio_uart = ((tx == USBTX) && (rx == USBRX));
153     
154     if (is_stdio_uart) {
155         stdio_uart_inited = 1;
156         memcpy(&stdio_uart, obj, sizeof(serial_t));
157     }
158 }
159
160 void serial_free(serial_t *obj) {
161     uart_used &= ~(1 << obj->index);
162     serial_irq_ids[obj->index] = 0;
163 }
164
165 // serial_baud
166 // set the baud rate, taking in to account the current SystemFrequency
167 void serial_baud(serial_t *obj, int baudrate) {
168     /* Integer divider:
169          BRG = UARTSysClk/(Baudrate * 16) - 1
170        
171        Frational divider:
172          FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
173        
174        where
175          FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
176        
177        (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
178            register is 0xFF.
179        (2) In ADD register value, depending on the value of UartSysClk,
180            baudrate, BRG register value, and SUB register value, be careful
181            about the order of multiplier and divider and make sure any
182            multiplier doesn't exceed 32-bit boundary and any divider doesn't get
183            down below one(integer 0).
184        (3) ADD should be always less than SUB.
185     */
186     obj->uart->BRG = UARTSysClk / 16 / baudrate - 1;
187     
188     // To use of the fractional baud rate generator, you must write 0xFF to the DIV
189     // value to yield a denominator value of 256. All other values are not supported.
190     LPC_SYSCON->FRGCTRL = 0xFF;
191     
192     LPC_SYSCON->FRGCTRL |= ( ( ((UARTSysClk / 16) * (0xFF + 1)) /
193                                 (baudrate * (obj->uart->BRG + 1))
194                               ) - (0xFF + 1) ) << 8;
195
196 }
197
198 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
199     MBED_ASSERT((stop_bits == 1) || (stop_bits == 2)); // 0: 1 stop bits, 1: 2 stop bits
200     MBED_ASSERT((data_bits > 6) && (data_bits < 10)); // 0: 7 data bits ... 2: 9 data bits
201     MBED_ASSERT((parity == ParityNone) || (parity == ParityEven) || (parity == ParityOdd));
202
203     stop_bits -= 1;
204     data_bits -= 7;
205     
206     int paritysel;
207     switch (parity) {
208         case ParityNone: paritysel = 0; break;
209         case ParityEven: paritysel = 2; break;
210         case ParityOdd : paritysel = 3; break;
211         default:
212             break;
213     }
214
215     // First disable the the usart as described in documentation and then enable while updating CFG
216
217     // 24.6.1 USART Configuration register
218     // Remark: If software needs to change configuration values, the following sequence should
219     // be used: 1) Make sure the USART is not currently sending or receiving data. 2) Disable
220     // the USART by writing a 0 to the Enable bit (0 may be written to the entire register). 3)
221     // Write the new configuration value, with the ENABLE bit set to 1.
222     obj->uart->CFG &= ~(1 << 0);
223
224     obj->uart->CFG = (1 << 0) // this will enable the usart
225                    | (data_bits << 2)
226                    | (paritysel << 4)
227                    | (stop_bits << 6);
228 }
229
230 /******************************************************************************
231  * INTERRUPTS HANDLING
232  ******************************************************************************/
233 static inline void uart_irq(SerialIrq irq_type, uint32_t index) {
234     if (serial_irq_ids[index] != 0)
235         irq_handler(serial_irq_ids[index], irq_type);
236 }
237
238 void uart0_irq() {uart_irq((LPC_USART0->INTSTAT & 1) ? RxIrq : TxIrq, 0);}
239 void uart1_irq() {uart_irq((LPC_USART1->INTSTAT & 1) ? RxIrq : TxIrq, 1);}
240 void uart2_irq() {uart_irq((LPC_USART2->INTSTAT & 1) ? RxIrq : TxIrq, 2);}
241
242 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
243     irq_handler = handler;
244     serial_irq_ids[obj->index] = id;
245 }
246
247 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
248     IRQn_Type irq_n = (IRQn_Type)0;
249     uint32_t vector = 0;
250     switch ((int)obj->uart) {
251         case LPC_USART0_BASE: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
252         case LPC_USART1_BASE: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
253         case LPC_USART2_BASE: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
254     }
255     
256     if (enable) {
257         NVIC_DisableIRQ(irq_n);
258         obj->uart->INTENSET |= (1 << ((irq == RxIrq) ? 0 : 2));
259         NVIC_SetVector(irq_n, vector);
260         NVIC_EnableIRQ(irq_n);
261     } else { // disable
262         int all_disabled = 0;
263         SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
264         obj->uart->INTENCLR |= (1 << ((irq == RxIrq) ? 0 : 2)); // disable the interrupt
265         all_disabled = (obj->uart->INTENSET & (1 << ((other_irq == RxIrq) ? 0 : 2))) == 0;
266         if (all_disabled)
267             NVIC_DisableIRQ(irq_n);
268     }
269 }
270
271 /******************************************************************************
272  * READ/WRITE
273  ******************************************************************************/
274 int serial_getc(serial_t *obj) {
275     while (!serial_readable(obj));
276     return obj->uart->RXDATA;
277 }
278
279 void serial_putc(serial_t *obj, int c) {
280     while (!serial_writable(obj));
281     obj->uart->TXDATA = c;
282 }
283
284 int serial_readable(serial_t *obj) {
285     return obj->uart->STAT & RXRDY;
286 }
287
288 int serial_writable(serial_t *obj) {
289     return obj->uart->STAT & TXRDY;
290 }
291
292 void serial_clear(serial_t *obj) {
293     // [TODO]
294 }
295
296 void serial_pinout_tx(PinName tx) {
297     
298 }
299
300 void serial_break_set(serial_t *obj) {
301     obj->uart->CTRL |= TXBRKEN;
302 }
303
304 void serial_break_clear(serial_t *obj) {
305     obj->uart->CTRL &= ~TXBRKEN;
306 }
307
308 void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
309     if ((FlowControlNone == type || FlowControlRTS == type)) txflow = NC;
310     if ((FlowControlNone == type || FlowControlCTS == type)) rxflow = NC;
311     switch_pin(&SWM_UART_RTS[obj->index], rxflow);
312     switch_pin(&SWM_UART_CTS[obj->index], txflow);
313     if (txflow == NC) obj->uart->CFG &= ~CTSEN;
314     else              obj->uart->CFG |=  CTSEN;
315 }
316