赞
踩
真没想到距离写第一篇S32K144入门笔记(1) 从零开始进行开发环境搭建已经过去了半年。
当时是项目紧逼,20天之前要把这个片子的大部分外设跑起来,做好BOOT+APP架构,在十一之前出一个demo。
只能每天调完一个外设,本来计划是给每个外设都写一篇总结的。
后来demo完成就转手给其他同事了,然后进了其他项目,一转眼就是半年。
这半年里,S32K已经推到了多个项目里使用,形成S32K + ADAS(海思3566/赛灵思zynq/zux)的架构,但是都是在上层的业务做修改,底下的一些外设接口基本没怎么变过,所以没怎么遇到大问题,就没再回来这个项目做修改。唯一遇到的问题就是lin的,这个后面开单独一节来写。
最近正好面临工作交接,再次把项目过一遍,整理一些文档,留给后面的同事。
这件事证明了:自己一定要抽时间来做总结,单纯地不停赶项目,会给自己很充实的错觉。一定要思考,才能沉淀。
跑偏了,拉回,汽车电子设备,先写can。
S32K144的资料很少,我们直接从SDK里拉个demo来分析把。
用的是Pal层的demo程序,调用的是can_pal这个组件。
要注意就是,调can,这个开发板必须使用12V供电,否则can phy那边起不来。
quickStart文档上标识了要使用的接口:
注意就是J107的跳线帽,需要使用12V电源供电,并切换。切换到1-2脚连接。
先看原理图
芯片上脚是: PTE4 和 PTE5.
然后过一个电平转换,这块我们不用管。
然后到can phy,输出
实际接线如下,注意跳线帽
这个demo程序实现比较简单,和can相关流程就是,
CAN_Init(&can_pal1_instance, &can_pal1_Config0);
can_buff_config_t buffCfg = {
.enableFD = true,
.enableBRS = true,
.fdPadding = 0U,
.idType = CAN_MSG_ID_STD,
.isRemote = false
};
/* Configure RX buffer with index RX_MAILBOX */
CAN_ConfigRxBuff(&can_pal1_instance, RX_MAILBOX, &buffCfg, RX_MSG_ID);
分析几个重要的接口吧,无非是过滤、发送、接收。
CAN_ConfigRxBuff调用了FLEXCAN_DRV_ConfigRxMb,进而调用FLEXCAN_SetRxMsgBuff。
这个是通过配置flexcan_mb_id来实现过滤。
volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
volatile uint32_t *flexcan_mb_id = &flexcan_mb[1];
再找FLEXCAN_GetMsgBuffRegion,返回的第N个message buffer的地址。
然后给flexcan_mb_id 赋值,看代码是赋给了message buffer的4字节偏移的位置。
再向下的机制就没再深究。
CAN_Send是can发送接口,
调用完可以用 while(CAN_GetTransferStatus(INST_CAN_PAL1, TX_BUFF_IDX) == STATUS_BUSY); 来判断是否发送完成。
但是这种情况下,如果板子没接can线,就会一直卡在这里,所以可以用CAN_SendBlocking(INST_CAN_PAL1, TX_BUFF_IDX, &sendMsg,1);加一个超时机制。
看实际情况来使用吧。
与发送同理,有一个CAN_ReceiveBlocking超时机制的接口,这样做起来会比较灵活。
CAN_Receive(&can_pal1_instance, RX_MAILBOX, &recvMsg); 中接收buffer地址recvMsg会配给mb_message。
然后通过EDMA_DRV_ConfigSingleBlockTransfer接口,配置source地址和dest地址做一次搬运。
源数据都是放在RAMn地址上的。
基于这个demo来做了我们自己的工程,记录几个实际遇到的问题把。
因为加了过滤机制,只能收ID 为0x2的报文。
所以只能收到RX_MSG_ID的数据。
demo设计就是按键会发送一个can报文,但是实测在按键中断里,调用Can_send 无法发出can数据。
单步跟踪到FLEXCAN_StartSendData接口里面的
if (state->mbs[mb_idx].state != FLEXCAN_MB_IDLE)
{
return STATUS_BUSY;
}
status返回的是STATUS_BUSY,但是接收能收到。
解决方法:
在配置界面里把can_fd勾掉。
payload_size 改成8。
接收到数据:
if(cs->msgIdType == FLEXCAN_MSG_ID_STD)
{
/* ID[28-18] */
*flexcan_mb_id &= ~CAN_ID_STD_MASK;
*flexcan_mb_id |= (msgId << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;
/* make sure IDE and SRR are not set */
flexcan_mb_config &= ~(CAN_CS_IDE_MASK | CAN_CS_SRR_MASK);
}
只有第一次进来是对的,cs->msgIdType = 0.是数据帧,会把帧号赋给flexcan_mb_id 。
后面就进不来了。
再往上跟踪
FLEXCAN_StartSendData()
里的 cs.msgIdType = tx_info->msg_id_type; 赋值的
这个msg_id_type是从
CAN_Send里的
flexcan_data_info_t dataInfo = {
.msg_id_type = (flexcan_msgbuff_id_type_t) s_hwObjConfigs[instance][buffIdx]->idType,
赋值的
2. 有时候消息会变成远程帧出去。
是数据帧还是远程帧,是由
CAN_Send里的dataInfo的is_remote决定的。
.is_remote = s_hwObjConfigs[instance][buffIdx]->isRemote,
单步调试,这个值只有第一次的时候为0,后面(第二次跑到这里)怎么就变成了43?
这个s_hwObjConfigs数组是从哪里来的?
3.
综合上述两个bug。
都是在Can_Send这个接口里出的问题。
都是读取s_hwObjConfigs这个配置出错的。
为啥呢?
来找这个s_hwObjConfigs是在哪里配的?
void ConfigCan0Buffer()
{
can_buff_config_t buffConfig = {
.enableFD = false,
.enableBRS = false,
.fdPadding = 0x00,
.idType = CAN_MSG_ID_STD,
.isRemote = false
};
CAN_ConfigTxBuff(INST_CAN_PAL1, TX_BUFF_IDX, &buffConfig);
CAN_ConfigRxBuff(INST_CAN_PAL1, RX_BUFF_IDX, &buffConfig, 0x55);
}
问题找到了,这个参数是指针传的,每次发送都要读取。
不能把buffConfig 写到函数内部,运行完了就释放了。
要写成全局变量。
网上下载了一个NXP的demo,
使用 CAN_InstallEventCallback(INST_CAN_PAL1, can0_Callback, NULL); 注册中断回调就好。
在中断中可以做一些存储策略,比如用自己的环形队列。
在组件上右键有Doxygen documentation,里面也有一些说明和例子,可以参考。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。