LPCOpen Platform for LPC18XX/43XX microcontrollers: C:/w/lpcopen_docs/software/lpc_core/lpc_chip/chip_18xx_43xx/uart_18xx_43xx.c Source File

| LPCOpen Platform for LPC18XX/43XX microcontrollers 18XX43XX LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

uart_18xx_43xx.c
Go to the documentation of this file.
1 /*
2 * @brief LPC18xx/43xx 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
38 /* Autobaud status flag */
39 STATIC volatile FlagStatus ABsyncSts = RESET;
40
41 /*****************************************************************************
42 * Public types/enumerations/variables
43 ****************************************************************************/
44
45 /*****************************************************************************
46 * Private functions
47 ****************************************************************************/
48 /* UART Peripheral clocks */
49 static const CHIP_CCU_CLK_T UART_PClock[] = {CLK_MX_UART0, CLK_MX_UART1, CLK_MX_UART2, CLK_MX_UART3};
50
51 /* UART Bus clocks */
52 static const CHIP_CCU_CLK_T UART_BClock[] = {CLK_APB0_UART0, CLK_APB0_UART1, CLK_APB2_UART2, CLK_APB2_UART3};
53
54 /* Returns clock index for the peripheral block */
55 static int Chip_UART_GetIndex(LPC_USART_T *pUART)
56 {
57 uint32_t base = (uint32_t) pUART;
58 switch(base) {
59 case LPC_USART0_BASE:
60 return 0;
61 case LPC_UART1_BASE:
62 return 1;
63 case LPC_USART2_BASE:
64 return 2;
65 case LPC_USART3_BASE:
66 return 3;
67 default:
68 return 0; /* Should never come here */
69 }
70 }
71
72 /* UART Autobaud command interrupt handler */
73 STATIC void Chip_UART_ABIntHandler(LPC_USART_T *pUART)
74 {
75 /* Handle End Of Autobaud interrupt */
76 if((Chip_UART_ReadIntIDReg(pUART) & UART_IIR_ABEO_INT) != 0) {
77 Chip_UART_SetAutoBaudReg(pUART, UART_ACR_ABEOINT_CLR);
78 Chip_UART_IntDisable(pUART, UART_IER_ABEOINT);
79 if (ABsyncSts == RESET) {
80 ABsyncSts = SET;
81 }
82 }
83
84 /* Handle Autobaud Timeout interrupt */
85 if((Chip_UART_ReadIntIDReg(pUART) & UART_IIR_ABTO_INT) != 0) {
86 Chip_UART_SetAutoBaudReg(pUART, UART_ACR_ABTOINT_CLR);
87 Chip_UART_IntDisable(pUART, UART_IER_ABTOINT);
88 }
89 }
90
91 /*****************************************************************************
92 * Public functions
93 ****************************************************************************/
94
95 /* Initializes the pUART peripheral */
96 void Chip_UART_Init(LPC_USART_T *pUART)
97 {
98 volatile uint32_t tmp;
99
100 /* Enable UART clocking. UART base clock(s) must already be enabled */
101 Chip_Clock_EnableOpts(UART_PClock[Chip_UART_GetIndex(pUART)], true, true, 1);
102
103 /* Enable FIFOs by default, reset them */
104 Chip_UART_SetupFIFOS(pUART, (UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS));
105
106 /* Disable Tx */
107 Chip_UART_TXDisable(pUART);
108
109 /* Disable interrupts */
110 pUART->IER = 0;
111 /* Set LCR to default state */
112 pUART->LCR = 0;
113 /* Set ACR to default state */
114 pUART->ACR = 0;
115 /* Set RS485 control to default state */
116 pUART->RS485CTRL = 0;
117 /* Set RS485 delay timer to default state */
118 pUART->RS485DLY = 0;
119 /* Set RS485 addr match to default state */
120 pUART->RS485ADRMATCH = 0;
121
122 /* Clear MCR */
123 if (pUART == LPC_UART1) {
124 /* Set Modem Control to default state */
125 pUART->MCR = 0;
126 /*Dummy Reading to Clear Status */
127 tmp = pUART->MSR;
128 }
129
130 /* Default 8N1, with DLAB disabled */
131 Chip_UART_ConfigData(pUART, (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_DIS));
132
133 /* Disable fractional divider */
134 pUART->FDR = 0x10;
135 }
136
137 /* De-initializes the pUART peripheral */
138 void Chip_UART_DeInit(LPC_USART_T *pUART)
139 {
140 /* Disable Tx */
141 Chip_UART_TXDisable(pUART);
142
143 /* Disable clock */
144 Chip_Clock_Disable(UART_PClock[Chip_UART_GetIndex(pUART)]);
145 }
146
147 /* Transmit a byte array through the UART peripheral (non-blocking) */
148 int Chip_UART_Send(LPC_USART_T *pUART, const void *data, int numBytes)
149 {
150 int sent = 0;
151 uint8_t *p8 = (uint8_t *) data;
152
153 /* Send until the transmit FIFO is full or out of bytes */
154 while ((sent < numBytes) &&
155 ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) != 0)) {
156 Chip_UART_SendByte(pUART, *p8);
157 p8++;
158 sent++;
159 }
160
161 return sent;
162 }
163
164 /* Check whether if UART is busy or not */
165 FlagStatus Chip_UART_CheckBusy(LPC_USART_T *pUART)
166 {
167 if (pUART->LSR & UART_LSR_TEMT) {
168 return RESET;
169 }
170 else {
171 return SET;
172 }
173 }
174
175 /* Transmit a byte array through the UART peripheral (blocking) */
176 int Chip_UART_SendBlocking(LPC_USART_T *pUART, const void *data, int numBytes)
177 {
178 int pass, sent = 0;
179 uint8_t *p8 = (uint8_t *) data;
180
181 while (numBytes > 0) {
182 pass = Chip_UART_Send(pUART, p8, numBytes);
183 numBytes -= pass;
184 sent += pass;
185 p8 += pass;
186 }
187
188 return sent;
189 }
190
191 /* Read data through the UART peripheral (non-blocking) */
192 int Chip_UART_Read(LPC_USART_T *pUART, void *data, int numBytes)
193 {
194 int readBytes = 0;
195 uint8_t *p8 = (uint8_t *) data;
196
197 /* Send until the transmit FIFO is full or out of bytes */
198 while ((readBytes < numBytes) &&
199 ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_RDR) != 0)) {
200 *p8 = Chip_UART_ReadByte(pUART);
201 p8++;
202 readBytes++;
203 }
204
205 return readBytes;
206 }
207
208 /* Read data through the UART peripheral (blocking) */
209 int Chip_UART_ReadBlocking(LPC_USART_T *pUART, void *data, int numBytes)
210 {
211 int pass, readBytes = 0;
212 uint8_t *p8 = (uint8_t *) data;
213
214 while (readBytes < numBytes) {
215 pass = Chip_UART_Read(pUART, p8, numBytes);
216 numBytes -= pass;
217 readBytes += pass;
218 p8 += pass;
219 }
220
221 return readBytes;
222 }
223
224 /* Determines and sets best dividers to get a target bit rate */
225 uint32_t Chip_UART_SetBaud(LPC_USART_T *pUART, uint32_t baudrate)
226 {
227 uint32_t div, divh, divl, clkin;
228
229 /* Determine UART clock in rate without FDR */
230 clkin = Chip_Clock_GetRate(UART_BClock[Chip_UART_GetIndex(pUART)]);
231 div = clkin / (baudrate * 16);
232
233 /* High and low halves of the divider */
234 divh = div / 256;
235 divl = div - (divh * 256);
236
237 Chip_UART_EnableDivisorAccess(pUART);
238 Chip_UART_SetDivisorLatches(pUART, divl, divh);
239 Chip_UART_DisableDivisorAccess(pUART);
240
241 /* Fractional FDR alreadt setup for 1 in UART init */
242
243 return clkin / div;
244 }
245
246 /* UART receive-only interrupt handler for ring buffers */
247 void Chip_UART_RXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB)
248 {
249 /* New data will be ignored if data not popped in time */
250 while (Chip_UART_ReadLineStatus(pUART) & UART_LSR_RDR) {
251 uint8_t ch = Chip_UART_ReadByte(pUART);
252 RingBuffer_Insert(pRB, &ch);
253 }
254 }
255
256 /* UART transmit-only interrupt handler for ring buffers */
257 void Chip_UART_TXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB)
258 {
259 uint8_t ch;
260
261 /* Fill FIFO until full or until TX ring buffer is empty */
262 while ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) != 0 &&
263 RingBuffer_Pop(pRB, &ch)) {
264 Chip_UART_SendByte(pUART, ch);
265 }
266
267 /* Turn off interrupt if the ring buffer is empty */
268 if (RingBuffer_IsEmpty(pRB)) {
269 /* Shut down transmit */
270 Chip_UART_IntDisable(pUART, UART_IER_THREINT);
271 }
272 }
273
274 /* Populate a transmit ring buffer and start UART transmit */
275 uint32_t Chip_UART_SendRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, const void *data, int bytes)
276 {
277 uint32_t ret;
278 uint8_t *p8 = (uint8_t *) data;
279
280 /* Don't let UART transmit ring buffer change in the UART IRQ handler */
281 Chip_UART_IntDisable(pUART, UART_IER_THREINT);
282
283 /* Move as much data as possible into transmit ring buffer */
284 ret = RingBuffer_InsertMult(pRB, p8, bytes);
285 Chip_UART_TXIntHandlerRB(pUART, pRB);
286
287 /* Add additional data to transmit ring buffer if possible */
288 ret += RingBuffer_InsertMult(pRB, (p8 + ret), (bytes - ret));
289
290 /* Enable UART transmit interrupt */
291 Chip_UART_IntEnable(pUART, UART_IER_THREINT);
292
293 return ret;
294 }
295
296 /* Copy data from a receive ring buffer */
297 int Chip_UART_ReadRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, void *data, int bytes)
298 {
299 (void) pUART;
300
301 return RingBuffer_PopMult(pRB, (uint8_t *) data, bytes);
302 }
303
304 /* UART receive/transmit interrupt handler for ring buffers */
305 void Chip_UART_IRQRBHandler(LPC_USART_T *pUART, RINGBUFF_T *pRXRB, RINGBUFF_T *pTXRB)
306 {
307 /* Handle transmit interrupt if enabled */
308 if (pUART->IER & UART_IER_THREINT) {
309 Chip_UART_TXIntHandlerRB(pUART, pTXRB);
310
311 /* Disable transmit interrupt if the ring buffer is empty */
312 if (RingBuffer_IsEmpty(pTXRB)) {
313 Chip_UART_IntDisable(pUART, UART_IER_THREINT);
314 }
315 }
316
317 /* Handle receive interrupt */
318 Chip_UART_RXIntHandlerRB(pUART, pRXRB);
319
320 /* Handle Autobaud interrupts */
321 Chip_UART_ABIntHandler(pUART);
322 }
323
324 /* Determines and sets best dividers to get a target baud rate */
325 uint32_t Chip_UART_SetBaudFDR(LPC_USART_T *pUART, uint32_t baud)
326 {
327 uint32_t sdiv = 0, sm = 1, sd = 0;
328 uint32_t pclk, m, d;
329 uint32_t odiff = -1UL; /* old best diff */
330
331 /* Get base clock for the corresponding UART */
332 pclk = Chip_Clock_GetRate(UART_BClock[Chip_UART_GetIndex(pUART)]);
333
334 /* Loop through all possible fractional divider values */
335 for (m = 1; odiff && m < 16; m++) {
336 for (d = 0; d < m; d++) {
337 uint32_t diff, div;
338 uint64_t dval = (((uint64_t) pclk << 28) * m) / (baud * (m + d));
339
340 /* Lower 32-bit of dval has diff */
341 diff = (uint32_t) dval;
342 /* Upper 32-bit of dval has div */
343 div = (uint32_t) (dval >> 32);
344
345 /* Closer to next div */
346 if ((int)diff < 0) {
347 diff = -diff;
348 div ++;
349 }
350
351 /* Check if new value is worse than old or out of range */
352 if (odiff < diff || !div || (div >> 16) || (div < 3 && d)) {
353 continue;
354 }
355
356 /* Store the new better values */
357 sdiv = div;
358 sd = d;
359 sm = m;
360 odiff = diff;
361
362 /* On perfect match, break loop */
363 if(!diff) {
364 break;
365 }
366 }
367 }
368
369 /* Return 0 if a vaild divisor is not possible */
370 if (!sdiv) {
371 return 0;
372 }
373
374 /* Update UART registers */
375 Chip_UART_EnableDivisorAccess(pUART);
376 Chip_UART_SetDivisorLatches(pUART, UART_LOAD_DLL(sdiv), UART_LOAD_DLM(sdiv));
377 Chip_UART_DisableDivisorAccess(pUART);
378
379 /* Set best fractional divider */
380 pUART->FDR = (UART_FDR_MULVAL(sm) | UART_FDR_DIVADDVAL(sd));
381
382 /* Return actual baud rate */
383 return (pclk >> 4) * sm / (sdiv * (sm + sd));
384 }
385
386 /* UART interrupt service routine */
387 FlagStatus Chip_UART_GetABEOStatus(LPC_USART_T *pUART)
388 {
389 (void) pUART;
390 return ABsyncSts;
391 }
392
393 /* Start/Stop Auto Baudrate activity */
394 void Chip_UART_ABCmd(LPC_USART_T *pUART, uint32_t mode, bool autorestart, FunctionalState NewState)
395 {
396 uint32_t tmp = 0;
397
398 if (NewState == ENABLE) {
399 /* Clear DLL and DLM value */
400 pUART->LCR |= UART_LCR_DLAB_EN;
401 pUART->DLL = 0;
402 pUART->DLM = 0;
403 pUART->LCR &= ~UART_LCR_DLAB_EN;
404
405 /* FDR value must be reset to default value */
406 pUART->FDR = 0x10;
407
408 if (mode == UART_ACR_MODE1) {
409 tmp = UART_ACR_START | UART_ACR_MODE;
410 }
411 else {
412 tmp = UART_ACR_START;
413 }
414
415 if (autorestart == true) {
416 tmp |= UART_ACR_AUTO_RESTART;
417 }
418 pUART->ACR = tmp;
419 }
420 else {
421 pUART->ACR = 0;
422 }
423 }
424