123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- /*
- * @brief UART ROM API declarations and functions
- *
- * @note
- * Copyright(C) NXP Semiconductors, 2014
- * All rights reserved.
- *
- * @par
- * Software that is described herein is for illustrative purposes only
- * which provides customers with programming information regarding the
- * LPC products. This software is supplied "AS IS" without any warranties of
- * any kind, and NXP Semiconductors and its licensor disclaim any and
- * all warranties, express or implied, including all implied warranties of
- * merchantability, fitness for a particular purpose and non-infringement of
- * intellectual property rights. NXP Semiconductors assumes no responsibility
- * or liability for the use of the software, conveys no license or rights under any
- * patent, copyright, mask work right, or any other intellectual property rights in
- * or to any products. NXP Semiconductors reserves the right to make changes
- * in the software without notification. NXP Semiconductors also makes no
- * representation or warranty that such application will be suitable for the
- * specified use without further testing or modification.
- *
- * @par
- * Permission to use, copy, modify, and distribute this software and its
- * documentation is hereby granted, under NXP Semiconductors' and its
- * licensor's relevant copyrights in the software, without fee, provided that it
- * is used in conjunction with NXP Semiconductors microcontrollers. This
- * copyright, permission, and disclaimer notice must appear in all copies of
- * this code.
- */
- #include "error.h"
- #include "hw_uart_rom_api.h"
- #define UART_IDLE_FIX /* Remove once IDLE problem is fixed */
- /* UART Driver internal data structure */
- typedef struct {
- void *pUserData; /* Pointer to user data */
- UART_REGS_T *pREGS; /* Pointer to Registers */
- UART_DATA_T xfer[2]; /* TX/RX transfer data */
- #ifdef UART_IDLE_FIX
- uint32_t dly; /* Delay to count 1 bit time; REMOVE: when H/W is fixed */
- #endif
- void(*cbTable[UART_CB_RESERVED]) (UART_HANDLE_T, UART_EVENT_T, void *); /* Call-back index table */
- } UART_DRIVER_T;
- /* PRIVATE: Division logic to divide without integer overflow */
- static uint32_t _UART_DivClk(uint32_t pclk, uint32_t m)
- {
- uint32_t q, r, u = pclk >> 24, l = pclk << 8;
- m = m + 256;
- q = (1 << 24) / m;
- r = (1 << 24) - (q * m);
- return ((q * u) << 8) + (((r * u) << 8) + l) / m;
- }
- /* PRIVATE: Get highest Over sampling value */
- static uint32_t _UART_GetHighDiv(uint32_t val, uint8_t strict)
- {
- int32_t i, max = strict ? 16 : 5;
- for (i = 16; i >= max; i--) {
- if (!(val % i)) {
- return i;
- }
- }
- return 0;
- }
- /* PRIVATE: Queue a transfer in UART */
- static ErrorCode_t _UART_Xfer(UART_DRIVER_T *pUART, void *buff, uint16_t len, uint8_t op)
- {
- UART_DATA_T *xfr = &pUART->xfer[op];
- /* Xfer of 0 bytes in a UART should always be successful */
- if (!len) {
- return LPC_OK;
- }
- /* Check if a Xfer is alredy in progress */
- if (xfr->count > xfr->offset) {
- return ERR_BUSY;
- }
- xfr->buf = (void *) buff;
- xfr->count = len;
- xfr->offset = 0;
- xfr->state = UART_ST_BUSY;
- if (!op) {
- pUART->pREGS->INTENSET = UART_INT_TXRDY;
- }
- else {
- pUART->pREGS->INTENSET = UART_INT_RXRDY | UART_INT_FRMERR | UART_INT_RXNOISE | UART_INT_START | UART_INT_OVR;
- }
- return LPC_OK;
- }
- /* Calculate error difference */
- static int32_t _CalcErr(uint32_t n, uint32_t d, uint32_t *prev)
- {
- uint32_t err = n - (n / d) * d;
- uint32_t herr = ((n / d) + 1) * d - n;
- if (herr < err) {
- err = herr;
- }
- if (*prev <= err) {
- return 0;
- }
- *prev = err;
- return (herr == err) + 1;
- }
- /* Calculate the base DIV value */
- static ErrorCode_t _UART_CalcDiv(UART_BAUD_T *ub)
- {
- int32_t i = 0;
- uint32_t perr = ~0UL;
- if (!ub->div) {
- i = ub->ovr ? ub->ovr : 16;
- }
- for (; i > 4; i--) {
- int32_t tmp = _CalcErr(ub->clk, ub->baud * i, &perr);
- /* Continue when no improvement seen in err value */
- if (!tmp) {
- continue;
- }
- ub->div = tmp - 1;
- if (ub->ovr == i) {
- break;
- }
- ub->ovr = i;
- }
- if (!ub->ovr) {
- return ERR_UART_BAUDRATE;
- }
- ub->div += ub->clk / (ub->baud * ub->ovr);
- if (!ub->div) {
- return ERR_UART_BAUDRATE;
- }
- ub->baud = ub->clk / (ub->div * ub->ovr);
- return LPC_OK;
- }
- /* Calculate the best MUL value */
- static void _UART_CalcMul(UART_BAUD_T *ub)
- {
- uint32_t m, perr = ~0UL, pclk = ub->clk, ovr = ub->ovr;
- /* If clock is UART's base clock calculate only the divider */
- for (m = 0; m < 256; m++) {
- uint32_t ov = ovr, x, v, tmp;
- /* Get clock and calculate error */
- x = _UART_DivClk(pclk, m);
- tmp = _CalcErr(x, ub->baud, &perr);
- v = (x / ub->baud) + tmp - 1;
- /* Update if new error is better than previous best */
- if (!tmp || (ovr && (v % ovr)) ||
- (!ovr && ((ov = _UART_GetHighDiv(v, ovr)) == 0))) {
- continue;
- }
- ub->ovr = ov;
- ub->mul = m;
- ub->clk = x;
- ub->div = tmp - 1;
- }
- }
- /* PRIVATE: Invoke UART Call back functions */
- static void _UART_InvokeCB(UART_DRIVER_T *pUART, UART_EVENT_T event, void *arg)
- {
- void (*cbfn)(UART_HANDLE_T, UART_EVENT_T, void *);
- cbfn = pUART->cbTable[(uint32_t) event >> 1];
- if (cbfn != NULL) {
- cbfn((UART_HANDLE_T) pUART, event, arg);
- }
- }
- /* PRIVATE: Handler for data transfers */
- static void _UART_HandleTxRx(UART_HANDLE_T hUART, UART_EVENT_T event, void *arg)
- {
- UART_DATA_T *dat = (UART_DATA_T *) arg;
- UART_DRIVER_T *pUART = (UART_DRIVER_T *) hUART;
- uint16_t *buf16 = dat->buf;
- uint8_t *buf8 = dat->buf;
- /* Transmit data */
- if (event == UART_TX_DATA) {
- while (dat->count && (pUART->pREGS->INTSTAT & UART_INT_TXRDY)) {
- if (dat->dwidth) {
- pUART->pREGS->TXDAT = *buf16++;
- }
- else {
- pUART->pREGS->TXDAT = *buf8++;
- }
- dat->count--;
- }
- return;
- }
- /* Receive data */
- while (dat->count && (pUART->pREGS->INTSTAT & UART_INT_RXRDY)) {
- if (dat->dwidth) {
- *buf16++ = pUART->pREGS->RXDAT & 0x1FF;
- }
- else {
- *buf8++ = pUART->pREGS->RXDAT & 0xFF;
- }
- dat->count--;
- }
- }
- /* Handle UART Receive event */
- static int32_t _UART_HandleXfer(UART_DRIVER_T *pUART, uint8_t op)
- {
- UART_DATA_T dat;
- UART_DATA_T *xfr = &pUART->xfer[op];
- /* See if the transfer is already complete */
- if (xfr->offset >= xfr->count) {
- return 2;
- }
- /* Fill the buffer data structure */
- dat.count = xfr->count - xfr->offset;
- dat.dwidth = ((pUART->pREGS->CFG >> 2) & 3) > 1;
- if (dat.dwidth) {
- dat.buf = &((uint16_t *) xfr->buf)[xfr->offset];
- }
- else {
- dat.buf = &((uint8_t *) xfr->buf)[xfr->offset];
- }
- if (!xfr->offset && xfr->count) {
- _UART_InvokeCB(pUART, UART_TX_START, xfr);
- }
- pUART->cbTable[UART_CB_DATA]((UART_HANDLE_T) pUART, (UART_EVENT_T) (UART_TX_DATA + op), &dat);
- xfr->offset = (xfr->count - dat.count);
- if (xfr->offset >= xfr->count) {
- if (!op) {
- pUART->pREGS->INTENCLR = UART_INT_TXRDY;
- }
- else {
- pUART->pREGS->INTENCLR = UART_INT_RXRDY;
- }
- _UART_InvokeCB(pUART, (UART_EVENT_T) (UART_TX_DONE + op), xfr);
- if (xfr->state == UART_ST_BUSY) {
- xfr->state = UART_ST_DONE;
- }
- return 1;
- }
- return 0;
- }
- /* STOP Receive under progress */
- static void _UART_StopRx(UART_HANDLE_T hUART)
- {
- UART_DRIVER_T *pUART = (UART_DRIVER_T *) hUART;
- UART_DATA_T *rx = &pUART->xfer[1];
- volatile uint16_t *idx = (volatile uint16_t *) &rx->offset;
- if (*idx >= rx->count) {
- return;
- }
- /* Disable further receive interrupts */
- pUART->pREGS->INTENCLR = UART_INT_RXRDY;
- rx->count = *idx;
- _UART_InvokeCB(pUART, UART_RX_DONE, rx);
- }
- /* EXPROTED API: Returns memory required for UART ROM driver */
- uint32_t UART_GetMemSize(void)
- {
- return sizeof(UART_DRIVER_T);
- }
- /* EXPORTED API: Calculate UART Baudrate divisors */
- ErrorCode_t UART_CalculateBaud(UART_BAUD_T *ub)
- {
- if (!ub->mul) {
- _UART_CalcMul(ub);
- }
- return _UART_CalcDiv(ub);
- }
- /* EXPORTED API: UART Initialization function */
- UART_HANDLE_T UART_Init(void *mem, uint32_t base_addr, void *args)
- {
- UART_DRIVER_T *pUART;
- /* Check if the memory is word aligned */
- if ((uint32_t) mem & 0x3) {
- return NULL;
- }
- /* Assign memory provided by application */
- pUART = (UART_DRIVER_T *) mem;
- memset(pUART, 0, sizeof(UART_DRIVER_T));
- /* Assign the base address */
- pUART->pREGS = (UART_REGS_T *) base_addr;
- pUART->pUserData = args;
- /* Set default handler for TX and RX */
- pUART->cbTable[UART_CB_DATA] = _UART_HandleTxRx;
- return (UART_HANDLE_T) pUART;
- }
- /* EXPORTED API: Configure UART parameters */
- ErrorCode_t UART_Configure(UART_HANDLE_T hUART, const UART_CFG_T *cfg)
- {
- UART_DRIVER_T *pUART = (UART_DRIVER_T *) hUART;
- UART_REGS_T *pREGS = pUART->pREGS;
- if (((cfg->cfg & UART_PAR_MASK) == (1 << 4)) ||
- ( (cfg->cfg & UART_DATA_MASK) == (3 << 2)) ) {
- return ERR_UART_PARAM;
- }
- /* Enable parity error when parity is enabled */
- if ((cfg->cfg & UART_PAR_MASK) >> 4) {
- pREGS->INTENSET = UART_INT_PARERR;
- }
- if (((int32_t) cfg->div <= 0) || ((int32_t) cfg->ovr <= 0)) {
- return ERR_UART_PARAM;
- }
- pREGS->OSR = (cfg->ovr - 1) & 0x0F;
- pREGS->BRG = (cfg->div - 1) & 0xFFFF;
- pREGS->CFG = UART_CFG_ENABLE | (cfg->cfg & ~UART_CFG_RES);
- /* Enabled RX of BREAK event */
- if (cfg->cfg & UART_CFG_BRKRX) {
- pREGS->INTENSET = UART_INT_BREAK;
- }
- /* Enable CTS interrupt if requested */
- if (cfg->cfg & UART_CFG_CTSEV) {
- pREGS->INTENSET = UART_INT_CTS;
- }
- #ifdef UART_IDLE_FIX
- /* REMOVE: if/else block after H/W idle is fixed */
- if (cfg->res > 224) {
- pUART->dly = 3072 * (cfg->res - 224);
- }
- else {
- pUART->dly = cfg->res << 2;
- }
- #endif
- return LPC_OK;
- }
- /* EXPORTED API: UART setup special operation like BREAK etc. */
- void UART_SetControl(UART_HANDLE_T hUART, uint32_t cfg)
- {
- uint32_t en, dis;
- UART_REGS_T *pREGS = ((UART_DRIVER_T *) hUART)->pREGS;
- /* Get list of enabled and disabled options */
- en = ((cfg >> 16) & (cfg & 0xFFFF)) << 1;
- dis = ((cfg >> 16) & ~(cfg & 0xFFFF)) << 1;
- /* See if it is RX Stop request */
- if (cfg & UART_RX_STOP) {
- _UART_StopRx(hUART);
- }
- /* See if any IDLEs are enabled */
- if (cfg & (UART_IDLE_MASK << 16)) {
- pREGS->INTENSET = (en >> 1) & UART_IDLE_MASK;
- pREGS->INTENCLR = (dis >> 1) & UART_IDLE_MASK;
- }
- /* See if it is a request BREAK after TX */
- if (en & UART_CTL_TXDIS) {
- if (en & UART_CTL_TXBRKEN) {
- pREGS->CTL = (pREGS->CTL & ~UART_CTL_RES) | UART_CTL_TXDIS;
- while (!(pREGS->STAT & UART_INT_TXDIS)) {}
- #ifdef UART_IDLE_FIX
- if (1) {
- volatile uint32_t dly = ((UART_DRIVER_T *) hUART)->dly;
- while (dly--) {}/* Provide some idling time H/W does not do this */
- }
- #endif
- }
- else {
- pREGS->INTENSET = UART_INT_TXDIS;
- }
- }
- /* See if we are releasing break and resume TX operation */
- if ((dis & UART_CTL_TXDIS) && (dis & UART_CTL_TXBRKEN)) {
- pREGS->CTL = pREGS->CTL & ~(UART_CTL_RES | UART_CTL_TXBRKEN);
- #ifdef UART_IDLE_FIX
- if (1) {
- volatile uint32_t dly = ((UART_DRIVER_T *) hUART)->dly;
- while (dly--) {} /* Provide some idling time H/W does not do this */
- }
- #endif
- }
- /* Check for autobaud and enable autobaud err interrupt */
- if (en & UART_CTL_AUTOBAUD) {
- pREGS->INTENSET = UART_INT_ABAUDERR;
- }
- pREGS->CTL = ((pREGS->CTL | en) & ~dis) & ~UART_CTL_RES;
- }
- /* EXPORTED API: Register a call-back function */
- ErrorCode_t UART_RegisterCB(UART_HANDLE_T hUART,
- UART_CBINDEX_T idx,
- void (*cb_func)(UART_HANDLE_T, UART_EVENT_T, void *))
- {
- if (idx < UART_CB_RESERVED) {
- ((UART_DRIVER_T *) hUART)->cbTable[idx] = cb_func;
- }
- else {
- return ERR_UART_PARAM;
- }
- /* Restore internal data handlers when external ones are un-registered */
- if ((idx == UART_CB_DATA) && (cb_func == NULL)) {
- ((UART_DRIVER_T *) hUART)->cbTable[idx] = _UART_HandleTxRx;
- }
- return LPC_OK;
- }
- /* EXPORTED API: UART Event handler */
- void UART_Handler(UART_HANDLE_T hUART)
- {
- UART_DRIVER_T *pUART = (UART_DRIVER_T *) hUART;
- uint32_t flags = pUART->pREGS->INTENSET & pUART->pREGS->INTSTAT;
- if (flags & UART_INT_TXRDY) {
- _UART_HandleXfer(pUART, 0);
- }
- if (flags & UART_INT_FRMERR) {
- pUART->pREGS->STAT = UART_INT_FRMERR;
- if (pUART->xfer[1].state == UART_ST_BUSY) {
- pUART->xfer[1].state = UART_ST_ERRFRM;
- }
- _UART_InvokeCB(pUART, UART_EV_ERROR, (void *) UART_ERROR_FRAME);
- }
- if (flags & UART_INT_PARERR) {
- pUART->pREGS->STAT = UART_INT_PARERR;
- if (pUART->xfer[1].state == UART_ST_BUSY) {
- pUART->xfer[1].state = UART_ST_ERRPAR;
- }
- _UART_InvokeCB(pUART, UART_EV_ERROR, (void *) UART_ERROR_PARITY);
- }
- if (flags & UART_INT_ABAUDERR) {
- pUART->pREGS->STAT = UART_INT_ABAUDERR;
- if (pUART->xfer[1].state == UART_ST_BUSY) {
- pUART->xfer[1].state = UART_ST_ERR;
- }
- _UART_InvokeCB(pUART, UART_EV_ERROR, (void *) UART_ERROR_AUTOBAUD);
- }
- if (flags & UART_INT_RXNOISE) {
- pUART->pREGS->STAT = UART_INT_RXNOISE;
- if (pUART->xfer[1].state == UART_ST_BUSY) {
- pUART->xfer[1].state = UART_ST_ERRNOISE;
- }
- _UART_InvokeCB(pUART, UART_EV_ERROR, (void *) UART_ERROR_RXNOISE);
- }
- if (flags & UART_INT_OVR) {
- pUART->pREGS->STAT = UART_INT_OVR;
- if (pUART->xfer[1].state == UART_ST_BUSY) {
- pUART->xfer[1].state = UART_ST_ERROVR;
- }
- _UART_InvokeCB(pUART, UART_EV_ERROR, (void *) UART_ERROR_OVERRUN);
- }
- if (flags & UART_INT_RXRDY) {
- _UART_HandleXfer(pUART, 1);
- #ifdef UART_IDLE_FIX
- if (1) {
- volatile uint32_t dly = ((UART_DRIVER_T *) hUART)->dly;
- while ((pUART->pREGS->STAT & UART_STAT_RXIDLE) && dly--) {}
- }
- #else
- while (pUART->pREGS->STAT & UART_STAT_RXIDLE) {}
- #endif
- _UART_InvokeCB(pUART, (UART_EVENT_T) (UART_RX_INPROG + ((pUART->pREGS->STAT >> 1) & 1)), &pUART->xfer[1]);
- }
- if (flags & UART_INT_TXIDLE) {
- _UART_InvokeCB(pUART, UART_EV_EVENT, (void *) UART_EVENT_TXIDLE);
- }
- if (flags & UART_INT_TXDIS) {
- pUART->pREGS->INTENCLR = UART_INT_TXDIS;/* Disable interrupt */
- _UART_InvokeCB(pUART, UART_EV_EVENT, (void *) UART_EVENT_TXPAUSED);
- }
- if (flags & UART_INT_CTS) {
- pUART->pREGS->STAT = UART_INT_CTS;
- _UART_InvokeCB(pUART, UART_EV_EVENT,
- (void *) ((pUART->pREGS->STAT & UART_STAT_CTS) ? UART_EVENT_CTSHI : UART_EVENT_CTSLO));
- }
- if (flags & UART_INT_BREAK) {
- pUART->pREGS->STAT = UART_INT_BREAK | UART_INT_FRMERR;
- _UART_InvokeCB(pUART, UART_EV_EVENT,
- (void *) ((pUART->pREGS->STAT & UART_STAT_BREAK) ? UART_EVENT_BREAK : UART_EVENT_NOBREAK));
- }
- if (flags & UART_INT_START) {
- pUART->pREGS->STAT = UART_INT_START;
- _UART_InvokeCB(pUART, UART_RX_START, &pUART->xfer[1]);
- }
- }
- /* EXPORTED API: UART Transmit API */
- ErrorCode_t UART_Tx(UART_HANDLE_T hUART, const void *buff, uint16_t len)
- {
- return _UART_Xfer((UART_DRIVER_T *) hUART, (void *) buff, len, 0);
- }
- /* EXPORTED API: UART Receive API */
- ErrorCode_t UART_Rx(UART_HANDLE_T hUART, void *buff, uint16_t len)
- {
- return _UART_Xfer((UART_DRIVER_T *) hUART, buff, len, 1);
- }
- /* EXPORTED API: Flush the TX buffer */
- void UART_WaitTX(UART_HANDLE_T hUART)
- {
- while (!_UART_HandleXfer(hUART, 0)) {}
- }
- /* EXPORTED API: Fetch the data from UART into RX buffer */
- void UART_WaitRX(UART_HANDLE_T hUART)
- {
- UART_REGS_T *pREGS = ((UART_DRIVER_T *) hUART)->pREGS;
- /* See if the data needs to be discarded */
- if (_UART_HandleXfer(hUART, 1) == 2) {
- volatile uint32_t dummy;
- while ((pREGS->STAT & UART_INT_RXRDY) || !(pREGS->STAT & UART_STAT_RXIDLE)) {
- dummy = pREGS->RXDAT;
- }
- }
- while (!_UART_HandleXfer(hUART, 1)) {}
- }
- /* EXPORTED API: Function to Get the firmware Version */
- uint32_t UART_GetDriverVersion(void)
- {
- return UART_DRIVER_VERSION;
- }
- /**
- * @brief Table of the addresses of all the UART ROM APIs
- * @note This table of function pointers is the API interface.
- */
- const ROM_UART_API_T uartrom_api = {
- UART_GetMemSize,
- UART_CalculateBaud,
- UART_Init,
- UART_Configure,
- UART_SetControl,
- UART_RegisterCB,
- UART_Handler,
- UART_Tx,
- UART_Rx,
- UART_WaitTX,
- UART_WaitRX,
- UART_GetDriverVersion,
- };
|