【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例

0. 引言

S32K的Lin这块是我一直没弄懂的部分。很多东西一知半解,当时感觉是硬凑了答案出来。
果然过标的时候出了问题,几个小伙伴帮忙一起刷夜也没搞定,好在标还是顺利过了,不然罪过大了。
之前做lin这块一直用的是linStack组件,这部分包含了协议栈部分,需要对lin的协议比较清楚和理解才好配置。
尤其是,图形界面配置完成后会生成一个ldf文件,这个文件很重要,所有的代码都是基于这个文件生成的,但是这个文件我确认没找到什么介绍资料,所以很多配置都是一点一点凑出来的,再实际验证的。
抓住这次写文档的机会,把当时的流程记录一遍,再好好的理一理。

其实S32K 里关于Lin的组件有两个: LinLinStack
Lin就是基本的接口封装,LinStack是带了协议栈的。
正常情况下,应该从Lin组件入手的,当初做第一版工程的时候眼神不好,没看到有这个Demo,直接以一个完全没接触过Lin的小白强上了LinStack组件,被ldf文件搞了好几天,找不到资料,各种瞎猜乱试摸索,最后总归是实现了功能,也有了自己的一些认识和感触,先记录下来。
可能存在错误,因为完全是摸索碰出来的,也欢迎讨论指正。

1. lin总线

LIN的全称为Local Interconnect Network。LIN主要功能是为CAN总线网络提供辅助功能,是车上的低速总线,相关的介绍可以见上一篇【硬件】Lin总线。

2. S32K的Lin开发方式

  1. 基于寄存器开发
    S32K这边没有找到专用的Lin的寄存器,对比之前做mpc5744的lin,同是NXP家的片子,5744就有专用的lin控制器,进行相关的Lin配置即可,而S32K这块就复杂很多。
    Lin的Demo是基于串口又封装了一层。
  2. 基于SDK3.0的库开发
    我们还是使用库来做。
    库里关于Lin这边有两个组件
    在这里插入图片描述
    LinLinStack
    顾名思义,LinStack就是带协议栈的Lin驱动组件。
    这个组件,基本上你只要配置好ldf文件,lin相关的代码就一切Ok了。

3. S32K SDK Demo: Lin & LinStack

对于一个完全没有接触过lin和ldf的人来说,只能先看一看Lin的基础知识,然后拉出S32K的Demo,开始看。
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第1张图片
Demo有4个:

  • lin_master_s32k144
  • lin_slave_s32k144
  • lin_master_baremetal_s32k144
  • lin_slave_baremetal_s32k144

因为我们是做Lin的主机的,所以只看master的工程

  1. lin_master_baremetal_s32k144
    使用Lin组件来做的,不包含协议栈的内容
    【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第2张图片
  2. lin_master_s32k144
    使用LinStack组件做的,通过ldf文件实现。
    LinStack内部代码会去调用Lin组件里的接口,相当于LinStack是位于Lin的上层的一个组件。
    【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第3张图片
    Ok,这一篇我们先看LinStack组件。

4. ldf文件

ldf文件在使用 LinStack组件开发时十分重要,基本代码都是基于ldf自动生成的。
那ldf文件是什么?
看这一段介绍:
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第4张图片

简单来说,ldf就是用来描述整个Lin网络的文件,就像设备树文件是描述整个硬件一样,ldf就是描述Lin网络的。

看一下Demo里的界面。
通过图形化界面的配置可以生成一个ldf文件。
包含节点、信号、帧、调度表 等属性。
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第5张图片
在source文件夹下,我们可以找到自动生成的ldf文件长这样:
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第6张图片
可以看出,文件开头描述了Lin的协议版本,lin的速度,接着定义了Lin网络中的节点node,信号signal,进而利用信号描述了帧Frame(各种类型的帧),最后描述了调度表。

对比上面两图,可以看出,ldf文件中描述的node节点,就是在窗口的图形化配置中填写的信息。同理,帧信息,调度表信息等信息都可以通过图形化配置,然后生成ldf文件,再通过ldf文件生成代码。

5. 实际工程

5.1 需求

工程需求其实很简单,配置两个超声波雷达,然后定时去读取即可。
具体雷达的资料就不附上了,总结要发的报文如下(雷达地址被配置为0x1和0x2)

 /* 控制0x1号
 *	0x38	写		0x01 0x00							//初始化0x1的雷达			—— 帧A
 *  0x1A	写		0xF1 0xF8 0x00 0xE0					//初始化0x1的雷达			—— 帧B
 *  0x00	写		0x02 0x00 0xC0						//激发0x1雷达进行测量		—— 帧C
 *  0x01	读											//读取0x1雷达的信号值		—— 帧D
 * 之后循环读后两条就行了
 *
 * 控制0x2号
 *	0x38	写		0x02 0x00							//初始化0x2的雷达			—— 帧E
 *  0x1A	写		0xF2 0xF8 0x00 0xE0					//初始化0x2的雷达			—— 帧F
 *  0x00	写		0x08 0x00 0xC0						//激发0x2雷达进行测量		—— 帧G
 *  0x02	读											//读取0x2雷达的信号值		—— 帧H
 *  之后循环读后两条就行了

 *
 * 如果两个雷达装的比较远,可以同时激发
 *  0x00	写		0xa	0x00	0xC0					//同时激发0x1和0x2雷达进行测量		——	帧J
 */

