在汽車領域,隨着人們對數據傳輸帶寬要求的增長,傳統的CAN總線因爲帶寬的限制難以知足這種增長的需求。此外爲了縮小CAN網絡(max. 1MBit/s)與FlexRay(max.10MBit/s)網絡的帶寬差距,BOSCH公司推出了CAN FD。
CAN FD(CAN with Flexible Data rate)繼承了CAN總線的主要特性。CAN總線採用雙線串行通信協議,基於非破壞性仲裁技術,分佈式實時控制,可靠的錯誤處理和檢測機制使CAN總線有很高的安全性,但CAN總線帶寬和數據場長度卻受到制約。CAN FD總線彌補了CAN總線帶寬和數據場長度的制約,CAN FD總線與CAN總線的區別主要在如下兩個方面:
1. 可變速率:CAN FD採用了兩種位速率。從控制場中的BRS位到ACK場以前(含CRC分界符)爲可變速率,其他部分爲原CAN總線用的速率。兩種速率各有一套位時間定義寄存器,它們除了採用不一樣的位時間單位TQ外,位時間各段的分配比例也可不一樣;
2. 新的數據場長度:CAN FD對數據場的長度做了很大的擴充,DLC最大支持64個字節,在DLC小於等於8時與原CAN總線是同樣的,大於8時有一個非線性的增加,因此最大的數據場長度可達64字節。算法
CAN FD數據幀在控制場新添加EDL位、BRS位、ESI位,採用了新的DLC編碼方式、新的CRC算法(CRC場擴展到21位)。CAN FD數據幀格式以下圖所示。
安全
CAN總線因爲位填充規則對CRC的干擾,形成錯幀漏檢率未達到設計意圖。CAN FD對CRC算法作了改變,即CRC以含填充位的位流進行計算。在校驗和部分爲避免再有連續位超過6個,就肯定在第一位以及之後每4位添加一個填充位加以分割,這個填充位的值是上一位的反碼,做爲格式檢查,若是填充位不是上一位的反碼,就做出錯處理。CAN FD的CRC場擴展到了21位。因爲數據場長度有很大變化區間,因此要根據DLC大小應用不一樣的CRC生成多項式,CRC_17,適合於幀長小於210位的幀,CRC_21,適適合於幀長小於1023位的幀。網絡
CAN FD數據幀採用了新的新的DLC編碼方式,在數據場長度在0-8個字節時,採用線性規則,數據場長度爲12-64個字節時,使用非線性編碼。以下圖所示。
框架
SylixOS的CAN驅動框架在原有CAN的基礎上增長了對CAN FD的支持。對應於新的CAN幀格式,SylixOS增長了新的幀結構定義,以下所示。分佈式
typedef struct { UINT32 CAN_uiId; /* 標識碼 */ UINT32 CAN_uiChannel; /* 通道號 */ BOOL CAN_bExtId; /* 是不是擴展幀 */ BOOL CAN_bRtr; /* 是不是遠程幀 */ UINT32 CAN_uiCanFdFlags; /* CAN FD 相關設置 */ #define CAN_FD_FLAG_EDL 1 #define CAN_FD_FLAG_BRS 2 #define CAN_FD_FLAG_ESI 4 UCHAR CAN_ucLen; /* 數據長度 */ UCHAR CAN_ucData[CAN_FD_MAX_DATA]; /* 幀數據 */ } CAN_FD_FRAME; typedef CAN_FD_FRAME *PCAN_FD_FRAME; /* CAN FD 幀指針類型 */
爲了同時兼容CAN與CAN FD,系統在建立CAN設備申請幀緩衝區時,以幀結構較大的CAN FD幀報文爲單位進行申請。同時經過ioctl新增長的CAN_DEV_CAN_FD選項查看CAN設備驅動以及控制器是否支持CAN FD。這次查詢決定了後續驅動對幀緩衝區進行讀寫時的幀報文格式,即標準CAN或CAN FD。所以CAN FD驅動的ioctl接口除了要實現標準CAN驅動的選項外,還要額外實現CAN_DEV_CAN_FD選項,以下所示。ui
case CAN_DEV_CAN_FD: *(UINT *)lArg = CAN_STD_CAN_FD; break;
應用層須要收發CAN FD報文時,必須經過ioctl的CAN_FIO_CAN_FD選項對CAN FD進行設置,以下所示。this
CAN_FD_FRAME canfdframe[10]; ssize_t size; ssize_t frame_num; long status; ... canfile = open("/dev/can0", O_RDWR); ioctl(canfile, CAN_DEV_SET_MODE, 1); ioctl(canfile, CAN_DEV_SET_BAUD, LW_OSIOD_LARG(*)); /* * must call this before read() write() */ ioctl(canfile, CAN_FIO_CAN_FD, CAN_STD_CAN_FD); ioctl(canfile, CAN_DEV_STARTUP); size = read(canfile, canfdframe, 10 * sizeof(CAN_FD_FRAME)); frame_num = size / sizeof(CAN_FD_FRAME); if (frame_num <= 0) { ioctl(canfile, CAN_DEV_GET_BUS_STATE, &status); ... ioctl(canfile, CAN_DEV_REST_CONTROLLER); } ... size = write(canfile, canfdframe, 10 * sizeof(CAN_FD_FRAME)); frame_num = size / sizeof(CAN_FD_FRAME);
《CAN FD協議介紹》:http://www.cechina.cn/company/50633_156096/messagedetail.aspx編碼