zoukankan      html  css  js  c++  java
  • [Nios][UART] 使用UART 的一些問題?

    我在研究NIOS的UART時有遇到一些問題,做一下分享。

    Nios II在讀取周邊設備資訊時,可以用輪詢跟中斷方式兩種方式來讀取資料。

    測試前的前置作業:

    1.在Qsys中加入一個UART,並在Quartus中將新增的UART裝置的RX、TX對接。

    問題一: 使用輪詢方式讀程式

    當我用以下程式碼去輪詢時,會發現須等到第62筆資料傳完後,status暫存器的RRDY才會正常判斷。

     1 /*
     2  * UART test: polling test, design by Shih-An Li
     3  * 
     4  */
     5 
     6 #include <stdio.h>
     7 #include <system.h>
     8 #include "altera_avalon_uart.h"
     9 #include "altera_avalon_uart_regs.h"
    10 #include "alt_types.h"
    11 #include "sys/alt_irq.h"
    12 #include <unistd.h>
    13 #include <io.h>
    14 
    15 
    16 int main(void)
    17 {
    18   int rxdata=0,k=0,t=0;
    19   unsigned int status;
    20 
    21   IOWR_ALTERA_AVALON_UART_CONTROL(UART_TX_BASE, 0x1C0);  // clear status
    22 
    23   while(1)
    24   {
    25       status =IORD_ALTERA_AVALON_UART_STATUS(UART_TX_BASE);  // read status register
    26       if(status & ALTERA_AVALON_UART_STATUS_TRDY_MSK){  // check trdy flag
    27           if(status & 0x040){// transmit shift register is empty
    28               printf("Uart ready (0x%2x) and send %3d ", status, t);
    29               IOWR(UART_TX_BASE,1, t++);  // send tx data
    30           }
    31       }
    32 
    33       usleep(100000);
    34       status =IORD_ALTERA_AVALON_UART_STATUS(UART_TX_BASE);
    35       printf(" status=0x%x %d
    ", status,k++);
    36       if (status & ALTERA_AVALON_UART_STATUS_RRDY_MSK) // check RRDY flag
    37       {
    38           rxdata = IORD(UART_TX_BASE,0);
    39         printf("Your character rxd is:	%d  %d
    ", rxdata, k);
    40       }
    41 
    42   }
    43   return 0;
    44 }

    執行結果如下:

     1 Uart ready (0x60) and send  59  status=0x60 59
     2 Uart ready (0x60) and send  60  status=0x60 60
     3 Uart ready (0x60) and send  61  status=0x60 61
     4 Uart ready (0x60) and send  62  status=0xe0 62
     5 Your character rxd is:    62  63
     6 Uart ready (0x60) and send  63  status=0xe0 63
     7 Your character rxd is:    63  64
     8 Uart ready (0x60) and send  64  status=0xe0 64
     9 Your character rxd is:    64  65
    10 Uart ready (0x60) and send  65 

    讓我覺得很好奇的是去抓他硬體波形來看,發現只讀一次

    status =IORD_ALTERA_AVALON_UART_STATUS(UART_TX_BASE);

     結果硬體居然送出了好幾次的chip_select訊號,而Fig.1最後那次的chip_select居然是讀取addr 0 位置RXDATA暫存器,因此會把rx_char_ready訊號拉下,之後Fig2會在連續讀取幾次address 2位置的status暫存器,此時已經變成0x60了。

    一直要到62筆之後才會正常收值。

     Fig 1. UART波形

     Fig 2. 接續Fig 1. 波形

    方法二: 使用中斷方式

    程式碼如下,使用Nios II HAL模式來讀寫資料。

    此模式會用ISR函數來判斷RRDY旗標使否為1,是則去收值,因此判斷上比較準確。

     1 /*
     2  * Nios使用HAL指令,開啟以及讀寫UART設備, design by Shih-An Li
     3  */
     4 
     5 #include <stdio.h>
     6 #include <system.h>
     7 #include <unistd.h>  // define usleep()
     8 #include <stddef.h>  // define NULL
     9 #include <fcntl.h>   // define O_NONBLOCK
    10 #define BUF_SIZE 128
    11 
    12 
    13 int main()
    14 {
    15     int iCount, iUart_rxcount;
    16     int fdterm;           // FILEDESCRIPTOR RETURNED BY OPEN
    17     FILE *fpterm;         // FILE pointer returned by fdopen
    18     unsigned char uCUart1_rxbuffer[255], ucTX[128];
    19     // O_ACCMODE all access mode
    20     fdterm = open("/dev/uart_tx", O_ACCMODE | O_NONBLOCK);
    21     fpterm = fdopen(fdterm,"rw+");
    22     if(fpterm){
    23         fprintf(fpterm,"uart_tx STARTED
    "); // check initial output
    24           iUart_rxcount = fread(&uCUart1_rxbuffer, 1, sizeof(uCUart1_rxbuffer), fpterm);
    25           usleep(100000);
    26         printf("received:%s
    ",uCUart1_rxbuffer);
    27     }
    28     ucTX[0]=0;
    29     while(1) {
    30       write(fdterm, &ucTX[0], 1);  // write tx value to uart
    31       ucTX[0]++;  // tx value + 1
    32       // read uart data to rxbuffer and return receive data number
    33       iUart_rxcount = read(fdterm, &uCUart1_rxbuffer, sizeof(uCUart1_rxbuffer));
    34       for(iCount=0; iCount<iUart_rxcount; iCount++) {
    35 //          fprintf(fpterm,"received:%s
    ",uart1_rxbuffer);
    36           printf("%d
    ",uCUart1_rxbuffer[iCount]);
    37       }
    38       usleep(10000);
    39   }
    40   return 0;
    41 }

    執行結果如下

    received:uart_tx STARTED
    
    
    0
    1
    2
    3
    4
    5
    6
    7
    8

    因此推薦還是以HAL方式來讀取周邊資料比較不會有資料lost問題。

    source code 下載

  • 相关阅读:
    使用Java实现简单的局域网设备扫描
    Spring集成ElasticSearch搜索引擎
    Mysql 自定义函数示例
    Ehcache缓存配置以及基本使用
    SpringBoot-学习笔记
    【年度总结】2017年年度总结
    Android权限之动态权限
    Android沉浸式状态栏的简单实现
    Android自定义多宫格解锁控件
    Android For OpenCV的环境搭建
  • 原文地址:https://www.cnblogs.com/lishyhan/p/9128734.html
Copyright © 2011-2022 走看看