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 // math.h required for floating point operations for baud rate calculation
17 #include "mbed_assert.h"
21 #include "serial_api.h"
24 #include "mbed_error.h"
26 /******************************************************************************
28 ******************************************************************************/
31 static const SWM_Map SWM_UART_TX[] = {
37 static const SWM_Map SWM_UART_RX[] = {
43 static const SWM_Map SWM_UART_RTS[] = {
49 static const SWM_Map SWM_UART_CTS[] = {
55 // bit flags for used UARTs
56 static unsigned char uart_used = 0;
57 static int get_available_uart(void) {
60 if ((uart_used & (1 << i)) == 0)
66 #define UART_EN (0x01<<0)
68 #define CTS_DELTA (0x01<<5)
69 #define RXBRK (0x01<<10)
70 #define DELTA_RXBRK (0x01<<11)
72 #define RXRDY (0x01<<0)
73 #define TXRDY (0x01<<2)
75 #define TXBRKEN (0x01<<1)
76 #define CTSEN (0x01<<9)
78 static uint32_t UARTSysClk;
80 static uint32_t serial_irq_ids[UART_NUM] = {0};
81 static uart_irq_handler irq_handler;
83 int stdio_uart_inited = 0;
86 void serial_init(serial_t *obj, PinName tx, PinName rx) {
87 int is_stdio_uart = 0;
89 int uart_n = get_available_uart();
91 error("No available UART");
94 obj->uart = (LPC_USART_TypeDef *)(LPC_USART0_BASE + (0x4000 * uart_n));
95 uart_used |= (1 << uart_n);
100 swm = &SWM_UART_TX[uart_n];
101 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
102 LPC_SWM->PINASSIGN[swm->n] = regVal | (tx << swm->offset);
104 swm = &SWM_UART_RX[uart_n];
105 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
106 LPC_SWM->PINASSIGN[swm->n] = regVal | (rx << swm->offset);
108 /* uart clock divided by 1 */
109 LPC_SYSCON->UARTCLKDIV = 1;
111 /* disable uart interrupts */
112 NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
114 /* Enable UART clock */
115 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (14 + uart_n));
117 /* Peripheral reset control to UART, a "1" bring it out of reset. */
118 LPC_SYSCON->PRESETCTRL &= ~(0x1 << (3 + uart_n));
119 LPC_SYSCON->PRESETCTRL |= (0x1 << (3 + uart_n));
121 // Derive UART Clock from MainClock
122 UARTSysClk = MainClock / LPC_SYSCON->UARTCLKDIV;
124 // set default baud rate and format
125 serial_baud (obj, 9600);
126 serial_format(obj, 8, ParityNone, 1);
128 /* Clear all status bits. */
129 obj->uart->STAT = CTS_DELTA | DELTA_RXBRK;
131 /* enable uart interrupts */
132 NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + uart_n));
134 /* Enable UART interrupt */
135 // obj->uart->INTENSET = RXRDY | TXRDY | DELTA_RXBRK;
138 obj->uart->CFG |= UART_EN;
140 is_stdio_uart = ((tx == USBTX) && (rx == USBRX));
143 stdio_uart_inited = 1;
144 memcpy(&stdio_uart, obj, sizeof(serial_t));
148 void serial_free(serial_t *obj) {
149 uart_used &= ~(1 << obj->index);
150 serial_irq_ids[obj->index] = 0;
154 // set the baud rate, taking in to account the current SystemFrequency
155 void serial_baud(serial_t *obj, int baudrate) {
157 BRG = UARTSysClk/(Baudrate * 16) - 1
160 FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
163 FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
165 (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
167 (2) In ADD register value, depending on the value of UartSysClk,
168 baudrate, BRG register value, and SUB register value, be careful
169 about the order of multiplier and divider and make sure any
170 multiplier doesn't exceed 32-bit boundary and any divider doesn't get
171 down below one(integer 0).
172 (3) ADD should be always less than SUB.
174 obj->uart->BRG = UARTSysClk / 16 / baudrate - 1;
176 LPC_SYSCON->UARTFRGDIV = 0xFF;
177 LPC_SYSCON->UARTFRGMULT = ( ((UARTSysClk / 16) * (LPC_SYSCON->UARTFRGDIV + 1)) /
178 (baudrate * (obj->uart->BRG + 1))
179 ) - (LPC_SYSCON->UARTFRGDIV + 1);
183 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
184 // 0: 1 stop bits, 1: 2 stop bits
185 MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
186 MBED_ASSERT((data_bits > 6) && (data_bits < 10)); // 0: 7 data bits ... 2: 9 data bits
187 MBED_ASSERT((parity == ParityNone) || (parity == ParityEven) || (parity == ParityOdd));
193 case ParityNone: paritysel = 0; break;
194 case ParityEven: paritysel = 2; break;
195 case ParityOdd : paritysel = 3; break;
200 obj->uart->CFG = (data_bits << 2)
205 /******************************************************************************
206 * INTERRUPTS HANDLING
207 ******************************************************************************/
208 static inline void uart_irq(uint32_t iir, uint32_t index) {
209 // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
212 case 1: irq_type = TxIrq; break;
213 case 2: irq_type = RxIrq; break;
217 if (serial_irq_ids[index] != 0)
218 irq_handler(serial_irq_ids[index], irq_type);
221 void uart0_irq() {uart_irq((LPC_USART0->STAT & (1 << 2)) ? 2 : 1, 0);}
222 void uart1_irq() {uart_irq((LPC_USART1->STAT & (1 << 2)) ? 2 : 1, 1);}
223 void uart2_irq() {uart_irq((LPC_USART2->STAT & (1 << 2)) ? 2 : 1, 2);}
225 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
226 irq_handler = handler;
227 serial_irq_ids[obj->index] = id;
230 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
231 IRQn_Type irq_n = (IRQn_Type)0;
233 switch ((int)obj->uart) {
234 case LPC_USART0_BASE: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
235 case LPC_USART1_BASE: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
236 case LPC_USART2_BASE: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
240 obj->uart->INTENSET = (1 << ((irq == RxIrq) ? 0 : 2));
241 NVIC_SetVector(irq_n, vector);
242 NVIC_EnableIRQ(irq_n);
244 int all_disabled = 0;
245 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
246 obj->uart->INTENSET &= ~(1 << ((irq == RxIrq) ? 0 : 2));
247 all_disabled = (obj->uart->INTENSET & (1 << ((other_irq == RxIrq) ? 0 : 2))) == 0;
249 NVIC_DisableIRQ(irq_n);
253 /******************************************************************************
255 ******************************************************************************/
256 int serial_getc(serial_t *obj) {
257 while (!serial_readable(obj));
258 return obj->uart->RXDATA;
261 void serial_putc(serial_t *obj, int c) {
262 while (!serial_writable(obj));
263 obj->uart->TXDATA = c;
266 int serial_readable(serial_t *obj) {
267 return obj->uart->STAT & RXRDY;
270 int serial_writable(serial_t *obj) {
271 return obj->uart->STAT & TXRDY;
274 void serial_clear(serial_t *obj) {
278 void serial_pinout_tx(PinName tx) {
282 void serial_break_set(serial_t *obj) {
283 obj->uart->CTRL |= TXBRKEN;
286 void serial_break_clear(serial_t *obj) {
287 obj->uart->CTRL &= ~TXBRKEN;
290 void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) {
291 const SWM_Map *swm_rts, *swm_cts;
292 uint32_t regVal_rts, regVal_cts;
294 swm_rts = &SWM_UART_RTS[obj->index];
295 swm_cts = &SWM_UART_CTS[obj->index];
296 regVal_rts = LPC_SWM->PINASSIGN[swm_rts->n] & ~(0xFF << swm_rts->offset);
297 regVal_cts = LPC_SWM->PINASSIGN[swm_cts->n] & ~(0xFF << swm_cts->offset);
299 if (FlowControlNone == type) {
300 LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset);
301 LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset);
302 obj->uart->CFG &= ~CTSEN;
305 if ((FlowControlRTS == type || FlowControlRTSCTS == type) && (rxflow != NC)) {
306 LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (rxflow << swm_rts->offset);
307 if (FlowControlRTS == type) {
308 LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (0xFF << swm_cts->offset);
309 obj->uart->CFG &= ~CTSEN;
312 if ((FlowControlCTS == type || FlowControlRTSCTS == type) && (txflow != NC)) {
313 LPC_SWM->PINASSIGN[swm_cts->n] = regVal_cts | (txflow << swm_cts->offset);
314 obj->uart->CFG |= CTSEN;
315 if (FlowControlCTS == type) {
316 LPC_SWM->PINASSIGN[swm_rts->n] = regVal_rts | (0xFF << swm_rts->offset);