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
[] = {
32 {0, 0}, // Pin assign register0, 7:0bit
33 {1, 8}, // Pin assign register1, 15:8bit
34 {2, 16}, // Pin assign register2, 23:16bit
37 static const SWM_Map SWM_UART_RX
[] = {
43 static const SWM_Map SWM_UART_RTS
[] = {
46 {3, 0}, // not available
49 static const SWM_Map SWM_UART_CTS
[] = {
52 {3, 8} // not available
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 static void switch_pin(const SWM_Map
*swm
, PinName pn
)
91 // check if we have any function mapped to this pin already and remove it
92 for (uint32_t n
= 0; n
< sizeof(LPC_SWM
->PINASSIGN
)/sizeof(*LPC_SWM
->PINASSIGN
); n
++) {
93 regVal
= LPC_SWM
->PINASSIGN
[n
];
94 for (uint32_t j
= 0; j
<= 24; j
+= 8) {
95 if (((regVal
>> j
) & 0xFF) == (uint32_t)pn
)
96 regVal
|= (0xFF << j
);
98 LPC_SWM
->PINASSIGN
[n
] = regVal
;
102 regVal
= LPC_SWM
->PINASSIGN
[swm
->n
] & ~(0xFF << swm
->offset
);
103 LPC_SWM
->PINASSIGN
[swm
->n
] = regVal
| (pn
<< swm
->offset
);
106 void serial_init(serial_t
*obj
, PinName tx
, PinName rx
) {
107 int is_stdio_uart
= 0;
109 int uart_n
= get_available_uart();
111 error("No available UART");
115 case 0: obj
->uart
= (LPC_USART0_Type
*)LPC_USART0_BASE
; break;
116 case 1: obj
->uart
= (LPC_USART0_Type
*)LPC_USART1_BASE
; break;
117 case 2: obj
->uart
= (LPC_USART0_Type
*)LPC_USART2_BASE
; break;
119 uart_used
|= (1 << uart_n
);
121 switch_pin(&SWM_UART_TX
[uart_n
], tx
);
122 switch_pin(&SWM_UART_RX
[uart_n
], rx
);
124 /* uart clock divided by 6 */
125 LPC_SYSCON
->UARTCLKDIV
=6;
127 /* disable uart interrupts */
128 NVIC_DisableIRQ((IRQn_Type
)(UART0_IRQn
+ uart_n
));
130 /* Enable UART clock */
131 LPC_SYSCON
->SYSAHBCLKCTRL1
|= (1 << (17 + uart_n
));
133 /* Peripheral reset control to UART, a "1" bring it out of reset. */
134 LPC_SYSCON
->PRESETCTRL1
|= (0x1 << (17 + uart_n
));
135 LPC_SYSCON
->PRESETCTRL1
&= ~(0x1 << (17 + uart_n
));
137 UARTSysClk
= SystemCoreClock
/ LPC_SYSCON
->UARTCLKDIV
;
139 // set default baud rate and format
140 serial_baud (obj
, 9600);
141 serial_format(obj
, 8, ParityNone
, 1);
143 /* Clear all status bits. */
144 obj
->uart
->STAT
= CTS_DELTA
| DELTA_RXBRK
;
146 /* enable uart interrupts */
147 NVIC_EnableIRQ((IRQn_Type
)(UART0_IRQn
+ uart_n
));
150 obj
->uart
->CFG
|= UART_EN
;
152 is_stdio_uart
= ((tx
== USBTX
) && (rx
== USBRX
));
155 stdio_uart_inited
= 1;
156 memcpy(&stdio_uart
, obj
, sizeof(serial_t
));
160 void serial_free(serial_t
*obj
) {
161 uart_used
&= ~(1 << obj
->index
);
162 serial_irq_ids
[obj
->index
] = 0;
166 // set the baud rate, taking in to account the current SystemFrequency
167 void serial_baud(serial_t
*obj
, int baudrate
) {
169 BRG = UARTSysClk/(Baudrate * 16) - 1
172 FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
175 FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
177 (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
179 (2) In ADD register value, depending on the value of UartSysClk,
180 baudrate, BRG register value, and SUB register value, be careful
181 about the order of multiplier and divider and make sure any
182 multiplier doesn't exceed 32-bit boundary and any divider doesn't get
183 down below one(integer 0).
184 (3) ADD should be always less than SUB.
186 obj
->uart
->BRG
= UARTSysClk
/ 16 / baudrate
- 1;
188 // To use of the fractional baud rate generator, you must write 0xFF to the DIV
189 // value to yield a denominator value of 256. All other values are not supported.
190 LPC_SYSCON
->FRGCTRL
= 0xFF;
192 LPC_SYSCON
->FRGCTRL
|= ( ( ((UARTSysClk
/ 16) * (0xFF + 1)) /
193 (baudrate
* (obj
->uart
->BRG
+ 1))
194 ) - (0xFF + 1) ) << 8;
198 void serial_format(serial_t
*obj
, int data_bits
, SerialParity parity
, int stop_bits
) {
199 MBED_ASSERT((stop_bits
== 1) || (stop_bits
== 2)); // 0: 1 stop bits, 1: 2 stop bits
200 MBED_ASSERT((data_bits
> 6) && (data_bits
< 10)); // 0: 7 data bits ... 2: 9 data bits
201 MBED_ASSERT((parity
== ParityNone
) || (parity
== ParityEven
) || (parity
== ParityOdd
));
208 case ParityNone
: paritysel
= 0; break;
209 case ParityEven
: paritysel
= 2; break;
210 case ParityOdd
: paritysel
= 3; break;
215 // First disable the the usart as described in documentation and then enable while updating CFG
217 // 24.6.1 USART Configuration register
218 // Remark: If software needs to change configuration values, the following sequence should
219 // be used: 1) Make sure the USART is not currently sending or receiving data. 2) Disable
220 // the USART by writing a 0 to the Enable bit (0 may be written to the entire register). 3)
221 // Write the new configuration value, with the ENABLE bit set to 1.
222 obj
->uart
->CFG
&= ~(1 << 0);
224 obj
->uart
->CFG
= (1 << 0) // this will enable the usart
230 /******************************************************************************
231 * INTERRUPTS HANDLING
232 ******************************************************************************/
233 static inline void uart_irq(SerialIrq irq_type
, uint32_t index
) {
234 if (serial_irq_ids
[index
] != 0)
235 irq_handler(serial_irq_ids
[index
], irq_type
);
238 void uart0_irq() {uart_irq((LPC_USART0
->INTSTAT
& 1) ? RxIrq
: TxIrq
, 0);}
239 void uart1_irq() {uart_irq((LPC_USART1
->INTSTAT
& 1) ? RxIrq
: TxIrq
, 1);}
240 void uart2_irq() {uart_irq((LPC_USART2
->INTSTAT
& 1) ? RxIrq
: TxIrq
, 2);}
242 void serial_irq_handler(serial_t
*obj
, uart_irq_handler handler
, uint32_t id
) {
243 irq_handler
= handler
;
244 serial_irq_ids
[obj
->index
] = id
;
247 void serial_irq_set(serial_t
*obj
, SerialIrq irq
, uint32_t enable
) {
248 IRQn_Type irq_n
= (IRQn_Type
)0;
250 switch ((int)obj
->uart
) {
251 case LPC_USART0_BASE
: irq_n
=UART0_IRQn
; vector
= (uint32_t)&uart0_irq
; break;
252 case LPC_USART1_BASE
: irq_n
=UART1_IRQn
; vector
= (uint32_t)&uart1_irq
; break;
253 case LPC_USART2_BASE
: irq_n
=UART2_IRQn
; vector
= (uint32_t)&uart2_irq
; break;
257 NVIC_DisableIRQ(irq_n
);
258 obj
->uart
->INTENSET
|= (1 << ((irq
== RxIrq
) ? 0 : 2));
259 NVIC_SetVector(irq_n
, vector
);
260 NVIC_EnableIRQ(irq_n
);
262 int all_disabled
= 0;
263 SerialIrq other_irq
= (irq
== RxIrq
) ? (TxIrq
) : (RxIrq
);
264 obj
->uart
->INTENCLR
|= (1 << ((irq
== RxIrq
) ? 0 : 2)); // disable the interrupt
265 all_disabled
= (obj
->uart
->INTENSET
& (1 << ((other_irq
== RxIrq
) ? 0 : 2))) == 0;
267 NVIC_DisableIRQ(irq_n
);
271 /******************************************************************************
273 ******************************************************************************/
274 int serial_getc(serial_t
*obj
) {
275 while (!serial_readable(obj
));
276 return obj
->uart
->RXDATA
;
279 void serial_putc(serial_t
*obj
, int c
) {
280 while (!serial_writable(obj
));
281 obj
->uart
->TXDATA
= c
;
284 int serial_readable(serial_t
*obj
) {
285 return obj
->uart
->STAT
& RXRDY
;
288 int serial_writable(serial_t
*obj
) {
289 return obj
->uart
->STAT
& TXRDY
;
292 void serial_clear(serial_t
*obj
) {
296 void serial_pinout_tx(PinName tx
) {
300 void serial_break_set(serial_t
*obj
) {
301 obj
->uart
->CTRL
|= TXBRKEN
;
304 void serial_break_clear(serial_t
*obj
) {
305 obj
->uart
->CTRL
&= ~TXBRKEN
;
308 void serial_set_flow_control(serial_t
*obj
, FlowControl type
, PinName rxflow
, PinName txflow
) {
309 if ((FlowControlNone
== type
|| FlowControlRTS
== type
)) txflow
= NC
;
310 if ((FlowControlNone
== type
|| FlowControlCTS
== type
)) rxflow
= NC
;
311 switch_pin(&SWM_UART_RTS
[obj
->index
], rxflow
);
312 switch_pin(&SWM_UART_CTS
[obj
->index
], txflow
);
313 if (txflow
== NC
) obj
->uart
->CFG
&= ~CTSEN
;
314 else obj
->uart
->CFG
|= CTSEN
;