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