]> git.gir.st - tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KLXX/TARGET_KL46Z/serial_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_Freescale / TARGET_KLXX / TARGET_KL46Z / 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 #include "mbed_assert.h"
17 #include "serial_api.h"
18
19 // math.h required for floating point operations for baud rate calculation
20 #include <math.h>
21
22 #include <string.h>
23
24 #include "cmsis.h"
25 #include "pinmap.h"
26 #include "clk_freqs.h"
27 #include "PeripheralPins.h"
28
29 //Devices either user UART0 or UARTLP
30 #ifndef UARTLP_BASES
31 #define UARTLP_C2_RE_MASK UART0_C2_RE_MASK
32 #define UARTLP_C2_TE_MASK UART0_C2_TE_MASK
33 #define UARTLP_BDH_SBNS_MASK UART0_BDH_SBNS_MASK
34 #define UARTLP_BDH_SBNS_SHIFT UART0_BDH_SBNS_SHIFT
35 #define UARTLP_S1_TDRE_MASK UART0_S1_TDRE_MASK
36 #define UARTLP_S1_OR_MASK UART0_S1_OR_MASK
37 #define UARTLP_C2_RIE_MASK UART0_C2_RIE_MASK
38 #define UARTLP_C2_TIE_MASK UART0_C2_TIE_MASK
39 #define UARTLP_C2_SBK_MASK UART0_C2_SBK_MASK
40 #define UARTLP_S1_RDRF_MASK UART0_S1_RDRF_MASK
41 #endif
42
43 #ifdef UART2
44 #define UART_NUM 3
45 #else
46 #define UART_NUM 1
47 #endif
48
49 /******************************************************************************
50 * INITIALIZATION
51 ******************************************************************************/
52
53 static uint32_t serial_irq_ids[UART_NUM] = {0};
54 static uart_irq_handler irq_handler;
55
56 int stdio_uart_inited = 0;
57 serial_t stdio_uart;
58
59 void serial_init(serial_t *obj, PinName tx, PinName rx) {
60 // determine the UART to use
61 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
62 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
63 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
64 MBED_ASSERT((int)uart != NC);
65
66 obj->uart = (UARTLP_Type *)uart;
67 // enable clk
68 switch (uart) {
69 case UART_0: if (mcgpllfll_frequency() != 0) //PLL/FLL is selected
70 SIM->SOPT2 |= (1<<SIM_SOPT2_UART0SRC_SHIFT);
71 else
72 SIM->SOPT2 |= (2<<SIM_SOPT2_UART0SRC_SHIFT);
73 SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
74 #if UART_NUM > 1
75 case UART_1: SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
76 case UART_2: SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;
77 #endif
78 }
79 // Disable UART before changing registers
80 obj->uart->C2 &= ~(UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
81
82 switch (uart) {
83 case UART_0: obj->index = 0; break;
84 #if UART_NUM > 1
85 case UART_1: obj->index = 1; break;
86 case UART_2: obj->index = 2; break;
87 #endif
88 }
89
90 // set default baud rate and format
91 serial_baud (obj, 9600);
92 serial_format(obj, 8, ParityNone, 1);
93
94 // pinout the chosen uart
95 pinmap_pinout(tx, PinMap_UART_TX);
96 pinmap_pinout(rx, PinMap_UART_RX);
97
98 // set rx/tx pins in PullUp mode
99 if (tx != NC) {
100 pin_mode(tx, PullUp);
101 }
102 if (rx != NC) {
103 pin_mode(rx, PullUp);
104 }
105
106 obj->uart->C2 |= (UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
107
108 if (uart == STDIO_UART) {
109 stdio_uart_inited = 1;
110 memcpy(&stdio_uart, obj, sizeof(serial_t));
111 }
112 }
113
114 void serial_free(serial_t *obj) {
115 serial_irq_ids[obj->index] = 0;
116 }
117
118 // serial_baud
119 //
120 // set the baud rate, taking in to account the current SystemFrequency
121 void serial_baud(serial_t *obj, int baudrate) {
122
123 // save C2 state
124 uint8_t c2_state = (obj->uart->C2 & (UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK));
125
126 // Disable UART before changing registers
127 obj->uart->C2 &= ~(UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
128
129 uint32_t PCLK;
130 if (obj->uart == UART0) {
131 if (mcgpllfll_frequency() != 0)
132 PCLK = mcgpllfll_frequency();
133 else
134 PCLK = extosc_frequency();
135 } else
136 PCLK = bus_frequency();
137
138 // First we check to see if the basic divide with no DivAddVal/MulVal
139 // ratio gives us an integer result. If it does, we set DivAddVal = 0,
140 // MulVal = 1. Otherwise, we search the valid ratio value range to find
141 // the closest match. This could be more elegant, using search methods
142 // and/or lookup tables, but the brute force method is not that much
143 // slower, and is more maintainable.
144 uint16_t DL = PCLK / (16 * baudrate);
145
146 // set BDH and BDL
147 obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f);
148 obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff);
149
150 // restore C2 state
151 obj->uart->C2 |= c2_state;
152 }
153
154 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
155 MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
156 MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven));
157 MBED_ASSERT(data_bits == 8); // TODO: Support other number of data bits (also in the write method!)
158
159 // save C2 state
160 uint8_t c2_state = (obj->uart->C2 & (UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK));
161
162 // Disable UART before changing registers
163 obj->uart->C2 &= ~(UARTLP_C2_RE_MASK | UARTLP_C2_TE_MASK);
164
165
166 uint8_t parity_enable, parity_select;
167 switch (parity) {
168 case ParityNone: parity_enable = 0; parity_select = 0; break;
169 case ParityOdd : parity_enable = 1; parity_select = 1; data_bits++; break;
170 case ParityEven: parity_enable = 1; parity_select = 0; data_bits++; break;
171 default:
172 break;
173 }
174
175 stop_bits -= 1;
176
177 // data bits, parity and parity mode
178 obj->uart->C1 = ((parity_enable << 1)
179 | (parity_select << 0));
180
181 // stop bits
182 obj->uart->BDH &= ~UARTLP_BDH_SBNS_MASK;
183 obj->uart->BDH |= (stop_bits << UARTLP_BDH_SBNS_SHIFT);
184
185 // restore C2 state
186 obj->uart->C2 |= c2_state;
187 }
188
189 /******************************************************************************
190 * INTERRUPTS HANDLING
191 ******************************************************************************/
192 static inline void uart_irq(uint8_t status, uint32_t index) {
193 if (serial_irq_ids[index] != 0) {
194 if (status & UARTLP_S1_TDRE_MASK)
195 irq_handler(serial_irq_ids[index], TxIrq);
196
197 if (status & UARTLP_S1_RDRF_MASK)
198 irq_handler(serial_irq_ids[index], RxIrq);
199 }
200 }
201
202 void uart0_irq() {
203 uart_irq(UART0->S1, 0);
204 if (UART0->S1 & UARTLP_S1_OR_MASK)
205 UART0->S1 |= UARTLP_S1_OR_MASK;
206 }
207 #if UART_NUM > 1
208 void uart1_irq() {uart_irq(UART1->S1, 1);}
209 void uart2_irq() {uart_irq(UART2->S1, 2);}
210 #endif
211
212 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
213 irq_handler = handler;
214 serial_irq_ids[obj->index] = id;
215 }
216
217 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
218 IRQn_Type irq_n = (IRQn_Type)0;
219 uint32_t vector = 0;
220 switch ((int)obj->uart) {
221 case UART_0: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
222 #if UART_NUM > 1
223 case UART_1: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
224 case UART_2: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
225 #endif
226 }
227
228 if (enable) {
229 switch (irq) {
230 case RxIrq: obj->uart->C2 |= (UARTLP_C2_RIE_MASK); break;
231 case TxIrq: obj->uart->C2 |= (UARTLP_C2_TIE_MASK); break;
232 }
233 NVIC_SetVector(irq_n, vector);
234 NVIC_EnableIRQ(irq_n);
235
236 } else { // disable
237 int all_disabled = 0;
238 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
239 switch (irq) {
240 case RxIrq: obj->uart->C2 &= ~(UARTLP_C2_RIE_MASK); break;
241 case TxIrq: obj->uart->C2 &= ~(UARTLP_C2_TIE_MASK); break;
242 }
243 switch (other_irq) {
244 case RxIrq: all_disabled = (obj->uart->C2 & (UARTLP_C2_RIE_MASK)) == 0; break;
245 case TxIrq: all_disabled = (obj->uart->C2 & (UARTLP_C2_TIE_MASK)) == 0; break;
246 }
247 if (all_disabled)
248 NVIC_DisableIRQ(irq_n);
249 }
250 }
251
252 /******************************************************************************
253 * READ/WRITE
254 ******************************************************************************/
255 int serial_getc(serial_t *obj) {
256 while (!serial_readable(obj));
257 return obj->uart->D;
258 }
259
260 void serial_putc(serial_t *obj, int c) {
261 while (!serial_writable(obj));
262 obj->uart->D = c;
263 }
264
265 int serial_readable(serial_t *obj) {
266 // check overrun
267 if (obj->uart->S1 & UARTLP_S1_OR_MASK) {
268 obj->uart->S1 |= UARTLP_S1_OR_MASK;
269 }
270 return (obj->uart->S1 & UARTLP_S1_RDRF_MASK);
271 }
272
273 int serial_writable(serial_t *obj) {
274 // check overrun
275 if (obj->uart->S1 & UARTLP_S1_OR_MASK) {
276 obj->uart->S1 |= UARTLP_S1_OR_MASK;
277 }
278 return (obj->uart->S1 & UARTLP_S1_TDRE_MASK);
279 }
280
281 void serial_clear(serial_t *obj) {
282 }
283
284 void serial_pinout_tx(PinName tx) {
285 pinmap_pinout(tx, PinMap_UART_TX);
286 }
287
288 void serial_break_set(serial_t *obj) {
289 obj->uart->C2 |= UARTLP_C2_SBK_MASK;
290 }
291
292 void serial_break_clear(serial_t *obj) {
293 obj->uart->C2 &= ~UARTLP_C2_SBK_MASK;
294 }
295
Imprint / Impressum