2011年6月3日 星期五

UART Baud Rate and FDR計算 1/2

這問題是在使用 LPC17xx MCB1700 Sample Code Bundle for LPC17xx Peripherals using Keil's MDK-ARM V2.00 (Jan 10, 2011)  Project UART 時遇到的問題.



UARTInit(0, 57600); /* baud rate setting */
UARTInit(1, 57600); /* baud rate setting */




程式中將UART0/1 設定 Baud Rate 57600 (bps) , 8bit , 1 stop bit,no parity , no flow ctrl ,這個範例實驗是接上rs232後,pc端開啟 HT. 或是 pUTTY,在 pUTTY中敲鍵盤按鍵,該按鍵 ACSII 碼會透過 PC RS232 TX 傳送至 LPC17xx UART Rx , 再由 LPC17xx Tx將同樣的字元傳送至PC端,顯示在 putty上.  相同的實驗在,LPCXpresso for LPC1114 code 中也有.


1. baud rate 57600


問題是將 UART 0/1的 Baud Rate改為 115200的時候,顯示就不正常.
而57600的時後就沒問題.

這是怎麼一回事?


基本的排除方法,我列出:
  1. Cable有無問題?(這類Cable常遇到 TX/RX有交換過)
  2. TX/RX 有沒接反?( PC TX to MCU RX , MCU TX to PC RX 當然這中間有 Level shift or USB to RS232 or to UART IC)
  3. 使用ICE Debug,設定中斷點監看接收資料
  4. 實際使用示波器量測訊號

1,2 點在我的環境下都沒問題,一直都在使用. ( 不過工作經驗告訴我,偶爾還是會遇到該去拜拜的時候,明明前一天還都正常,隔天來就出問題 ), 不過因為開頭敘述的, baud rate 設定 57600的時候實驗是正常的.所以更可增強1,2項 OK這點.

3. 使用ICE Debug,設定中斷點監看接收資料
在下列程式中,紅色字體部分設下中斷點.
所以在UART0/1 接收到字元之後,中斷. 查看是否進入中斷,若有接著檢查接收資料.


  while (1)
  {                /* Loop forever */
    if ( UART0Count != 0 )
    {
      LPC_UART0->IER = IER_THRE | IER_RLS;            /* Disable RBR */
  
      UARTSend( 0, (uint8_t *)UART0Buffer, UART0Count );
      UART0Count = 0;
      LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR;    /* Re-enable RBR */
    }       
    if ( UART1Count != 0 )
    {
      LPC_UART1->IER = IER_THRE | IER_RLS;            /* Disable RBR */
      UARTSend( 1, (uint8_t *)UART1Buffer, UART1Count );
      UART1Count = 0;
      LPC_UART1->IER = IER_THRE | IER_RLS | IER_RBR;    /* Re-enable RBR */
    }
  }



實驗後中斷發生,
檢查接收資料並非0x55.  (大寫 U的ASCII code)

於是進行4,實際量測訊號.



輪到3,4. 理論上....... 順序應該是4先做. XD (不早說 )
寫到這裡才想到,但是懶的掉換順序嘛....

分別量測得到 57600 (第一張圖),與 115200 下圖

2. baud rate 115200

訊號都沒有問題. 算出來的1 bit寬度也都在範圍內(後面會介紹如何計算).
所以推測硬體訊號正常,但是程式中斷看到的卻不是正確的值.
因此覺得訊號進IC後到軟體中斷這中間出現問題.
因為 UART (Universal Asynchronous Receiver/Transmitter) 非同步傳送接收訊號.  也就是沒有同步的Clock訊號( 像是I2C, SPI 都有CLOCK訊號). 所以兩端要能解讀正確訊號,必須先兩端要有默契. 要有哪些默契?


從這張圖就可看出, Speed ( Baud Rate ), Data bits, Stop bits, Parity, Flow Control
這些設定就是所謂雙方需要的默契.

其中的解釋可以參考  WIKI : UART 或是 搜尋 UART能見到很多資料.
而通常遇過的問題之中,就屬 Baud Rate 出錯的問題較多.

查看 Line Control Register ( LCR ) 設定



LPC_UART1->LCR = 0x83;        /* 8 bits, no Parity, 1 Stop bit */





以及程式中 MCR ( Modem Control Register ) 都未設定( default為 disable) ,就等同 Flow Control 無.

到此為止,可以差不多推論出問題就是 Baud Rate設定上出了問題.  WIKI :Baud
換言之,Baud Rate在這邊就是每秒(傳送/接收)的bit數量.
因此 Baud Rate 115200 也就是 115200 bit/per sec ,
換算回來 1個bit 的時間是 1/115200 = 8.68555x10(-6) [sec] = 8.68555 usec
圖2 一個 pulse的寬度 8.4 us ( cursor 不是對很準稍有誤差 )


在LPC1114系列中Baud Rate相關 register 如何計算填寫?
就在這個 UARTInit  function中,



