]> git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC15XX/serial_api.c
Merge commit '1fe4406f374291ab2e86e95a97341fd9c475fcb8'
[tmk_keyboard.git] / tmk_core / 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
Imprint / Impressum