Content originally posted in LPCWare by pausten on Mon Jan 03 10:34:09 MST 2011
Hi,
I read the datasheet and I agree that it appears higher baud rates should work.
I prototyped the code in python to enable me to test the algorithm I used to generate the fractional baud rate values. I checked that the code produced the same results for the two examples in the data sheet and then transferred the code to C. The C code gives the correct baud rates as I tested the bit transition time using the Oscilloscope when sending 'U' characters (at 115200, 230400, 460800 and 921600 Bps
) from the LPC1768 and the PC receives these fine at all baud rates so it appears that the baud rate is being set correctly.
The main elements of the C code I used to set the baud rate is shown below.
Thanks for your help on this.
Paul
float FRList[BR_LOOKUP_SIZE] = {1.000,1.067,1.071,1.077,1.083,1.091,1.100,1.111,1.125,1.133,1.143,1.154,1.167,1.182,1.200,1.214,1.222,1.231,1.250,
1.267,1.273,1.286,1.300,1.308,1.333,1.357,1.364,1.375,1.385,1.400,1.417,1.429,1.444,1.455,1.462,1.467,1.500,1.533,1.538,1.545,1.556,
1.571,1.583,1.600,1.615,1.625,1.636,1.643,1.667,1.692,1.700,1.714,1.727,1.733,1.750,1.769,1.778,1.786,1.800,1.818,1.833,1.846,1.857,
1.867,1.875,1.889,1.900,1.909,1.917,1.923,1.929,1.933};
float DIVADDVALList[BR_LOOKUP_SIZE] = {0.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.0,1.0,2.0,1.0,2.0,1.0,3.0,2.0,3.0,1.0,4.0,3.0,2.0,3.0,4.0,1.0,5.0,4.0,3.0,
5.0,2.0,5.0,3.0,4.0,5.0,6.0,7.0,1.0,8.0,7.0,6.0,5.0,4.0,7.0,3.0,8.0,5.0,7.0,9.0,2.0,9.0,7.0,5.0,8.0,11.0,3.0,10.0,7.0,11.0,4.0,9.0,5.0,
11.0,6.0,13.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0};
float MULVALList[BR_LOOKUP_SIZE] = {1.0,15.0,14.0,13.0,12.0,11.0,10.0,9.0,8.0,15.0,7.0,13.0,6.0,11.0,5.0,14.0,9.0,13.0,4.0,15.0,11.0,7.0,10.0,13.0,3.0,
14.0,11.0,8.0,13.0,5.0,12.0,7.0,9.0,11.0,13.0,15.0,2.0,15.0,13.0,11.0,9.0,7.0,12.0,5.0,13.0,8.0,11.0,14.0,3.0,13.0,10.0,7.0,11.0,15.0,
4.0,13.0,9.0,14.0,5.0,11.0,6.0,13.0,7.0,15.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0};
/**
* Return 1 if the double is an int value, 0 if not
*/
static int isIntValue(double value) {
int intValue = (int)value;
if( value == intValue ) {
return 1;
}
return 0;
}
/*
* Get the fraction values for the given FRest value.
*/
static int getFRValues(double FRest, float *divAddVal, float *mulVal) {
float lastDiff = -1;
float thisDiff;
int index;
//Look through the lookup table and find the index of the value
//that provides the smallest difference between the FRest value
//and the lookup table value.
for( index=0 ; index<BR_LOOKUP_SIZE ; index++ ) {
if( FRest > FRList[index] ) {
thisDiff = FRest-FRList[index];
}
else {
thisDiff = FRList[index]-FRest;
}
if( lastDiff != -1 && thisDiff > lastDiff ) {
//Set the fractional values required
*divAddVal=DIVADDVALList[index-1];
*mulVal=MULVALList[index-1];
return 0;
}
lastDiff=thisDiff;
}
return -1;
}
/*
* Get the fraction values required to set an accurate BR
*
* Return -1 on error, 0 on success.
*/
static int getFractionValues(int pclk, int baudRate, int *dlEst, float *divAddVal, float *mulVal) {
float dlEstFloat = pclk/(16.0*baudRate);
//If this pclk and baud rate give and integer division
//we don't need the fractional calculation
if( isIntValue(dlEstFloat) ) {
*dlEst = (int)dlEstFloat;
*divAddVal=0.0;
*mulVal=1.0;
return 0;
}
double FRest = 1.5;
int DLest;
while(1) {
DLest = (int)(pclk/(16.0*baudRate*FRest));
FRest = pclk/(16.0*baudRate*DLest);
//If we have the required accuracy
if( FRest >= 1.1 && FRest < 1.9) {
break;
}
if( FRest <= 1.5 ) {
FRest=FRest-0.001;
if( FRest < 1.1 ) {
FRest=1.5001;
}
else {
FRest=FRest+0.001;
if( FRest >= 1.9 ) {
return -1;
}
}
}
}
*dlEst=(int)DLest;
return getFRValues(FRest, divAddVal, mulVal);
}
Some of this code was taken from the RDB1768cmsis_UART_printf example project.
/*
* Functions to setup the UART 0,1,2 & 3 using the fraction baud rate divider.
* Gives a more accurate (within 1.1%) baud rate regardless of the system
* clock frequency.
*
* Return -1 on error, 0 on success.
*/
int initUart0(int baudRate) {
int pclk;
int dlEest;
float divAddVal, mulVal;
// PCLK_UART0 is being set to 1/4 of SystemCoreClock
pclk = SystemCoreClock / 4;
//Get the correct fractional values for the given pclk and required baud rate
if( getFractionValues(pclk, baudRate, &dlEest, &divAddVal, &mulVal) == -1 ) {
return -1;
}
// Turn on power to UART0
LPC_SC->PCONP |= PCUART0_POWERON;
// Turn on UART0 peripheral clock
LPC_SC->PCLKSEL0 &= ~(PCLK_UART0_MASK);
LPC_SC->PCLKSEL0 |= (0 << PCLK_UART0); // PCLK_periph = CCLK/4
// Set PINSEL0 so that P0.2 = TXD0, P0.3 = RXD0
LPC_PINCON->PINSEL0 &= ~0xf0;
LPC_PINCON->PINSEL0 |= ((1 << 4) | (1 << 6));
LPC_UART0->LCR = 0x83; // 8 bits, no Parity, 1 Stop bit, DLAB=1
LPC_UART0->DLM = dlEest / 256;
LPC_UART0->DLL = dlEest % 256;
//Setup the fractional divider register
LPC_UART0->FDR = (((int)mulVal)<<4)|(int)divAddVal;
LPC_UART0->LCR = 0x03; // 8 bits, no Parity, 1 Stop bit DLAB = 0
LPC_UART0->FCR = 0x07; // Enable and reset TX and RX FIFO
LPC_UART0->LCR = 0x03; // 8 bits, no Parity, 1 Stop bit, DLAB=0
return 0;
}
//This is the code I used to echo characters received by the LPC1768 back to the PC
int main(void) {
initUart0(921600);
while(1) {
UART0_Sendchar( UART0_Getchar() );
}
}
I replaced the above loop with the following to test the transmittion of data
from the LPC1768 to the PC
while(1) {
UART0_Sendchar('U');
c=0;
while(c < 1E6) {
c++;
}
}
The example code I used
// ***********************
// Function to send character over UART
void UART0_Sendchar(char c)
{
while( (LPC_UART0->LSR & LSR_THRE) == 0 ); // Block until tx empty
LPC_UART0->THR = c;
}
// ***********************
// Function to get character from UART
char UART0_Getchar()
{
char c;
while( (LPC_UART0->LSR & LSR_RDR) == 0 ); // Nothing received so just block
c = LPC_UART0->RBR; // Read Receiver buffer register
return c;
}