1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 ARM Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "mbed_assert.h"
17 #include "serial_api.h"
19 // math.h required for floating point operations for baud rate calculation
26 #include "clk_freqs.h"
27 #include "PeripheralPins.h"
29 //Devices either user UART0 or UARTLP
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
49 /******************************************************************************
51 ******************************************************************************/
53 static uint32_t serial_irq_ids
[UART_NUM
] = {0};
54 static uart_irq_handler irq_handler
;
56 int stdio_uart_inited
= 0;
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
);
66 obj
->uart
= (UARTLP_Type
*)uart
;
69 case UART_0
: if (mcgpllfll_frequency() != 0) //PLL/FLL is selected
70 SIM
->SOPT2
|= (1<<SIM_SOPT2_UART0SRC_SHIFT
);
72 SIM
->SOPT2
|= (2<<SIM_SOPT2_UART0SRC_SHIFT
);
73 SIM
->SCGC4
|= SIM_SCGC4_UART0_MASK
; break;
75 case UART_1
: SIM
->SCGC4
|= SIM_SCGC4_UART1_MASK
; break;
76 case UART_2
: SIM
->SCGC4
|= SIM_SCGC4_UART2_MASK
; break;
79 // Disable UART before changing registers
80 obj
->uart
->C2
&= ~(UARTLP_C2_RE_MASK
| UARTLP_C2_TE_MASK
);
83 case UART_0
: obj
->index
= 0; break;
85 case UART_1
: obj
->index
= 1; break;
86 case UART_2
: obj
->index
= 2; break;
90 // set default baud rate and format
91 serial_baud (obj
, 9600);
92 serial_format(obj
, 8, ParityNone
, 1);
94 // pinout the chosen uart
95 pinmap_pinout(tx
, PinMap_UART_TX
);
96 pinmap_pinout(rx
, PinMap_UART_RX
);
98 // set rx/tx pins in PullUp mode
100 pin_mode(tx
, PullUp
);
103 pin_mode(rx
, PullUp
);
106 obj
->uart
->C2
|= (UARTLP_C2_RE_MASK
| UARTLP_C2_TE_MASK
);
108 if (uart
== STDIO_UART
) {
109 stdio_uart_inited
= 1;
110 memcpy(&stdio_uart
, obj
, sizeof(serial_t
));
114 void serial_free(serial_t
*obj
) {
115 serial_irq_ids
[obj
->index
] = 0;
120 // set the baud rate, taking in to account the current SystemFrequency
121 void serial_baud(serial_t
*obj
, int baudrate
) {
124 uint8_t c2_state
= (obj
->uart
->C2
& (UARTLP_C2_RE_MASK
| UARTLP_C2_TE_MASK
));
126 // Disable UART before changing registers
127 obj
->uart
->C2
&= ~(UARTLP_C2_RE_MASK
| UARTLP_C2_TE_MASK
);
130 if (obj
->uart
== UART0
) {
131 if (mcgpllfll_frequency() != 0)
132 PCLK
= mcgpllfll_frequency();
134 PCLK
= extosc_frequency();
136 PCLK
= bus_frequency();
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
);
147 obj
->uart
->BDH
= (obj
->uart
->BDH
& ~(0x1f)) | ((DL
>> 8) & 0x1f);
148 obj
->uart
->BDL
= (obj
->uart
->BDL
& ~(0xff)) | ((DL
>> 0) & 0xff);
151 obj
->uart
->C2
|= c2_state
;
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!)
160 uint8_t c2_state
= (obj
->uart
->C2
& (UARTLP_C2_RE_MASK
| UARTLP_C2_TE_MASK
));
162 // Disable UART before changing registers
163 obj
->uart
->C2
&= ~(UARTLP_C2_RE_MASK
| UARTLP_C2_TE_MASK
);
166 uint8_t parity_enable
, parity_select
;
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;
177 // data bits, parity and parity mode
178 obj
->uart
->C1
= ((parity_enable
<< 1)
179 | (parity_select
<< 0));
182 obj
->uart
->BDH
&= ~UARTLP_BDH_SBNS_MASK
;
183 obj
->uart
->BDH
|= (stop_bits
<< UARTLP_BDH_SBNS_SHIFT
);
186 obj
->uart
->C2
|= c2_state
;
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
);
197 if (status
& UARTLP_S1_RDRF_MASK
)
198 irq_handler(serial_irq_ids
[index
], RxIrq
);
203 uart_irq(UART0
->S1
, 0);
204 if (UART0
->S1
& UARTLP_S1_OR_MASK
)
205 UART0
->S1
|= UARTLP_S1_OR_MASK
;
208 void uart1_irq() {uart_irq(UART1
->S1
, 1);}
209 void uart2_irq() {uart_irq(UART2
->S1
, 2);}
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
;
217 void serial_irq_set(serial_t
*obj
, SerialIrq irq
, uint32_t enable
) {
218 IRQn_Type irq_n
= (IRQn_Type
)0;
220 switch ((int)obj
->uart
) {
221 case UART_0
: irq_n
=UART0_IRQn
; vector
= (uint32_t)&uart0_irq
; break;
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;
230 case RxIrq
: obj
->uart
->C2
|= (UARTLP_C2_RIE_MASK
); break;
231 case TxIrq
: obj
->uart
->C2
|= (UARTLP_C2_TIE_MASK
); break;
233 NVIC_SetVector(irq_n
, vector
);
234 NVIC_EnableIRQ(irq_n
);
237 int all_disabled
= 0;
238 SerialIrq other_irq
= (irq
== RxIrq
) ? (TxIrq
) : (RxIrq
);
240 case RxIrq
: obj
->uart
->C2
&= ~(UARTLP_C2_RIE_MASK
); break;
241 case TxIrq
: obj
->uart
->C2
&= ~(UARTLP_C2_TIE_MASK
); break;
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;
248 NVIC_DisableIRQ(irq_n
);
252 /******************************************************************************
254 ******************************************************************************/
255 int serial_getc(serial_t
*obj
) {
256 while (!serial_readable(obj
));
260 void serial_putc(serial_t
*obj
, int c
) {
261 while (!serial_writable(obj
));
265 int serial_readable(serial_t
*obj
) {
267 if (obj
->uart
->S1
& UARTLP_S1_OR_MASK
) {
268 obj
->uart
->S1
|= UARTLP_S1_OR_MASK
;
270 return (obj
->uart
->S1
& UARTLP_S1_RDRF_MASK
);
273 int serial_writable(serial_t
*obj
) {
275 if (obj
->uart
->S1
& UARTLP_S1_OR_MASK
) {
276 obj
->uart
->S1
|= UARTLP_S1_OR_MASK
;
278 return (obj
->uart
->S1
& UARTLP_S1_TDRE_MASK
);
281 void serial_clear(serial_t
*obj
) {
284 void serial_pinout_tx(PinName tx
) {
285 pinmap_pinout(tx
, PinMap_UART_TX
);
288 void serial_break_set(serial_t
*obj
) {
289 obj
->uart
->C2
|= UARTLP_C2_SBK_MASK
;
292 void serial_break_clear(serial_t
*obj
) {
293 obj
->uart
->C2
&= ~UARTLP_C2_SBK_MASK
;