/* Determines and sets best dividers to get a target baud rate */ uint32_t Chip_UART_SetBaudFDR(LPC_USART_T *pUART, uint32_t baudrate) { uint32_t uClk; uint32_t dval, mval; uint32_t dl; uint32_t rate16 = 16 * baudrate; uint32_t actualRate = 0; /* Get Clock rate */ uClk = Chip_Clock_GetMainClockRate(); /* The fractional is calculated as (PCLK % (16 * Baudrate)) / (16 * Baudrate) * Let's make it to be the ratio DivVal / MulVal */ dval = uClk % rate16; // NOTE: added initialization. Otherwise value may be used without initialization. mval = 0; /* The PCLK / (16 * Baudrate) is fractional * => dval = pclk % rate16 * mval = rate16; * now mormalize the ratio * dval / mval = 1 / new_mval * new_mval = mval / dval * new_dval = 1 */ if (dval > 0) { mval = rate16 / dval; dval = 1; /* In case mval still bigger then 4 bits * no adjustment require */ if (mval > 12) { dval = 0; } } dval &= 0xf; // TODO: mval may be non initialized. mval &= 0xf; dl = uClk / (rate16 + rate16 * dval / mval); /* Update UART registers */ Chip_UART_EnableDivisorAccess(pUART); Chip_UART_SetDivisorLatches(pUART, UART_LOAD_DLL(dl), UART_LOAD_DLM(dl)); Chip_UART_DisableDivisorAccess(pUART); /* Set best fractional divider */ pUART->FDR = (UART_FDR_MULVAL(mval) | UART_FDR_DIVADDVAL(dval)); /* Return actual baud rate */ actualRate = uClk / (16 * dl + 16 * dl * dval / mval); return actualRate; }
/* * UART Init function */ void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits, uart_stopbit_t data_nb_stop, uart_parity_t data_parity, uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval) { uint32_t lcr_config; uint32_t uart_port; uart_port = uart_num; switch(uart_num) { case UART0_NUM: /* use PLL1 as clock source for UART0 */ CGU_BASE_UART0_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART1_NUM: /* use PLL1 as clock source for UART1 */ CGU_BASE_UART1_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART2_NUM: /* use PLL1 as clock source for UART2 */ CGU_BASE_UART2_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART3_NUM: /* use PLL1 as clock source for UART3 */ CGU_BASE_UART3_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; default: return; /* error */ } /* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared) */ UART_FCR(uart_port) = ( UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS); /* Disable FIFO */ UART_FCR(uart_port) = 0; // Dummy read (to clear existing data) while (UART_LSR(uart_port) & UART_LSR_RDR ) { dummy_read = UART_RBR(uart_port); } /* Wait end of TX & disable TX */ UART_TER(uart_port) = UART_TER_TXEN; /* Wait for current transmit complete */ while (!(UART_LSR(uart_port) & UART_LSR_THRE)); /* Disable Tx */ UART_TER(uart_port) = 0; /* Disable interrupt */ UART_IER(uart_port) = 0; /* Set LCR to default state */ UART_LCR(uart_port) = 0; /* Set ACR to default state */ UART_ACR(uart_port) = 0; /* Dummy Read to Clear Status */ dummy_read = UART_LSR(uart_port); /* Table 835. USART Fractional Divider Register: UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) ) The value of MULVAL and DIVADDVAL should comply to the following conditions: 1. 1 <= MULVAL <= 15 2. 0 <= DIVADDVAL <= 14 3. DIVADDVAL < MULVAL */ /* Set DLAB Bit */ UART_LCR(uart_port) |= UART_LCR_DLAB_EN; UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor); UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor); /* Clear DLAB Bit */ UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; UART_FDR(uart_port) = (UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval)) & UART_FDR_BITMASK; /* Read LCR config & Force Enable of Divisor Latches Access */ lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) & UART_LCR_BITMASK; lcr_config |= data_nb_bits; /* Set Nb Data Bits */ lcr_config |= data_nb_stop; /* Set Nb Stop Bits */ lcr_config |= data_parity; /* Set Data Parity */ /* Write LCR (only 8bits) */ UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK); /* Enable TX */ UART_TER(uart_port) = UART_TER_TXEN; }
/*********************************************************************//** * @brief Determines best dividers to get a target clock rate * @param[in] UARTx Pointer to selected UART peripheral, should be: * - LPC_UART0: UART0 peripheral * - LPC_UART1: UART1 peripheral * - LPC_UART2: UART2 peripheral * - LPC_UART3: UART3 peripheral * @param[in] baudrate Desired UART baud rate. * @return Error status, could be: * - SUCCESS * - ERROR **********************************************************************/ static Status uart_set_divisors(LPC_UART_TypeDef *UARTx, uint32_t baudrate) { Status errorStatus = ERROR; uint32_t uClk; uint32_t calcBaudrate = 0; uint32_t temp = 0; uint32_t mulFracDiv, dividerAddFracDiv; uint32_t diviser = 0 ; uint32_t mulFracDivOptimal = 1; uint32_t dividerAddOptimal = 0; uint32_t diviserOptimal = 0; uint32_t relativeError = 0; uint32_t relativeOptimalError = 100000; /* get UART block clock */ if (UARTx == LPC_UART0) { uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART0); } else if (UARTx == (LPC_UART_TypeDef *)LPC_UART1) { uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART1); } else if (UARTx == LPC_UART2) { uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART2); } else if (UARTx == LPC_UART3) { uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART3); } uClk = uClk >> 4; /* div by 16 */ /* In the Uart IP block, baud rate is calculated using FDR and DLL-DLM registers * The formula is : * BaudRate= uClk * (mulFracDiv/(mulFracDiv+dividerAddFracDiv) / (16 * (DLL) * It involves floating point calculations. That's the reason the formulae are adjusted with * Multiply and divide method.*/ /* The value of mulFracDiv and dividerAddFracDiv should comply to the following expressions: * 0 < mulFracDiv <= 15, 0 <= dividerAddFracDiv <= 15 */ for (mulFracDiv = 1 ; mulFracDiv <= 15 ;mulFracDiv++) { for (dividerAddFracDiv = 0 ; dividerAddFracDiv <= 15 ;dividerAddFracDiv++) { temp = (mulFracDiv * uClk) / ((mulFracDiv + dividerAddFracDiv)); diviser = temp / baudrate; if ((temp % baudrate) > (baudrate / 2)) diviser++; if (diviser > 2 && diviser < 65536) { calcBaudrate = temp / diviser; if (calcBaudrate <= baudrate) relativeError = baudrate - calcBaudrate; else relativeError = calcBaudrate - baudrate; if ((relativeError < relativeOptimalError)) { mulFracDivOptimal = mulFracDiv ; dividerAddOptimal = dividerAddFracDiv; diviserOptimal = diviser; relativeOptimalError = relativeError; if (relativeError == 0) break; } } /* End of if */ } /* end of inner for loop */ if (relativeError == 0) break; } /* end of outer for loop */ if (relativeOptimalError < ((baudrate * UART_ACCEPTED_BAUDRATE_ERROR)/100)) { if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) { ((LPC_UART1_TypeDef *)UARTx)->LCR |= UART_LCR_DLAB_EN; ((LPC_UART1_TypeDef *)UARTx)->/*DLIER.*/DLM = UART_LOAD_DLM(diviserOptimal); ((LPC_UART1_TypeDef *)UARTx)->/*RBTHDLR.*/DLL = UART_LOAD_DLL(diviserOptimal); /* Then reset DLAB bit */ ((LPC_UART1_TypeDef *)UARTx)->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; ((LPC_UART1_TypeDef *)UARTx)->FDR = (UART_FDR_MULVAL(mulFracDivOptimal) \ | UART_FDR_DIVADDVAL(dividerAddOptimal)) & UART_FDR_BITMASK; } else { UARTx->LCR |= UART_LCR_DLAB_EN; UARTx->/*DLIER.*/DLM = UART_LOAD_DLM(diviserOptimal); UARTx->/*RBTHDLR.*/DLL = UART_LOAD_DLL(diviserOptimal); /* Then reset DLAB bit */ UARTx->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; UARTx->FDR = (UART_FDR_MULVAL(mulFracDivOptimal) \ | UART_FDR_DIVADDVAL(dividerAddOptimal)) & UART_FDR_BITMASK; } errorStatus = SUCCESS; } return errorStatus; }