2010-09-10 49 views
2

我的波特率應該是115200,但它是892.9ARM LPC1768 UART0的配置,錯誤的波特率

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

和它的作品!

我必須經歷,看看我錯了什麼。我懷疑寄存器設置的順序是關閉的。

+0

對於25MHz的pclk和波特率115200,DLest出來到13.56。用戶手冊中有一個使用12MHz和115200的例子,它給出了我計算出的DLest的大約一半。所以我知道這個部分是有效的。我認爲我的pclk實際上並沒有設置爲cclk/4,但我是這個平臺的新手,並且無法確定一個堅如磐石的測試來確定這一點。 – michael 2010-09-10 22:34:34

+0

您是否看過恩智浦爲lpc17xx設備提供的CMSIS庫? – 2010-09-10 23:58:36

+0

實際上,現在我將100MHz除以4而不是4,波特率爲2 * 892.9 – michael 2010-09-11 00:07:40

回答

0

懷疑UART的時鐘是從cclk進一步分開的。您需要檢查數據表並相應地更新。

+0

你能詳細說明一下嗎? – michael 2010-09-10 23:26:40

2

看看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。

+0

該評論還提到了一個錯誤的PLL輸出速率(64MHz),我懷疑這裏有一個複製和粘貼錯誤。它也是CCLK速率和*不* PLL0速率。 – 2010-09-10 23:34:29

+0

是的,這是一個複製粘貼錯誤。我解決了這個問題,並將pclksel0和pclksel1移到了pll之上。但是我的波特率仍然太低。 – michael 2010-09-10 23:53:16

0

我想爲我的LPC1768 UART1端口使用一個簡化的驅動程序,所以我寫了一個基於CMSIS代碼的波特率計算器應用程序。

您提供外設時鐘頻率和所需的波特率,它將生成DLL,分數乘法器&分頻器,並最終重新計算計算出的值以指示可實現的波特率。

我已經用25MHz的外設時鐘和115200 & 9600的波特率測試過,並且成功。它不計算在4800以上的bauds通常爲0的DLM。

它可以在免費下載站點上獲得。 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; 
}