vxWorks6.6下基於VxBus架構的Can控制器(sja1000t)驅動編寫
vxWorks6.6下基於VxBus架構的Can控制器驅動編寫 |
1 VxBus下驅動的架構
Workbench3.0是VxWorks 6.x 的整合開發環境,而VxWorks 5.5是採用Tornado2.2 來進行開發的。Workbench3.0相比Tornado2.2來說提供了更為強大的功能,在Workbench3.0可以根據需要建立各種工程,常用的有以下幾種VxWorks Image Projects,Boot Loader/BSP Projects,VxWorks Real-time Process Projects,VxWorks Downloadable Kernel ModuleProjects.
在進行驅動開發時需要建立VxWorks Image Projects。基於VxBus架構模型驅動在開發環境Workbench3.0中是以元件的形式體現的,這樣的話就方便開發人員根據需要進行驅動的新增,重新編譯VxWorks image後就可將驅動編進核心。開發人員只需將精力集中在驅動原始碼的編寫上了。VxWorks5.5中沒有VxBus架構,它的驅動的呼叫直接在BSP中的sysLIib.c中呼叫即可,這樣開發的驅動可移植性不夠好,當更換BSP時,又得重新移植。
關於Workbench3.0 的使用詳見wr_workbench_vxworks_users_guide_3.0.pdf。
驅動原始碼結構
VxBus下驅原始碼主要由以下幾個檔案組成:
README
Makefile
driverName.dr
driverName.dc
driverName.c
1 README
關於驅動的說明檔案
2 Makefile
驅動的編譯規則
3 driverName.cdf
驅動的描述檔案,裡邊包括的該驅動依賴的元件,驅動的位置,父目錄以及子目錄,在Workbench3.0下的說明資訊等,很重要,若不正確,在Workbench3.0無法新增。
4 driverName.dr
向VxBus進行註冊的函式。
5 driverName.dc
向VxBus進行註冊的函式的宣告。
6 driverName.c
驅動的核心檔案,驅動原始碼基本結構如下(用CAN1000t.c來舉例)
A)晶片自身的資料結構,在驅動開發的過程中逐步完善,必需有這個結構VXB_DEVICE_ID,以便同VxBu進行通訊。
typedef struct can1000tHwmonCtrl
{
VXB_DEVICE_ID _pDev;
*;
} CAN1000T_HWMON_CTRL;
B)三個基本的必需的函式,這幾個函式在系統初始化的不同階段進行呼叫
LOCAL voidcan1000tHwmonInstInit(VXB_DEVICE_ID);
LOCAL void can1000tHwmonInstInit2(VXB_DEVICE_ID);
LOCAL voidcan1000tHwmonInstConnect(VXB_DEVICE_ID);
C)驅動所提供的方法結構宣告
LOCAL device_method_tcan1000tHwmon_methods[] =
{
DEVMETHOD(HwmonSendData,can1000tHwmonSendData),
DEVMETHOD(HwmonRecvData,can1000tHwmonRecvData),
DEVMETHOD_END
};
D)三個基本的必需的函式的宣告
LOCAL struct drvBusFuncs can1000tHwmonFuncs=
{
can1000tHwmonInstInit, /* devInstanceInit */
can1000tHwmonInstInit2, /* devInstanceInit2 */
can1000tHwmonInstConnect /* devInstanceConnect */
};
E)向VxBus註冊的結構,包含了以上C,D。
LOCAL DRIVER_REGISTRATIONcan1000tHwmonDevRegistration =
{
NULL, /* pNext */
VXB_DEVID_DEVICE, /* devID */
VXB_BUSID_PLB, /* busID = Processor Local Bus */
VXBUS_VERSION_3, /* busVer 1 */
"can1000t", /* drvName */
&can1000tHwmonFuncs, /* pDrvBusFuncs */
can1000tHwmon_methods, /* pMethods */
NULL /* devProbe */
};
F)向VxBus註冊的函式
void can1000tHwmonRegister(void)
{
vxbDevRegister((struct vxbDevRegInfo*)&can1000tHwmonDevRegistration);
}
install: 指vxWorks的安裝目錄
1) 在cmd下執行
wrenv.exe -p vxworks-6.6
2) 進入如下目錄
cd installDir\vxworks-6.x\target\config\comps\src\hwif
3)執行下列命令 make vxbUsrCmdLine.c
注意:若已經存在vxbUsrCmdLine.c的話則手工刪除掉
4)進入下列目錄
cd installDir\vxworks-6.x\target\config\comps\vxWorks
5)執行下列命令
Del CxrCat.txt
6)執行下列命
make
7)進入如下目錄
cd installDir\vxworks-6.x\target\3rdparty\vendor\driver
8)執行下列命令
make CPU=cpuName TOOL=tool
注意:cpuName是所選BSP對應處理器的型號,如PPC32;
tool是對應的編譯工具,如sfdiab 和 gnu
至此就可以在對應的庫目錄下看見剛編譯生成的庫件
installDir\vxworks-6.x\target\lib\ppc\PPC32\common\下
此時在workbench中建立image工程,在kernel configuration下就可以看到剛才編譯的
當然也可以把這些命令寫成一個指令碼直接點執行即可。也可以進入所寫的驅動目錄下單獨編譯該驅動命令如:
makeCPU=PPC32 TOOL=sfidab
2 Can控制器的驅動編寫
CAN是控制器區域網絡(Controller Area Network, CAN)的簡稱,是由研發和生產汽車電子產品著稱的德國BOSCH公司開發了的,並最終成為國際標準(ISO118?8)。是國際上應用最廣泛的現場匯流排之一。在我看來,CAN其實就是一種通訊的模式。使用如下
SJA1000T是一款CAN控制器的晶片,要編寫它的驅動,首先必須熟悉它的工作模式。有兩種工作模式:BasicCAN(相容PCA82C20)和PeliCAN。通過閱讀SJA1000T的DataSheet,來熟悉它的暫存器的佈局,以及它的工作模式。
VxBus下的驅動按類進行區分,選擇一個合適的驅動模板很重要,我選擇的是adt7461(溫度感測器)的驅動,然後進行修改,刪除一些無用的程式碼,最終只有一個空的架子,然後按前面講的方法進行編譯,編譯通過後,在WorkBench3.0中選擇合適的BSP建立VxWorks Image Projects,在第三方驅動元件下新增所編寫的驅動元件,若不能新增檢查驅動中的driverName.cdf檔案是否正確。若正確後則可以新增該元件如下圖所示
開啟相應的BSP中的檔案hwconf.c新增驅動所需的資源,暫存器基地址和中斷號,以便在驅動初始化時使用新增如下:
1中斷資源
#ifdefDRV_HWMON_ZKHXET_CAN1000T
{ EPIC_VEC_EXT_IRQ0, "can1000t", 0, 0 },
{ EPIC_VEC_EXT_IRQ0, "can1000t", 1, 0 },
#endif/*DRV_HWMON_ZKHXET_CAN1000T*/
2暫存器等資源
#ifdefDRV_HWMON_ZKHXET_CAN1000T
const structhcfResource can1000t1Resources[] = {
{VXB_REG_BASE, HCF_RES_INT, { (void *)(0xEE000000) } },
{"irq", HCF_RES_INT, {(void *)EPIC_VEC_EXT_IRQ0} },
{ "busno", HCF_RES_INT, { (void *)(0) } },
};
#definecan1000t1Num NELEMENTS(can1000t1Resources)
#endif /*DRV_HWMON_ZKHXET_CAN1000T */
3驗證驅動是否載入成功
修改hwconf.c檔案後,在WorkBench3.0建立Boot Loader/BSP Projects,選擇相應BSP進行編譯,編譯完成後,更新要新增驅動板子的boot。載入編譯了驅動的核心映像,載入後,輸入VxBusShow命令就可以看到載入後的驅動。若沒有看到,檢查驅動中裝置名字是否正確。
經過以上步驟,驅動的基本架構已經基本搭建完成,下來就是根據具體的CAN控制器晶片來按部就班的實現相應的功能。
2.3.3.1 SJA1000T的初始化
總體來說SJA1000T的初始話比較簡單,主要是如下步驟
1) 通過配置模式暫存器(MOD)進入復位模式,因為進入復位模式後,一些暫存器才允許配置。
2) 配置時鐘分頻暫存器,選擇PeliCAN模式,根據具體的電路,是否使能時鐘等。
3) 配置模式暫存器,選擇合適工作模式,是單濾波還是雙濾波等。
4) 配置驗收程式碼/遮蔽暫存器,配置一些初始值,一般配置全部接收,這個允許使用者配置。
5) 配置匯流排定時器,選擇合適的波特率,這些允許使用者重新配置。
6) 通過配置模式暫存器(MOD)進入正常模式,此時SJA1000T就可以工作了。
詳見驅動中的函式:
CanControllerInit(VXB_DEVICE_IDpDev);
2.3.3.2 SJA1000T傳送資料
傳送資料採用查詢模式。每次傳送之前查詢狀態暫存器的傳送緩衝器狀態是否釋放。注意傳送前允許使用者配置一下幀格式的資訊,如擴充套件幀還是標準幀,是否是遠端幀,幀ID等資訊。
詳見驅動中的函式:
CanControllerTransmit(VXB_DEVICE_IDpDev, unsigned char *TXdata, int len);
2.3.3.3 SJA1000T接收資料
驅動的結構中分配儲存資料的buffer,buffer包括幀的全部資訊。
1) 中斷處理
當有接收中斷時,中斷處理函式負責將資料存到分配的buffer中,相應的標誌進行記錄。
詳見驅動中的函式:
Can1000tHwmonRecvInt(VXB_DEVICE_IDpDev);
2) 接收資料
當應用程式讀取資料時,驅動只需將buffer中的資料傳給應用層,相應的標誌進行記錄。
詳見驅動中的函式:
can1000tHwmonRecvData(VXB_DEVICE_IDpDev, int* id, int* ext_flag, int * rtr_flag, int * time_stamp, int* data, intbuf_len);
2.3.3.4 SJA1000T的配置
CAN和串列埠不一樣,並不是單純的傳送接收資料,它有自己的幀格式,如ID等,這些都需要使用者設定,使用者根據所需的資料設定相應的遮蔽碼,確定哪些想接收,哪些想遮蔽,所以驅動必須提供使用者可配置函式介面。如ioctl函式
詳見驅動中的函式:
hwmonIoctl(HWMON_DEV_HDR*pDevHdr, int func, int arg);
至此為止CAN控制器SJA1000T的驅動完成,下來進入關鍵的一步調式。
3 驅動除錯
除錯要用到USBCAN-2I除錯工具,CAN傳送和接收的應用程式。連線好硬體電路,就可以除錯了。
以下是我用到的方法:
7) 在驅動中建立全域性變數,然後在應用程式呼叫時列印。系統載入驅動時,一些資訊沒辦法看見,可以先將儲存到全域性變數中,最後在列印,這樣就可知道了。
8) 利用logMsg進行列印。
9) 示波器的使用,在沒有任何輸出時,可以使用示波器在電路級聯的地方進行波形的檢測。
遇到的問題有以下幾個
1) WorkBench3.0中無法新增驅動的元件,最後檢查是driverName.cdf中的檔案目錄不正確。
正確的:_CHILDREN FOLDER_3RD_DRIVERS
2) 驅動載入後,在命令列用VxBusShow檢視驅動的資訊時,最後檢查是驅動檔案中的名字不匹配。