1. 簡介
控制器局域網(wǎng)絡(CAN)根據(jù) ISO11898-1:2015和 Bosch CAN FD規(guī)范進行通信。連接到物理層需要額外的收發(fā)器硬件。所有有關處理消息的函數(shù)都由接收處理程序和發(fā)送處理程序?qū)崿F(xiàn)。
CAN/CANFD特性介紹:
- 數(shù)據(jù)長度擴展:傳統(tǒng)CAN的數(shù)據(jù)段長度固定為8字節(jié),而CAN FD將數(shù)據(jù)段長度擴展至最大64字節(jié)。這意味著單次報文可傳輸更多數(shù)據(jù),減少了報文發(fā)送次數(shù),降低了總線負載,尤其適用于需要傳輸大量參數(shù)或傳感器數(shù)據(jù)的場景。
- 傳輸速率提升:CAN FD采用“雙速率段”設計,報文的仲裁段(用于ID識別和總線仲裁)仍沿用經(jīng)典CAN的速率(最高1Mbps),確保與傳統(tǒng)CAN節(jié)點的兼容性;而數(shù)據(jù)段則可切換至更高速率(理論最大值:8 Mbps——部分高端控制器在實驗室條件下,實際應用典型值:2-5 Mbps,受物理層限制(線纜質(zhì)量、終端電阻、EMC 等),大幅提升了數(shù)據(jù)傳輸效率。
- BRS位控制速率切換:通過報文中的“總線速率切換位(BRS)”控制是否啟用高速數(shù)據(jù)段。當BRS=1時,數(shù)據(jù)段采用高速率;BRS=0時,數(shù)據(jù)段與仲裁段速率一致,靈活適配不同傳輸需求。
- 向下兼容:CAN FD節(jié)點可與傳統(tǒng)CAN節(jié)點在同一總線上共存,CAN FD控制器能正確接收和解析傳統(tǒng)CAN報文,傳統(tǒng)CAN節(jié)點雖無法解析CAN FD報文,但不會影響總線正常通信,保障了系統(tǒng)升級的平滑性。
本章我們將向大家介紹如何使用 AS32A601和1042CAN控制器來實現(xiàn)CANFD的收發(fā)功能: 我們使用的AS32A601帶有兩個CAN控制器,而我們本章只使用了CAN3。
2. 硬件設計

3. 軟件設計
幀結(jié)構表

3.1 基礎配置代碼分析
CAN/CANFD的GPIO配置,注意配置正確的復用模式
/*
*/
void User_CANFD3_GPIO_Init()
{
CANFD3_CLK_ENABLE();
GPIOC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
CANFD_InitTypeDef CANFD_InitStructure;
PLIC_InitTypeDef PLIC_InitStructure;
/* Set GPIO multiplex mapping */
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_CAN3);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_CAN3);
/* GPIO Configure */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_Out_PP;
GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_IType = GPIO_IPU;
GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
根據(jù)改公式可配置出CANFD的仲裁域、數(shù)據(jù)域波特率。計算時需要注意的是BRPTS1TS2寄存器已為加1之后的數(shù)值,不需要再加1。
波特率計算公式

void CAN_ConfigBaudrate(void)
{
/* Initializes the CANFD3 */
/* Arbitration Phase (Nominal) Baud Rate 500KHz */
/* Data Phase Baud Rate 2MHz */
CANFD_StructInit(&CANFD_InitStructure);
CANFD_InitStructure.CANFD_SRR = CANFD_SRR_RESET;
CANFD_InitStructure.CANFD_APBRPR = CANFD_APBRPR_4tp;
CANFD_InitStructure.CANFD_APBTR_APTS1 = CANFD_APBTR_TS1_30tp;
CANFD_InitStructure.CANFD_APBTR_APTS2 = CANFD_APBTR_TS2_9tp;
CANFD_InitStructure.CANFD_APBTR_APSJW = CANFD_APBTR_SJW_2tp;
CANFD_InitStructure.CANFD_DPBRPR = CANFD_DPBRPR_4tp;
CANFD_InitStructure.CANFD_DPBTR_DPTS1 = CANFD_DPBTR_TS1_30tp;
CANFD_InitStructure.CANFD_DPBTR_DPTS2 = CANFD_DPBTR_TS2_9tp;
CANFD_InitStructure.CANFD_DPBTR_DPSJW = CANFD_DPBTR_SJW_1tp;
CANFD_Init(CANFD3, &CANFD_InitStructure);
}
ID 的具體字段說明

測試設置 AFMR0 為 0xFFE00000,AFIR 為 22E00000,且寫入 AFR 寄
存器的 UAF0 位為 1,則表示只有符合 ID 為 0x117 的消息才能被接收。
void CANFD3_Parm_Init(void)
{
/* CANFD receive filter configure */
CANFD_FilterInit(CANFD3, TB0, 0xFFE00000, 0x22E00000);
CANFD_AutoRetransConfig(CANFD3,ENABLE);
/* Enable new message received interrupt */
CANFD_ITConfig(CANFD3, CANFD_IT_ERXOK, ENABLE);
/* CANFD Enable */
CANFD_Enable(CANFD3);
PLIC_StructInit(&PLIC_InitStructure);
/* Configer the CANFD1 interrupt */
PLIC_InitStructure.PLIC_IRQChannel = CANFD3_IRQn;
PLIC_InitStructure.PLIC_IRQPriority = 2;
PLIC_InitStructure.PLIC_IRQChannelCmd = ENABLE;
PLIC_Init(&PLIC_InitStructure);
CANFD_ClearITPendingBit(CANFD3, CANFD_CLEAR_ALL);
}
DLC 的具體字段說明

