1、LIN总线诞生背景
LIN: Local Interconnect Network,本地连接网络
由于汽车电子电气架构很复杂,汽车上的电子ECU非常多。导致汽车局域网络的线束越来越多。线束增加会导致成本上升以及接线不良等造成的电子故障增加,对汽车的品质和可靠性都有很大影响。所以有些通信速率以及可靠性要求都不高的外围ECU,引入LIN总线。LIN总线是单线通信,成本比CAN总线更低。
2、LIN总线协议
和大部分通讯总线一样,LIN总线也是由LIN控制器、LIN收发器组成。LIN的控制器是基于SCI(UART)数据格式,采用单主控制器/多从设备的模式。
LIN和CAN、ETH等通信总线一样,在AutoSAR上的分层架构基本类似。
2.1、LIN协议格式
LIN的拓扑结构为单线总线,总线电平为12V,传输速率最高为20kbps,一个LIN网络最多可以连接16个节点,主机节点有且只有一个,从机节点有1到15个。
主机任务可以发送帧头和数据,从机任务不能主动发送数据,需要接收主机发送的帧头,根据帧头包含的信息判断:(1)发送应答;(2)接收应答;(3)忽略应答。
LIN采用UART功能传输,传输时需要包含一位起始位和一位停止位,共10位数据,按照LSB方式传输。
帧包含帧头和应答两部分。帧头包含同步间隔段、同步段以及受保护ID段,应答部分包含数据段和校验和段。其中值"0"为显性电平,值"1"为隐形电平,总线上实行"线与":当总线上有大于等于一个节点发送显性电平时,总线呈显性电平;所有的节点都发送隐形电平或不发送信息时,总线才呈隐形电平,即显性电平起主导作用。
2.1.1、同步间隔段
同步间隔段是由至少13位的显性电平组成,代表一帧的开始,其中同步间隔段的间隔符至少为1位隐形电平。
2.1.2、同步段
LIN同步以下降沿为判断标志,采用字节0x55(转换为二进制为01010101b)。从节点可以不使用高精度的时钟,由此带来的与主机节点时钟产生的偏差,需要通过同步段进行调整,调整的结果是使从机节点数据的位速率与主机节点一致。同步段用于同步的基准时钟为主机节点的时钟。从机节点通过接收主机节点发出的同步段,计算出主机节点位速率,根据计算结果调整自身的位速率。计算公式为:
2.1.3、受保护ID段
受保护ID段的前六位叫做帧ID,加上两个奇偶校验位后称作PID。
校验公式如下:
由公式可以看出,PID不会出现全0或者全1的情况,因此,如果从机节点收到了"0xFF"或"0x00"可判断为传输错误
帧ID的范围为0x00~0x3F,共64个。帧ID标识了帧的类别和目的地。
2.1.4、数据段
节点发送的数据位于数据段,包含1-8个字节,采用低位在前的方式发送(小端)。
2.1.5、校验和段
校验和段是对帧中所传输的内容进行校验,校验和分为标准型校验及增强型校验。
经典校验和计算方法:
校验和场是数据场所有字节的和的反码。
算法(Classical):累加所有字节。对每次加和进行判断,如果和大于0xFF,那么就把高八位的1,与低八位相加。得到最后的结果后,取其反码,我们就得到了最后的校验和。
计算下边4字节数据的奇偶校验和:DATA=0x4A、0x55、0x93、0xE5
0x4A+0x55 = 0x9F,再加0x93 = 0x132,很明显,超过了0xFF,分解为0x1和0x32,突出的高8位删除,加到低8位中,0x1+0x32=0x33。再加0xE5 = 0x118,又超了,0x1+0x18=0x19。取反(Not),0xE6。
或者采用下面这种方法也可以:
2.2、帧的类型
LIN总线根据帧ID不同,将报文分为信号携带帧(0x00~0x3B)、诊断帧(0x3C、0x3D)、保留帧(0x3E、0x3F)。LIN总线根据帧ID不同,将报文分为信号携带帧(0x00~0x3B)、诊断帧(0x3C、0x3D)、保留帧(0x3E、0x3F)。
2.2.1、无条件帧
无条件帧是具有单一发布节点,无论信号是否发生变化,帧头都被无条件应答的帧。
2.2.2、事件触发帧
事件触发帧是主机节点查询各从机节点的信号是否发生变化时使用的帧,事件触发帧允许一帧中只有帧头无应答,当存在多个发布节点时,通过冲突解决进度表来解决冲突。
当从节点信号发生变化频率较低的时候,主机任务一次次地轮询各个信号会占用一定的带宽,为了减小带宽,引入了事件触发帧的概念。
原先用作轮询的无条件帧,称为与该事件触发帧关联的无条件帧,即事件触发帧的应答部分是与其关联的无条件帧所提供的应答。当发生冲突时,需要立刻中断当前的进度表,启动冲突解决进度表,重新调用这些关联的无条件帧,冲突解决进度表要求包含所有的关联的无条件帧。
与事件触发帧关联的多个无条件帧需要满足以下五个条件:
(1)数据段包含的数据字节数等长;
(2)使用相同的校验和类型;
(3)数据段的第一个字节为该无条件帧的受保护ID,这样才能够知道应答是哪个关联的无条件帧发送的;
(4)由不同的从机节点发布;
(5)不能与事件触发帧处于同一个进度表。
2.2.3、偶发帧
偶发帧是当主节点自身信号发生变化时向总线发送的帧。当存在多个关联的应答信号发生变化时,通过事先设定的优先级来仲裁。
与事件触发帧一样,偶发帧的应答也关联了一组无条件帧,规定偶发帧只能由主机节点作为发布节点。
偶发帧的传输可能出现三种情况:1)当关联的无条件帧没有信号发生变化时,该时隙保持沉默,主节点连帧头都不需要发送;2)当其中一个关联的无条件帧包含的信号发生了变化,则发送该关联的无条件帧的应答部分;3)如果有两个或两个关联的无条件帧包含的信号发生了变化,则按照事先规定好的优先级,优先级较高的关联的无条件帧获得发送权,优先级较低的要等到下一个偶发帧的帧头到来时才能发送应答。由于主机节点是唯一的发布节点,所以主节点事先就知道各个关联信号的优先级别,这样在传输时就不会产生冲突。
2.2.4、诊断帧
诊断帧包括主机请求帧和从机应答帧。主机请求帧,帧ID=0x3C,应答部分的发布节点为主节点;从机应答帧,帧ID=0x3D,应答部分的发布节点为从机节点。数据段规定为8个字节,采用标准型校验和。
2.3、进度表
进度表是帧的调度表,规定总线上帧的传输次序以及各帧在总线上的传输时间,进度表位于主机节点,根据应用层需要进行调度。进度表可以有多个,一般情况下,轮到某个进度表执行的时候,从该进度表规定的入口处开始顺序执行,到进度表的最后一个帧时,如果没有新的调度表启动,则返回到当前的进度表第一个帧循环执行;也有可能在执行某个进度表当中发生中断,执行另一个进度表后再返回,例如事件触发帧的解决过程。
进度表除规定了帧ID的传输次序外,还规定了帧时隙的大小。帧时隙是进度表规定的一个帧的帧头起始到下一个帧的帧头起始的时间,每个帧的帧时隙可以不同。
3、LIN协议栈架构图
3.1、传输层
传输层的任务单一,把来自 诊断服务 的消息(Message)翻译成协议层可以处理的PDU,或者反过来,把协议层收到的 PDU翻译成诊断服务需要的消息。消息到 PDU 的转换过程称为拆分 (Packing) , PDU到消息的转换过程称为重组 。 PDU 对应着帧结构的数据段,并通过诊断帧发送或接收。
3.2、核心层
信号通过信号携带帧通信可以不经过传输层,信号处理功能由核心API完成,信号处理功能与API的对应关系如下:
4、API
4.1、核心 API
l_sys_init(void);
调用模块:应用层
参数:无。
含义:初始化整个Lin节点,包括应用层,传输层和协议层,在调用其他API函数前,必须先调用此函数。
l_ifc_init(l_ifc_handle iii);
调用模块:应用层
参数:要初始化的LIN通道ID。
含义:初始化Lin通道。
l_sch_set(l_ifc_handle iii,l_schedule_handle schedule_iii,l_u8 entry)
调用模块:应用层
参数:LIN通道ID、要设置的调度表ID、调度表起始入口。
含义:用于选择当前有效的进度表,可以选择某个调度表入口。
l_sch_tick(l_ifc_handle iii)
调用模块:应用层。
参数:LIN通道ID。
含义:遵循调度表来管理和触发帧的传输。
lin_master_update_signal(l_ifc_handle iii)
调用模块:核心层。
参数:LIN通道ID。
含义:更新LIN主节点的信号数据。
lin_pid_resp_callback_handler(l_ifc_handle iii,const lin_dal_event_id_t event_id, l_u8 id)
调用模块:驱动抽象层。
参数:iii:LIN通道ID;event_id:LIN事件ID;id:帧ID。
含义:处理不同类型LIN事件的响应,根据不同的事件类型执行相应的处理逻辑,如处理PID响应、更新收发状态。
lin_process_id(l_ifc_handle iii,l_u8 id)
调用模块:核心层。
参数:iii:LIN通道ID;id:帧ID。
含义:处理帧ID,根据帧ID类型执行不同操作。
lin_switch_sch_table(l_ifc_handle iii)
调用模块:核心层。
参数:iii:LIN通道ID。
含义:根据当前调度表类型更新和切换活跃调度表ID。
4.2、传输层API
ld_init(l_ifc_handle iii);
调用模块:应用层
参数:用来指定初始化的传输层通道ID。
含义:初始化传输层。
ld_send_message(l_ifc_handle iii,l_u16 length,l_u8 NAD,const l_u8 * const data)
调用模块:应用层
参数:iii:LIN通道ID;length:要发送的数据长度;NAD:节点地址;data:指向数据的指针。
含义:把由数据和长度指定的信息打包进一个或多个诊断帧。
4.3、驱动抽象层API
lin_dal_init(l_ifc_handle iii)
调用模块:初始化时由l_ifc_init()调用。
参数:iii:LIN通道ID。
含义:初始化驱动抽象层。
lin_dal_timeout_service(l_ifc_handle iii)
调用模块:每500us由TMR_ISR()调用一次。
参数:iii:LIN通道ID。
含义:获取Lin Driver的状态,处理与LIN总线活动相关的超时事件和状态更新。
lin_dal_tx_header(l_ifc_handle iii,l_u8 id)
调用模块:核心层。
参数:iii:LIN通道ID;id: 表示要发送的LIN帧的ID。
含义:用于在LIN总线上发送帧头。
lin_dal_rx_response(l_ifc_handle iii,l_u8 response_length)
调用模块:核心层。
参数:iii:LIN通道ID;response_length:设置接收的响应数据长度。
含义:设置LIN总线响应数据的参数:响应类型、数据长度。
lin_calculate_pdu_info(l_ifc_handle iii, l_u8 id)
调用模块:核心层。
参数:iii:LIN通道ID;id:帧ID。
含义:根据帧ID计算PID,确定校验和类型。
lin_dal_set_response(l_ifc_handle iii,l_u8 response_length)
调用模块:核心层。
参数:iii:LIN通道ID;response_length:设置响应数据长度。
含义:设置LIN总线响应数据的参数:响应类型、数据长度、指向SDU的指针。
lin_dal_ignore_response(l_ifc_handle iii)
调用模块:核心层。
参数:iii:LIN通道ID。
含义:忽略响应。
4.4、驱动层API
Lin_43_LPUART_FLEXIO_Init(const Lin_43_LPUART_FLEXIO_ConfigType * Config);
调用模块:应用层。
参数:指向Lin驱动配置的指针。
含义:初始化Lin驱动。
Lin_43_LPUART_FLEXIO_SendFrame(uint8 Channel, const Lin_PduType * PduInfoPtr)
调用模块:驱动抽象层。
参数:Channel:LIN硬件通道;PduInfoPtr:指向LIN PDU信息的指针
含义:LIN通信模块通过LPUART和FLEXIO接口发送帧。