电子说
YTM32微控制器的LINFlexD外设模块,实现了LIN协议控制器的功能,可以支持LIN总线协议的主机和从机功能。如图x所示。
图x LINFlexD在LIN总线系统中的位置
LINFlexD 可以实现使用较少 CPU 介入的情况下,高效管理大量的 LIN 通信帧:
LINFlexD_BIDR[CCS]
寄存器位中指定将要发送或者接收的帧使用扩展性校验和还是经典款校验和。LINFlexD 还支持 UART 模式,用于实现常规的 UART 通信。本文主要面向 LIN 通信引擎介绍,关于 UART 介绍,可见后续文章。
手册中对 LINFlexD 的工作模式划分为:初始化模式(Initialization)、常规工作模式(Normal)和休眠模式(Sleep)。在硬件复位后,LINFlexD 处于休眠模式以节约用电。若要配置 LINFlexD 开始工作,需要先通过软件配置,切换至初始化模式,在初始化模式下进行一些专属的配置后,再切换至常规工作模式,才能顺利启动 LINFlexD 外设。这个初始化模式,相当于为配置 LINFlexD 外设设计了一个同步锁,或者说关键区,使得在初始化阶段配置 LINFlexD 外设的各项功能时都不会立刻生效,以避免产生不确定的不安全状态,最后退出初始化模式,硬件同步一并打开所有的配置功能,稳当。
软件配置寄存器LINFlexD_LINCR1[INIT]=1
,切换至初始化模式。当然,还可以通过配置LINFlexD_LINCR1[INIT]=0
,退出初始化模式(至Normal模式?)。
进入初始化模式后,LINFlexD 引擎同 LIN 总线的传输将全部停掉(木头人不许动),并且推送总线上位高电平(隐形信号)。如果在某个总线传输的过程中进入初始化模式,则该传输将被打断并退出。所以说,在切入初始化状态之前,软件一定要先查一下 LINFlexD 的状态标志位,确保不会打断正在进行的传输,再进入初始化模式。
在初始化模式下,可以对 LINFlexD 外设进行初始化配置:
在初始化模式中,配置寄存器LINFlexD_LINCR1[INIT]=0
,切换至常规工作模式。
在常规工作模式下,LINFlexD 可以执行正常的收发通信。
配置软件寄存器LINFlexD_LINCR1[SLEEP]=1
,切换至休眠模式。当然,也可以通过配置LINFlexD_LINCR1[SLEEP]=0
,退出休眠模式(至Normal模式)。
进入休眠模式后,LINFlexD引擎就暂停工作,等待唤醒事件到来后,自动切回正常模式响应外部的通信请求。
如果软件在 LIN 总线上检测到一个 150us 的唤醒脉冲,可以请求 LINFlexD 从休眠模式唤醒。
通过配置寄存器LINFlexD_LINCR1[LPKM]=1
启用回环模式。回环工作模式可用于自测试通信协议,当启动回环模式后,芯片内部的Tx和Rx引脚相连,通过Tx发送的信号会直接被反馈会接收通道(忽略Rx引脚的输入)。如图x所示。
图x LINFlexD的回环模式
通过配置寄存器LINFlexD_LINCR1[MME]=1
,设定本设备为主机模式工作。
根据LIN协议的描述,LIN总线的上通信,都是由主机(具体是主机节点的主机任务)发送帧头开始的。当发送帧头时,由软件先写入LINFlexD_BIDR
寄存器中的字段,包括:ID(6位的帧ID,硬件自动补完校验位)、DFL(数据段长度)、DIR(帧通信的方向)及CCS(启用经典校验的控制位,后续硬件自动生成校验字节)。然后,设置寄存器LINFlexD_LINCR2[HTRQ]=1
,请求发送帧头。在启动发送帧头之后,在发送完成本帧之前,不要人为修改LINFlexD_BIDR
寄存器中的内容,LINFlexD 从总线上捕获到已经发送帧的ID会被自动复制到LINFlexD_BIDR
寄存器中。
当主机节点执行发布任务时(发送数据到总线),主机节点上运行的从任务(主机节点上的主任务仅发送帧头)会继续发送数据部分。因此,软件需要在发起发送帧头的请求之前,就将需要发送的数据准备好,将数据存放至消息缓冲区LINFlexD_DATA[]
中,同时,需要在LINFlexD_BIDR[DFL]
寄存器中指定将要发送字节数据的数量,硬件根据软件在LINFlex_BIDR[CCS]
控制位的配置(这个数据位可能是总线上捕获到的帧头中的信息),自动计算经典校验和或是增强校验和。
当应答的数据发送成功后,会置位硬件标志位LINFlexD_LINSR[DTF]
,但如果发送过程中出现错误,标志位LINFlexD_LINSR[DTF]
不会置位,LINFlexD_LINSR
寄存器的其它对应标志位会置位。
应答数据的方向(发送?或是接收)由寄存器LINFlexD_BIDR[DIR]
设定,但哪怕是发送过程,将数据发送上总线后,也会监听总线,将总线上的数据捕获下来并存入数据缓冲区中。
当主机节点从从机节点读取数据时,应先发出一个帧头(约定为读操作的ID)。从机节点捕获到帧头之后,会向总线上发送应答数据,此时主机节点(的从机任务)会从总线上捕获数据,并将数据内容存放至数据缓冲区中,寄存器LINFlexD_LINSR
寄存器中对应的标志位也会置位。
当应答的数据接收成功后,会置位硬件标志位LINFlexD_LINSR[DRF]
,但如果发送过程中出现错误,标志位LINFlexD_LINSR[DRF]
不会置位,LINFlexD_LINSR
寄存器的其它对应标志位会置位。
若用户需要抛弃发送帧头之后捕获到的应答数据,可预先设置寄存器LINFlexD_LINCR2[DDRQ]=1
。这对应的是LIN通信中,实现“不应答”的操作。
注意:哪怕是在主机模式中,也是分为主机任务和从机任务两部分,主机任务仅负责发送帧头,主机模式中的从机任务和下文描述的从机模式一致,都是通过 LINFlexD_BIDR
寄存器中捕获的帧头信息同自己的ID Filter进行匹配,从而启动对应的发送或接收数据的过程。
通过配置寄存器LINFlexD_LINCR1[MME]=0
,设定本设备为从机模式工作。
当从LIN总线上捕获到主机任务发送的帧头后,根据对ID的定义,若要求本节点提供应答数据,则硬件标志位LINFlexD_LINSR[HRF]
寄存器会置位,并产生一个接收中断。此时,软件需要尽快填写将要发送的数据到数据缓冲区中:
LINFlexD_BIDR
寄存器,判定接收到帧头的IDLINFlexD_DATA
寄存器中填入将要发送的数据LINFlexD_BIDR
寄存器,写入CCS
(校验和计算方式)、DIR
(数据方向),以及DFL
(数据长度)寄存器。设置寄存器LINFlexD_LINCR[DTRQ]
请求发送数据后,软件才能清零LINFlexD_LINSR[HRF]
标志位。为了确保LINFlexD_LINCR[DTRQ]
寄存器控制位能够起作用,需要先保持LINFlexD_LINSR[HRF]
置位,这是为了防止LINFlexD_LINCR[DTRQ]
不会被意外地被置位,而必须跟在发送一个帧头的操作之后进行(增加了一个操作约束条件)。在接收数据过程中,LINFlexD_LINSR[RXBUSY]
寄存器保持置位,此时LINFlexD_BIDR[DIR]
和LINFlexD_LINCR[DTRQ]
位不能被软件置位。
当需要使用ID过滤器时(Identifier Filter),可配置LINFlexD_IFER
寄存器启用过滤器功能。若命中其中一个过滤器时,硬件会产生一个发送中断,此时,硬件可从寄存器LINFlexD_IFMI
中保存的指针从RAM从自动搬运数据内容到LINFlexD_DATA
寄存器缓冲区中。
使用ID过滤器可以减少软件从LINFlexD_BIDR
寄存器中读ID、判定、配置数据长度和校验和类型的过程。
如果 LINFlexD 外设模块中需要使用的过滤器不够应用中使用,还可以通过设置过滤器掩码的方式,模糊匹配ID,以实现匹配更多ID的效果。
同主机模式相同,本机发送的数据,也会被捕获至本机的接收缓冲区中。
当收到主机任务发送的帧头后,若要求本节点接收应答数据,则硬件标志位LINFlexD_LINSR[HRF]
寄存器会置位,并产生一个接收中断。此时,软件需要尽快读BIDR寄存器,从中读帧ID进行匹配,并写入数据段长度(在收到第一个数据字节的停止位之前)。当收到校验和之后,LINFlexD_LINSR[RMB]
寄存器位会置位,并会产生一个接收中断,此时,软件可从LINFlexD_DATA
寄存器缓冲区中读数,读数完成后,需要软件清零LINFlex_LINSR[RMB]
寄存器位,以释放接收数据缓冲区。
当至少一个配置为接收的ID过滤器被激活命中,将在收到校验和之后,产生一个接收中断。在接收到ID的时候不会产生中断。
如果使用软件方式过滤ID,当HRF标志位置位时,若要抛弃数据(不应答),可以通过写LINFlexD_LINCR[DDRQ]
寄存器实现。若使用软件过滤机制,软件需要在接收到校验和之前设定校验的类型(配置LINFlexD_BIDR[CCS]
)。
LINFlexD 硬件集成了协议栈的业务逻辑,但由于总线上是多设备仲裁运行的环境,有时硬件总线的行为不是完全按照预期的情形运作,时不时就会报错。LINFlexD 对处理不了的情况设计了对应的监测机制,对于硬件无法处理的情况,会尽量及时地报错,上报给软件,交由应用逻辑裁决。
LINFlexD_LINESR
寄存器中包含了 LINFlexD 外设能够检测到的所有错误标志位,分别对应检测各自的错误机制。LINFlexD_LINESR
寄存器的位定义,如图x所示。
图x LINFlexD_LINESR寄存器的位定义
发生Stuck-at-zero超时错误。大体上是描述LIN总线被意外地长时间拉低(显式电平),后续无法传输数据的状态。详见下文超时错误机制。
输出比较事件是LINFlexD在管理超时机制中产生的一个事件。
LINFlexD_LINTCSR[CNT]
中的计数值同LINFlexD_LINOCR[OC2]
寄存器的设定值相等时,起OCF标志位。LINFlexD_LINTCSR[CNT]
中的计数值同LINFlexD_LINOCR[OC2]
或LINFlexD_LINOCR[OC1]
寄存器的设定值相等时,起OCF标志位。LINFlexD_LINTCSR[MODE] = 0
(LIN模式)并且LINFlexD_LINTCSR[IOT] = 1
, 若OCF标志位被置位,则LINFlexD进入Idle状态。LINFlexD_LINTCSR[MODE] = 0
(LIN模式), OCF由处于初始化模式下的硬件外设自动清零。LINFlexD_LINTCSR[MODE] = 1
(输出比较模式), OCF单纯表示输出比较的状态,同LIN的通信状态无关。位错误可能发生在发送过程中(发送帧头和发送应答数据),当从总线上读回的值同发送的值不一致时,会出现位错误。检测每个数据位的意义在于,确保收发器的延迟时间小于一个可以接受的容限(位时间的长度再减去6个功能时钟周期),例如:
这个49.925us将用于选型合适的LIN收发器。
在发送的间隔段中不检测位错误。
如果出现位错误的情况,若此时已经配置了LINFlexD_LINCR2[IOBE]=1
(Idle on Identifier Parity Error),LINFlexD的接收状态机会立刻退出接收帧头的状态变成Idle。若是LINFlexD_LINCR2[IOBE]=0
,发送过程将继续,不管位错误。如果配置了LINFlexD_LINIER[BEIE]=1
,则此时会产生中断。一种极端的情况,如果不配置退出、不配置中断,哪怕出现了位错误,仍可坚持完成发送过程。
当接收机收到数据帧及校验和字节后,会自动计算校验和,当计算结果同数据内容不一致时,会抛弃收到的数据包,同时会起一个CEF标志位。如果预先配置寄存器LINFlexD_LINIER[CEIE]=1
,则对应还可以产生一个中断。
如果是LINFlexD发出的数据包,因LINFlexD在发送过程中会自动计算校验和,所以若再用 LINFlexD 收到数据包仍会产生校验和错误,那就要查看传输线路是否受到较大的干扰。如果发送方的校验和是人工计算的,那也要再确认软件计算校验和的方法是否正确。
从机任务在接收帧头过程中发现的错误,都算是帧头错误。这些错误包括
(1)帧间隔段分隔符错误(Break Delimiter Error, SDEF)
这个分隔符的长度应至少为1位的时间,否则时间太短,接收方会丢弃当前帧头的同步段,进而丢弃整个帧。如果LINFlexD_LINIER[HEIE]=1
,则此时会触发一个中断。
(2)同步段错误(Sync Field Error,SFEF)
同步段错误的情况在是否开启自动同步的配置(LINCR1[LASE]=1)时是不同的。
0x55
,如果不是这个值,则会报错,后续的整个LIN帧都会被抛弃。(3)ID校验错误(Identifier Parity Error,IDPEF)
PID段中包含6个比特的ID和2个比特的校验码,IDPEF检测的就是这6个比特的ID和2个比特校验码的一致性。在从机任务中,当LINFlexD收到帧头的PID段后,将6比特的ID值送至BIDR寄存器后,会由硬件自动计算核验校验码。如果出现不一致的情况,若此时已经配置了LINFlexD_LINCR2[IOPE]=1
(Idle on Identifier Parity Error),LINFlexD的接收状态机会立刻退出接收帧头的状态变成Idle。
帧错误标识的是在当前接收字节(LIN帧的同步段、ID段、数据段、校验和段)的停止位检测到一个显性信号(本应为隐形信号,拉高电平),此时LINFlexD会抛弃当前接收到的帧,然后返回到Idle状态。如果预先配置了LINFlexD_LINIER[FEIE]=1
,则会产生一个中断。
当出现帧错误时,导致错误的字节数据仍会被送入数据缓冲区(毕竟已经送进去了),但LINFlexD_LINSR[DRF]
标志位(数据接收完成标志位)不会置位。
当收到一个新的数据时,若标志位LINFlexD_LINSR[RMB]=1
尚为清零(数据缓冲区满,软件可读),则判定为缓冲区溢出,报错。此时还需通过寄存器LINFlexD_LINCR1[RBLM]
的配置值,确定如何处理新数据:
LINFlexD_LINCR1[RBLM]=0
,则之前未被都走的数据包将会被新的数据包覆盖,旧的数据包将被丢失。LINFlexD_LINCR1[RBLM]=1
,则之前未被都走的数据包将会被保持,新的数据包将被丢失。在从机模式下,如果再未读完数的情况下来了新的LIN帧,不仅仅是数据,连带帧ID也会被一同抛弃。当接收器检测到噪声时,起本标志位。关于噪声,是在检测开始信号和间隔符信号时,进行连续3次隔点采样,未能达到判决条件时,即认定为总线上有噪声。
当主机发送了帧头后,如果在指定的时间段内未收到应答数据,则会产生超时错误。LINFlexD外设内部设计了一个超时定时器(Timerout Counter),专门用于检测同超时相关的检测和响应事件。
图x LINFlexD的超时报错机制
LINFlexD_LINOCR[OC2]
载入到LINFlex_LINTOCR[CNT]
寄存器,并启动内部的定时器开始倒计数,若在计数器计数清零之前未完成接收数据,则产生超时事件。这相当于是个看门狗。LINFlexD_LINOCR[OC2]
寄存器的值到定时器,开始计数。若未使用ID过滤器,则在收到数据帧并由软件进行识别后,人工写入DFL寄存器时,硬件载入LINFlexD_LINOCR[OC2]
寄存器的值到定时器,启动定时器。LINFlexD_LINOCR[OC1]
到LINFlexD_TOCR[HTO]
,启动定时器。注意,这里的定时器也可以用来检测其他的超时事件,但需要配置LINFlexD_LINTCSR[MODE]=0
,然后软件向寄存器LINFlexD_LINTOCR
中写入输出比较值。
如果显性信号在总线上保持的时间超过了100个比特的时间,就会起标志位LINFlexD_LINESR[SZF]
。人工清零标志位后,如果显性信号未消除并继续,那么接下来只要连续保持87个比特的时间,就会再次激活标志位LINFlexD_LINESR[SZF]
。
在LIN协议中,消息的ID号并不是对应节点的地址,而是标识消息中携带的内容(命令,或者消息类型)。发送器将消息广播到LIN总线,所有的接收机都能收到,接收机通过识别消息的ID,接收机们决定是继续收数据,或是发送数据应答(根据消息ID的含义做出反应),如果接收机不识别消息(不做处理),就会抛弃它。
为了实现这样的机制,LINFlexD外设设计了可配置的ID过滤器,以简化原本需要软件去匹配消息ID的工作,节约了CPU资源。LINFlexD中集成了16个过滤器,只有在初始化模式下才能配置他们,可以通过将LINFlexD_IFER[FACT]
寄存器中的对应位置位,激活相应的过滤器,然后在每个过滤器专属的LINFlexD_IFCRn寄存器中配置各自过滤器的参数。
每个ID过滤器有两种可选的工作模式(通过寄存器IFMR[IFM]):
LINFlexD_IFMR[IFM]=0
,则接收到LIN帧头的消息ID必须按位同IFCR_n寄存器中的完全相同才能满足匹配条件。LINFlexD_IFMR[IFM]=1
,则IFCR_2n寄存器和IFCR_2n+1寄存器形成一个掩码模式,IFCR_2n中的ID是一个模板ID,IFCR_2n+1中的ID是一个掩码,当收到LIN帧头的消息ID后,先同掩码做个与运算,过滤掉不关心的位,然后再同模板ID进行匹配。在ID掩码模式下,LINFlexD_IFER[FACT]
寄存器中是否激活IFCR_2n+1,已经不影响了,此时IFCR_2n+1总是被激活的。当需要本接收机相应的消息ID多于硬件ID过滤器支持的数量时,就需要用ID掩码模式扩展能识别ID的范围了。无论在何种过滤器模式下,一旦编号为m的过滤器被匹配到,则值m+1将被硬件写入到IFMI寄存器中,而IFMI=0就表示没有当前还发生任何匹配事件。此时,软件可以通过读IFMI寄存器的值,识别是哪个过滤器被匹配到,进而从中查看识别到的消息ID。当完成一次匹配事件,LINFlexD硬件都会将匹配到的DFL、CCS和DIR寄存器的值,从IFCR寄存器复制到BIDR寄存器中(存放当前的帧头信息),此时至通信帧传输完成之前,BIDR寄存器都是只读,不能被软件写入。此时LINFlexD_BIDR[DIR]
指示了应答数据的传输方向(相对主机):
LINFlexD_BIDR[DIR]=1
,表示数据方向为发送,可以产生一个发送中断(LINFlexD_LINIER[HRIE]=1
),此时软件可以从IFMI寄存器中读ID过滤器的索引编号,然后向DATA缓冲区中填充将要发送的数据,然后再配置LINFlexD_LINCR2[DTRG]=1
,启动传输。LINFlexD_BIDR[DIR]=0
,表示数据方向为接收,在接收数据完毕后,包括校验和字节,并验证校验和无误后,可以产生一个接收中断(LINFlexD_LINIER[DRIE]=1
),此时,软件可以从DATA缓冲区中读出接收到的数据。如果没有匹配到任何过滤器(通过IFMI=0判定):
LINFlexD_LINCR1[BF]=1
,则仍可产生一个接收中断。此时应由软件配置BIDR寄存器并启动传输(填充DATA数据缓冲区再配置LINFlexD_LINCR2[DTRQ]
),或放弃接收(配置LINFlexD_LINCR2[DDRQ]
)。LINFlexD_LINCR1[BF]=0
,则接收机直接抛弃已经收到的帧头(包含消息ID),转入Idle状态,等待接收下一个帧间隔段(开始信号)。注意,如果接收的消息ID同时匹配到了两个过滤器,一个处于列表模式,另一个处于掩码模式,则优先匹配到处于列表模式的过滤器。如果同时匹配到两个位于掩码模式的过滤器,则优先匹配到编号较小的过滤器。如果同时匹配到两个处于列表模式的过滤器,好吧,能将同一个ID写到两个列表模式下的过滤器,一定是写错了,但此时也会优先匹配到编号较小的过滤器。
LINFlexD内部检测串行信号模式的方法非常有趣。接收器内部设计了一个10比特的移位采样寄存器,捕获收到的串行信号,LSB送入。移位寄存器中的比特位在平时是全0,当其中的值变为1110
,然后在之后进行隔点采样(每两个连续的点取一个样本),连续3个样本中,有2个为0,即可判定是一个开始信号(帧间隔符)。类似的,为了检测帧间隔符分隔符,在继续检测到0001
的模式,然后再之后进行隔点采样,连续3个样本中,有2个为1,即可判定是一个分隔符。如果只能检测到两个有效的样本,噪声标志位(Noise Flag)将会被置位。
图x 使用移位器检测开始信号和分隔符模式
关于检测模式的更细节的机制,可继续参见手册详述,因同用户使用关联不大,此处不再赘述。
配置LIN总线的(发送和接收)波特率,主要设计两个寄存器:LINFlexD_LINIBRR
和LINFlexD_LINFBRR
,分别对应分频因子的整数部分和小数部分。
LINFlexD_UARTCR[ROSE]=1
(only for UART mode),baudrate = f_clksrc / ( OSR x LDIV )LINFlexD_UARTCR[ROSE]=0
(for LIN and UART mode),baudrate = f_clksrc / (16 x LDIV)其中,f_clksrc
是 LINFlexD 的功能时钟,在 SCU 外设模块中分配时钟源。LDIV
是一个无符号的定点数,整数部分存放在20-bit的LINFlexD_LINIBRR
寄存器中,小数部分存放在4-bit的LINFlexD_LINFBRR
寄存器中。
当停用过采样功能,就不再使用LINFlexD_LINFBRR
寄存器(可清零),此时LDIV仅使用整数部分,配置至LINFlexD_LINIBRR
寄存器。
例如:
若要通过测量LIN通信帧的同步段,可以先随便写两个波特率发生寄存器LINFlexD_LINIBRR
和LINFlexD_LINFBRR
,然后设定寄存器LINFlexD_LINCR1[LASE]=1
启用自动同步机制。
当启用自动同步波特率机制后,在每个通信帧的同步间隔段间隔符之后,将会使用波特率时钟源,在LINFlexD_RX
引脚上采样连续5个下降沿的时间???
处于休眠中的LIN总线可以由其中任何节点发起唤醒请求。节点将LIN总线信号强制拉低(保持显性信号)保持 250us 至 5ms,每个从机节点将会检测到唤醒请求(一个长于 150us 的低电平脉冲),并在释放显性信号的上升沿开始 100ms 以内准备好监听来自总线的命令。主机在检测到总线上的唤醒请求后也会醒过来,待从机准备好之后,主机将发送帧头以探查唤醒的源头和原因。如果在收到唤醒请求后的 150ms 内,主机没来得及发送帧头,则原本唤醒总线的从机节点可以试着再次发起一个新的唤醒请求。
使用LINFlexD产生一个唤醒请求,可以通过向 DATA0 寄存器写一个唤醒字符(0x0)并设定寄存器位LINFlexD_LINCR2[WURQ]
。当写WURQ寄存器位时,DATA0中的数就已经被送上总线了。
使用LINFlexD检测LIN总线上的唤醒请求,可以有两种方式:
LINFlexD_LINCR1[SLEEP]
寄存器位由硬件清零(退出休眠模式),LINFlexD_LINCR1[WUF]
标志位置位,如果此时LINFlexD_LINIER[WUIE]
=1,则可以产生一个中断,此时 LINFlexD 处于常规工作模式并准备接收通信帧。LINFlexD_LINCR1[WUF]
标志位置位,如果此时LINFlexD_LINIER[WUIE]=1
,则可以产生一个中断,此时需要由软件决定是否要清零LINFlexD_LINCR1[SLEEP]
寄存器位以返回常规工作模式。图x LIN的唤醒时序
YTMicro SDK中包含了LinFlexD的驱动程序,并提供了lin_master
、lin_salve
、lin_slave_filter
等样例工程。
全部0条评论
快来发表一下你的评论吧 !