本發明涉及linux串口驅動開發技術領域,更具體而言,涉及一種基于阻塞接收機制的嵌入式linux串口驅動開發方法。
背景技術:
近年來,隨著嵌入式系統的快速發展,嵌入式linux系統以其源碼開放、系統本身獨特的特點在嵌入式開發領域中占據著重要的地位。雖然linux系統本身擁有很多的通用設備驅動程序支持,但是針對具體的開發應用要求用戶需要添加自己的程序(如機制的聯合、添加協議解析等),通用的設備驅動并不適用。現在多數嵌入式設備中針對串口數據的實時采集和處理通用的技術方法是采用在驅動層中完成數據包的采集、應用層對數據包進行處理的開發方法,具體開發模式和存在的問題如下:
(1)通用的驅動層中完成串口數據包采集方法是:在驅動層為了降低cpu占有率,采用串口中斷、休眠和喚醒等機制實現數據的接收,一般流程是:驅動層read串口讀取函數首先進入休眠,然后在中斷來臨的情況下接收數據并進行中斷喚醒read進程,并將單字節數據/數據包上傳給應用層。這種機制會導致以下沖突:由于驅動層read讀取之前接收的數據或數據包上傳給應用層之前都是出于休眠狀態,只有在中斷接收數據情況下才將read進程喚醒,當read函數被喚醒后正準備從緩存區讀取數據時,中斷又接收到新的數據,將新的數據存儲于read函數讀取的緩存區中,這樣寫入和讀取緩存區的時序沖突而被新的數據覆蓋,導致read讀取出現丟幀。在串口通信速率較高的情況下,由于沖突引起通信丟幀問題更嚴重;
(2)應用層對串口數據的讀取通過調用驅動層的read函數,一般情況下采用無阻塞讀取方法(如定時查詢、實時查詢)或者阻塞讀取方法(接收隊列被掛起直至數據或數據包接收完成),非阻塞定時查詢能夠解決(1)所述的機制沖突問題,會降低接收數據的實時性;非阻塞實時查詢和阻塞讀取方法需要驅動層相應機制配合,同樣會導致(1)所述的問題;
(3)對串口數據包進行處理(如檢測數據幀頭和幀尾、檢查數據長度和校驗位等)的開發方法一般是在應用層進行開發,而串口數據都需要經過linux內核層傳送,降低了數據的實時性能,尤其是當應用層數據處理之后錯誤的情況下仍需重新對串口進行收發,應用層再一次調用linux內核層驅動,必然會再次降低數據的實時性能。
基于此,有必要發明一種穩定性高、實時性強的嵌入式linux串口驅動開發方法,以解決linux串口驅動中通信丟幀問題,提高串口數據采集和處理的實時性能。
技術實現要素:
為了克服現有技術中所存在的不足,本發明提供一種基于阻塞接收機制的嵌入式linux串口驅動開發方法,該方法穩定性高、實時性強,解決了linux串口驅動中通信丟幀的問題,并且提高了串口數據采集和處理的實時性能。
為了解決上述技術問題,本發明所采用的技術方案為:
一種基于阻塞接收機制的嵌入式linux串口驅動開發方法,按照以下步驟進行:步驟一、采用字符型設備框架,設計linux串口驅動程序;步驟二、設計接收數據緩存區;步驟三、設計read函數阻塞讀取機制;步驟四、設計數據包實時處理機制。
所述步驟一具體為:
1)定義一個結構體file_operationsmyuart_fops,并向結構體中添加open、read、write、close、ioctl函數;
2)定義設備名稱,并向內核注冊該設備;
3)定義串口寄存器并進行虛擬地址映射,配置寄存器和引腳;
4)聲明串口休眠等待隊列,在open函數中初始化,并在open函數中申請串口接收中斷號,初始化串口配置,初始化休眠等待隊列,使其能接收中斷;
5)編寫write函數:判斷當前發送緩存區是否為空,然后將要發送的數據寫入發送緩存區,發送數據;循環上述步驟,直至發送完指定的發送數據長度tx_count。
所述步驟二具體為:
1)定義緩存區結構體rx_fifo,成員為:緩存區長度fifo_size、緩存區起始偏移地址fifo_in、緩存區結束偏移地址fifo_out;fifo_out-fifo_in=rx_count,rx_count為串口驅動當前接收的數據長度;
2)設計接收緩存區環形存儲模式:
當(fifo_size-fifo_out)≥app_rx_count,說明剩余緩存區空間可以緩存app_rx_count長度數據,初始化fifo_out=fifo_in,串口中斷一直處于接收狀態,一旦有數據就放入緩存區,進行下一步判斷;
當(fifo_size-fifo_out)<app_rx_count或者fifo_size等于fifo_out,說明接收緩存區不足以緩存app_rx_count長度的數據或者接收緩存區已滿,令fifo_in=0和fifo_out=fifo_in,緩存區回到起始狀態,這樣形成了緩存區回環存儲機制。
所述步驟三具體為:
1)linux串口驅動接收采用中斷+休眠/喚醒機制進行數據的實時接收,驅動層read函數采用阻塞讀取機制以配合應用層非阻塞實時查詢read讀取的實時調用;
2)設置好環形緩存區后,驅動層中斷函數每接收一個字節數據放入rx_fifo緩存區;驅動層read函數中采用如下阻塞機制和數據包實時處理機制:
①先判斷當rx_count≥app_rx_count,即串口當前接收的數據長度大于或等于應用層需要讀取的數據長度,直接讀取緩存區的數據,有效避免驅動層read函數只有休眠后被中斷喚醒才能讀取上傳數據、中斷接收數據的時序沖突;
②當rx_count<app_rx_count,即串口當前接收的數據長度小于應用層需要讀取的數據長度,才會讓read進程休眠,這時,read函數沒有數據的讀取和上傳,只有等到rx_count≥app_rx_count才去執行①步驟。
所述步驟四具體為:驅動層read讀取緩存區接收的數據后,進行數據包解析,如果數據正確,則通過copy_to_user函數將解析后的數據傳遞到應用層read函數,如果數據不正確,調用驅動層write函數再一次發送之前的命令信息,通過read函數再一次解析接收數據,如果數據仍不正確,read函數向應用層會發送接收錯誤信息。
與現有技術相比,本發明所具有的有益效果為:
其一,與現有的阻塞串口驅動開發技術相比,本發明通過采用環形緩存機制和read阻塞讀取判斷機制,解決了驅動層read函數被調用過程中和中斷之間的時序沖突而引起的數據丟幀問題;其二,與現有的非阻塞串口驅動開發技術相比,本發明通過應用程序實時調用read讀取函數,驅動層采用read阻塞讀取判斷機制和中斷休眠機制實時接收串口數據,解決了非阻塞串口驅動開發技術中所采用的應用層定時讀取函數造成的實時性差問題,或者應用層實時接收數據導致的cpu占用率高等問題;其三,與傳統的應用層解析數據包機制相比,本發明在驅動層read函數采用兩次解析數據,提高了數據通信準確率和實時處理數據性能。
綜上所述,本發明所述的一種基于阻塞接收機制的嵌入式linux串口驅動開發方法基于原有的中斷+休眠/喚醒方法進行的優化和改進,有效解決了阻塞串口驅動開發技術中的丟幀問題和非阻塞串口驅動開發技術中的實時性差等問題,提高了串口通信的穩定性和實時性。
附圖說明
圖1為linux串口驅動阻塞機制流程圖;
圖2為linux串口驅動中斷接收流程圖。
圖中:
app_rx_count為應用層read函數讀取串口接收的數據長度;
rx_count為串口驅動當前接收的數據長度;
fifo_in為環形緩沖區接收數據之前的起始偏移地址;
fif0_out為環形緩沖區接收一定數據長度的結束偏移地址;
fifo_size為環形緩沖區大小;
ev_press為中斷標志位;
rx_queue為接收等待隊列。
具體實施方式
下面將結合附圖對本發明作進一步詳細的描述,使本發明所記載的方案更加容易理解。
如圖1-圖2所示,本發明公開了一種基于阻塞接收機制的嵌入式linux串口驅動開發方法,該方法是采用如下步驟實現的。
步驟一、linux串口驅動程序采用字符型設備框架設計,即:
1)定義一個結構體file_operationsmyuart_fops,并向結構體中添加open、read、write、close、ioctl函數;
2)定義設備名稱,并向內核注冊該設備;
3)定義串口寄存器并進行虛擬地址映射,配置寄存器和引腳;
4)聲明串口休眠等待隊列,在open函數中初始化,并在open函數中申請串口接收中斷號,初始化串口配置,初始化休眠等待隊列,使能接收中斷;
5)編寫write函數:判斷當前發送緩存區是否為空,然后將要發送的數據寫入發送緩存區,發送數據;循環上述步驟,直至發送完指定的發送數據長度tx_count。
步驟二、設計接收數據緩存區,如圖1所示,即:
1)定義緩存區結構體rx_fifo,成員為:緩存區長度fifo_size、緩存區起始偏移地址fifo_in、緩存區結束偏移地址fifo_out。
2)設計接收緩存區環形存儲模式:
當(fifo_size-fifo_out)≥app_rx_count,說明剩余緩存區空間可以緩存app_rx_count長度數據,初始化fifo_out=fifo_in,串口中斷一直處于接收狀態,一旦有數據就放入緩存區,進行下一步判斷;
當(fifo_size-fifo_out)<app_rx_count或者fifo_size等于fifo_out,說明接收緩存區不足以緩存app_rx_count長度的數據或者接收緩存區已滿,令fifo_in=0和fifo_out=fifo_in,緩存區回到起始狀態,這樣形成了緩存區回環存儲機制。
通過設計環形存儲區,方便了驅動層read函數緩存讀取和中斷函數的接收數據,環形存儲機制保證存儲空間的重復利用和存儲數據的不丟失。
步驟三、設計read函數阻塞讀取機制,如圖1所示,即:
1)linux串口驅動接收采用中斷+休眠/喚醒機制進行數據的實時接收,如圖2所示,以降低cpu的占用率。驅動層read函數采用阻塞讀取機制以配合應用層非阻塞實時查詢read讀取的實時調用,以提高串口接收的實時性。
2)設置好環形緩存區后,驅動層中斷函數每接收一個字節數據放入rx_fifo緩存區。由于應用層read函數一直在實時調用驅動層read函數,因此驅動層read函數中采用如下阻塞機制和數據包實時處理機制:
①先判斷當rx_count≥app_rx_count,即串口當前接收的數據長度大于或等于應用層需要讀取的數據長度,直接讀取緩存區的數據,這樣有效地避免了驅動層read函數只有休眠后被中斷喚醒才能讀取上傳數據、中斷接收數據的時序沖突。
②當rx_count<app_rx_count,即串口當前接收的數據長度小于應用層需要讀取的數據長度,才會讓read進程休眠,大大降低了cpu的使用率。在這種情況下,read函數沒有數據的讀取和上傳,只有等到rx_count≥app_rx_count才去執行①步驟。
步驟四、設計數據包實時處理機制,如圖1所示,即:
本發明將數據包解析放置在驅動層而不放在應用層,主要是為了提高應用層向內核調用數據的實時性。驅動層read讀取緩存區接收的數據后,進行數據包解析(如判斷幀頭和幀尾、校驗等),如果數據正確,則通過copy_to_user函數將解析后的數據傳遞到應用層read函數,如果數據不正確,調用驅動層write函數再一次發送之前的命令信息,通過read函數再一次解析接收數據,如果數據仍不正確,read函數向應用層會發送接收錯誤信息。通過驅動層兩次解析數據,提高了數據的通信正確率,也避免了應用層read函數多次調用內核層read函數,提高了數據通信的實時性。