| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
uart_17xx_40xx.c
Go to the documentation of this file.
1 /*
2 * @brief LPC17xx/40xx UART chip driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licensor disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31
32 #include "chip.h"
33
34 /*****************************************************************************
35 * Private types/enumerations/variables
36 ****************************************************************************/
37
39 static UART_RingBuffer_T rb;
40
42 static __IO FlagStatus TxIntStat;
43
44 FlagStatus ABsyncSts = RESET;
45
46 /*****************************************************************************
47 * Public types/enumerations/variables
48 ****************************************************************************/
49
50 /*****************************************************************************
51 * Private functions
52 ****************************************************************************/
53
54 /* Get UART number based on selected UART */
55 static IP_UART_ID_T Chip_UART_Get_UARTNum(LPC_USART_T *pUART)
56 {
57 if (pUART == LPC_UART0) {
58 return UART_0;
59 }
60 else if (pUART == LPC_UART1) {
61 return UART_1;
62 }
63 else if (pUART == LPC_UART2) {
64 return UART_2;
65 }
66 else if (pUART == LPC_UART3) {
67 return UART_3;
68 }
69
70 return UART_4;
71 }
72
73 /* Determine UART clock based in selected UART */
74 static CHIP_SYSCTL_CLOCK_T Chip_UART_DetermineClk(LPC_USART_T *pUART) {
75 CHIP_SYSCTL_CLOCK_T uartclk;
76
77 /* Pick clock for uart BASED ON SELECTED uart */
78 if (pUART == LPC_UART1) {
79 uartclk = SYSCTL_CLOCK_UART1;
80 }
81 else if (pUART == LPC_UART2) {
82 uartclk = SYSCTL_CLOCK_UART2;
83 }
84 else if (pUART == LPC_UART3) {
85 uartclk = SYSCTL_CLOCK_UART3;
86 }
87 #if !defined(CHIP_LPC175X_6X)
88 else if (pUART == LPC_UART4) {
89 uartclk = SYSCTL_CLOCK_UART4;
90 }
91 #endif
92 else {
93 uartclk = SYSCTL_CLOCK_UART0;
94 }
95 return uartclk;
96 }
97
98 static uint32_t Chip_UART_GetClockRate(LPC_USART_T *pUART) {
99 #if !defined(CHIP_LPC175X_6X)
100 return Chip_Clock_GetPeripheralClockRate();
101 #else
102 /* Pick clock for uart BASED ON SELECTED uart */
103 if (pUART == LPC_UART1) {
104 return Chip_Clock_GetPeripheralClockRate(SYSCTL_PCLK_UART1);
105 }
106 else if (pUART == LPC_UART2) {
107 return Chip_Clock_GetPeripheralClockRate(SYSCTL_PCLK_UART2);
108 }
109 else if (pUART == LPC_UART3) {
110 return Chip_Clock_GetPeripheralClockRate(SYSCTL_PCLK_UART3);
111 }
112 else {
113 return Chip_Clock_GetPeripheralClockRate(SYSCTL_PCLK_UART0);
114 }
115 #endif
116 }
117
118 /*****************************************************************************
119 * Public functions
120 ****************************************************************************/
121
122 /* Initializes the pUART peripheral */
123 void Chip_UART_Init(LPC_USART_T *pUART)
124 {
125 IP_UART_ID_T UARTPort = Chip_UART_Get_UARTNum(pUART);
126
127 /* Enable UART clocking. UART base clock(s) must already be enabled */
128 Chip_Clock_EnablePeriphClock(Chip_UART_DetermineClk(pUART));
129
130 IP_UART_Init(pUART, UARTPort);
131 }
132
133 /* De-initializes the pUART peripheral */
134 void Chip_UART_DeInit(LPC_USART_T *pUART)
135 {
136 IP_UART_ID_T UARTPort = Chip_UART_Get_UARTNum(pUART);
137
138 IP_UART_DeInit(pUART, UARTPort);
139
140 /* Disable UART clocking */
141 Chip_Clock_DisablePeriphClock(Chip_UART_DetermineClk(pUART));
142 }
143
144 /* Determines best dividers to get a target baud rate */
145 Status Chip_UART_SetBaud(LPC_USART_T *pUART, uint32_t baudrate)
146 {
147 uint32_t uClk;
148
149 /* Get UART clock rate */
150 uClk = Chip_UART_GetClockRate(pUART);
151
152 return IP_UART_SetBaud(pUART, baudrate, uClk);
153 }
154
155 /* Enable/Disable transmission on UART TxD pin */
156 void Chip_UART_TxCmd(LPC_USART_T *pUART, FunctionalState NewState)
157 {
158 IP_UART_ID_T UARTPort = Chip_UART_Get_UARTNum(pUART);
159
160 IP_UART_TxCmd(pUART, UARTPort, NewState);
161 }
162
163 /* Get Interrupt Stream Status */
164 IP_UART_INT_STATUS_T Chip_UART_GetIntStatus(LPC_USART_T *pUART)
165 {
166 uint32_t intsrc, tmp, tmp1;
167 IP_UART_INT_STATUS_T ret = UART_INTSTS_ERROR;
168
169 /* Determine the interrupt source */
170 intsrc = Chip_UART_IntGetStatus(pUART);
171
172 tmp = intsrc & UART_IIR_INTID_MASK;
173
174 /* Receive Line Status */
175 if (tmp == UART_IIR_INTID_RLS) {
176 /* Check line status */
177 tmp1 = (uint32_t) Chip_UART_GetLineStatus(pUART);
178 /* Mask out the Receive Ready and Transmit Holding empty status */
179 tmp1 &= (UART_LSR_OE | UART_LSR_PE | UART_LSR_FE \
180 | UART_LSR_BI | UART_LSR_RXFE);
181 /* If any error exist */
182 if (tmp1) {
183 return UART_INTSTS_ERROR;
184 }
185 }
186
187 /* Receive Data Available or Character time-out */
188 if ((tmp == UART_IIR_INTID_RDA) || (tmp == UART_IIR_INTID_CTI)) {
189 ret |= UART_INTSTS_RTR;
190 }
191
192 /* Transmit Holding Empty */
193 if (tmp == UART_IIR_INTID_THRE) {
194 ret |= UART_INTSTS_RTS;
195 }
196
197 if (intsrc & UART_IIR_ABEO_INT) {
198 ret |= UART_INTSTS_ABEO;
199 }
200 else if (intsrc & UART_IIR_ABTO_INT) {
201 ret |= UART_INTSTS_ABTO;
202 }
203 return ret;
204 }
205
206 /* UART interrupt service routine */
207 void Chip_UART_Interrupt_Handler(LPC_USART_T *pUART)
208 {
209 uint8_t tmpc;
210 uint32_t rLen;
211 IP_UART_INT_STATUS_T Sts = Chip_UART_GetIntStatus(pUART);
212 if (Sts == UART_INTSTS_ERROR) {
213 return; /* error */
214 }
215 if (Sts & UART_INTSTS_RTR) { /* ready for Read Data */
216 while (1) {
217 /* Call UART read function in UART driver */
218 rLen = Chip_UART_Receive(pUART, &tmpc, 1, NONE_BLOCKING);
219 /* If data received */
220 if (rLen) {
221 /* Check if buffer is more space
222 * If no more space, remaining character will be trimmed out
223 */
224 if (!__BUF_IS_FULL(rb.rx_head, rb.rx_tail)) {
225 rb.rx[rb.rx_head] = tmpc;
226 __BUF_INCR(rb.rx_head);
227 }
228 }
229 /* no more data */
230 else {
231 break;
232 }
233 }
234 }
235
236 if (Sts & UART_INTSTS_RTS) { /* ready for Write Data */
237 /* Disable THRE interrupt */
238 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, DISABLE);
239
240 /* Wait for FIFO buffer empty, transfer UART_TX_FIFO_SIZE bytes
241 * of data or break whenever ring buffers are empty */
242 /* Wait until THR empty */
243 while (Chip_UART_CheckBusy(pUART) == SET) {}
244
245 while (!__BUF_IS_EMPTY(rb.tx_head, rb.tx_tail)) {
246 /* Move a piece of data into the transmit FIFO */
247 if (Chip_UART_Send(pUART, (uint8_t *) &rb.tx[rb.tx_tail], 1, NONE_BLOCKING)) {
248 /* Update transmit ring FIFO tail pointer */
249 __BUF_INCR(rb.tx_tail);
250 }
251 else {
252 break;
253 }
254 }
255
256 /* If there is no more data to send, disable the transmit
257 interrupt - else enable it or keep it enabled */
258 if (__BUF_IS_EMPTY(rb.tx_head, rb.tx_tail)) {
259 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, DISABLE);
260 // Reset Tx Interrupt state
261 TxIntStat = RESET;
262 }
263 else {
264 /* Set Tx Interrupt state */
265 TxIntStat = SET;
266 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, ENABLE);
267 }
268 }
269
270 if (Sts & UART_INTSTS_ABEO) {
271 Chip_UART_ABClearIntPending(pUART, UART_INTSTS_ABEO);
272 }
273 if (Sts & UART_INTSTS_ABTO) {
274 Chip_UART_ABClearIntPending(pUART, UART_INTSTS_ABTO);
275 }
276 if (ABsyncSts == RESET) {
277 /* Interrupt caused by End of auto-baud */
278 if (Sts & UART_INTSTS_ABEO) {
279 // Disable AB interrupt
280 Chip_UART_IntConfig(pUART, UART_INTCFG_ABEO, DISABLE);
281 // Set Sync flag
282 ABsyncSts = SET;
283 }
284
285 /* Auto-Baudrate Time-Out interrupt (not implemented) */
286 if (Sts & UART_INTSTS_ABTO) {
287 /* Disable this interrupt - Add your code here */
288 Chip_UART_IntConfig(pUART, UART_INTCFG_ABTO, DISABLE);
289 }
290 }
291 }
292
293 /* UART transmit function for interrupt mode (using ring buffers) */
294 uint32_t Chip_UART_Interrupt_Transmit(LPC_USART_T *pUART, uint8_t *txbuf, uint8_t buflen)
295 {
296 uint8_t *data = (uint8_t *) txbuf;
297 uint32_t bytes = 0;
298
299 /* Temporarily lock out UART transmit interrupts during this
300 read so the UART transmit interrupt won't cause problems
301 with the index values */
302 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, DISABLE);
303
304 /* Loop until transmit run buffer is full or until n_bytes
305 expires */
306 while ((buflen > 0) && (!__BUF_IS_FULL(rb.tx_head, rb.tx_tail))) {
307 /* Write data from buffer into ring buffer */
308 rb.tx[rb.tx_head] = *data;
309 data++;
310
311 /* Increment head pointer */
312 __BUF_INCR(rb.tx_head);
313
314 /* Increment data count and decrement buffer size count */
315 bytes++;
316 buflen--;
317 }
318
319 /*
320 * Check if current Tx interrupt enable is reset,
321 * that means the Tx interrupt must be re-enabled
322 * due to call UART_IntTransmit() function to trigger
323 * this interrupt type
324 */
325 if (TxIntStat == RESET) {
326 // Disable THRE interrupt
327 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, DISABLE);
328
329 /* Wait for FIFO buffer empty, transfer UART_TX_FIFO_SIZE bytes
330 * of data or break whenever ring buffers are empty */
331 /* Wait until THR empty */
332 while (Chip_UART_CheckBusy(pUART) == SET) {}
333
334 while (!__BUF_IS_EMPTY(rb.tx_head, rb.tx_tail)) {
335 /* Move a piece of data into the transmit FIFO */
336 if (Chip_UART_Send(pUART, (uint8_t *) &rb.tx[rb.tx_tail], 1, NONE_BLOCKING)) {
337 /* Update transmit ring FIFO tail pointer */
338 __BUF_INCR(rb.tx_tail);
339 }
340 else {
341 break;
342 }
343 }
344
345 /* If there is no more data to send, disable the transmit
346 interrupt - else enable it or keep it enabled */
347 if (__BUF_IS_EMPTY(rb.tx_head, rb.tx_tail)) {
348 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, DISABLE);
349 /* Reset Tx Interrupt state */
350 TxIntStat = RESET;
351 }
352 else {
353 /* Set Tx Interrupt state */
354 TxIntStat = SET;
355 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, ENABLE);
356 }
357 }
358 /*
359 * Otherwise, re-enables Tx Interrupt
360 */
361 else {
362 Chip_UART_IntConfig(pUART, UART_INTCFG_THRE, ENABLE);
363 }
364
365 return bytes;
366 }
367
368 /* UART read function for interrupt mode (using ring buffers) */
369 uint32_t Chip_UART_Interrupt_Receive(LPC_USART_T *pUART, uint8_t *rxbuf, uint8_t buflen)
370 {
371 uint8_t *data = (uint8_t *) rxbuf;
372 uint32_t bytes = 0;
373
374 /* Temporarily lock out UART receive interrupts during this
375 read so the UART receive interrupt won't cause problems
376 with the index values */
377 Chip_UART_IntConfig(pUART, UART_INTCFG_RBR, DISABLE);
378
379 /* Loop until receive buffer ring is empty or
380 until max_bytes expires */
381 while ((buflen > 0) && (!(__BUF_IS_EMPTY(rb.rx_head, rb.rx_tail)))) {
382 /* Read data from ring buffer into user buffer */
383 *data = rb.rx[rb.rx_tail];
384 data++;
385
386 /* Update tail pointer */
387 __BUF_INCR(rb.rx_tail);
388
389 /* Increment data count and decrement buffer size count */
390 bytes++;
391 buflen--;
392 }
393
394 /* Re-enable UART interrupts */
395 Chip_UART_IntConfig(pUART, UART_INTCFG_RBR, ENABLE);
396
397 return bytes;
398 }
399
400 /* Reset Tx and Rx ring buffer (head and tail) */
401 void Chip_UART_InitRingBuffer(LPC_USART_T *pUART)
402 {
403 (void) pUART;
404
405 TxIntStat = RESET;
406
407 /* Reset ring buf head and tail idx */
408 __BUF_RESET(rb.rx_head);
409 __BUF_RESET(rb.rx_tail);
410 __BUF_RESET(rb.tx_head);
411 __BUF_RESET(rb.tx_tail);
412 }
413
414 /* UART interrupt service routine */
415 FlagStatus Chip_UART_GetABEOStatus(LPC_USART_T *pUART)
416 {
417 (void) pUART;
418
419 return ABsyncSts;
420 }