void CANFD3_Frame_Init()
{
CANFD_TXFrameTypeDef CANFD_TXFrameStruct;
/* Set the setting ID and setting mode */
CANFD_TXFrameStruct.CANFD_TX_PROTOCOL = CANFD;
CANFD_TXFrameStruct.CANFD_TX_FORMAT = EXTENDED;
CANFD_TXFrameStruct.CANFD_TX_TYPE = DATA;
CANFD_TXFrameStruct.CANFD_Frame_ID = 0x147;
CANFD_FrameInit(CANFD3, TB1, &CANFD_TXFrameStruct);
}
/*
- Function: CANFD3_IRQ_Handler
- Description: CANFD3 interrupt handler function.
- Param: None.
- Return: None.
*/
void CANFD3_IRQ_Handler()
{
if(CANFD_GetITStatus(CANFD3, CANFD_FLAG_RXOK) != RESET)
{
/* get the receive data */
Canfd1rx_flags = 1;
/* Clear the interrupt pending bits */
CANFD_ClearITPendingBit(CANFD3, CANFD_CLEAR_RXOK);
}
}
3.2多幀CAN發(fā)送配置代碼分析
需要發(fā)送多幀消息,可以直接向發(fā)送請求寄存器(TRR)寫發(fā)送多幀指令。如發(fā)送 TB0 到TB2,則可以向CAN 發(fā)送緩存就緒請求寄存器(CAN_TRR)寫 0x00000007。
程序同時配置并觸發(fā)三幀發(fā)送后,CAN 控制器(或驅(qū)動層)會根據(jù)ID優(yōu)先級規(guī)則自動仲裁:
發(fā)送初始化時,三幀數(shù)據(jù)均進入發(fā)送緩沖區(qū)(如 TB0、TB1 等發(fā)送郵箱),CAN 控制器檢測到總線空閑后,同時啟動三幀的位仲裁;
仲裁過程中,0x147 因 ID 最小優(yōu)先贏得總線控制權,先完成數(shù)據(jù)傳輸;
0x147 發(fā)送完成后,總線空閑,剩余兩幀再次仲裁,0x148 優(yōu)先發(fā)送,最后 0x149 完成傳輸;
void TB0_INIT(void)
{
CANFD_TXFrameTypeDef CANFD_TXFrameStruct;
/ * Setthe settingIDandsetting mode */
CANFD_TXFrameStruct.CANFD_TX_PROTOCOL=CANFD;
CANFD_TXFrameStruct.CANFD_TX_FORMAT=EXTENDED;
CANFD_TXFrameStruct.CANFD_TX_TYPE=DATA;
CANFD_TXFrameStruct.CANFD_Frame_ID=0x149 ;
CANFD_FrameInit(CANFD3, TB0, &CANFD_TXFrameStruct);
}
void TB1_INIT(void)
{
CANFD_TXFrameTypeDef CANFD_TXFrameStruct;
/ * Setthe settingIDandsetting mode */
CANFD_TXFrameStruct.CANFD_TX_PROTOCOL=CANFD;
CANFD_TXFrameStruct.CANFD_TX_FORMAT=EXTENDED;
CANFD_TXFrameStruct.CANFD_TX_TYPE=DATA;
CANFD_TXFrameStruct.CANFD_Frame_ID=0x148 ;
CANFD_FrameInit(CANFD3, TB1, &CANFD_TXFrameStruct);
}
void TB2_INIT(void)
{
CANFD_TXFrameTypeDef CANFD_TXFrameStruct;
/ * Setthe settingIDandsetting mode */
CANFD_TXFrameStruct.CANFD_TX_PROTOCOL=CANFD;
CANFD_TXFrameStruct.CANFD_TX_FORMAT=EXTENDED;
CANFD_TXFrameStruct.CANFD_TX_TYPE=DATA;
CANFD_TXFrameStruct.CANFD_Frame_ID=0x147 ;
CANFD_FrameInit(CANFD3, TB2, &CANFD_TXFrameStruct);
}
void CANFD3_Frame _Init()
{
TB0_INIT();
TB1_INIT();
TB2_INIT();
}
/ *
***** @brief 多幀發(fā)送函數(shù)
***** @param CANFDx: CANFD外設基地址
***** @param frames: 指向CANFD_MultiTxFrameInfo結(jié)構體數(shù)組的指針,包含了所有要發(fā)送的幀的信息
***** @param numFrames: 要發(fā)送的幀的數(shù)量
***** @retval****None
*/
void CANFD_MultiTransmit(CANFD_TypeDef ***** CANFDx, CANFD_MultiTxFrameInfo ***** frames, uint32_t numFrames)
{
/ * Check the parameters */
assert_param(IS_CANFD_ALL_PERIPH(CANFDx));
assert_param(frames !****=NULL);
assert_param(numFrames >0 );
uint32_t i, j;
uint32_t ***** txaddress;
uint32_t trr_mask=0 ; // 用于觸發(fā)發(fā)送的TRR位掩碼
//--- 步驟 1 : 填充所有發(fā)送緩沖區(qū)并準備TRR掩碼 ---
for(i=0 ; i < numFrames; i ++)
{
// 檢查當前幀的參數(shù)
assert_param(IS_CANFD_TB_NUMBER(frames[i].RSTBx));
assert_param(frames[i].Canfdbuf !****=NULL);
assert_param(IS_CANFD_DATA_LENGHT(frames[i].Buflength));
//1.1 設置數(shù)據(jù)長度DLC
CANFDx->TxMessage[frames[i].RSTBx].TB_DLC &****=~CANFD_TB_DLC_DLC;
CANFDx->TxMessage[frames[i].RSTBx].TB_DLC |****=(Can_DataLen2Dlc[frames[i].Buflength] << CANFD_TB_DLC_DLC_Pos);
CANFD_NormalStatus(CANFDx);// 確保CANFD處于正常工作狀態(tài)
//1.2 填充數(shù)據(jù)內(nèi)容
txaddress=(uint32_t ***** )&CANFDx->TxMessage[frames[i].RSTBx].TB_DW0;
for(j=0 ; j < frames[i].Buflength; j +=4 )
{
***** txaddress++=(((uint32_t)frames[i].Canfdbuf[j] <<24 ) |
((uint32_t)frames[i].Canfdbuf[j+1 ] << 16 ) |
((uint32_t)frames[i].Canfdbuf[j+2 ] << 8 ) |
(uint32_t)frames[i].Canfdbuf[j+3 ]);
}
//1.3 設置TRR掩碼,標記這個TB需要被發(fā)送
trr_mask |****= **(**1 << frames[i].RSTBx);
}
//--- 步驟 2 : 一次性觸發(fā)所有幀的發(fā)送 ---
CAcFDx->TRR=trr_mask;// 向TRR寄存器寫入掩碼,觸發(fā)所有指定TB的發(fā)送
//--- 步驟 3 : 等待所有幀發(fā)送完成 ---
// 注意:這種等待方式會阻塞CPU,直到所有幀發(fā)送完畢
While ((CANFDx->TRR & trr_mask) !****=0 )
// 說明:發(fā)送完成后,硬件會自動清除TRR中對應的位。
// 所以當 (TRR & trr_mask) 的結(jié)果為0時,代表所有請求發(fā)送的幀都已完成。
}
4 下板驗證
基礎配置驗證:
驗證在 CAN FD 通信中,切換BRS 位為 1(啟用高速數(shù)據(jù)段)和 0(禁用,使用仲裁段速率)時,總線可以成功地在沖裁域速率和數(shù)據(jù)域速率之間切換。

