LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
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 */
40 
41 /*****************************************************************************
42  * Public types/enumerations/variables
43  ****************************************************************************/
44 
45 /*****************************************************************************
46  * Private functions
47  ****************************************************************************/
48  /* UART Peripheral clocks */
50 
51 /* UART Bus clocks */
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 */
74 {
75  /* Handle End Of Autobaud interrupt */
76  if((Chip_UART_ReadIntIDReg(pUART) & UART_IIR_ABEO_INT) != 0) {
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) {
88  }
89 }
90 
91 /*****************************************************************************
92  * Public functions
93  ****************************************************************************/
94 
95 /* Initializes the pUART peripheral */
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 */
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 */
132 
133  /* Disable fractional divider */
134  pUART->FDR = 0x10;
135 }
136 
137 /* De-initializes the pUART peripheral */
139 {
140  /* Disable Tx */
141  Chip_UART_TXDisable(pUART);
142 
143  /* Disable clock */
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 */
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 */
231  div = clkin / (baudrate * 16);
232 
233  /* High and low halves of the divider */
234  divh = div / 256;
235  divl = div - (divh * 256);
236 
238  Chip_UART_SetDivisorLatches(pUART, divl, divh);
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 */
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 */
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 */
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 */
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 */
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 */
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)) {
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 */
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 */
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 */
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) {
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