接下来,我们把这个需求分解:

  1. 节点node:3个
    节点1:主机(我们的S32K)
    节点2:超声波雷达1
    节点3:超声波雷达2

  2. 调度表: 2个
    调度表1:发送帧A、B、E、F,只发送一次
    调度表2:发送帧 C 收 D,发送帧G 收 H ,
    也可以发送帧 J(同时激发),收D 和 H (这样雷达离的近的时候有干扰,会不准)

  3. 无条件帧
    帧A:ID 0x38 ,报文 0x01 0x00
    帧B:ID 0x1A,报文 0xF1 0xF8 0x00 0xE0
    帧C:ID 0x00,报文 0x02 0x00 0xC0
    帧D:ID 0x01,报文读取
    帧E:ID 0x38 ,报文 0x02 0x00
    帧F:ID 0x1A,报文 0xF2 0xF8 0x00 0xE0
    帧G:ID 0x00,报文 0x08 0x00 0xC0
    帧H:ID 0x02,报文读取
    帧J:ID 0x00,报文 0x0A 0x00 0xC0

  4. 信号
    信号这里说一下,命名应该填具体的物理意义,但是当时报文因为是固定的,为了简单,直接用了很简单的命名,只为了把固定数填上去。
    信号1:
    信号2:
    信号3:
    ……
    信号N:……

5.2 图形配置

按照上面功能分解,分别填到对应的图形框里就好。

5.2.1 节点 Node配置

  1. 节点node:3个
    节点1:主机(我们的S32K)
    节点2:超声波雷达1
    节点3:超声波雷达2
    【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第7张图片
    可以看出我们定义了3个节点。
    和我们最终生成的ldf文件对应。
    【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第8张图片

5.2.2 信号 signal配置

信号组成帧,帧组成调度表。
所以要先配置信号,这样配置帧的时候下拉框才有的选。

【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第9张图片
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第10张图片

每个信号要给出init value初始值。
这里配置

5.2.3 无条件帧Unconditional frame配置

这里只用了无条件帧,
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第11张图片
可以看出来,每一帧只需要把对应的signal填进去即可。
以StartRadar启动2个雷达测量这一帧来说,就是帧J。

帧J:ID 0x00,报文 0x0A 0x00 0xC0

把0x0a、0x00、0xc0 三个信号拖进来就好。(注意这里只是我起的名称,具体的值在信号那一栏配置的,并不是Char_0x0a发送值就一定是0xa)
这里只能配置这个信号在这一帧里的位置(Offset),值value是在signal definition那一栏配置的。

5.2.4 调度表schedule table配置

之前我们设计的调度表如下:

  1. 调度表: 2个
    调度表1:发送帧A、B、E、F,只发送一次
    调度表2:发送帧 C 收 D,发送帧G 收 H ,
    也可以发送帧 J(同时激发),收D 和 H (这样雷达离的近的时候有干扰,会不准)

对应下图中的InitTable 和 WorkTable。
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第12张图片
每个table也就是添加帧,然后从下拉框里选择之前定义的帧即可。
调度表里主要配置的就是帧之间的间隔时间

5.3 代码调用

5.3.1 代码生成

图形化配置完,保存,会在source文件夹下生成一个 * .ldf文件,选择generate code,会根据这个ldf文件生成完整的协议栈代码和驱动代码。
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第13张图片

5.3.2 初始化接口

使用起来十分简单,
初始化接口如下:

void MvInitLin0()
{
    l_sys_init();
    l_ifc_init(LI0);
    l_sch_set(LI0, LI0_NormalTable, 0u);			    /* Set Schedule table to Normal */
}

其中这个LI0_NormalTable就是我们配置的调度表:
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第14张图片
设置了调度表之后,系统会自动地按照调度表设置的帧数据来做数据的发送和读写。流程不需要用户再写。

5.3.3 获取结果接口

获取数据也十分简单,周期是读取就好:

	    	if(l_flg_tst_LI0_GetRslt0x01_flag())
	    	{
	    		l_flg_clr_LI0_GetRslt0x01_flag();
	    		res1 = l_u16_rd_LI0_WaveTime_0x01();
			}

l_flg_tst_LI0_GetRslt0x01_flag()、l_flg_clr_LI0_GetRslt0x01_flag()、l_u16_rd_LI0_WaveTime_0x01()都是自动生成的API,在lin_cfg.h中的宏定义接口。
因为我们在定signal的时候声明了这两个是接收信号,所以系统会生成对应的接收API。
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第15张图片
在这里插入图片描述

5. 实际工程遇到的问题

5.1 调度表切换后无法发送

雷达在初始化的时候需要发送一次报文A、B、C,之后就循环发送D、E即可。
最初的时候是设计两个调度表,第一个调度表发送一轮后,切换到第2个调度表做周期调用。
但是实际使用过程中,总是遇到切换调度表之后就无法正常发送lin。
最后只能无奈的把ABCDE所有报文都放进了一个调度表,每个周期都会发送5条报文出去。

5.2 同一个调度表无法插入两帧相同ID的报文

我们实际使用中有需求,同一个ID,要发送不同的数据。
但是在同一个调度表中,我就没法插入同一个ID的两帧数据。
这里最后也没有通过界面的方式实现,而是搜索到系统发送用的数组,g_lin_frame_data_buffer,自己计算次数,定期去修改这个buffer的值。(非正式做法)
【S32K】S32K144入门笔记(4) Lin (Lin stack组件) 驱动超声波雷达实例_第16张图片

参考链接

  • LDF文件

你可能感兴趣的:(s32k)