-
概述
本文檔是在AT91SAM9X25平臺上進行SylixOS CAN總線驅動開發時,對CAN總線底層傳輸流程的解析。
適用於正在學習CAN總線驅動的技術工程師。
-
技術實現
CAN總線的傳輸流程可以分成兩個部分:
一部分是CAN總線的發送流程,主要工作是將準備發送的數據填充到對應的寄存器,並使能開始傳輸位和郵箱中斷位;另一部分是CAN總線的中斷處理流程,主要工作是對觸發中斷的中斷源進行判斷,並對不同的中斷進行相關處理。
-
CAN總線的發送流程
在AT91SAM9X25平臺上,CAN總線發送流程如圖 21所示。在填寫數據的幀ID時,必須要將郵箱設置爲禁用模式。正常情況下,當我們將數據填充完成,開始發送數據時,就可以在總線上測到我們發送的數據。這裏使能的郵箱中斷是傳輸完成中斷。
圖 21 CAN總線的發送流程圖
具體的代碼實現如程序清單 21所示。
程序清單 21 CAN總線的傳輸函數
/********************************************************************************************************* ** 函數名稱: __canTransmit ** 功能描述: CAN的傳輸 ** 輸 入: pChannel 通道對象 ** pcanFrame can幀結構體指針 ** 輸 出: ** 返 回: LW_FALSE 傳輸出錯 ** LW_TRUE 傳輸成功 *********************************************************************************************************/ static INT __canTransmit (__PCAN_CHANNEL pChannel, CAN_FRAME *pcanFrame) { UINT uiRegMid; UINT uiRegMcr; if (pcanFrame->CAN_bExtId) { /* 如果是擴展幀 */ uiRegMid = (pcanFrame->CAN_uiId & CAN_EFF_MASK) | CAN_MID_MIDE; } else { /* 如果是標準幀 */ uiRegMid = (pcanFrame->CAN_uiId & CAN_SFF_MASK) << CAN_MID_MIDVA_SHIFT; } uiRegMcr = (pcanFrame->CAN_bRtr & 1 ? CAN_MCR_MRTR : 0) | (pcanFrame->CAN_ucLen << CAN_MSR_MDLC_SHIFT) | CAN_MCR_MTCR; writel((MB_MODE_DISABLED) | SET_PRIO_IS_0, /* 寫ID時,將郵箱設爲禁用模式 */ REG_CAN_MMR(CHANNEL, MB_TX)); writel(uiRegMid, REG_CAN_MID(CHANNEL, MB_TX)); /* 將ID寫到對應寄存器 */ writel((MB_MODE_TX) | SET_PRIO_IS_0, /* 設置爲TX模式 */ REG_CAN_MMR(CHANNEL, MB_TX)); if (!(readl(REG_CAN_MSR(CHANNEL, MB_TX)) & CAN_MSR_MRDY)) { printk("TX Mailbox is busy!\n"); return (LW_FALSE); } if (pcanFrame->CAN_ucLen > 0) { /* 如果有數據 */ UINT uiDataL; uiDataL = pcanFrame->CAN_ucData[0] << 0; uiDataL += pcanFrame->CAN_ucData[1] << 8; uiDataL += pcanFrame->CAN_ucData[2] << 16; uiDataL += pcanFrame->CAN_ucData[3] << 24; writel(uiDataL, REG_CAN_MDL(CHANNEL, MB_TX)); /* 填充數據寄存器 */ } if (pcanFrame->CAN_ucLen > 3) { /* 超過4個字節數據 */ UINT uiDataH; uiDataH = pcanFrame->CAN_ucData[4] << 0; uiDataH += pcanFrame->CAN_ucData[5] << 8; uiDataH += pcanFrame->CAN_ucData[6] << 16; uiDataH += pcanFrame->CAN_ucData[7] << 24; writel(uiDataH, REG_CAN_MDH(CHANNEL, MB_TX)); /* 填充數據寄存器 */ } writel(uiRegMcr, REG_CAN_MCR(CHANNEL, MB_TX)); /* 觸發傳輸 */ writel((1 << MB_TX), REG_CAN_IER(CHANNEL)); /* 使能發送郵箱中斷 */ return (LW_TRUE); }
-
CAN總線的中斷處理流程
CAN總線的中斷處理流程如圖 22所示。在AT91SAM9X25平臺上,讀狀態寄存器(REG_CAN_SR)就可以清除中斷標誌位。通過對狀態寄存器和中斷屏蔽寄存器的比較,可以判斷出是哪一種中斷,並進行相應的處理。
圖 22 CAN總線的中斷處理流程圖
具體代碼實現如程序清單 22所示。
程序清單 22 CAN總線的中斷處理函數
/********************************************************************************************************* ** 函數名稱: __canIrq ** 功能描述: 中斷服務函數 ** 輸 入 : pCanchan 通道對象 ** ulVector 中斷向量號 ** 輸 出 : LW_IRQ_HANDLED 系統中斷返回值 ** LW_IRQ_NONE 系統中斷返回值 *********************************************************************************************************/ static irqreturn_t __canIrq (__PCAN_CHANNEL pChannel, ULONG ulVector) { UINT uiRegSr; UINT uiRegImr; UINT uiRxOrErr; uiRegSr = readl(REG_CAN_SR(CHANNEL)); /* 清除中斷標誌位 */ uiRegImr = readl(REG_CAN_IMR(CHANNEL)); uiRegSr &= uiRegImr; if (!uiRegSr) { goto exit; } /* * Rx和錯誤中斷 */ uiRxOrErr = ((1 << MB_RX) /* RX和錯誤中斷的中斷位 */ | AT91_IRQ_ERR_FRAME); if (uiRegSr & uiRxOrErr) { if (uiRegSr & (1 << MB_RX)) { __canReadMsg(pChannel); } else { _DebugFormat(__PRINTMESSAGE_LEVEL, "__canIrq: Frame error!\r\n"); readl(REG_CAN_SR(CHANNEL)); /* 清除錯誤中斷標誌位 */ return (LW_IRQ_NONE); } } /* * Tx中斷 */ if (uiRegSr & (AT91_MB_MASK(MAILBOXES_NUM) & (~AT91_MB_MASK(MB_TX)))) { writel(1 << MB_TX, REG_CAN_IDR(CHANNEL)); /* 禁用發送郵箱的中斷 */ } exit: return (LW_IRQ_HANDLED); }
-
免責聲明
內部交流文檔,僅針對AT91SAM9X25相關平臺,若發現相關錯誤或者建議,請及時聯繫文檔創建者進行修訂和更新。
SylixOS 基於AT91SAM9X25的CAN總線傳輸流程解析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.