【S32K】S32K144入门笔记(2) Can(can_pal组件)

0. 引言

真没想到距离写第一篇S32K144入门笔记(1) 从零开始进行开发环境搭建已经过去了半年。
当时是项目紧逼,20天之前要把这个片子的大部分外设跑起来,做好BOOT+APP架构,在十一之前出一个demo。
只能每天调完一个外设,本来计划是给每个外设都写一篇总结的。
后来demo完成就转手给其他同事了,然后进了其他项目,一转眼就是半年。
这半年里,S32K已经推到了多个项目里使用,形成S32K + ADAS(海思3566/赛灵思zynq/zux)的架构,但是都是在上层的业务做修改,底下的一些外设接口基本没怎么变过,所以没怎么遇到大问题,就没再回来这个项目做修改。唯一遇到的问题就是lin的,这个后面开单独一节来写。
最近正好面临工作交接,再次把项目过一遍,整理一些文档,留给后面的同事。
这件事证明了:自己一定要抽时间来做总结,单纯地不停赶项目,会给自己很充实的错觉。一定要思考,才能沉淀。
跑偏了,拉回,汽车电子设备,先写can。

1. 开发环境

  • 硬件环境
    为了通用,硬件没用项目的硬件,还是使用的就是官网的黄色长条开发板,在第一篇里介绍过。
  • 软件环境
    SDK用的 S32 DESIGN STUDIO for ARM,Version : 2018.R1。
    库用的是 RTM3.0.0。
    组件用的can_pal。

2. Demo分析

S32K144的资料很少,我们直接从SDK里拉个demo来分析把。

2.1 demo

【S32K】S32K144入门笔记(2) Can(can_pal组件)_第1张图片

用的是Pal层的demo程序,调用的是can_pal这个组件。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第2张图片

2.2 硬件引脚

要注意就是,调can,这个开发板必须使用12V供电,否则can phy那边起不来。
quickStart文档上标识了要使用的接口:

【S32K】S32K144入门笔记(2) Can(can_pal组件)_第3张图片
注意就是J107的跳线帽,需要使用12V电源供电,并切换。切换到1-2脚连接。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第4张图片

先看原理图
芯片上脚是: PTE4 和 PTE5.
在这里插入图片描述
然后过一个电平转换,这块我们不用管。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第5张图片
然后到can phy,输出
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第6张图片

实际接线如下,注意跳线帽
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第7张图片

2.3 demo程序分析

这个demo程序实现比较简单,和can相关流程就是,

  1. 通过CAN_Init接口配置can,配置参数can_pal1_Config0是用pe图形化配置,自动生成的代码,主要配置就是波特率等属性。

CAN_Init(&can_pal1_instance, &can_pal1_Config0);

  1. 通过CAN_ConfigRxBuff接口配置can邮箱,配置参数 can_buff_config_t buffCfg是临时写明的。要注意就是,这个变量不能申请临时局部变量,配置进去是不会保存值的,只是存了指针,can每次都会回来找配置的。

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);

  1. 主流程中通过CAN_Receive接口去接收can消息。
  2. 按键中断中,通过CAN_Send来发送can消息。

2.4 库分析

分析几个重要的接口吧,无非是过滤、发送、接收。

2.4.1 配置过滤ID - CAN_ConfigRxBuff

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的地址。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第8张图片
在这里插入图片描述

然后给flexcan_mb_id 赋值,看代码是赋给了message buffer的4字节偏移的位置。
再向下的机制就没再深究。

2.4.2 Can发送 - CAN_Send

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);加一个超时机制。
看实际情况来使用吧。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第9张图片

2.4.3 Can接收 - CAN_Receive

与发送同理,有一个CAN_ReceiveBlocking超时机制的接口,这样做起来会比较灵活。
CAN_Receive(&can_pal1_instance, RX_MAILBOX, &recvMsg); 中接收buffer地址recvMsg会配给mb_message。
在这里插入图片描述
然后通过EDMA_DRV_ConfigSingleBlockTransfer接口,配置source地址和dest地址做一次搬运。
源数据都是放在RAMn地址上的。

3. 实际使用遇到的问题

基于这个demo来做了我们自己的工程,记录几个实际遇到的问题把。

3.1 基于demo测试,can收不到数据

因为加了过滤机制,只能收ID 为0x2的报文。
在这里插入图片描述
所以只能收到RX_MSG_ID的数据。

3.2 基于demo测试,can发不出数据

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。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第10张图片

接收到数据:
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第11张图片

3.3 数据发送混乱,第一次有帧号,后面就没了,can盒接收数据一会远程帧一会数据帧

  1. 第一次有帧号,后面就变成0了
    跟踪:
    在FLEXCAN_SetTxMsgBuff函数中,有这样一句:
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 写到函数内部,运行完了就释放了。
要写成全局变量。

3.4 实现中断接收

网上下载了一个NXP的demo,
使用 CAN_InstallEventCallback(INST_CAN_PAL1, can0_Callback, NULL); 注册中断回调就好。
在中断中可以做一些存储策略,比如用自己的环形队列。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第12张图片

3.5 其他资料

在组件上右键有Doxygen documentation,里面也有一些说明和例子,可以参考。
【S32K】S32K144入门笔记(2) Can(can_pal组件)_第13张图片

你可能感兴趣的:(【S32K】S32K144入门笔记(2) Can(can_pal组件))