UART baudrate error with LPCOpen2

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

UART baudrate error with LPCOpen2

541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgr on Tue Feb 18 03:40:23 MST 2014
Dear all,

I have migrated a project based on LPC1763 from LPCOpen 1.03 to LPCOpen 2.07 and the UART is not working at the right speed anymore.
I have checked both version source code of the "set baudrate" function and found that LPCOpen v1 was using the fractional divider but LPCOpen2 is using only the main divider.

I use a 12Mhz peripheral clock and would like a 115200bps speed, so the divider is computed to 6 that result in 125000bps speed...

Is this expected ? Why LPCOpen2 do not use fractional divider ?

Thanks in advance for your help

Labels (1)
0 Kudos
4 Replies

477 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgr on Thu Feb 27 02:58:31 MST 2014
Thanks, it works nicely fro my case.
0 Kudos

477 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wellsk on Wed Feb 26 10:28:00 MST 2014
We have an initial update to the FDR function for this that should appear in the next release...see below.

/* 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 actualRate = 0, d, m, bestd, bestm, tmp;
       uint32_t current_error, best_error;
       uint64_t best_divisor, divisor;
       uint32_t recalcbaud;

       /* Get Clock rate */
#if defined(CHIP_LPC175X_6X)
       uClk = Chip_Clock_GetPeripheralClockRate(Chip_UART_GetClkIndex(pUART));
#else
       uClk = Chip_Clock_GetPeripheralClockRate();
#endif
    
       /* 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 */
       best_error = 0xFFFFFFFF;/* Worst case */
       bestd = 0;
       bestm = 0;
       best_divisor = 0;
       for (m = 1; m <= 15; m++) {
              for (d = 0; d < m; d++) {

                     /*   The result here is a fixed point number.  The integer portion is in the upper 32 bits.
                     * The fractional portion is in the lower 32 bits.
                     */
                     divisor = ((uint64_t) uClk << 28) * m / (baudrate * (m + d));

                     /*   The fractional portion is the error. */
                     current_error = divisor & 0xFFFFFFFF;

                     /*   Snag the integer portion of the divisor. */
                     tmp = divisor >> 32;

                     /*   If closer to the next divisor... */
                     if (current_error > ((uint32_t) 1 << 31)) {

                           /* Increment to the next divisor... */
                           tmp++;

                           /* Now the error is the distance to the next divisor... */
                           current_error = -current_error;
                     }

                     /*   Can't use a divisor that's less than 1 or more than 65535. */
                     if ((tmp < 1) || (tmp > 65535)) {
                           /* Out of range */
                           continue;
                     }

                     /*   Also, if fractional divider is enabled can't use a divisor that is less than 3. */
                     if ((d != 0) && (tmp < 3)) {
                           /* Out of range */
                           continue;
                     }

                     /*   Do we have a new best? */
                     if (current_error < best_error) {
                           best_error = current_error;
                           best_divisor = tmp;
                           bestd = d;
                           bestm = m;

                           /*   If error is 0, that's perfect.  We're done. */
                           if (best_error == 0) {
                                  break;
                           }
                     }
              }      /* for (d) */

              /*   If error is 0, that's perfect.  We're done. */
              if (best_error == 0) {
                     break;
              }
       }      /* for (m) */

       if (best_divisor == 0) {
              /* can not find best match */
              return 0;
       }

       recalcbaud = (uClk >> 4) * bestm / (best_divisor * (bestm + bestd));

       /* reuse best_error to evaluate baud error */
       if (baudrate > recalcbaud) {
              best_error = baudrate - recalcbaud;
       }
       else {
              best_error = recalcbaud - baudrate;
       }

       best_error = (best_error * 100) / baudrate;

    /* Update UART registers */
       Chip_UART_EnableDivisorAccess(pUART);
       Chip_UART_SetDivisorLatches(pUART, UART_LOAD_DLL(best_divisor), UART_LOAD_DLM(best_divisor));
       Chip_UART_DisableDivisorAccess(pUART);

       /* Set best fractional divider */
       pUART->FDR = (UART_FDR_MULVAL(bestm) | UART_FDR_DIVADDVAL(bestd));

       /* Return actual baud rate */
       actualRate = recalcbaud;

       return actualRate;
}


0 Kudos

477 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wellsk on Wed Feb 19 10:29:11 MST 2014
Hmm, it's odd we keep missing this one and (seem to) have got it right in later package releases.
We'll fix this one for the updated release and try to provide a fix for this that correctly uses the FDR.
For now, I've added this as a known issue in the 17xx/40xx known issue list for v2.07.

http://www.lpcware.com/content/project/lpcopen-software-development-platform-nxp-lpc-microcontroller...
0 Kudos

477 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgr on Tue Feb 18 06:00:33 MST 2014
I have also tried the Chip_UART_SetBaudFDR function but the actualRate returned is still 125000bps...
So it seems the algorithms used by SetBaudFDR is not working properly...
0 Kudos