




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第6章嵌入式Linux設(shè)備驅(qū)動程序的設(shè)計與實現(xiàn)
6.1嵌入式Linux驅(qū)動程序簡介6.2嵌入式Linux驅(qū)動程序框架6.3嵌入式Linux模塊化驅(qū)動程序設(shè)計6.4嵌入式Linux的CAN總線通信6.5嵌入式Linux的IIC總線通信6.6嵌入式Linux的D/A轉(zhuǎn)換6.7嵌入式Linux的A/D轉(zhuǎn)換6.8嵌入式Linux的PS/2鍵盤6.9嵌入式Linux的8255驅(qū)動6.10嵌入式Linux的PWM驅(qū)動6.11嵌入式Linux的串口驅(qū)動6.12LCD測試6.13矩陣鍵盤6.1嵌入式Linux驅(qū)動程序簡介設(shè)備驅(qū)動程序是操作系統(tǒng)內(nèi)核和機器硬件之間的接口。設(shè)備驅(qū)動程序為應(yīng)用程序屏蔽了硬件細(xì)節(jié),對應(yīng)用程序來說硬件是透明的。在應(yīng)用程序看來,硬件設(shè)備只是一個設(shè)備文件,應(yīng)用程序可以像操作普通文件一樣對硬件設(shè)備進行操作。
Linux系統(tǒng)的設(shè)備分為字符設(shè)備(chardevice)、塊設(shè)備(blockdevice)、網(wǎng)絡(luò)設(shè)備(networkdevice)和其他設(shè)備。字符設(shè)備是不需要緩沖而直接讀/寫的設(shè)備,如串口、鍵盤和鼠標(biāo)等;塊設(shè)備的訪問通常需要緩沖來支持,以數(shù)據(jù)塊為單位來讀/寫,如磁盤設(shè)備等;網(wǎng)絡(luò)設(shè)備是通過套接字來訪問的特殊設(shè)備。用戶進程通過設(shè)備文件實現(xiàn)與硬件的交流。每個設(shè)備文件都有其文件屬性,表示是字符設(shè)備還是塊設(shè)備。另外每個文件都有兩個設(shè)備號:第一個是主設(shè)備號,標(biāo)識驅(qū)動程序;第二個是從設(shè)備號,標(biāo)識使用同一個設(shè)備驅(qū)動程序的不同硬件設(shè)備,比如有兩個軟盤,就可以用從設(shè)備號來區(qū)分它們。設(shè)備文件的主設(shè)備號必須與設(shè)備驅(qū)動程序在登記時申請的主設(shè)備號一致,否則用戶進程將無法訪問到驅(qū)動程序。
Linux的設(shè)備驅(qū)動程序可以分為三個主要組成部分:
(1)自動配置和初始化子程序,負(fù)責(zé)檢測所要驅(qū)動的硬件設(shè)備是否存在和是否能正常工作。如果該設(shè)備正常,則對這個設(shè)備及相關(guān)設(shè)備驅(qū)動程序需要的軟件狀態(tài)進行初始化。這部分驅(qū)動程序僅在初始化的時候被調(diào)用一次。
(2)服務(wù)于I/O請求子程序,又稱為驅(qū)動程序的上半部分。調(diào)用這部分是由于系統(tǒng)調(diào)用的結(jié)果。這部分程序在執(zhí)行的時候,系統(tǒng)仍認(rèn)為是和進行調(diào)用的進程屬于同一個進程,只是由用戶態(tài)變成了核心態(tài),并具有此系統(tǒng)調(diào)用的用戶程序的運行環(huán)境,所以可以在其中調(diào)用sleep()等與進程運行環(huán)境有關(guān)的函數(shù)。
(3)中斷服務(wù)子程序,又稱為驅(qū)動程序的下半部分。在Linux環(huán)境中,它與UNIX一樣并不是直接從中斷向量表中調(diào)用設(shè)備驅(qū)動程序的中斷服務(wù)子程序,而是由Linux系統(tǒng)來接受硬件中斷,再由系統(tǒng)調(diào)用中斷服務(wù)子程序。中斷可以在任何一個進程運行的時候產(chǎn)生,因此在中斷服務(wù)程序被調(diào)用的時候,不能依賴于任何進程的狀態(tài),也就不能調(diào)用任何與進程運行環(huán)境有關(guān)的函數(shù)。因為設(shè)備驅(qū)動程序一般支持同一類型的若干設(shè)備,所以一般在系統(tǒng)調(diào)用中斷服務(wù)子程序的時候,都帶有一個或多個參數(shù),以唯一標(biāo)識服務(wù)的設(shè)備。6.2嵌入式Linux驅(qū)動程序框架根據(jù)功能劃分,設(shè)備驅(qū)動程序代碼有以下幾個部分:
(1)驅(qū)動程序的注冊與注銷;
(2)設(shè)備的打開與釋放;
(3)設(shè)備的讀/寫操作;
(4)設(shè)備的控制操作;
(5)設(shè)備的中斷和輪詢處理。
1.驅(qū)動程序的注冊與注銷設(shè)備驅(qū)動程序可以在系統(tǒng)啟動時初始化,也可以在需要時動態(tài)加載。字符設(shè)備初始化由chr_dev_init()完成。塊設(shè)備初始化由blk_dev_init()完成。每個字符設(shè)備或塊設(shè)備的初始化都要通過devfs_
register_chrdev()或devfs_register_blkdev()向內(nèi)核注冊。在關(guān)閉字符設(shè)備或塊設(shè)備時,還需要通過devfs_unregister_
chrdev()或devfs_unregister_blkdev()從內(nèi)核中注銷設(shè)備。
2.設(shè)備的打開與釋放打開設(shè)備是由open()完成的。open主要完成如下工作:
(1)增加設(shè)備的使用計數(shù);
(2)檢查設(shè)備相關(guān)錯誤,如設(shè)備尚未準(zhǔn)備好或類似的硬件問題;
(3)如果是首次打開,則初始化設(shè)備;
(4)識別次設(shè)備號,如有必要更新f_op指針;
(5)如果需要,分配且設(shè)置放在filp->private_data里的數(shù)據(jù)結(jié)構(gòu)。釋放設(shè)備由release()完成,包括以下幾件事:
(1)釋放在filp->private_data中open分配的內(nèi)存;
(2)如果是最后一個釋放,則關(guān)閉設(shè)備;
(3)遞減設(shè)備的使用計數(shù)。
3.設(shè)備的讀/寫操作字符設(shè)備使用各自的read()和write()來進行數(shù)據(jù)讀/寫。塊設(shè)備使用通用的generic_file_read()和generic_file_write()來進行數(shù)據(jù)讀/寫。這兩個通用函數(shù)向請求表中添加讀/寫請求,內(nèi)核可以通過ll_rw_block()優(yōu)化請求順序。由于只是對內(nèi)存緩沖區(qū)而不是對設(shè)備進行操作,因而可以加快讀/寫請求。如果內(nèi)存緩沖區(qū)內(nèi)沒有要讀入的數(shù)據(jù)或者需要將寫請求寫入設(shè)備,那么就需要真正地執(zhí)行數(shù)據(jù)傳輸。這是通過數(shù)據(jù)結(jié)構(gòu)request_queue中的request_fn來完成的(include/Linux/blkdev.h)。
4.設(shè)備的控制操作除了讀/寫操作,有時還需要控制設(shè)備。通過設(shè)備驅(qū)動程序中的ioctl()完成。ioctl()的用法與具體設(shè)備密切相關(guān)。除了ioctl(),設(shè)備中還有其他控制函數(shù),例如llseek()等。
5.設(shè)備的輪詢和中斷處理對于不支持中斷的設(shè)備,讀/寫時需要輪詢設(shè)備狀態(tài),以決定是否繼續(xù)進行數(shù)據(jù)傳輸。如果設(shè)備支持中斷,則可按照中斷方式進行。6.3嵌入式Linux模塊化驅(qū)動程序設(shè)計
1.模塊的概念
Linux的內(nèi)核是一個整體內(nèi)核(MonolithicKernel),與之對應(yīng)的是微內(nèi)核(Microkernel),即所有的內(nèi)核功能連接在一起,在同一個地址空間執(zhí)行。但完全這樣做會帶來很多不便和浪費。如果新添加一個硬件,就需要重新編譯內(nèi)核;如果去掉一個硬件,那么這個硬件已經(jīng)編譯進內(nèi)核的驅(qū)動程序就是浪費。Linux操作系統(tǒng)提供了一種機制,即利用內(nèi)核模塊來解決這個問題??梢愿鶕?jù)需要,在不需要重新編譯內(nèi)核的情況下,把模塊插入內(nèi)核或者從內(nèi)核卸載。整個Linux是一個整體式的內(nèi)核結(jié)構(gòu),整個內(nèi)核是一個單獨且非常大的程序。它由五個子系統(tǒng)組成,每個子系統(tǒng)都提供了內(nèi)部接口的函數(shù)和變量。這些函數(shù)和變量可供內(nèi)核所有子系統(tǒng)調(diào)用。內(nèi)核的另外一種形式是微內(nèi)核結(jié)構(gòu),此時內(nèi)核的功能塊被劃成獨立的模塊,各部分之間通過嚴(yán)格的通信機制進行聯(lián)系,給內(nèi)核增加一個新成分的配置過程非常費時。整個內(nèi)核并不需要同時裝入內(nèi)存。應(yīng)該確認(rèn),為保證系統(tǒng)能夠正常運行,一些特定的內(nèi)核必須總是駐留在內(nèi)存中,例如,進程調(diào)度代碼就必須常駐內(nèi)存。但是內(nèi)核其他部分,例如大部分的設(shè)備驅(qū)動程序就應(yīng)該僅在內(nèi)核需要時才加載,而在其他情況下,則無需占用內(nèi)存。因此,Linux系統(tǒng)提供了一種全新的模塊機制,可以根據(jù)用戶的需求在不需對內(nèi)核進行重新編譯的情況下,在內(nèi)核中動態(tài)加載和卸載模塊。模塊是內(nèi)核的一部分且都是設(shè)備驅(qū)動程序,但它們并沒有被編譯進內(nèi)核中,而是被分別編譯并鏈接成一組目標(biāo)文件。根據(jù)需要動態(tài)載入模塊可以保證內(nèi)核達到最小,并且有很大的靈活性。
2.模塊化的優(yōu)缺點內(nèi)核模塊的動態(tài)加載具有以下優(yōu)點:將內(nèi)核映像的尺寸保持在最小,并且有最大的靈活性。這便于檢驗新的內(nèi)核代碼,而不需要重新編譯內(nèi)核并重新引導(dǎo)。但是,內(nèi)核模塊的引入也帶來如下問題:對系統(tǒng)性能和內(nèi)存利用有負(fù)面影響。裝入的內(nèi)核模塊與其他內(nèi)核部分一樣,具有相同的訪問權(quán)限,因此差的內(nèi)核模塊會導(dǎo)致系統(tǒng)崩潰。為了使內(nèi)核模塊能訪問所有內(nèi)核資源,內(nèi)核必須維護模塊符號表,并在加載和卸載模塊時修改這些符號表。內(nèi)核必須能夠在卸載模塊時通知模塊,并且釋放分配給模塊的內(nèi)存和中斷等資源。內(nèi)核版本和模塊版本的不兼容也可能導(dǎo)致系統(tǒng)崩潰,因此,嚴(yán)格的版本檢查是必需的。盡管內(nèi)核模塊的引入同時也帶來不少問題,但是模塊機制確實是擴充內(nèi)核功能的一種行之有效的方法,也是在內(nèi)核級進行編程的有效途徑。
3.兩個重要函數(shù)模塊的作用就是擴展內(nèi)核的功能,運行在內(nèi)核中模塊化的代碼。
init_module()函數(shù)在模塊調(diào)入內(nèi)核(insmod)時被調(diào)用,它在內(nèi)核中注冊一定的功能函數(shù)(如圖6.1中的功能1、功能2、功能3)。在注冊之后,如果有程序訪問內(nèi)核的某個功能,如功能1,則內(nèi)核將查表獲得功能1在Moudule中的位置,然后調(diào)用功能1的函數(shù)。
cleanup_moudule()函數(shù)在模塊從內(nèi)核中卸載時被調(diào)用,它把init_module()函數(shù)在內(nèi)核中注冊的功能函數(shù)完全卸載。如果沒有完全卸載,在此模塊下次調(diào)入時,將會因為有重名的函數(shù)而導(dǎo)致調(diào)入失敗。
_init定義的函數(shù)將在執(zhí)行一次后從內(nèi)存中被刪除,并且它請求的內(nèi)存也將收回。_init定義的函數(shù)只在與內(nèi)核一起編譯時才有用,當(dāng)作為模塊時無效。對于_exit定義的函數(shù),當(dāng)它與內(nèi)核一起編譯時,根本就不會編譯進內(nèi)核;當(dāng)作為模塊編譯時,_exit無效。Linux的模塊調(diào)用如圖6.1所示。圖6.1Linux的模塊調(diào)用6.4嵌入式Linux的CAN總線通信6.4.1CAN設(shè)備驅(qū)動程序設(shè)計在嵌入式Linux操作系統(tǒng)下使用CAN總線,必須設(shè)計嵌入式Linux上的CAN驅(qū)動程序。SJA1000CAN控制器集成了CAN協(xié)議的物理層與數(shù)據(jù)鏈路層,CAN控制器屬于字符型設(shè)備。當(dāng)SJA1000接收一個報文時,數(shù)據(jù)保存在接收緩存器中,并產(chǎn)生一個接收中斷;發(fā)送報文時,先將數(shù)據(jù)送入SJA1000的發(fā)送緩沖器中,再將數(shù)據(jù)串行化發(fā)送到CAN總線上。
1.?CAN設(shè)備驅(qū)動程序的處理流程
CAN設(shè)備驅(qū)動程序中最重要的是中斷處理程序。中斷處理程序首先是被來自CAN控制器的硬件中斷喚起,然后中斷處理程序分辨中斷類型(發(fā)送或接收)。驅(qū)動程序處理流程如圖6.2所示。如果中斷的類型為接收數(shù)據(jù),則中斷處理例程會調(diào)用接收數(shù)據(jù)處理函數(shù)(receive)從CAN控制器讀取數(shù)據(jù)到ReceiveFIFO,最后用戶使用系統(tǒng)調(diào)用從ReceiveFIFO中讀到完整的一幀數(shù)據(jù)。當(dāng)中斷類型為發(fā)送數(shù)據(jù)時,則中斷處理例程調(diào)用數(shù)據(jù)發(fā)送處理函數(shù)(Transmit),從TransmitFIFO中讀取數(shù)據(jù)送入CAN控制器。圖6.2CAN設(shè)備驅(qū)動程序處理流程
2.收發(fā)緩沖區(qū)管理收發(fā)緩沖區(qū)一般都采用環(huán)形FIFO隊列,使得讀/寫可以并發(fā)執(zhí)行。每一次讀/寫操作都要判斷隊列是否可操作。依據(jù)CAN通信協(xié)議,CAN控制器每次只接收或發(fā)送一幀數(shù)據(jù),一標(biāo)準(zhǔn)幀為11個字節(jié),它由1個字節(jié)的幀信息(FF、RTR和DLC位)、2個字節(jié)的標(biāo)識位(識別碼)、8個字節(jié)的數(shù)據(jù)區(qū)組成。所以我們在每次需要內(nèi)存緩沖區(qū)時,直接分配長度為11個字節(jié)的數(shù)據(jù)塊,這11個字節(jié)地址是線性連續(xù)的。在向緩沖區(qū)讀/寫數(shù)據(jù)時,只要判斷一次緩沖區(qū)可否操作,并獲得塊首地址,就可以一次讀/寫11個字節(jié)的數(shù)據(jù),減少了重復(fù)性條件判斷,提高了效率。在CAN設(shè)備驅(qū)動程序里,設(shè)立這樣一個CAN_FIFO_buffer數(shù)據(jù)結(jié)構(gòu)作為收發(fā)數(shù)據(jù)緩沖區(qū):
structCAN_FIFO_buffer{
intstart;
intend;
unsignedchardatabuffer[11*MAX_NR_FRAMES];
}rd_buf;
start=end=0,表示緩沖區(qū)為空,end=11*MAX_
NR_FRAMES,表示緩沖區(qū)為滿。
3.文件操作接口根據(jù)系統(tǒng)需求,CAN設(shè)備驅(qū)動程序?qū)崿F(xiàn)了部分重要的設(shè)備方法,采用標(biāo)記化格式聲明它的file_operations結(jié)構(gòu)如下:
structfile_operationsfops={
owner: THIS_MODULE,
read: can_read,
llseek: can_llseek,
write: can_write,
ioctl: can_ioctl,
open: can_open,
release: can_release,
};
can_read負(fù)責(zé)從ReceiveFIFO讀取數(shù)據(jù);can_write負(fù)責(zé)向TransmitFIFO寫入數(shù)據(jù);can_release負(fù)責(zé)關(guān)閉CAN控制器;can_ioctl負(fù)責(zé)向CAN控制器發(fā)各種操作命令;can_open負(fù)責(zé)打開CAN控制器,檢查CAN控制器是否打開。
4.驅(qū)動程序初始化
1)在內(nèi)核中注冊設(shè)備在實現(xiàn)了CAN_fops結(jié)構(gòu)體內(nèi)的各個入口點函數(shù)后,還要編寫一個CAN設(shè)備驅(qū)動程序初始化函數(shù),在內(nèi)核啟動時登記這個驅(qū)動程序,并完成CAN控制器的初始化設(shè)置。函數(shù)register_chrdev是設(shè)備驅(qū)動程序登記函數(shù),負(fù)責(zé)向系統(tǒng)注冊字符型設(shè)備驅(qū)動程序,注冊形式如下:
ret=register_chrdev(CAN_MAJOR,DEVICE_NAME,&fops);
if(ret<0)
{
printk("%sdevicefailedwith%d\n","Sorry,registeringthecharacter",ret);
returnret;
}參數(shù)CAN_MAJOR為CAN的主設(shè)備號,內(nèi)核中一個驅(qū)動程序?qū)?yīng)一個主設(shè)備號;DEVICE_NAME是CAN驅(qū)動程序的設(shè)備名稱;fops是前面定義的file_operations結(jié)構(gòu)體的操作指針。
2)注冊中斷使用函數(shù)request_irq()向系統(tǒng)登記,安裝中斷處理程序。request_irq()函數(shù)的原型如下:
ret=request_irq(IRQ_EXT1,sja1000_can_irq,SA_
INTERRUPT,"can_irq",NULL);
if(ret<0)
{
printk("%sdevicefailedwith%d\n","Sorry,registeringtheIRQ",ret);
returnret;
}其中,參數(shù)IRQ_EXT1是CAN驅(qū)動程序使用的中斷號;sja1000_can_irq是要安裝的CAN中斷處理函數(shù)指針;SA_INTERRUPT表示快速中斷;"can_irq"用來在/proc/interrupts中顯示中斷的擁有者。
3)?SJA1000初始化
SJA1000的初始化只有在復(fù)位模式下才可以進行。?初始化主要是針對硬件的寄存器進行設(shè)置,包括工作方式的設(shè)定、接收屏蔽寄存器(AMR)和驗收代碼寄存器(ACR)的設(shè)置、總線時序寄存器的設(shè)置、輸出模式寄存器和中斷寄存器的設(shè)置等。初始化設(shè)置完成以后,SJA1000就可以進入工作狀態(tài),進行正常的通信工作。需要初始化的CAN控制寄存器有:模式寄存器、時分寄存器、接收代碼寄存器、屏蔽寄存器、總線定時寄存器和輸出控制寄存器等。它們均在InitializeSJA(void)函數(shù)中完成。6.4.2CAN總線通信的測試測試程序編寫的shell根據(jù)輸入命令的不同,執(zhí)行不同的操作。兩個開發(fā)板的CAN口可以進行正常通信,也可以回環(huán)測試。測試的流程如圖6.3所示。圖6.3CAN測試流程
shell支持的命令如下:●?init:初始化SJA1000;●?wsja:用于向SJA1000的寄存器寫入數(shù)據(jù);●?rsja:用于讀出SJA1000的寄存器的內(nèi)容;●?sfrm:用于發(fā)送數(shù)據(jù);●?gfrm:用于接收數(shù)據(jù);●?exit:退出程序。
1.測試操作步驟測試操作步驟如下:
~#cd/dev
/dev#mknodcanc1200
//建立DS1337設(shè)備
/dev#cd/
~#ifconfigeth072//設(shè)置網(wǎng)口eth0
~#tftp-g-rsja1000.o71//從服務(wù)器上下載驅(qū)動程序
~#tftp-g-rcan_test71//從服務(wù)器上下載測試程序
~#chmod777can_test//修改程序的運行權(quán)限
~#./can_test//運行實踐表明,SJA1000是一種較好的CAN總線控制器件,它的抗干擾性能極好,通信速率較高,電路也比較簡單。在PeliCAN模式下,其識別碼可達29位,因而可滿足各種應(yīng)用場合。在自動化控制系統(tǒng)中,合理安排這29位識別碼可以使許多問題得以簡化。PeliCAN模式增加的各種功能,大大地方便了通信的調(diào)試。
2.舉例
1)?help命令測試之前,可用help命令,顯示如下:
myshell>help
init--initthesja
dein--deinitthesja
rsja--readfromthesja
wsja--writetothesja
gfrm--gettheframe
sfrm--sendtheframe
conf--configthefilter
help--getcommandinformation
exit--exittheshell
quit--quitfromtheshell
2)?init命令初始化SJA1000
myshell>init
initsjasucceeded
3)回環(huán)測試回環(huán)測試之前,需要設(shè)置SJA1000的模式寄存器。首先設(shè)置模式寄存器為復(fù)位模式,然后再設(shè)置為自檢測模式。測試代碼如下:
myshell>wsja
pleasetellmetheaddressyouwanttowriteto:
Theaddressis:0
ok,youraddressis0
pleasetellmethevalueyouwanttowrite:
Thevalueis:1
ok,yourvaluwrite_sja_reg_addr=0
eis1
write_sja_reg_value=1
ok,youwrote1into0
myshell>wsja
pleasetellmetheaddressyouwanttowriteto:
Theaddressis:0
ok,youraddressis0
pleasetellmethevalueyouwanttowrite:
Thevalueis:4
ok,yourvaluwrite_sja_reg_addr=0
eis4
write_sja_reg_value=4
ok,youwrote4into0
myshell>rsja
pleasetellmetheaddressyouwanttoreadfrom:
Theaddressis:0
enterread
sja_reg_addr=0
sja_reg_value=4
usr_sja_reg_value=4
ok,yourdatareadfrom0is4發(fā)送數(shù)據(jù):8,0,0,1,1,1,1,1,1,1,1
myshell>sfrm
wewillsendsomefrmames
pleaseinputcommand.formatis:
8addr0addr1d0d1d2d3d4d5d6d7
8,0,0,1,1,1,1,1,1,1,1
xx--xx--xx--[0]=8xx--xx--xx
[1]=0[2]=0[3]=1[4]=1[5]=1[6]=1[7]=1[8]=1[9]=1[10]=1
xxxxxxxxxxxx
TXdata[0]=8TXdata[1]=0TXdata[2]=0TXdata[3]=1TXdata[4]=1TXdata[5]=1TXdata[6]=1TXdata[7]=1TXdata[8]=1TXdata[9]=1TXdata[10]=1[0]=8[1]=0[2]=0[3]=1[4]=1[5]=1[6]=1[7]=1[8]=1[9]=1[10]=1
myshell>gfrm
wewillgetsomefrmames
readin1frames
8--0--0--1--1--1--1--1--1--1--1–
4)兩個CAN口通信用一般導(dǎo)線(可用雙絞線、光纖)連接兩個CAN口,CANH1與CANH1相連接,CANL1與CANL1相連接。SJA1000處于工作模式,一個開發(fā)板發(fā)數(shù)據(jù),另一個開發(fā)板收數(shù)據(jù),若相互交換收發(fā)數(shù)據(jù)正確無誤,則表示通信正常。6.5嵌入式Linux的IIC總線通信6.5.1IIC總線概述
1.IIC總線特點
IIC總線最主要的優(yōu)點是其簡單性和有效性。由于接口直接在組件之上,因此IIC總線占用的空間非常小,減少了電路板的空間和芯片管腳的數(shù)量,降低了互聯(lián)成本。總線的長度可高達25英尺,并且能夠以10kb/s的最大傳輸速率支持40個組件。IIC總線的另一個優(yōu)點是,它支持多主控(multimastering),其中任何能夠進行發(fā)送和接收的設(shè)備都可以成為主總線。一個主控能夠控制信號的傳輸和時鐘頻率。當(dāng)然,在任何時間點上只能有一個主控。
2.IIC總線工作原理
IIC總線是由數(shù)據(jù)線SDA和時鐘SCL構(gòu)成的串行總線,可發(fā)送和接收數(shù)據(jù)。在CPU與被控IC之間、IC與IC之間進行雙向傳送,最高傳送速率為400?kb/s。各種被控制電路均并聯(lián)在這條總線上,但就像電話機一樣只有撥通各自的號碼才能工作,所以每個電路和模塊都有唯一的地址,在信息的傳輸過程中,IIC總線上并接的每一模塊電路既是主控器(或被控器),又是發(fā)送器(或接收器),這取決于它所要完成的功能。CPU發(fā)出的控制信號分為地址碼和控制量兩部分,地址碼用來選址,即接通需要控制的電路,確定控制的種類;控制量決定該調(diào)整的類別(如對比度、亮度等)及需要調(diào)整的量。這樣,各控制電路雖然掛在同一條總線上,卻彼此獨立,互不相關(guān)。
IIC總線在傳送數(shù)據(jù)過程中共有3種類型信號,它們分別是:開始信號、結(jié)束信號和應(yīng)答信號。●開始信號:SCL為高電平時,SDA由高電平向低電平跳變,開始傳送數(shù)據(jù)?!窠Y(jié)束信號:SCL為高電平時,SDA由低電平向高電平跳變,結(jié)束傳送數(shù)據(jù)。●應(yīng)答信號:接收數(shù)據(jù)的IC在接收到8?bit數(shù)據(jù)后,向發(fā)送數(shù)據(jù)的IC發(fā)出特定的低電平脈沖,表示已收到數(shù)據(jù)。CPU向受控單元發(fā)出一個信號后,等待受控單元發(fā)出一個應(yīng)答信號,CPU接收到應(yīng)答信號后,根據(jù)實際情況作出是否繼續(xù)傳遞信號的判斷。若未收到應(yīng)答信號,則判斷受控單元出現(xiàn)故障。
3.IIC總線的硬件實現(xiàn)在嵌入式系統(tǒng)中,IIC總線的硬件實現(xiàn)有3種:
(1)利用微處理器的兩個I/O口模擬SDA和SCL,用軟件實現(xiàn)SDA和SCL上的信號;
(2)微處理器本身帶有IIC總線硬件電路,只對微處理器的相應(yīng)寄存器寫入數(shù)據(jù)就實現(xiàn)IIC總線;
(3)微處理器的其他總線(如SPI或ISA)上接IIC總線專用芯片。
EP9315的IIC總線屬于第一種情況,在IIC總線上接有DS1337實時時鐘芯片和MAX5821數(shù)模轉(zhuǎn)換芯片。6.5.2IIC總線驅(qū)動程序的設(shè)計
1.DS1337實時時鐘原理圖
DS1337實時時鐘芯片原理圖如圖6.4所示。圖6.4DS1337實時時鐘連接圖
2.文件操作接口根據(jù)系統(tǒng)需求,DS1337設(shè)備驅(qū)動程序?qū)崿F(xiàn)了部分重要的設(shè)備方法,采用標(biāo)記化格式聲明它的file_operations結(jié)構(gòu)如下:
structfile_operationsds1337_fops={
owner: THIS_MODULE,
read: ds1337_read,
write: ds1337_write,
open: ds1337_open,
release: ds1337_release,
};
ds1337_write負(fù)責(zé)對DS1337寫命令控制字;DS1337_open負(fù)責(zé)打開DS1337,檢查DS1337是否打開;ds1337_release負(fù)責(zé)關(guān)閉DS1337。
ds1337_write函數(shù)中的WriteI2Creg()是對IIC總線的具體操作,參看IIC總線原理。6.5.3DS1337驅(qū)動程序測試在測試DS1337時鐘時,以動態(tài)模塊方式加載。用Tftp把DS1337的驅(qū)動程序ds1337.c的可執(zhí)行文件、測試程序iic_test.c的可執(zhí)行文件下載到開發(fā)板上運行,可用下面的命令運行:
~#cd/dev
/dev#mknodds1337c1210//建立DS1337設(shè)備
/dev#cd/
~#ifconfigeth072//設(shè)置網(wǎng)口eth0
~#tftp-g-rds1337.o71 //從服務(wù)器上下載驅(qū)動程序
~#tftp-g-riic_test71//從服務(wù)器上下載測試程序
~#chmod777iic_test//修改程序的運行權(quán)限
~#./iic_test
//運行
StartTestDS1337
DoyouwanttoResetTime(Y/N)y//設(shè)置時間
year(00-99):07
month(1-12):1date(1-31):19week(1-7):5hour(0-23):16minute(0-59):1second(0-59):0顯示信息:Yourinputstringis=711951610Nowis19-Jan-200716:1:0Friday0Nowis19-Jan-200716:1:1Friday1在IIC總線的應(yīng)用中應(yīng)注意的事項總結(jié)為以下幾點:
(1)嚴(yán)格按照時序圖的要求進行操作;
(2)若與口線上帶內(nèi)部上拉電阻的單片機接口連接,可以不外加上拉電阻;
(3)程序中為配合相應(yīng)的傳輸速率,在對口線操作的命令后可用udelay加一定的延時。6.6嵌入式Linux的D/A轉(zhuǎn)換6.6.1MAX5821驅(qū)動程序設(shè)計
1.?MAX5821原理圖
MAX5821連接原理圖如圖6.5所示。圖6.5MAX5821硬件連接圖
2.文件操作接口根據(jù)系統(tǒng)需求,D/A轉(zhuǎn)換設(shè)備驅(qū)動程序?qū)崿F(xiàn)了部分重要的設(shè)備方法,采用標(biāo)記化格式聲明它的file_operations結(jié)構(gòu)如下:
structfile_operationsmax5821_fops={ owner: THIS_MODULE, read: max5821_read, write: max5821_write, open: max5821_open, release: max5821_release,
};
max5821_write負(fù)責(zé)對MAX5821寫命令控制字;MAX5821_open負(fù)責(zé)打開MAX5821,檢查MAX5821是否打開;MAX5821_release負(fù)責(zé)關(guān)閉MAX5821。因為IIC總線是用GPIO口模擬實現(xiàn)的,所以模擬時鐘頻率最高達220?kHz,而操作MAX5821,需要寫3次控制字,才完成1次數(shù)據(jù)轉(zhuǎn)換。完成1次的頻率為7kHz左右,操作時序如圖6.6所示。第1個字節(jié)為器件地址和讀/寫標(biāo)志位;第2個字節(jié)為控制字(C3C2C1C0)和待轉(zhuǎn)換數(shù)據(jù)的高四位;第3個字節(jié)為待轉(zhuǎn)換數(shù)據(jù)的低六位。
C3C2C1C0分別表示以下含義:
0000:LoadDACAinputandDACregisterswithnewdata.ContentsofDACBinputregistersaretransferredtotheDACregister.Alloutputsareupdated.
0001:LoadDACBinputandDACregisterswithnewdata.ContentsofDACAinputregistersaretransferredtotheDACregister.Alloutputsareupdated.
0100:LoadDACAinputregisterwithnewdata.DACoutputsremainunchanged.
0101:LoadDACBinputregisterwithnewdata.DACoutputsremainunchanged.
1000:DatainallinputregistersistransferredtorespectiveDAC
registers.AllDACoutputsareupdatedsimultaneously.NewdataisloadedintoDACAinputregister.
1001:DatainallinputregistersistransferredtorespectiveDACregisters.AllDACoutputsareupdatedsimultaneously.NewdataisloadedintoDACBinputregister.
1100:LoadallDACswithnewdataandupdateallDACoutputssimultaneously.BothinputandDACregistersareupdatedwithnewdata.
1101:Loadallinputregisterswithnewdata.DACoutputsremainunchanged.寫操作的時序如圖6.6所示。需要寫3次控制字,才可完成1次數(shù)據(jù)轉(zhuǎn)換,IIC總線模擬操作參見IIC總線原理。圖6.6寫操作時序6.6.2MAX5821驅(qū)動程序測試驅(qū)動程序測試的方法如下:
(1)?A口作為脈寬調(diào)制輸出(由于模擬IIC的限制,頻率有如下要求):Dutyfactor為占空比,F(xiàn)requencymaximum為頻率的最大值。
Dutyfactor=0.1****Frequencymaximum=650?Hz
Dutyfactor=0.2****Frequencymaximum=1300?Hz
Dutyfactor=0.3****Frequencymaximum=2000?Hz
Dutyfactor=0.4****Frequencymaximum=2650?Hz
Dutyfactor=0.5****Frequencymaximum=3300?Hz
(2)?B口作為普通模擬輸出。輸入需要轉(zhuǎn)換的值(0~1023),即完成轉(zhuǎn)換。測試程序流程如圖6.7所示。圖6.7測試流程圖在測試MAX5821數(shù)/模轉(zhuǎn)換時,以動態(tài)模塊方式加載。用Tftp把MAX5821的驅(qū)動程序max5821.c的可執(zhí)行文件max5821.o、測試程序da_test.c的可執(zhí)行文件da_test下載到開發(fā)板上運行,可用下面的命令運行:
~#ifconfigeth072 //設(shè)置網(wǎng)口eth0
~#mknod/dev/max5821c1230 //建立MAX5821設(shè)備節(jié)點
~#tftp-g-rmax5821.o71//從服務(wù)器上下載驅(qū)動程序
~#tftp-g-rda_test71 //從服務(wù)器上下載測試程序
~#chmod777da_test//修改測試程序的運行權(quán)限
~#insmodmax5821.o//加載驅(qū)動程序
~#./da_test6.7嵌入式Linux的A/D轉(zhuǎn)換6.7.1MAX1261驅(qū)動程序設(shè)計
1.?A/D轉(zhuǎn)換驅(qū)動程序設(shè)計
1)實現(xiàn)MAX1261的file_operations結(jié)構(gòu)
structfile_operationsmax1261_fops={
read:read_max1261,
write:write_max1261,
ioctl:ioctl_max1261,
open:open_max1261,
release:release_max1261,
};
2)中斷服務(wù)子程序在中斷服務(wù)子程序中,讀出MAX1261轉(zhuǎn)換后的數(shù)據(jù),因為是八位數(shù)據(jù)線,且是12位的數(shù)據(jù),所以讀兩次。先置低HBEN,讀取低八位;后置高,讀取高四位。程序代碼如下:
voidmax1261_irq(intirq,void*dev_id,structpt_regs*regs) {charbuffer[2]={0};
max1261_read(buffer);
in_rd_buf(buffer);
}
voidmax1261_read(char*data)
{
intuiPADR;
uiPADR=inl(GPIO_PADR)&0xfe;//outdatais0:egpio0HBEN=0,讀取低八位
outl(uiPADR,GPIO_PADR);
data[0]=readb(AD_DATA_BASE);
uiPADR=inl(GPIO_PADR)|0x01;//outdatais1:egpio0HBEN=1,讀取高四位
outl(uiPADR,GPIO_PADR);
data[1]=readb(AD_DATA_BASE)&0xf;
}
3)初始化初始化時,首先設(shè)置EGPIO0為輸出,EGPIO9為輸入,再配置EGPIO9為低電平觸發(fā)。6.7.2MAX1261驅(qū)動程序測試測試時,還需要對MAX1261進行配置,確定它的模擬輸入方式。測試流程如圖6.8所示。圖6.8A/D測試程序流程圖(1)圖6.8A/D測試程序流程圖(2)
1.操作步驟進行測試時運行如下命令:
~#mknod/dev/max1261c1220
//設(shè)備文件下設(shè)置結(jié)點
~#ifconfigeth072
//設(shè)置網(wǎng)口eth0
~#tftp-g-rmax1261.o71//從服務(wù)器上下載驅(qū)動程序
~#tftp-g-rad_test71//從服務(wù)器上下載測試程序
~#chmod777ad_test
//修改程序的運行權(quán)限
~#./ad_test
//運行
2.支持的命令●?config1:用于配置MAX1261工作的模式。
0:完全掉電模式,時鐘模式無影響;
1:備用掉電模式,時鐘模式無影響;
2:正常工作模式,內(nèi)部時鐘模式;
3:正常工作模式,外部時鐘模式?!?config2:用于配置MAX1261的模擬輸入模式。
0:偽差分模擬輸入模式;
1:單端模擬輸入模式?!?config3:用于配置MAX1261的極性。
0:雙極性;
1:單極性?!?config4:用于配置MAX1261的通道?!?startin:用于使MAX1261開始轉(zhuǎn)換的命令,且采用內(nèi)部捕捉模式。●?startex:用于使MAX1261開始轉(zhuǎn)換的命令,且采用外部捕捉模式?!?exitadc:用于退出測試程序。
3.?舉例具體A/D測試操作如下:
#ifconfigeth072
//設(shè)置網(wǎng)口eth0
~#tftp-g-rmax1261.o27 //從服務(wù)器上下載驅(qū)動程序
~#tftp-g-rad_test27 //從服務(wù)器上下載測試程序
~#chmod777ad_test //改變測試程序權(quán)限
~#mknod/dev/max1261c1220 //建立設(shè)備結(jié)點
~#insmodmax1261.o //加載驅(qū)動Usingmax1261.oSMCBCR3=0x2000ffe1SMCBCR3=0xffefSYSCON_CLKSET1=0x2a4e39eGPIO_PBDR=0xffcongraulation,max1261aresucGPIO_PBDR=0xff~#./ad_testDAC:max1261deviceopenmyshell>config40channel0isselected.myshell>startin10thereceivedvalueis0x1,0.000610myshell>startin100thereceivedvalueis0x0,0.000000myshell>●查看MAX1261產(chǎn)生的中斷次數(shù),如下所示:
~#cat/proc/interrupts
4:30927timer
17:
0ide0
31:
0graphics
39:167ep93xx_ethernet
52:836uart1
56:0usb-ohci
58:0FPU
59:110max1261_irq
Err:0
max1261_irq中斷號59產(chǎn)生了110次中斷。6.8嵌入式Linux的PS/2鍵盤6.8.1鍵盤工作原理鍵盤的處理器花費很長的時間來掃描或監(jiān)視按鍵矩陣,如果它發(fā)現(xiàn)有鍵被按下、釋放或按住,鍵盤將發(fā)送掃描碼的信息到計算機。掃描碼有通碼和斷碼兩種不同的類型,當(dāng)一個鍵被按下或按住時,就發(fā)送通碼;當(dāng)一個鍵被釋放時,就發(fā)送斷碼。每個按鍵被分配了唯一的通碼和斷碼,這樣主機通過查找唯一的掃描碼,就可以測定是哪個按鍵。每個鍵的通斷碼組成了掃描碼集,有3套標(biāo)準(zhǔn)的掃描碼集。所有現(xiàn)代的鍵盤默認(rèn)使用第2套掃描碼。只要鍵一按下通碼就會被發(fā)送,每個鍵都有它自己唯一的通碼。它們也都有唯一的斷碼,在通碼和斷碼之間存在著必然的聯(lián)系。多數(shù)第二套斷碼有兩字節(jié)長,它們的第1個字節(jié)是F0h,第2個字節(jié)是這個鍵的通碼。部分?jǐn)U展按鍵的斷碼通常有3個字節(jié),它們的前兩個字節(jié)是E0h和F0h,最后一個字節(jié)是這個按鍵通碼的最后一個字節(jié),見表6.1。按下按鍵“A”,發(fā)送到計算機的數(shù)據(jù)應(yīng)該是1Ch,F(xiàn)0h,1Ch。如果按下按鍵Shift和2,輸出@,發(fā)到計算機的數(shù)據(jù)應(yīng)該是12h,1Eh,F(xiàn)0h,1Eh,F(xiàn)0h,12h。表6.1鍵碼轉(zhuǎn)換表6.8.2PS/2模塊硬件連接本系統(tǒng)中,擴展PS/2口為鍵盤接口,支持標(biāo)準(zhǔn)鍵盤輸入。PS/2的傳輸通過數(shù)據(jù)線K-DATA和時鐘線K-CLK來完成,與SPI復(fù)用。對應(yīng)的硬件連接圖如圖6.9所示。
PS/2向主機發(fā)送鍵值通過SPI的接收線、時鐘線傳送給主機,主機向PS/2發(fā)送命令通過EGPIO[14]和[12]實現(xiàn)。運行程序時,需要將對應(yīng)4個跳線接通,保證PS/2鍵盤和主機通信正常,配置超級終端以觀測按鍵值。圖6.9PS/2鍵盤連接圖6.8.3鍵盤驅(qū)動程序的設(shè)計程序開始運行后,等待接收PS/2鍵盤輸入的按鍵值。當(dāng)有按鍵按下時,從寄存器SSPDR中讀取按鍵值,進行判斷。如果不是Esc按鍵,則調(diào)用Translate函數(shù),將對應(yīng)的掃描碼轉(zhuǎn)換為對應(yīng)的字符并輸出;如果按下按鍵Esc,則退出程序。在Translate函數(shù)中,首先將SPI數(shù)據(jù)線接收進來的11位標(biāo)準(zhǔn)數(shù)據(jù)通過反相器還原成鍵盤的輸入值;其次,從11位SPI數(shù)據(jù)中提取出8位數(shù)據(jù)位,去掉起始位、校驗位等;最后進行鍵值轉(zhuǎn)換處理,相關(guān)代碼如下。
b=~a; /*將數(shù)據(jù)通過取反還原*/
c=((b&0x004)<<5); /*從11位SPI數(shù)據(jù)中提取出8位數(shù)據(jù)位*/
c|=((b&0x008)<<3);
c|=((b&0x010)<<1);
c|=((b&0x020)>>1);
c|=((b&0x040)>>3);
c|=((b&0x080)>>5);
c|=((b&0x100)>>7);
c|=((b&0x200)>>9);
if((c<0x87)&&(prep!=0xf0)) /*鍵值是否是標(biāo)準(zhǔn)的128鍵盤值?是否是斷碼值?*/
{if(c==0x58) /*如果是cap大小寫轉(zhuǎn)換鍵,則計數(shù)器加1*/
N++;
if(prep==0x12) /*前一個按鍵是Shift鍵,則輸出復(fù)合值*/
{printk("1%c\n",KScan1[c]);}
if((c!=0x58)&&(prep!=0x12)) /*如果是普通按鍵*/
{if((N%2==1)&&('A'<=KScan[c])&&(KScan[c]<='Z'))/*判斷大小寫,默認(rèn)為大寫*/
printk("2%c\n",KScan[c]+32);
elseprintk("3%c\n",KScan[c]);
}
}
prep=c; /*更新前一個標(biāo)志位*/
}對應(yīng)流程圖如圖6.10所示。圖6.10驅(qū)動設(shè)計流程圖6.8.4測試步驟
(1)開發(fā)板Uart1和PC機COM1通過串口連接,同時通過網(wǎng)線連接。
(2)開啟超級終端,建立名為EP9315的新連接,波特率配置為115200,8位數(shù)據(jù)位,無奇偶校驗位,1位停止位,無數(shù)據(jù)流控制。
(3)開啟PC機上的Tftp服務(wù),config配置下載路徑到對應(yīng)的驅(qū)動(.o文件)及測試程序(test)存放路徑如D:\MyDocuments,d:\MyDocuments\ps2.o),然后打開超級終端。
(4)在tmp路徑下創(chuàng)建名為PS2的節(jié)點,主設(shè)備號為117,次設(shè)備號為0:
~# cd/dev
/dev# mknodps2c1170
(5)配置開發(fā)板的IP地址,與主機保證在同一網(wǎng)段內(nèi)即可:
/dev# cd/
~# ifconfigeth026
~# cd/tmp
(6)通過Tftp命令,將驅(qū)動及測試程序傳到開發(fā)板tmp目錄下:
/tmp# tftp-g-rps2.o25
/tmp# tftp-g-rps2test25
(7)加載驅(qū)動程序,將控制權(quán)限轉(zhuǎn)至測試程序ps2test,運行測試程序:
/tmp# insmodps2.o
/tmp# chmod777ps2test
/tmp# ./ps2test根據(jù)提示,從PS/2鍵盤輸入任意按鍵進行測試,然后按Esc鍵,退出測試。為了調(diào)試方便,字母前添加數(shù)字3表示大寫字母,2表示小寫字母,1表示復(fù)合字母。測試完成后,調(diào)用rmmodps2卸載驅(qū)動即可。6.8.5調(diào)試中的注意事項
PS/2鍵盤不能熱插拔,開發(fā)板上電時,必須保證PS/2鍵盤已經(jīng)連上,鍵盤所需的5?V、3.3?V電壓需在開發(fā)板上電時一起提供給鍵盤。6.9嵌入式Linux的8255驅(qū)動6.9.18255芯片原理
8255是8路并行輸出芯片,具有3個8位端口PORTA、PORTB和PORTC。其中,各個端口可單獨設(shè)置其輸入/輸出狀態(tài)。輸出時,通過開發(fā)板向?qū)?yīng)端口寫入8位數(shù)據(jù)即可向外輸出;輸入時程序讀取對應(yīng)端口可得到外部發(fā)送的8位數(shù)據(jù)。其具體控制字將在下文結(jié)合開發(fā)板實際連接介紹。本開發(fā)板上留有8路并行輸入/輸出接口,由8255芯片實現(xiàn)。其電路原理圖如圖6.11所示。圖6.11電路原理圖
此芯片接在BANKCS3上,片選地址連接如圖6.12所示。圖6.12BANK選通連接圖當(dāng)向地址0x30800000上寫入對應(yīng)數(shù)據(jù)時,即可選通8255芯片,對其各端口進行對應(yīng)操作。
A、B、C端口對應(yīng)地址為:
PORTA:0x30800000
PORTB:0x30800001
PORTC:0x30800002狀態(tài)控制字寄存器地址為:
CONTROL:0x30800003本驅(qū)動試驗程序?qū)⑵渥魅缦略O(shè)置:
PORTA、PORTB為輸出;PORTC為輸入。芯片工作方式為0工作方式,對應(yīng)的8位控制字為0x89。由于ARM各BANK默認(rèn)采用32位傳輸方式,而8255是8位工作芯片。所以,在使用8255芯片時應(yīng)將BANKCS3設(shè)置為8位寬度。這一點在程序開始時向地址0x8008000c處寫入0x0000ffef即可。6.9.2Linux下8255驅(qū)動的實現(xiàn)本試驗驅(qū)動主要通過ioctl函數(shù)完成驅(qū)動對各端口狀態(tài)的控制以及向各端口輸入/輸出數(shù)據(jù)。驅(qū)動程序流程如圖6.13所示。圖6.13驅(qū)動程序流程在針對此驅(qū)動的測試程序中外接測試電路,?由PORTA端口控制8盞LED燈。連接PORTB與PORTC,PORTB輸出數(shù)據(jù),再由PORTC讀取回顯在超級終端中。測試程序中調(diào)動內(nèi)核驅(qū)動程序的基本函數(shù)為
fd=open("/dev/port8255",O_RDWR);設(shè)置端口工作方式函數(shù)為
ioctl(fd,1,0x89);操作A、B、C端口的函數(shù)為
ioctl(fd,0,arg);測試流程如圖6.14所示。圖6.14測試流程圖以上就是8255試驗驅(qū)動程序的基本情況介紹。注意:①在驅(qū)動程序中,不能直接操作物理地址空間。因此,需使用地址映射函數(shù):
addr=ioremap(0x30800000,4)其中,分配到的addr即為以0x30800000開始的連續(xù)4個地址空間的首地址。②關(guān)于8255設(shè)置上的其他信息,請參閱資料中附帶的8255數(shù)據(jù)手冊。6.10嵌入式Linux的PWM驅(qū)動6.10.1PWM控制器介紹
EP9315芯片內(nèi)帶有兩個獨立的PWM控制器,通過軟件設(shè)置輸出頻率及占空比,可以輸出不同的脈寬調(diào)制波形。在內(nèi)部寄存器中,主要通過PWMtermcnt及PWMdutycycle來設(shè)置頻率及占空比。換算公式如下:
PWMTermCnt=PWMDutyCycle?=?(期望占空比×(PWMTermCnt+1))-1;
PWM計算實例如下:要在66??MHz(15?nsec)的系統(tǒng)頻率下產(chǎn)生一個100kHz(10μsec)、20%占空比的PWM輸出。
(1)?PWMxTermCnt=(66MHz/0.1MHz)-1=695(十進制);
(2)?PWMxDutyCycle=(0.2×(695+1))-1=131(十進制)6.10.2PWM驅(qū)動設(shè)計
Linux下驅(qū)動實現(xiàn)流程如圖6.15所示。圖6.15驅(qū)動實現(xiàn)流程通過調(diào)用該驅(qū)動,即可產(chǎn)生要求的PWM波形。在對該驅(qū)動的驗證程序中,我們用PWM波形驅(qū)動外接蜂鳴器以產(chǎn)生旋律。驗證程序流程如圖6.16所示。圖6.16測試流程圖當(dāng)外接蜂鳴器奏出音樂時,說明此驅(qū)動可用,工作正常。注意:①應(yīng)設(shè)置蜂鳴器的頻率在人耳的聽覺接收范圍(20Hz~20?kHz)。②在程序中設(shè)置頻率及占空比時,應(yīng)遵循如下規(guī)則:當(dāng)欲設(shè)置頻率大于當(dāng)前運行頻率時,先設(shè)置頻率而后設(shè)置占空比;當(dāng)欲設(shè)置頻率小于當(dāng)前運行頻率時,先設(shè)置占空比而后設(shè)置頻率。6.11嵌入式Linux的串口驅(qū)動
EP93XX系列的ARM9微控制器均具有3個UART,它們的結(jié)構(gòu)及寄存器符合16C550工業(yè)標(biāo)準(zhǔn)。16C550是一種工業(yè)標(biāo)準(zhǔn)的UART,此類UART芯片內(nèi)部集成了可編程的波特率發(fā)生器、發(fā)送和接收FIFO、處理中斷系統(tǒng)和各種總線狀態(tài)錯誤檢測電路等,并具有完全的MODEM控制能力。工作模式為全雙工模式,支持5~8位的數(shù)據(jù)長度,具有1/2位停止位,可選奇偶校驗位。6.11.1UART串行口數(shù)據(jù)傳輸格式異步串行方式是將傳輸數(shù)據(jù)的每個字符一位接一位(例如先低位、后高位)地傳送的方式。數(shù)據(jù)的各不同位可以分時使用同一傳輸通道,因此串行I/O可以減少信號連線,最少用一對線即可進行。接收方對于同一根線上一連串的數(shù)字信號,首先要分割成位,再按位組成字符。為了恢復(fù)發(fā)送的信息,雙方必須協(xié)調(diào)工作。在微型計算機中大量使用異步串行I/O方式,雙方使用各自的時鐘信號,而且允許時鐘頻率有一定誤差,因此實現(xiàn)較容易。但是由于每個字符都要獨立確定起始和結(jié)束(即每個字符都要重新同步),字符和字符間還可能有長度不定的空閑時間,因此效率較低。串行通信的字符格式如圖6.17所示。圖6.17串行通信的字符格式圖6.17給出了異步串行通信中一個字符的傳送格式。開始前,線路處于空閑狀態(tài),送出連續(xù)“1”。傳送開始時首先發(fā)一個“0”作為起始位,然后出現(xiàn)在通信線上的是字符的二進制編碼數(shù)據(jù)。每個字符的數(shù)據(jù)位長可以約定為5位、6位、7位或8位,一般采用ASCII編碼。后面是奇偶校驗位,根據(jù)約定,用奇偶校驗位將所傳字符中為“1”的位數(shù)湊成奇數(shù)個或偶數(shù)個。也可以約定不要奇偶校驗,這樣就取消奇偶校驗位。最后是表示停止位的“1”信號,這個停止位可以約定持續(xù)1位或2位的時間寬度。至此一個字符傳送完畢,線路又進入空閑,持續(xù)為“1”。經(jīng)過一段隨機的時間后,在下一個字符開始傳送時才又發(fā)出起始位。每一個數(shù)據(jù)位的寬度等于傳送波特率的倒數(shù)。在微機異步串行通信中,常用的波特率為50,95,110,150,300,600,1200,2400,4800,9600等。接收方按約定的格式接收數(shù)據(jù),并進行檢查,可以查出以下三種錯誤:
(1)奇偶錯。在約定奇偶檢查的情況下,接收到的字符奇偶狀態(tài)和約定不符。
(2)幀格式錯。一個字符從起始位到停止位的總位數(shù)不對。
(3)溢出錯。若先接收的字符尚未被微機讀取,后面的字符又傳送過來,則產(chǎn)生溢出錯。以上每一種錯誤都會給出相應(yīng)的出錯信息,提示用戶處理。6.11.2EP9315的UART串口傳輸波特率
EP9315片內(nèi)外設(shè)各模塊需要外部晶振來提供工作時鐘,外部晶振的時鐘頻率為14.7456?MHz,記作Fosc=
14.7456?MHz。在EP9315內(nèi)部有一個鎖相環(huán)電路,可以把外部晶振頻率提升到處理器和所有外設(shè)的工作頻率。處理器的工作頻率記作Fclk。EP9315片內(nèi)外設(shè)可分為AHB設(shè)備和APB設(shè)備,AHB設(shè)備的工作頻率記作Hclk,APB設(shè)備的工作頻率記作Pclk。鎖相環(huán)的倍頻工作可以通過設(shè)置寄存器ClkSet1、ClkSet2來完成,ClkSet1用于給第一個鎖相環(huán)通道PLL1編程,?ClkSet2用于給第二個鎖相環(huán)通道PLL2編程。?圖6.18以PLL1為例,說明Fosc的倍頻過程。圖6.18外部晶振的倍頻原理Fout的計算公式為其中,PLL1_X1FBD、PLL1_X2FBD、PLL1_X2IPD、PLL1_PS的取值可以在寄存器ClkSet1中進行設(shè)置。第一個鎖相環(huán)通道PLL1主要用于對處理器工作頻率(Fclk)和總線設(shè)備工作頻率(Hclk、Pclk)進行管理。通過設(shè)置SetClk1寄存的PLL1_X1FBD、PLL1_X2FBD、PLL1_X2IPD、PLL1_PS位可以得到PLL1的輸出頻率PLL1Fout,通設(shè)置SetClk1寄存器的FCLKDIV位可以選擇PLL1Fout到Fclk的除數(shù)因子。通過設(shè)置SetClk1寄存器的HCLKDIV位可以選擇PLL1Fout到Hclk的除數(shù)因子。通過設(shè)置SetClk1寄存器的PCLKDIV位可以選擇HCLK到PCLK的除數(shù)因子。Fclk、Hclk、Pclk設(shè)置時應(yīng)滿足以下關(guān)系:
Fclk<=200?MHz;
Hclk<=100?MHz;
Pclk<=50?MHz;
Pclk<Hclk<=Fclk。第二個鎖相環(huán)通道PLL2主要用于對USB設(shè)備模塊和FastIrDA(FIR)模塊的工作頻率進行管理。另外,還可以選擇使外部晶振不經(jīng)過鎖相環(huán)PLLs,而直接為片內(nèi)外設(shè)提供工作時鐘,例如用于串口通信的UART模塊就可通過設(shè)置系統(tǒng)控制寄存器的PwrCnt的UARTBAUD位選擇使其工作在Fosc或Fosc/2。各個設(shè)備模塊工作頻率的分配如圖6.19所示。圖6.19EP9315各設(shè)備模塊的時鐘分配串口通信的正常進行,是依靠收發(fā)雙方使用相同的傳輸率來進行同步的,圖6.20說明了傳輸/發(fā)送波特率的產(chǎn)生原理。圖6.20UART模塊傳輸波特率的產(chǎn)生原理以上是接收和發(fā)射信號的時鐘頻率產(chǎn)生的原理圖,其中Baudratedivisor是一個16bits的二進制數(shù),其數(shù)值由寄存器UART1LinCtrlMid和UART1LinCtrlLow共同決定。Baud16的周期是UARTCLK周期的Baudratedivisor倍,而Baudrate的周期又是Baud16周期的16倍。因此根據(jù)需要的Baudrate和UARTCLK就可計算出Baudratedivisor的值,計算公式如下:
DAUDDIV=-1例如,假設(shè)通過設(shè)置EP9315系統(tǒng)控制寄存器PwrCnt的位UARTBAUD使得UART模塊的工作頻率為14.7456?MHz
(直接使用外部晶振),即FUARTCLK=14.7456?MHz。同時需要串口的傳輸波特率為57600,則我們可以通過上式計算得到DAUDDIV=15。從而設(shè)置寄存器UART1LinCtrlMid
=0x00,UART1LinCtrlLow=0x0F。6.11.3EP9315的UART串口模塊及其工作原理
UART模塊的工作原理如圖6.21所示。圖6.21UART模塊的工作原理
TransmitFIFO:?大小為16B,是一種先進先出的緩存,每一字節(jié)用來存放等待發(fā)送的5~8bits的信息數(shù)據(jù)。TransmitFIFO也可被禁用,從而僅作為1個8bit的寄存器使用。
Transmitterlogic:在數(shù)據(jù)傳輸過程中扮演并-串變換的角色(數(shù)據(jù)在EP9315內(nèi)部為并行傳輸,EP9315和外部通信為串行傳輸)。從而Transmitterlogic輸出的串行字符數(shù)據(jù)的結(jié)構(gòu)依次為:起始位(startbit)、數(shù)據(jù)位(databit)、奇偶校驗位(paritybit)、停止位(stopbit)。
ReiceiveFIFO:由16個11??bits的存儲單元構(gòu)成,在每一個11??bit的存儲單元中,8??bit用于存放數(shù)據(jù)信息,3??bit用于存放狀態(tài)信息。通過Receivelogic接收到的數(shù)據(jù)信息以及傳輸過程中產(chǎn)生的錯誤比特(errorbit)被存放在ReceiveFIFO中,然后被CPU通過APBinterface或DMAinterface讀出。同樣,ReceiveFIFO可被禁用作為一個一個字節(jié)的寄存器使用。
Receivelogic:在一個有效的開始脈沖被檢測到后,Receivelogic將接收到的信息流進行串-并變換。Parity、frameerrorchecking以及breakerrorbits同樣被進行串-并變換,并被存儲到ReceiveFIFO中。對于發(fā)送數(shù)據(jù)情況而言,要發(fā)射的數(shù)據(jù)信息被寫入TransmitFIFO,形成一個數(shù)據(jù)幀,這個要發(fā)送的數(shù)據(jù)幀以在寄存器UART1LinCtrlHigh中定義的格式為準(zhǔn)。寄存器UART1Flag中的BUSY信號在TansmitFIFO中有數(shù)據(jù)被寫入或有數(shù)據(jù)被發(fā)射的情況下都為高,只有TransmitFIFO中為空時,BUSY信號才被撤銷。對于接收數(shù)據(jù)情況而言,當(dāng)Receiver是無效狀態(tài)時(這時UARTRxD為持續(xù)的高電平),若在數(shù)據(jù)輸入端(UARTRxD)已檢測到低電平,說明一個數(shù)據(jù)幀的startbit已被接收。這時受Baud16信號驅(qū)動的Receivecounter開始計數(shù),并且在Baud16的第8個周期上(也就是1/2的Baudrate周期)進行數(shù)據(jù)采樣;如果在Baud16的第8個周期上UARTRxD仍為低電平,則說明startbit有效,否則startbit無效;如果startbit已被檢測到是有效的,那么每16個Baud16周期(一個Baudrate周期)就會采樣一次數(shù)據(jù)信息,根據(jù)寄存器UART1LinCtrlHigh中定義的每一
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 體育場地建設(shè)中的工程難題及應(yīng)對措施
- 初中德育課程改革計劃
- 城市綠化帶維護保修及售后措施
- 2024學(xué)年數(shù)學(xué)課堂教學(xué)創(chuàng)新計劃
- 以形助數(shù):高中代數(shù)可視化教學(xué)的探索與實踐
- 以幼兒為本:A幼兒園“同課異構(gòu)”教研活動的實踐探索與成效研究
- 以學(xué)生為中心:中職基礎(chǔ)英語課堂教學(xué)有效性的多維探究
- 以太極柔力球教學(xué)為鑰:開啟大學(xué)生體育鍛煉與心理和諧之門
- 以聲為翼:中學(xué)音樂教學(xué)中歌唱訓(xùn)練的多維探索與實踐
- 工廠工業(yè)用地買賣合同協(xié)議書范文
- 公務(wù)員培訓(xùn)包過班協(xié)議書范本
- 2021學(xué)堂在線網(wǎng)課《生活英語讀寫》課后作業(yè)單元考核答案
- 中國近現(xiàn)代史綱要超星爾雅答案貴州大學(xué)-
- 生理心理學(xué)(三版)教學(xué)課件全套電子教案匯總整本書課件最全教學(xué)教程完整版教案(最新)
- 職業(yè)危害防護設(shè)施、器具檢查維護記錄
- 食品全過程防護工作手冊(食品防護計劃)
- Q∕GDW 12162-2021 隔離開關(guān)分合閘位置雙確認(rèn)系統(tǒng)技術(shù)規(guī)范
- 燃?xì)馊霊舭矙z培訓(xùn)PPT.ppt
- 臨概題庫(南醫(yī)大)--內(nèi)科部分
- 古代漢語授課教案(郭錫良版)教案分享
- 裝載機驅(qū)動橋培訓(xùn)
評論
0/150
提交評論