嵌入式uClinux下的CAN總線設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)
1、uClinux操作系統(tǒng)概述
uClinux是Linux2.0的一個(gè)分支,它被設(shè)計(jì)用于沒有MMU的微控制器領(lǐng)域,即被廣泛應(yīng)用于嵌入式Linux領(lǐng)域。uClinux的最大特征就是沒有MMU(內(nèi)存管理單元模塊)。它很適合那些沒有MMU的處理器,如ARM7TDMI,m68ez328等。
uClinux具有完全的TCP/IP協(xié)議棧,同時(shí)對(duì)其他許多的網(wǎng)絡(luò)協(xié)議都提供支持。這些網(wǎng)絡(luò)協(xié)議都在uClinux上得到了很好的實(shí)現(xiàn)。uClinux可以稱作是一個(gè)針對(duì)嵌入式系統(tǒng)的優(yōu)秀網(wǎng)絡(luò)操作系統(tǒng)。
2、Linux驅(qū)動(dòng)程序設(shè)計(jì)概述
Linux系統(tǒng)內(nèi)核通過設(shè)備驅(qū)動(dòng)程序與外圍設(shè)備交互,設(shè)備驅(qū)動(dòng)程序是Linux內(nèi)核的一部分,它是一組數(shù)據(jù)結(jié)構(gòu)和函數(shù),這些數(shù)據(jù)結(jié)構(gòu)和函數(shù)通過定義的接口控制一個(gè)或多個(gè)設(shè)備。
和UNIX一樣,Linux中所有的設(shè)備均作為文件來對(duì)待,這些文件一般稱為特殊文件,這樣做的一個(gè)好處是使用戶或應(yīng)用程序可按操縱普通文件的方式進(jìn)行訪問控制硬件設(shè)備。
Linux內(nèi)核有三種類型的設(shè)備驅(qū)動(dòng)程序:字符設(shè)備驅(qū)動(dòng)程序、塊設(shè)備驅(qū)動(dòng)程序和網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序。Linux的設(shè)備由一個(gè)主設(shè)備號(hào)(major)和一個(gè)次設(shè)備號(hào)(minor)標(biāo)識(shí)。主設(shè)備號(hào)唯一標(biāo)識(shí)了設(shè)備類型,它是塊設(shè)備表或字符設(shè)備表中設(shè)備表的索引。次設(shè)備號(hào)僅由設(shè)備驅(qū)動(dòng)程序解釋,用于識(shí)別同類設(shè)備中,I/O請(qǐng)求所涉及到的那個(gè)設(shè)備。設(shè)備驅(qū)動(dòng)程序可以分為3個(gè)主要組成部分:
?。╨)自動(dòng)配置和初始化子程序,負(fù)責(zé)檢測(cè)所要驅(qū)動(dòng)的硬件設(shè)備是否能正常工作。
?。?)服務(wù)于I/O請(qǐng)求的子程序,又稱為驅(qū)動(dòng)程序的上半部分。
(3)中斷服務(wù)子程序,又稱為驅(qū)動(dòng)程序的下半部分。
3、uClinux下CAN設(shè)備的驅(qū)動(dòng)程序編寫
根據(jù)上文對(duì)LINUX下設(shè)備驅(qū)動(dòng)程序的描述,以及參考相關(guān)的實(shí)例分析,下面對(duì)CAN總線設(shè)備SJA1000的驅(qū)動(dòng)程序進(jìn)行編寫。
CAN設(shè)備驅(qū)動(dòng)程序?qū)嶋H上是linux內(nèi)核直接對(duì)sja1000器件的初始化與讀寫操作。經(jīng)分析,sja1000 CAN驅(qū)動(dòng)程序構(gòu)成包括如下幾個(gè)部分:
1)定義sja1000芯片內(nèi)所有寄存器的訪問地址,用于完成對(duì)其內(nèi)部寄存器以及緩沖區(qū)的讀寫訪問。例如:
#define IO_PMOD (*(volatile unsigned *)0x3ff5000)
#define IO_PDATA (*(volatile unsigned *)0x3ff5008)
#define IO_PCON (*(volatile unsigned *)0x3ff5004)
#define SJA_MOD (0x2700000) #define SJA_CMR (0x2700004)
…………………
#define SJA_CANRXB7 (0x270006c) #define SJA_CANRXB8 (0x2700070)
因?yàn)樵谖覀兊南到y(tǒng)中,對(duì)sja1000的讀寫是采用的部分模擬時(shí)序的方式,所以用到了S3C4510的IO端口。下面對(duì)sja1000地址的定義進(jìn)行分析。因?yàn)閡Clinux運(yùn)行的時(shí)候,采用的是32位方式,即兩個(gè)相鄰地址間相隔4個(gè)字節(jié),而在sja1000內(nèi)部的地址間的間隔只有1個(gè)字節(jié)。雖然可以對(duì)S3C4510的內(nèi)部寄存器定義為在訪問sja1000的時(shí)候,將位寬度定義為8位,但這樣會(huì)與linux系統(tǒng)運(yùn)行不匹配,經(jīng)測(cè)試發(fā)現(xiàn)讀寫不正常。所以將sja1000的地址定義為32位寬度。于是各個(gè)寄存器地址為(基址+sja1000內(nèi)部地址×4)。這里將sja1000的基址定義為0x2700000。
2)編寫對(duì)SJA1000內(nèi)部寄存器訪問的讀寫函數(shù)
因?yàn)?a class="contentlabel" href="http://butianyuan.cn/news/listbylabel/label/S3C4510B">S3C4510B處理器的地址和數(shù)據(jù)總線是分開的,而SJA1000的地址與數(shù)據(jù)總線是8位分時(shí)復(fù)用的。所以我們只有采用先向sja1000的8位地址數(shù)據(jù)總線上送出地址,然后再送數(shù)據(jù)或者讀數(shù)據(jù)的方式。片選信號(hào)/CS,讀信號(hào)/RD,寫信號(hào)/WR仍由S3C4510B自己產(chǎn)生。需要模擬的是鎖存信號(hào)ALE、地址數(shù)據(jù)總線AD0-AD7。參照sja1000時(shí)序圖,具體的操作步驟見下面程序和注釋。
寫子程序如下:
void sja_write(unsigned int data, unsigned int addr)
{ unsigned char tmp;
tmp=(addr)>>2;//將32位地址右移2位,tmp的低8位即為sja1000實(shí)際地址。
outl(tmp,addr);//將地址信息作為數(shù)據(jù)送往SJA1000數(shù)據(jù)總線
IO_PDATA=0x32;//ALE=0,讓SJA1000將該地址鎖存
outl(data,addr);//將數(shù)據(jù)信息送往SJA1000數(shù)據(jù)總線
O_PDATA=0x33; } //將ALE置高電平,74HC245的/OE置高位
讀子程序如下:
unsigned char sja_read(unsigned int addr)
{ unsigned char data;
volatile unsigned int data1;
unsigned char tmp;
tmp=(addr)>>2; //將32位地址右移2位,tmp的低8位即為sja1000實(shí)際地址S3C2410
outl(tmp,addr); //將地址信息作為數(shù)據(jù)送往SJA1000數(shù)據(jù)總線
IO_PDATA=0x32; //p0-ALE=0,鎖存地址信息
IO_PDATA=0x12; //p5-245dir=0,將74HC245的方向置為CPU輸入方向
data1=inl(addr); //讀出所需的數(shù)據(jù)
IO_PDATA=0x33; //ALE置高,74HC245置為不工作狀態(tài)
data=data1; return(data); }//返回?cái)?shù)據(jù)
后面對(duì)sja1000的初始化、CAN發(fā)送與CAN接收函數(shù)中需要對(duì)寄存器操作均調(diào)用sja_write()和sja_read()函數(shù)進(jìn)行。
評(píng)論