Example #1
0
/* 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;
}
Example #2
0
/*
* 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;
}