[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 下載

原文地址:https://www.cnblogs.com/lishyhan/p/9128734.html