0 引言
嵌入式系統廣泛應用于生活中的各行各業,嵌入式軟硬件復雜度也在不斷增加,嵌入式系統開發與維護變得越來越復雜,然而嵌入式系統的開發與維護工具發展相對很滯后。為了提高嵌入式系統開發與維護的效率,發展嵌入式開發與維護工具是非常重要的。通過基于 Qt 平臺開發各種開發維護工具,實現嵌入式開發與維護的平臺化,是當前嵌入式開發和維護的趨勢[1-2]。當一款新的設備出廠之后,后期維護成了人們越來越關注的問題,為了延長設備使用周期,節約生產成本,使設備創造更大的價值,設備的操作與維護越來越受到人們的重視。
每當設備出現問題之后,就會調試底層驅動,這時可能需要調整寄存器的設置。面對這個問題,當前國內外開發與維護人員的通常做法是直接在程序里面修改硬件寄存器的數據,然后重新編譯程序,下載到設備,以此來檢驗設備運行情況[3-4]。但是這種方法比較麻煩,效率低下,不利于維護。為了提高開發人員開發和維護設備的效率,需要設計一個可視化工具,從而可以直接方便地對硬件內部寄存器進行修改與調試。這個工具擁有圖形化界面,可以直接讀寫下位機硬件寄存器的數值,首先輸入硬件寄存器要傳入的物理地址(這個物理地址可以通過芯片手冊確定,在驅動程序里面要通過映射為虛擬地址才能使用),然后根據要求來讀寫下位機任意硬件寄存器的數值。
1 系統設計框架
該系統采用嵌入式Linux操作系統作為開發的核心,包括三部分,分別為客戶端圖形化界面、服務器端和硬件設備。客戶端用來與用戶進行交互,如輸入下位機硬件寄存器地址和數據,服務器端用來接收上位機客戶端用戶傳來的數據或者向客戶端發送數據,底層驅動用來操作硬件設備內部寄存器的數值。本系統采用Linux 網絡通信的方式連接上位機和下位機,使交互更加方便和高效。整個系統框架如圖1所示。
圖1系統框架
該網絡通信系統包括服務器端和客戶端兩個部分。服務器端實現對數據的采集和發送,以及通過TCP協議進行網絡傳輸;客戶端主要是接收服務器傳輸過來的數據并進行圖形化顯示。服務器端和客戶端使用 TCP協議進行網絡通信的具體流程圖如圖2所示。
圖2TCP網絡通信流程圖
客戶端和服務器端的交互過程如下:服務器端先初始化socket,分配文件描述符;然后調用bind() 將套接字與本地IP地址和端口綁定;接著調用listen()對端口進行監聽,并設置監聽隊列的大小;繼續調用accept()阻塞,等待客戶端連接[5]。如果有客戶端初始化一個socket()后調用connect()向服務器端發送連接請求,若經過三次握手,則連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求并處理請求,然后把回應數據發送給客戶端,客戶端讀取數據,最后調用close() 關閉連接,一次交互結束。
2.1服務器端設計
服務器端通過三次握手與客戶端建立連接之后,將驅動端映射到內核空間的數據讀取出來并且發送到客戶端,或者將客戶端要發送的數據接收到服務器端并發送給驅動端。
下位機服務器端的部分程序如下:
while(1){
//服務器阻塞,直到獲得連接請求并建立連接
int socklis=accept(sock,(struct sockaddr *)&.clientAddr,
&.len);
if(socklis<0){
perror("accept")
exit(1);
}
While(1){// 清空數組
memset(buff,0,1024);
//從客戶端接收數據
n=recv(socklis,buff,1024,0);
if(n<0){
perror("recv");
return—1
}
msgtype=*(unsigned int *)buff;
switch(msgtype){
case REGISTER_CTRL:{
structregister_ctrlregmsg;
structregister_info reg;
//內存拷貝
memcpy(&.regmsg,buff,sizeof(regmsg));
reg.addr=regmsg.addr;
reg.data=regmsg.data;
if(regmsg.cmd==1){
ioctl(fd_reg,REG_READ,);
printf("read reg:addr=%#x,data=%#x ",reg.
addr,reg.data);
//發送數據到客戶端
send(socklis,&.reg,sizeof(reg),0);
}else if(regmsg.cmd==0){
printf("write reg:addr=%#x,data =%#x ",reg.addr,
reg.data);
ioctl(fd_reg,REG_WRITE,&.reg);
}
break;
}
}
}
}
2.2客戶端設計
為了滿足人性化要求,本文設計了一個Qt客戶端圖形化界面,從而方便用戶操作和讀寫數據。Qt是一個跨平臺的C++圖形用戶界面應用程序框架,由挪威Troll- Tech公司出品,目前包括 QtCreator、Qt Embedded、Qt Designer等快速開發工具[6]。其中 Qt Creator是一個全新的、完整的、輕量級的圖形開發平臺,它可以按照設計人員的意愿建立圖形用戶界面,隨時進行顯示和修改,具有良好的適應性,保證了不同平臺之間設計的兼容性[7]。
在客戶端圖形化界面中,首先設計一個“寄存器地址”輸入框,用來輸入用戶需要操作的下位機寄存器物理地址;然后設計一個“寄存器數據”輸入框,用來顯示從下位機讀取的存儲在該寄存器里面的數據,或者向下位機發送用戶需要寫入到該寄存器中的數據;接著在旁邊設計一個“讀”數據復選框和一個“寫”數據復選框,用來發送“讀”或者“寫”命令;最后在界面下端設計一個“確定”按鈕,來確認需要執行的操作。Qt圖形化界面如圖3所示。該界面清晰明確、步驟簡單、操作方便、簡潔高效,大大縮短了用戶查看和編輯下位機設備硬件寄存器中數據的時間,提高了用戶調試和維護設備的效率。
圖3Qt圖形化界面
在Qt中通過使用Linux系統調用中的 TCP協議實現客戶端與服務器端的連接,并進行數據讀取、發送以及顯示,按下“確定”按鈕,建立網絡通信,開始進行數據的讀取、發送和顯示。
上位機客戶端部分應用程序如下:
void MainWindow::on_send_clicked(){
struetregister_ctrlreg;
structregister_inforeg_rsp;
reg.msgtype=REGISTERCTRL;
reg.addr=ui->addr->text().toUInt(NULL,16);
reg.data=ui->data->text().toUInt(NULL,16);
if(ui->read->isChecked()){
reg.cmd=1;
qDebug("read");
}
if(ui->write->isChecked()){
reg.cmd=0;
qDebug("write");
}
//發送數據到服務器端
send(m_fd_client,&.reg,sizeof(reg),0);
if(reg.cmd ==1){
//從服務器端接收數據
recv(m_fd_client,&.reg_rsp,sizeof(reg_rsp),0);
ui->data->setText(QString::number(reg_rsp.data,
16)):
}
}
3 底層驅動端設計
系統在運行時,外設的I/O內存資源的物理地址是已知的,由硬件設計決定,但是 CPU 通常并沒有為這些已知的外設I/O內存資源物理地址預定義虛擬地址范圍,驅動程序并不能直接通過物理地址訪問I/O內存資源,而必須將它們映射到核心虛地址空間內(通過頁表),然后根據映射所得到的核心虛擬地址范圍通過訪內指令訪問這些I/O內存資源[8]。
嵌入式處理器訪問外設都是以地址指針的形式訪問,也就是說要想訪問外設,必須知道這個外設的物理地址。在Linux系統中,不管是在用戶空間還是內核空間,一律不允許直接訪問外設的物理地址,要想訪問需要提前將物理地址映射到內核虛擬地址或者用戶虛擬地址上,將來程序訪問用戶虛擬地址或者內核虛擬地址就是在訪問物理地址[9]。將Linux系統4G虛擬地址空間劃分如下,用戶虛擬地址為0x00000000~0xBFFF FFFF(0G~3G),內核虛擬地址為0xC0000000~0xFFFF FFFF(3G~4G)[10]。一個物理地址可以有多個虛擬地址,一個虛擬地址不能對應多個物理地址。如果要將物理地址映射到內核虛擬地址上,可以使用ioremap()函數;若要解除地址映射,可以使用iounmap() 函數。Linux地址映射機制如圖4所示。
圖4Linux 地址映射機制
驅動端部分程序如下:
staticlongreg_ioctl(structfile*file,unsignedintemd,unsigneclongarg){
//定義內核緩沖區
structreg_infokreg;
unsignedlong*gpiobase;
//拷貝用戶緩沖區到內核
copy_to_user((structreg_info *)arg,&kreg,sizeof
(kreg));
//將外設的物理地址映射到內核虛擬地址上
gpiobase=ioremap(kreg.addr,4);
//解析命令,操作硬件
switch(cmd){
case REG_READ:
kreg.data=*gpiobase;
copy_to_user((structreg_info *)arg,&kreg,sizeof
(kreg));
break;
case REG_WRITE:
*gpiobase=kreg.data;
break;
}
//解除地址映射
iounmap(gpiobase);
return0;
}
4 實驗結果
本系統使用基于Cortex-A53架構處理器的S5P6818開發板上面的點陣LED燈來驗證實驗結果。首先在下位機運行Linux系統,點亮第一個LED燈,將第二個和第三個LED燈關閉。然后查看芯片手冊,將物理地址為0xC001C000的32位寄存器的bit[12]、設為低電平,bit[11]和bit[7]設為高電平。對此,向該寄存器寫入數據0x880,并選中右邊的“寫”復選框,點擊“確認”按鈕(如圖5所示)后,發現開發板第一個LED燈被點亮,驗證成立,如圖6所示。接著選中右邊的“讀”復選框,再次點擊“確認”按鈕,發現寄存器數據顯示為0x880(如圖7所示),因為讀取的正是剛才寫入到該寄存器的數值。
圖5向寄存器寫數據
圖6點陣LED被點亮
圖7 從寄存器讀數據
結語
本文所設計的寄存器讀寫器工具,只需知道設備的硬件寄存器物理地址就能快速準確地讀寫任意硬件寄存器的數值,操作簡單方便,快速高效,為設備操作與維護提供了一種有效的解決方案。特別是當系統邏輯比較復雜時,圖形化界面的調試工具可以大大節省用戶發現問題的時間,能夠讓用戶方便快速地處理設備中出現的各種問題,從而更好地維護產品和設備。
審核編輯:劉清
-
嵌入式
+關注
關注
5082文章
19126瀏覽量
305255 -
寄存器
+關注
關注
31文章
5343瀏覽量
120379 -
Linux系統
+關注
關注
4文章
593瀏覽量
27397 -
上位機
+關注
關注
27文章
942瀏覽量
54815 -
TCP通信
+關注
關注
0文章
146瀏覽量
4223
原文標題:Linux 系統下對硬件寄存器調試的應用研究
文章出處:【微信號:麥克泰技術,微信公眾號:麥克泰技術】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論