/*LPC17xx */
uint32_t UARTInit( uint32_t PortNum, uint32_t baudrate )
{
  uint32_t Fdiv;
  uint32_t pclkdiv, pclk;

  if ( PortNum == 0 )
  {
    LPC_PINCON->PINSEL0 &= ~0x000000F0;
    LPC_PINCON->PINSEL0 |= 0x00000050;  /* RxD0 is P0.3 and TxD0 is P0.2 */
    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemFrequency. */
    /* Bit 6~7 is for UART0 */
    pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;
    switch ( pclkdiv )
    {
      case 0x00:
      default:
        pclk = SystemFrequency/4;
        break;
      case 0x01:
        pclk = SystemFrequency;
        break;
      case 0x02:
        pclk = SystemFrequency/2;
        break;
      case 0x03:
        pclk = SystemFrequency/8;
        break;
    }

    LPC_UART0->LCR = 0x83;        /* 8 bits, no Parity, 1 Stop bit */
    Fdiv = ( pclk / 16 ) / baudrate ;    /*baud rate */
    LPC_UART0->DLM = Fdiv / 256;                           
    LPC_UART0->DLL = Fdiv % 256;
    LPC_UART0->LCR = 0x03;        /* DLAB = 0 */
    LPC_UART0->FCR = 0x07;        /* Enable and reset TX and RX FIFO. */
    LPC_UART0->FDR = ((10<<4)|1);
       NVIC_EnableIRQ(UART0_IRQn);

    LPC_UART0->IER = IER_RBR | IER_THRE | IER_RLS;    /* Enable UART0 interrupt */
    return (TRUE);
  }
  else if ( PortNum == 1 )
  {
    LPC_PINCON->PINSEL4 &= ~0x0000000F;
    LPC_PINCON->PINSEL4 |= 0x0000000A;    /* Enable RxD1 P2.1, TxD1 P2.0 */
   
    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemFrequency. */
    /* Bit 8,9 are for UART1 */
    pclkdiv = (LPC_SC->PCLKSEL0 >> 8) & 0x03;
    switch ( pclkdiv )
    {
      case 0x00:
      default:
        pclk = SystemFrequency/4;
        break;
      case 0x01:
        pclk = SystemFrequency;
        break;
      case 0x02:
        pclk = SystemFrequency/2;
        break;
      case 0x03:
        pclk = SystemFrequency/8;
        break;
    }

    LPC_UART1->LCR = 0x83;        /* 8 bits, no Parity, 1 Stop bit */
    Fdiv = ( pclk / 16 ) / baudrate ;    /*baud rate */
    LPC_UART1->DLM = Fdiv / 256;                           
    LPC_UART1->DLL = Fdiv % 256;
    LPC_UART1->LCR = 0x03;        /* DLAB = 0 */
    LPC_UART1->FCR = 0x07;        /* Enable and reset TX and RX FIFO. */
    LPC_UART1->FDR = ((10<<4)|1);
       NVIC_EnableIRQ(UART1_IRQn);
                  
    LPC_UART1->IER = IER_RBR | IER_THRE | IER_RLS;    /* Enable UART1 interrupt */
    return (TRUE);
  }
  return( FALSE );
}


下篇繼續講解.. UART Baud Rate and FDR計算 2/2

附錄:  ASCII Table


9 則留言:

  1. 想請教一下,我是使用LPC1114F,想請問如何使用UART TX發送訊號,然後拉出接腳在示波器上看到,我是初學著~這方面不是很會,謝謝~~

    回覆刪除
  2. 不好意思,我是使用LPC1114F,想請問要如何像你一樣把訊號拉出來,在示波器上看,我的範例程式都是發射字串用終端機顯示的,想請問如何用市波器看~~謝謝

    回覆刪除
  3. Hi 葉老二,
    針對你的問題,簡單的說就是將 TX 訊號接到示波器上,地接好就可以看訊號。

    回覆刪除
    回覆
    1. 謝謝您的協助,已經可以在示波器看到訊號了,也成功地將UART訊號加到LED燈上了,另外想請問大大會用SPI介面嗎?因為我看書上都有,他的速度比UART快很多,我想將SPI產生的訊號拉出來加到LED燈上面,不知行不行得通??

      刪除
    2. 作者已經移除這則留言。

      刪除
    3. 作者已經移除這則留言。

      刪除
  4. 接上LED? 速度很快的時候肉眼其實也看不出什麼。不過你還是可以試看看。
    另外我也有些 SPI相關文章
    http://mcudiy.blogspot.tw/search/label/SPI

    回覆刪除
  5. 忘記跟大大說,因為要做光通訊,要用可見光LED傳資料,UART太慢了,最快只能到115200k所以才想說要用SPI,只是現在卡在訊號不知怎麼讓他從LPC1114送出來~~

    回覆刪除
    回覆
    1. http://mcudiy.blogspot.tw/search/label/SPI 給你參考看看。 輸出就看 MOSI pin.

      刪除

Related Posts Plugin for WordPress, Blogger...