I'm looking some code that configures a UART for 115200 baud and assumes that the PCLK to for the UART is 12MHz. Which works fine if my CCLK is 48MHz and the peripheral clock divider is 4.
U1LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit*/ U1DLL = 3; /* for 12MHz PCLK Clock */ U1FDR = 0x67; /* Fractional Divider */ U1LCR = 0x03; /* DLAB = 0 */
That really doesn't work if CCLK is e.g. 72MHz, and this code doesn't work too well either:
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */ U1DLM = Fdiv / 256; U1DLL = Fdiv % 256;
Has anyone got some code that correctly configures the DLL, DLM and FDR values given a desired baud rate?
The LPC23xx user manual has a flowchart and a lookup table which is pretty scary - I'm hoping someone has done the hard work already
Thanks, David
I came up with this code which appears to work correctly (at least for CCLK 72MHz and baud rate 115200).
static float FR_Vals[] = { 1.500, 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.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 }; static uint8_t divaddvals[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 2, 3, 1, 4, 3, 2, 3, 4, 1, 5, 4, 3, 5, 2, 5, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 7, 3, 8, 5, 7, 9, 2, 9, 7, 5, 8, 11, 3, 10, 7, 11, 4, 9, 5, 11, 6, 13, 7, 8, 9, 10, 11, 12, 13, 14 }; static uint8_t mulvals[] = { 2, 15, 14, 13, 12, 11, 10, 9, 8, 15, 7, 13, 6, 11, 5, 14, 9, 13, 4, 15, 11, 7, 10, 13, 3, 14, 11, 8, 13, 5, 12, 7, 9, 11, 13, 15, 15, 13, 11, 9, 7, 12, 5, 13, 8, 11, 14, 3, 13, 10, 7, 11, 15, 4, 13, 9, 14, 5, 11, 6, 13, 7, 15, 8, 9, 10, 11, 12, 13, 14, 15 }; uint8_t closestIndex(float value) { uint8_t result = 0; float curr = FR_Vals[0]; for (uint8_t i = 0; i < sizeof(FR_Vals)/sizeof(float); i++) { if (fabsf(value - FR_Vals[i]) < fabsf(value - curr)) result = i; } return result; } /*---------------------------------------------------------------------------- * init_serial: Initialize Serial Interface *---------------------------------------------------------------------------*/ void init_serial (void) { /* Initialize the serial interface */ /* Configure UART1 for 115200 baud. */ const uint32_t baudrate = 115200; PINSEL0 &= ~0xC0000000; PINSEL0 |= 0x40000000; /* Enable TxD1 pin */ PINSEL1 &= ~0x00000003; PINSEL1 |= 0x00000001; /* Enable RxD1 pin */ uint16_t divaddval = 0, mulval = 1; /* PCLK_UART1=CCLK/2 */ PCLKSEL0 &= ~(3<<8); /* PCLK_UART1 = CCLK/4 (e.g. 18MHz) */ PCLKSEL0 |= (2<<8); /* PCLK_UART1 = CCLK/2 (e.g. 36MHz) */ float pclk = (float)SystemCoreClock/2; // Say 36MHz or 24MHz float DL_est = pclk/(16 * baudrate); float FR_est = 0.0; uint32_t DL = (uint32_t) DL_est; if (0 != DL_est - DL) { bool solved = false; for (uint8_t i = 0; i < sizeof(FR_Vals)/sizeof(float); i++) { FR_est = FR_Vals[i]; // Start with 1.5 DL_est = floorf(pclk/(16*baudrate*FR_est)); DL = DL_est; FR_est = pclk/(16*baudrate*DL); if (1.05 < FR_est && FR_est < 1.95) { solved = true; break; } // Not solved try next FR_est value } if (!solved) do {} while(true); uint8_t index = closestIndex(FR_est); divaddval = divaddvals[index]; mulval = mulvals[index]; } U1LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit, DLAB = 1 */ U1FDR = (mulval<<4) | divaddval; U1DLM = (DL >> 8) & 0xFF; U1DLL = DL & 0xFF, U1LCR = 0x03; /* DLAB = 0 */ }
I hope someone finds this helpful
Thanks for coming back to share the solution you found with the community.