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"
28 /******************************************************************************
30 ******************************************************************************/
33 static const SWM_Map SWM_UART_TX
[] = {
39 static const SWM_Map SWM_UART_RX
[] = {
45 static const SWM_Map SWM_UART_RTS
[] = {
51 static const SWM_Map SWM_UART_CTS
[] = {
57 // bit flags for used UARTs
58 static unsigned char uart_used
= 0;
60 static int get_available_uart(void)
63 for (i
=0; i
<UART_NUM
; i
++) {
64 if ((uart_used
& (1 << i
)) == 0)
70 #define UART_EN (0x01<<0)
72 #define CTS_DELTA (0x01<<5)
73 #define RXBRK (0x01<<10)
74 #define DELTA_RXBRK (0x01<<11)
76 #define RXRDY (0x01<<0)
77 #define TXRDY (0x01<<2)
82 #define TXBRKEN (0x01<<1)
83 #define CTSEN (0x01<<9)
85 static uint32_t UARTSysClk
;
87 static uint32_t serial_irq_ids
[UART_NUM
] = {0};
88 static uart_irq_handler irq_handler
;
90 int stdio_uart_inited
= 0;
93 static int check_duplication(serial_t
*obj
, PinName tx
, PinName rx
)
99 uint32_t assigned_tx
, assigned_rx
;
101 for (ch
=0; ch
<UART_NUM
; ch
++) {
102 // read assigned TX in the UART channel of switch matrix
103 swm
= &SWM_UART_TX
[ch
];
104 assigned_tx
= LPC_SWM
->PINASSIGN
[swm
->n
] & (0xFF << swm
->offset
);
105 assigned_tx
= assigned_tx
>> swm
->offset
;
106 // read assigned RX in the UART channel of switch matrix
107 swm
= &SWM_UART_RX
[ch
];
108 assigned_rx
= LPC_SWM
->PINASSIGN
[swm
->n
] & (0xFF << swm
->offset
);
109 assigned_rx
= assigned_rx
>> swm
->offset
;
110 if ((assigned_tx
== (uint32_t)(tx
>> PIN_SHIFT
)) && (assigned_rx
== (uint32_t)(rx
>> PIN_SHIFT
))) {
112 obj
->uart
= (LPC_USART0_Type
*)(LPC_USART0_BASE
+ (0x4000 * ch
));
119 void serial_init(serial_t
*obj
, PinName tx
, PinName rx
)
121 int is_stdio_uart
= 0;
123 if (check_duplication(obj
, tx
, rx
) == 1)
126 int uart_n
= get_available_uart();
128 error("No available UART");
131 obj
->uart
= (LPC_USART0_Type
*)(LPC_USART0_BASE
+ (0x4000 * uart_n
));
132 uart_used
|= (1 << uart_n
);
137 swm
= &SWM_UART_TX
[uart_n
];
138 regVal
= LPC_SWM
->PINASSIGN
[swm
->n
] & ~(0xFF << swm
->offset
);
139 LPC_SWM
->PINASSIGN
[swm
->n
] = regVal
| ((tx
>> PIN_SHIFT
) << swm
->offset
);
141 swm
= &SWM_UART_RX
[uart_n
];
142 regVal
= LPC_SWM
->PINASSIGN
[swm
->n
] & ~(0xFF << swm
->offset
);
143 LPC_SWM
->PINASSIGN
[swm
->n
] = regVal
| ((rx
>> PIN_SHIFT
) << swm
->offset
);
145 /* uart clock divided by 1 */
146 LPC_SYSCON
->UARTCLKDIV
= 1;
148 /* disable uart interrupts */
149 NVIC_DisableIRQ((IRQn_Type
)(UART0_IRQn
+ uart_n
));
151 /* Enable UART clock */
152 LPC_SYSCON
->SYSAHBCLKCTRL
|= (1 << (14 + uart_n
));
154 /* Peripheral reset control to UART, a "1" bring it out of reset. */
155 LPC_SYSCON
->PRESETCTRL
&= ~(0x1 << (3 + uart_n
));
156 LPC_SYSCON
->PRESETCTRL
|= (0x1 << (3 + uart_n
));
158 UARTSysClk
= MainClock
/ LPC_SYSCON
->UARTCLKDIV
;
160 // set default baud rate and format
161 serial_baud (obj
, 9600);
162 serial_format(obj
, 8, ParityNone
, 1);
164 /* Clear all status bits. */
165 obj
->uart
->STAT
= CTS_DELTA
| DELTA_RXBRK
;
167 /* enable uart interrupts */
168 NVIC_EnableIRQ((IRQn_Type
)(UART0_IRQn
+ uart_n
));
171 obj
->uart
->CFG
|= UART_EN
;
173 is_stdio_uart
= ((tx
== USBTX
) && (rx
== USBRX
));
176 stdio_uart_inited
= 1;
177 memcpy(&stdio_uart
, obj
, sizeof(serial_t
));
181 void serial_free(serial_t
*obj
)
183 uart_used
&= ~(1 << obj
->index
);
184 serial_irq_ids
[obj
->index
] = 0;
187 void serial_baud(serial_t
*obj
, int baudrate
)
190 BRG = UARTSysClk/(Baudrate * 16) - 1
193 FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
196 FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
198 (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
200 (2) In ADD register value, depending on the value of UartSysClk,
201 baudrate, BRG register value, and SUB register value, be careful
202 about the order of multiplier and divider and make sure any
203 multiplier doesn't exceed 32-bit boundary and any divider doesn't get
204 down below one(integer 0).
205 (3) ADD should be always less than SUB.
207 obj
->uart
->BRG
= UARTSysClk
/ 16 / baudrate
- 1;
209 LPC_SYSCON
->UARTFRGDIV
= 0xFF;
210 LPC_SYSCON
->UARTFRGMULT
= ( ((UARTSysClk
/ 16) * (LPC_SYSCON
->UARTFRGDIV
+ 1)) /
211 (baudrate
* (obj
->uart
->BRG
+ 1))
212 ) - (LPC_SYSCON
->UARTFRGDIV
+ 1);
215 void serial_format(serial_t
*obj
, int data_bits
, SerialParity parity
, int stop_bits
)
217 // 0: 1 stop bits, 1: 2 stop bits
218 MBED_ASSERT((stop_bits
== 1) || (stop_bits
== 2));
219 MBED_ASSERT((data_bits
> 6) && (data_bits
< 10)); // 0: 7 data bits ... 2: 9 data bits
220 MBED_ASSERT((parity
== ParityNone
) || (parity
== ParityEven
) || (parity
== ParityOdd
));
226 case ParityNone
: paritysel
= 0; break;
227 case ParityEven
: paritysel
= 2; break;
228 case ParityOdd
: paritysel
= 3; break;
233 obj
->uart
->CFG
= (data_bits
<< 2)
238 /******************************************************************************
239 * INTERRUPTS HANDLING
240 ******************************************************************************/
241 static inline void uart_irq(SerialIrq irq_type
, uint32_t index
)
243 if (serial_irq_ids
[index
] != 0)
244 irq_handler(serial_irq_ids
[index
], irq_type
);
247 void uart0_irq() {uart_irq((LPC_USART0
->INTSTAT
& RXRDY
) ? RxIrq
: TxIrq
, 0);}
248 void uart1_irq() {uart_irq((LPC_USART1
->INTSTAT
& RXRDY
) ? RxIrq
: TxIrq
, 1);}
249 void uart2_irq() {uart_irq((LPC_USART2
->INTSTAT
& RXRDY
) ? RxIrq
: TxIrq
, 2);}
251 void serial_irq_handler(serial_t
*obj
, uart_irq_handler handler
, uint32_t id
)
253 irq_handler
= handler
;
254 serial_irq_ids
[obj
->index
] = id
;
257 void serial_irq_set(serial_t
*obj
, SerialIrq irq
, uint32_t enable
)
259 IRQn_Type irq_n
= (IRQn_Type
)0;
261 switch ((int)obj
->uart
) {
262 case LPC_USART0_BASE
: irq_n
=UART0_IRQn
; vector
= (uint32_t)&uart0_irq
; break;
263 case LPC_USART1_BASE
: irq_n
=UART1_IRQn
; vector
= (uint32_t)&uart1_irq
; break;
264 case LPC_USART2_BASE
: irq_n
=UART2_IRQn
; vector
= (uint32_t)&uart2_irq
; break;
268 NVIC_DisableIRQ(irq_n
);
269 obj
->uart
->INTENSET
|= (1 << ((irq
== RxIrq
) ? 0 : 2));
270 NVIC_SetVector(irq_n
, vector
);
271 NVIC_EnableIRQ(irq_n
);
273 obj
->uart
->INTENCLR
|= (1 << ((irq
== RxIrq
) ? 0 : 2));
274 if ( (obj
->uart
->INTENSET
& (RXRDYEN
| TXRDYEN
)) == 0) {
275 NVIC_DisableIRQ(irq_n
);
280 /******************************************************************************
282 ******************************************************************************/
283 int serial_getc(serial_t
*obj
)
285 while (!serial_readable(obj
));
286 return obj
->uart
->RXDAT
;
289 void serial_putc(serial_t
*obj
, int c
)
291 while (!serial_writable(obj
));
292 obj
->uart
->TXDAT
= c
;
295 int serial_readable(serial_t
*obj
)
297 return obj
->uart
->STAT
& RXRDY
;
300 int serial_writable(serial_t
*obj
)
302 return obj
->uart
->STAT
& TXRDY
;
305 void serial_clear(serial_t
*obj
)
310 void serial_pinout_tx(PinName tx
)
315 void serial_break_set(serial_t
*obj
)
317 obj
->uart
->CTL
|= TXBRKEN
;
320 void serial_break_clear(serial_t
*obj
)
322 obj
->uart
->CTL
&= ~TXBRKEN
;
325 void serial_set_flow_control(serial_t
*obj
, FlowControl type
, PinName rxflow
, PinName txflow
)
327 const SWM_Map
*swm_rts
, *swm_cts
;
328 uint32_t regVal_rts
, regVal_cts
;
330 swm_rts
= &SWM_UART_RTS
[obj
->index
];
331 swm_cts
= &SWM_UART_CTS
[obj
->index
];
332 regVal_rts
= LPC_SWM
->PINASSIGN
[swm_rts
->n
] & ~(0xFF << swm_rts
->offset
);
333 regVal_cts
= LPC_SWM
->PINASSIGN
[swm_cts
->n
] & ~(0xFF << swm_cts
->offset
);
335 if (FlowControlNone
== type
) {
336 LPC_SWM
->PINASSIGN
[swm_rts
->n
] = regVal_rts
| (0xFF << swm_rts
->offset
);
337 LPC_SWM
->PINASSIGN
[swm_cts
->n
] = regVal_cts
| (0xFF << swm_cts
->offset
);
338 obj
->uart
->CFG
&= ~CTSEN
;
341 if ((FlowControlRTS
== type
|| FlowControlRTSCTS
== type
) && (rxflow
!= NC
)) {
342 LPC_SWM
->PINASSIGN
[swm_rts
->n
] = regVal_rts
| ((rxflow
>> PIN_SHIFT
) << swm_rts
->offset
);
343 if (FlowControlRTS
== type
) {
344 LPC_SWM
->PINASSIGN
[swm_cts
->n
] = regVal_cts
| (0xFF << swm_cts
->offset
);
345 obj
->uart
->CFG
&= ~CTSEN
;
348 if ((FlowControlCTS
== type
|| FlowControlRTSCTS
== type
) && (txflow
!= NC
)) {
349 LPC_SWM
->PINASSIGN
[swm_cts
->n
] = regVal_cts
| ((txflow
>> PIN_SHIFT
) << swm_cts
->offset
);
350 obj
->uart
->CFG
|= CTSEN
;
351 if (FlowControlCTS
== type
) {
352 LPC_SWM
->PINASSIGN
[swm_rts
->n
] = regVal_rts
| (0xFF << swm_rts
->offset
);