开发者

ARM LPC1768 UART0 configuration, wrong baud rate

开发者 https://www.devze.com 2023-01-15 11:53 出处:网络
My baud rate should be 115200, but it is 892.9 void UART0_Init(int pclk, int baudrate) { unsigned long int DLest;

My baud rate should be 115200, but it is 892.9

void UART0_Init(int pclk, int baudrate)
{
    unsigned long int DLest;
    //unsigned long int pclk;
    unsigned int temp;
    // Turn on power to UART0
    SC->PCONP |=  PCUART0_POWERON;

    // Set PINSEL0 so that P0.2 = TXD0, P0.3 = RXD0
    PINCON->PINSEL0 = (PINCON->PINSEL0 & ~0xf0) | (1 << 4) | (1 << 6);

    UART0->LCR = 0x83;      // 8 bits, no Parity, 1 Stop bit, DLAB=1
    DLest =  (pclk / 16) /  baudrate;   // Set baud rate
    UART0->DLM = DLest / 256;
    UART0->DLL = DLest % 256;
   // UART0->FDR =
    UART0->IER = 0x7;       //enable RBR (b0), THRE(b1), RLS(b2)
    UART0->LCR = 0x03;      // 8 bits, no Parity, 1 Stop bit DLAB = 0
    UART0->FCR = 0x07;      // Enable and reset TX and RX FIFO
}
void prvSetupHardware( void )
{
    /* Disable peripherals power. */
    SC->PCONP = 0;

    /* Enable GPIO power. */
    SC->PCONP = PCONP_PCGPIO;

    /* Disable TPIU. */
    PINCON->PINSEL10 = 0;

    if ( SC->PLL0STAT & ( 1 << 25 ) )
    {
        /* Enable PLL, disconnected. */
        SC->PLL0CON = 1;            
        SC->PLL0FEED = PLLFEED_FEED1;
        SC->PLL0FEED = PLLFEED_FEED2;
    }

    /* Disable PLL, disconnected. */
    SC->PLL0CON = 0;                
    SC->PLL0FEED = PLLFEED_FEED1;
    SC->PLL0FEED = PLLFEED_FEED2;

    /* Enable main OSC. */
    SC->SCS |= 0x20;            
    while( !( SC->SCS & 0x40 ) );

    /* select main OSC, 12MHz, as the PLL clock source. */
    SC->CLKSRCSEL = 0x1;        
    SC->PCLKSEL0 = 0xAAAAAAAA;  /* PCLK is 1/2 CCLK */
    SC->PCLKSEL1 = 0xAAAAAAAA;


    /*Fcc0 = 400MHz, M = 50, N = 3*/
    SC->PLL0CFG = 0x20031;

    SC->PLL0FEED = PLLFEED_FEED1;
    SC->PLL0FEED = PLLFEED_FEED2;

    /* Enable PLL, disconnected. */
    SC->PLL0CON = 1;                
    SC->PLL0FEED = PLLFEED_FEED1;
    SC->PLL0FEED = PLLFEED_FEED2;

    /* Set clock divider. */
    /*Clock = 100MHz, Fcc0 = 400MHz*/
    SC->CCLKCFG = 0x03;//divided by 4.

    /* Configure flash accelerator. */
    SC->FLASHCFG = 0x403a;

    /* Check lock bit status. */
    while( ( ( SC->PLL0STAT & ( 1 << 26 ) ) == 0 ) );   

    /* Enable and connect. */
    SC->PLL0CON = 3;                
    SC->PLL0FEED = PLLFEED_FEED1;
    SC->PLL0FEED = PLLFEED_FEED2;
    while( ( ( SC->PLL0STAT & ( 1 << 25 ) ) == 0 ) );   

    /* Configure the clock for the USB. */

    if( SC->PLL1STAT & ( 1 << 9 ) )
    {
        /* Enable PLL, disconnected. */
        SC->PLL1CON = 1;            
        SC->PLL1FEED = PLLFEED_FEED1;
        SC->PLL1FEED = PLLFEED_FEED2;
    }

    /* Disable PLL, disconnected. */
    SC->PLL1CON = 0;                
    SC->PLL1FEED = PLLFEED_FEED1;
    SC->PLL1FEED = PLLFEED_FEED2;

    SC->PLL1CFG = 0x23;
    SC->PLL1FEED = PLLFEED_FEED1;
    SC->PLL1FEED = PLLFEED_FEED2;

    /* Enable PLL, disconnected. */
    SC->PLL1CON = 1;                
    SC->PLL1FEED = PLLFEED_FEED1;
    SC->PLL1FEED = PLLFEED_FEED2;
    while( ( ( SC->PLL1STAT & ( 1 << 10 ) ) == 0 ) );

    /* Enable and connect. */
    SC->PLL1CON = 3;                
    SC->PLL1FEED = PLLFEED_FEED1;
    SC->PLL1FEED = PLLFEED_FEED2;
    while( ( ( SC->PLL1STAT & ( 1 << 9 ) ) == 0 ) );


    /* Configure the LEDs. */
    vParTestInitialise();

    /*pclk = 100MHZ/2, baud = 115200 */
    UART0_Init(100000000/2, 115200);


    /* Set the sleep mode to highest level sleep*/
    SC->PCON = 0x0;
    SCB->SCR = 0x0;

    /*set push button interrupt */
    PINCO开发者_JAVA技巧N->PINSEL4 |= 0x00100000;
    SC->EXTMODE =0;
    NVIC_SetPriority( EINT0_IRQn, configUIButton1_INTERRUPT_PRIORITY );
    NVIC_EnableIRQ( EINT0_IRQn );
    NVIC_SetPriority( UART0_IRQn, configUIButton1_INTERRUPT_PRIORITY + 1 );
    NVIC_EnableIRQ( UART0_IRQn );

}

I have confirmed that my cclk is running at 100MHz.


I replace the UART init code with code from an example project by Kunil (uart_interrupt_demo):

    void uart_init(int baudrate) {
int errorStatus = -1; //< Failure
        long int SystemFrequency = 100000000;
        // UART clock (FCCO / PCLK_UART0)
        unsigned int uClk = SystemFrequency / 4;
        unsigned int calcBaudrate = 0;
        unsigned int temp = 0;

        unsigned int mulFracDiv, dividerAddFracDiv;
        unsigned int divider = 0;
        unsigned int mulFracDivOptimal = 1;
        unsigned int dividerAddOptimal = 0;
        unsigned int dividerOptimal = 0;

        unsigned int relativeError = 0;
        unsigned int relativeOptimalError = 100000;

    // Turn on power to UART0
    SC->PCONP |=  PCUART0_POWERON;
    // Change P0.2 and P0.3 mode to TXD0 and RXD0
    PINCON->PINSEL0 = (1 << 4) | (1 << 6);

    // Set 8N1 mode
    UART0->LCR = 0x83;

    // Set the baud rate
    uClk = uClk >> 4; /* div by 16 */

        /*
         *  The formula is :
         * BaudRate= uClk * (mulFracDiv/(mulFracDiv+dividerAddFracDiv) / (16 * DLL)
         */

        /*
         * 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);

                divider = temp / baudrate;
                if ((temp % baudrate) > (baudrate / 2))
                    divider++;

                if (divider > 2 && divider < 65536) {
                    calcBaudrate = temp / divider;

                    if (calcBaudrate <= baudrate) {
                        relativeError = baudrate - calcBaudrate;
                    } else {
                        relativeError = calcBaudrate - baudrate;
                    }

                    if (relativeError < relativeOptimalError) {
                        mulFracDivOptimal = mulFracDiv;
                        dividerAddOptimal = dividerAddFracDiv;
                        dividerOptimal = divider;
                        relativeOptimalError = relativeError;
                        if (relativeError == 0)
                            break;
                    }
                }
            }

            if (relativeError == 0)
                break;
        }

        if (relativeOptimalError
                < ((baudrate * UART_ACCEPTED_BAUDRATE_ERROR) / 100)) {

            UART0->LCR |= DLAB_ENABLE;
            UART0->DLM = (unsigned char) ((dividerOptimal >> 8) & 0xFF);
            UART0->DLL = (unsigned char) dividerOptimal;
            UART0->LCR &= ~DLAB_ENABLE;

            UART0->FDR = ((mulFracDivOptimal << 4) & 0xF0) | (dividerAddOptimal
                    & 0x0F);

            errorStatus = 0; //< Success
        }


    // Enable TX and RX FIFO
    UART0->FCR |= FIFO_ENABLE;

    // Set FIFO to trigger when at least 14 characters available
    UART0->FCR |= (3 << 6);

    // Enable UART RX interrupt (for LPC17xx UART)
    UART0->IER = RBR_IRQ_ENABLE;

    // Enable the UART interrupt (for Cortex-CM3 NVIC)
    NVIC_EnableIRQ(UART0_IRQn);
}

And it works!

I have to go through and see what i had wrong. I suspect the order of register settings was off.


Have a look at the Errata sheet. You can't set SC->PCLKSEL0 after you fired up the main PLL, so the divider stays at CCLK/4. Just move the line
/* Setup the peripheral bus to be the same as the PLL output (64 MHz). */ SC->PCLKSEL0 = 0x05555555;

a few lines up, before you enable the PLL.


Suspect that clk for UART is further divided from the cclk. You need to check the datasheet and update accordingly.


I wanted a simplified driver for my LPC1768 UART1 port so I have written a baud rate calculator application based on CMSIS code.

You provide the Peripheral Clock Frequency and Desired Baud Rate and it will generate the DLL, Fractional Multiplier & Divider and finally recalculates with the computed values to indicate the Baud rate achievable.

I have tested it with a peripheral clock of 25MHz and baud rates of 115200 & 9600 with success. It does not calculate DLM which is generally 0 for bauds above 4800.

It is available at a freeware download site. http://sabercathost.com/6y6

I have a reputation to maintain and to that end the application I uploaded does not contain a virus.

HTH Mark

As requested by Drew I've appended the CMSIS function I used in my code below.

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

/* 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);
}


/* 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++)
    {
      divisor = ((uint64_t)uClk<<28)*m/(baudrate*(m+d));
      current_error = divisor & 0xFFFFFFFF;

      tmp = divisor>>32;

      /* Adjust error */
      if(current_error > ((uint32_t)1<<31)){
        current_error = -current_error;
        tmp++;
        }

      if(tmp<1 || tmp>65536) /* Out of range */
      continue;

      if( current_error < best_error){
        best_error = current_error;
        best_divisor = tmp;
        bestd = d;
        bestm = m;
        if(best_error == 0) break;
        }
    } /* end of inner for loop */

    if (best_error == 0)
      break;
} /* end of outer for loop  */

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

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;

if (best_error < UART_ACCEPTED_BAUDRATE_ERROR)
    {
        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(best_divisor);
            ((LPC_UART1_TypeDef *)UARTx)->/*RBTHDLR.*/DLL = UART_LOAD_DLL(best_divisor);
            /* Then reset DLAB bit */
            ((LPC_UART1_TypeDef *)UARTx)->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK;
            ((LPC_UART1_TypeDef *)UARTx)->FDR = (UART_FDR_MULVAL(bestm) \
                    | UART_FDR_DIVADDVAL(bestd)) & UART_FDR_BITMASK;
        }
        else
        {
            UARTx->LCR |= UART_LCR_DLAB_EN;
            UARTx->/*DLIER.*/DLM = UART_LOAD_DLM(best_divisor);
            UARTx->/*RBTHDLR.*/DLL = UART_LOAD_DLL(best_divisor);
            /* Then reset DLAB bit */
            UARTx->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK;
            UARTx->FDR = (UART_FDR_MULVAL(bestm) \
                    | UART_FDR_DIVADDVAL(bestd)) & UART_FDR_BITMASK;
        }
        errorStatus = SUCCESS;
    }

    return errorStatus;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消