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

數(shù)據(jù)寄存器,數(shù)據(jù)寄存器是什么意思
微控制器的寄存器的調(diào)試

移位寄存器怎么用_如何使用移位寄存器_移位寄存器的用途
開發(fā)一個(gè)Linux調(diào)試器就必須要知道寄存器和內(nèi)存!
Linux應(yīng)用層操作寄存器

寄存器寫保護(hù)的需求和硬件實(shí)現(xiàn)

評(píng)論