1. 程式人生 > >vxWorks6.6下基於VxBus架構的Can控制器(sja1000t)驅動編寫

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檢視驅動的資訊時,最後檢查是驅動檔案中的名字不匹配。