我們基于之前適配好的系統(tǒng)和PIN驅(qū)動的基礎(chǔ)上繼續(xù)適配S32K146的CAN 驅(qū)動,有了CAN 驅(qū)動我們就可以通過PCAN 模擬車輛內(nèi)部的CAN 總線數(shù)據(jù),接收發(fā)送CAN消息至車輛的CAN 總線,完成和其他ECU的信息交互。
CAN 收發(fā)器使用的TJA1043,該IC 只需要按照時序控制對應(yīng)的PIN腳即可讓其進入 normal 模式,對應(yīng)代碼如下:
void can1_control_init(void)
{
rt_base_t mcu_can1_en;
rt_base_t mcu_can1_wake;
rt_base_t mcu_can1_stby;
/* init can controler pin */
mcu_can1_en = rt_pin_get(MCU_CAN1_EN);
mcu_can1_wake = rt_pin_get(MCU_CAN1_WAKE);
mcu_can1_stby = rt_pin_get(MCU_CAN1_STBY);
rt_pin_mode(mcu_can1_en,PIN_MODE_OUTPUT);
rt_pin_mode(mcu_can1_wake,PIN_MODE_OUTPUT);
rt_pin_mode(mcu_can1_stby,PIN_MODE_OUTPUT);
/* init tja1043 */
rt_pin_write(mcu_can1_wake,PIN_HIGH);
rt_pin_write(mcu_can1_stby,PIN_LOW);
rt_pin_write(mcu_can1_en,PIN_LOW);
rt_thread_mdelay(1);
rt_pin_write(mcu_can1_stby,PIN_HIGH);
rt_pin_write(mcu_can1_en,PIN_HIGH);
rt_thread_mdelay(1);
rt_pin_write(mcu_can1_wake,PIN_LOW);
}
使用 S32K SDK 中的CAN驅(qū)動接口對CAN進行初始化,配置CAN 的波特率為500Kb,及CAN 參數(shù),配置CAN 首發(fā)mailbox 資源配置,配置CAN 接收過濾器配置,即可完成CAN 模塊的驅(qū)動配置對應(yīng)代碼如下:
void can1_init(void)
{
status_t ret = STATUS_SUCCESS;
flexcan_id_table_t id_filter_table[40];
uint16_t i = 0;
for(i =0; i < 40;i++)
{
id_filter_table[i].isRemoteFrame = false;
id_filter_table[i].isExtendedFrame =false;
id_filter_table[i].id = 0x400 + (0x10*i);
}
ret = FLEXCAN_DRV_Init(INST_FLEXCAN_CONFIG_1,&flexcanState0,&flexcanInitConfig0);
if(ret != STATUS_SUCCESS)
{
rt_kprintf("can1 init failed.n");
}
FLEXCAN_DRV_SetRxMaskType(INST_FLEXCAN_CONFIG_1,FLEXCAN_RX_MASK_INDIVIDUAL);
FLEXCAN_DRV_ConfigRxFifo(INST_FLEXCAN_CONFIG_1, FLEXCAN_RX_FIFO_ID_FORMAT_A, id_filter_table);
for(i = 0;i < 16; i++)
{
ret = FLEXCAN_DRV_SetRxIndividualMask(INST_FLEXCAN_CONFIG_1, FLEXCAN_MSG_ID_STD, i, 0x7ff);
if( ret != STATUS_SUCCESS )
{
rt_kprintf( "can1 set rx filter failed %x.n",ret);
}
}
}
驅(qū)動配置完之后,我們創(chuàng)建一收一發(fā)線程用于處理CAN 接收發(fā)送的數(shù)據(jù),對應(yīng)代碼如下:
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 5
void cantx_entry(void *parameter)
{
can1_control_init();
can1_init();
flexcan_data_info_t msg =
{
.data_length = 8,
.msg_id_type = FLEXCAN_MSG_ID_STD,
.enable_brs = false,
.fd_enable = false,
.fd_padding = 0U,
.is_remote = false
};
static uint8_t buff[8] = {0x55,0xaa,0x55,0xaa,0xaa,0xbb,0xcc,0xdd};
while(1)
{
FLEXCAN_DRV_Send(INST_FLEXCAN_CONFIG_1,16,&msg,0x100,buff);
rt_thread_mdelay(100);
}
}
void canrx_entry(void *parameter)
{
static flexcan_msgbuff_t data;
status_t ret = STATUS_SUCCESS;
while(1)
{
ret = FLEXCAN_DRV_RxFifo(INST_FLEXCAN_CONFIG_1,&data);
if(ret == STATUS_SUCCESS)
{
rt_kprintf("id = %x :%x %x %x %x %x %x %x %xn",data.msgId,
data.data[0],data.data[1],data.data[2],data.data[3],
data.data[4],data.data[5],data.data[6],data.data[7]);
}
rt_thread_mdelay(10);
}
}
int can_sample(void)
{
rt_thread_t tid = RT_NULL;
tid = rt_thread_create("cantx",
cantx_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (tid != RT_NULL)
rt_thread_startup(tid);
tid = rt_thread_create("canrx",
canrx_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (tid != RT_NULL)
rt_thread_startup(tid);
return 0;
}
MSH_CMD_EXPORT_ALIAS(can_sample, can ,can sample);
對應(yīng)玩上述驅(qū)動,我們通過usb can 模擬發(fā)送0x400 消息攜帶車速及車窗狀態(tài)信息,通過串口輸出運行如下,可以看到can 通信的發(fā)送接收都工作,已經(jīng)能模擬采集車輛的CAN總線數(shù)據(jù)了。
/*代碼路徑如下*/
https://gitee.com/andeyqi/rt-thread/tree/master/bsp/s32k14x