配置 CAN 接收端濾波參數(shù):根據(jù) CAN 控制器濾波機制(如掩碼模式、列表模式),設置驗收碼為 0x117,配置對應掩碼寄存器(確保僅匹配 0x117 精準 ID,無模糊匹配),啟用接收濾波功能。實現(xiàn)對所有非 0x117 的幀ID報文實現(xiàn)完全過濾(不觸發(fā)接收響應、不存入接收緩沖區(qū)、不產(chǎn)生相關中斷)。

多幀CAN發(fā)送配置驗證:
本次驗證充分證明:實際驗證(如通過 CAN 分析儀抓包)顯示:幀的發(fā)送順序嚴格遵循「0x147 → 0x148 → 0x149」,無亂序或優(yōu)先級倒置現(xiàn)象,證明多幀發(fā)送程序能夠嚴格遵循 CAN 總線 ID 優(yōu)先級仲裁規(guī)則,實現(xiàn)按 ID 從小到大的自動順序發(fā)送,確保了高優(yōu)先級數(shù)據(jù)的實時傳輸,符合 CAN 總線的通信特性和嵌入式系統(tǒng)的實時性要求。

審核編輯 黃宇
-
CAN控制器
+關注
關注
3文章
80瀏覽量
15585 -
CANFD
+關注
關注
0文章
105瀏覽量
5866
發(fā)布評論請先 登錄
TJA1042高速CAN 收發(fā)器
TJA1042 高速CAN收發(fā)器產(chǎn)品數(shù)據(jù)手冊
CAN控制器在CANFD中會導致什么問題
通用CAN接口芯片NCA1042兼容替代TI的TCAN1042/NXP的TJA1049T
CAN收發(fā)器與CAN控制器的區(qū)別
TCAN1042具有CAN FD和故障保護功能的CAN收發(fā)器數(shù)據(jù)表
如何使用 AS32A601和1042CAN控制器來實現(xiàn)CANFD的收發(fā)功能?
評論