【问题标题】:ARM LPC1768 UART0 configuration, wrong baud rateARM LPC1768 UART0 配置,波特率错误
【发布时间】:2011-04-10 23:15:34
【问题描述】:

我的波特率应该是 115200,但它是 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 */
    PINCON->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 );

}

我已确认我的 cclk 以 100MHz 运行。


我用 Kunil (uart_interrupt_demo) 的示例项目中的代码替换了 UART 初始化代码:

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

它有效!

我必须去看看我做错了什么。我怀疑寄存器设置的顺序是关闭的。

【问题讨论】:

  • 对于 25MHz 的 pclk 和 115200 的波特率,DLest 为 13.56。用户手册中有一个使用 12MHz 和 115200 的示例,它大约提供了我计算的 DLest 的一半。所以我知道那部分有效。我认为我的 pclk 实际上并没有设置为 cclk/4,但我是这个平台的新手,在决定一个坚如磐石的测试来确定这一点时遇到了麻烦。
  • 您看过恩智浦为 lpc17xx 设备提供的 CMSIS 库吗?
  • 实际上,现在我将 100MHz 除以 2 而不是 4,波特率为 2*892.9
  • 如果我将 pclk 作为低于 25000000 的任何值传递给 UART0_Init,波特率始终相同 (892.9)。我什至通过了 1。

标签: embedded serial-port arm lpc clockrates


【解决方案1】:

看看Errata sheet。 启动主 PLL 后无法设置 SC->PCLKSEL0,因此分频器保持在 CCLK/4。 移动线路
/* Setup the peripheral bus to be the same as the PLL output (64 MHz). */ SC->PCLKSEL0 = 0x05555555;

在启用 PLL 之前先排几行。

【讨论】:

  • 评论还提到了错误的 PLL 输出速率 (64MHz),我怀疑这里有复制和粘贴错误。它也是 CCLK 速率和 not PLL0 速率。
  • 是的,这是一个复制粘贴错误。我解决了这个问题,并将 pclksel0 和 pclksel1 移到 pll 东西上方。但我的波特率还是太低了。
【解决方案2】:

怀疑 UART 的 clk 是从 cclk 进一步分出来的。您需要检查数据表并进行相应更新。

【讨论】:

    【解决方案3】:

    我想要一个用于 LPC1768 UART1 端口的简化驱动程序,因此我编写了一个基于 CMSIS 代码的波特率计算器应用程序。

    您提供外设时钟频率和所需的波特率,它将生成 DLL、分数乘法器和除法器,最后使用计算值重新计算以指示可实现的波特率。

    我已经成功地使用 25MHz 的外围时钟和 115200 和 9600 的波特率对其进行了测试。不计算 DLM,4800 以上的波特率一般为 0。

    它可在免费软件下载站点获得。 http://sabercathost.com/6y6

    我需要维护声誉,为此我上传的应用程序不包含病毒。

    HTH 标记

    按照 Drew 的要求,我在下面的代码中附加了我在代码中使用的 CMSIS 函数。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-20
      • 1970-01-01
      • 2014-03-28
      • 1970-01-01
      相关资源
      最近更新 更多