S32K148自带3路CAN, 官方的SDK给了can_pal的例程, 本文更基础一点, 直接用flexcan组件相关的函数, CANFD需要相应的电平转换芯片速率上的支持, 我暂时用不到CANFD, 就只拿来做基础的CAN通信. 先测试CAN发送, 然后测试CAN的接收中断. 板子某宝淘的, 连接两路CAN到CAN分析仪:
左边是S32K148引出的两路CAN, 右边是CAN分析仪. 记得至少一边接120Ω终端电阻. CAN0和CAN1对应的引脚为:
CAN0_RX | PTE4 |
---|---|
CAN0_TX | PTE5 |
CAN1_RX | PTC6 |
CAN1_TX | PTC7 |
本文中CAN0设置为250K, CAN1设置为500K.
步骤:
双击工程名, 点击Components窗口Components目录下的 pin_mux:PinSetting
, CAN配置:
Component Library中双击添加两组flexcan组件:
CAN0组件配置如下图, Device选CAN0, 设置250kbit/s, 不使能FD:
CAN1组件配置如下图, 设置500kbit/s:
点击生成代码:
先是日常一贴的时钟和引脚配置:
/* For example: for(;;) { } */
CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,
g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_FORCIBLE);
PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
然后是CAN组件的初始化:
FLEXCAN_DRV_Init(INST_CANCOM0, &canCom0_State, &canCom0_InitConfig0);
FLEXCAN_DRV_Init(INST_CANCOM1, &canCom1_State, &canCom1_InitConfig0);
然后就可以发CAN报文了:
#define TX_MAILBOX_0 10
#define TX_MAILBOX_1 11
#define TIMEOUT 10U
flexcan_data_info_t data_std_info = {
.msg_id_type = FLEXCAN_MSG_ID_STD,
.data_length = 8U,
.is_remote = false
};
flexcan_data_info_t data_ext_info = {
.msg_id_type = FLEXCAN_MSG_ID_EXT,
.data_length = 8U,
.is_remote = false
};
uint32_t msg_id0 = 0x123;
uint8_t data0[8] = {1, 2, 3, 4, 5, 6, 7, 0xFF};
uint32_t msg_id1 = 0x1234567;
uint8_t data1[8] = {7, 6, 5, 4, 3, 2, 1, 0xFE};
//==============================================
while(1) {
++data0[7];
++data1[7];
FLEXCAN_DRV_SendBlocking(INST_CANCOM0, TX_MAILBOX_0 , &data_std_info , msg_id0, data0, TIMEOUT);
FLEXCAN_DRV_SendBlocking(INST_CANCOM1, TX_MAILBOX_1 , &data_ext_info , msg_id1, data1, TIMEOUT);
OSIF_TimeDelay(1);
}
调试运行, 可以看到CAN分析仪的上位机里面接收到了数据, 这里以500K CAN1接收的扩展帧为例:
可以看到上图中增量时间里面是1.8ms, 而我们程序里只有1ms的延时 OSIF_TimeDelay(1);
, 是因为Blocking占用了时间, 我们不用Block的方式, 直接Send:
while(1) {
++data0[7];
++data1[7];
FLEXCAN_DRV_Send(INST_CANCOM0, TX_MAILBOX_0 , &data_std_info , msg_id0, data0);
FLEXCAN_DRV_Send(INST_CANCOM1, TX_MAILBOX_1 , &data_ext_info , msg_id1, data1);
OSIF_TimeDelay(1);
}
这个是没有TIMEOUT参数的, 调试运行, 可以看到增量时间是正常的1ms, 大概是甩给DMA了吧, 要注意Blocking方式可以返回成功失败, 非Blocking返回的应该都是成功???:
具体是Blocking还是非阻塞, 看对结果看重还是对时间要求严格, 前者失败了可以设定重传以及最大重传次数, 在有一定CAN负载率时有一定的必要, 后者自信当甩手掌柜单发单收时用起来很爽.
步骤:
FLEXCAN_DRV_ConfigRxMb
配置接收缓存(message buffer)FLEXCAN_DRV_InstallEventCallback
添加中断FLEXCAN_DRV_Receive
开始接收(有一种FIFO的接收方式, 这里暂时未用)typedef void (*flexcan_callback_t)(uint8_t instance, flexcan_event_type_t eventType, uint32_t buffIdx, flexcan_state_t *flexcanState);
在接收中断里, 判断完成和端口, 然后把CAN0接收到ID为0x87的标准帧报文转发给CAN1; 把CAN1接收到ID为0x1234568的扩展帧报文转发给CAN0.#define RX_MAILBOX_0 0U
#define RX_MAILBOX_1 1U
flexcan_msgbuff_t recvMsg0;
flexcan_msgbuff_t recvMsg1;
void canRxCallback(uint8_t instance, flexcan_event_type_t eventType,
uint32_t buffIdx, flexcan_state_t *flexcanState) {
if(eventType == FLEXCAN_EVENT_RX_COMPLETE) {
if(instance == INST_CANCOM0) {
FLEXCAN_DRV_Receive(INST_CANCOM0, RX_MAILBOX_0, &recvMsg0);
FLEXCAN_DRV_Send(INST_CANCOM1, TX_MAILBOX_1, &data_std_info, recvMsg0.msgId, recvMsg0.data);
} else if(instance == INST_CANCOM1) {
FLEXCAN_DRV_Receive(INST_CANCOM1, RX_MAILBOX_1, &recvMsg1);
FLEXCAN_DRV_Send(INST_CANCOM0, TX_MAILBOX_0, &data_ext_info, recvMsg1.msgId, recvMsg1.data);
}
}
}
//main
FLEXCAN_DRV_ConfigRxMb(INST_CANCOM0, RX_MAILBOX_0, &data_std_info, 0x87);
FLEXCAN_DRV_InstallEventCallback(INST_CANCOM0, canRxCallback, NULL);
FLEXCAN_DRV_ConfigRxMb(INST_CANCOM1, RX_MAILBOX_1, &data_ext_info, 0x1234568);
FLEXCAN_DRV_InstallEventCallback(INST_CANCOM1, canRxCallback, NULL);
FLEXCAN_DRV_Receive(INST_CANCOM0, RX_MAILBOX_0, &recvMsg0);
FLEXCAN_DRV_Receive(INST_CANCOM1, RX_MAILBOX_1, &recvMsg1);
while(1) {
}
调试运行, 在CAN分析仪上位机里面可以看到CAN0发送的ID为0x87的报文可以在CAN1中收到:
至于增量时间不是10ms, 待排查. 同样CAN1发送ID为0x1234568的报文也可以在CAN1中收到.
https://download.csdn.net/download/weifengdq/11916783