面向数据流的CAN 驱动层设计

面向数据流的CAN 驱动层设计
    摘 要:本文目的在于设计面向数据流的CAN 驱动层,应用层或可直接使用该驱动层实现数据流方式访问CAN 总线,抑或另外添加设计一层传输层以便完成应用层间透明的端到端传输。本设计通过对CAN 驱动层合理的结构设计,引入了中断上下半部分开处理的机制,具体实现时,辅以两个运行实体(ISR、task)和两层buffer(ID 流缓冲和CAN 包收发队列),完全可以实现高效运行的面向数据流的CAN 驱动层。
    关键词: CAN;驱动层;数据流
    1 引言
    节点驱动层负责控制使用的CAN 控制器,并向上提供一组基于ID 流的标准操作接口。驱动层本身是平台相关层,但向上提供平台无关的一组接口。驱动层主要为上层提供了基于ID 数据流的读写能力(即基于数据流的CAN 总线通信能力)。
    在本设计中,以主板采用的LPC2378(LPC2000 系列)为目标MCU,设计CAN 节点驱动层。
    驱动层被设计成由两个运行实体:ISR(CAN 控制器中断服务例程)和驱动层task,和两
层buffer:ID 流缓冲和CAN 包收发队列构成。通过是把CAN 中断处理、流拆分成包、包聚合成流等待一系列动过分成中断上半部和中断下半部,同时也可加快对中断的响应过程。
    2 系统设计
    2.1 驱动层结构
    驱动层需要向上层提供的一组标准操作包括:initialize、open、close、read、write、ioctl。
    接口完成驱动层的初始化,初始化分别针对两个方面,1)一方面需要配置控制器,包括为CANBUS 收发线合适配置GPIO 相应管脚、给CAN 控制器配置合适的输入时钟、设置CAN 总线工作速率、设置CAN 中断、设置错误计数门限,另外针对LPC2378,还需设置是否使用查表(本设计中未使用,设置的是旁路模式)等,最后还要开启控制器;2)另一方面需要初始化驱动层模块所有的运行时OS 资源,包括互斥量、消息队列、任务、动态内存等。
    接口并不是提供开启某个CAN 控制器的通道,CAN 控制器的开启是在驱动层的中完成。当上层调用此接口时,是在申请开启对某个指定ID 流的发送能力。Open 接口中需要相应的初始化该ID 流所使用的两个高速流缓冲,分别供<read、和<write、task>使用。同时还需申请互斥量等OS 资源。
    接口是Open 接口的反向操作。当上层不再需要收、发特定ID 流的时候,通过此接口,释放掉驱动层中为此ID 流收发所使用的包括高速缓冲、互斥量在内的资源。
    上层通过Write 接口,把特定ID 数据流耦合如其所属的发送ID 流高速缓冲中。同时如果遇到ID 流缓冲需要动态扩充时,则从缓冲池中申请个新的缓冲块加入该ID 得发送流缓冲结构中。对应的task 会在适当时候把不再使用的缓冲块重新释放回缓冲池中(具体见高速ID流缓冲)。Write 接口均为非阻塞式接口,即write 操作当把待发送的数据流存入流缓冲中后便立即返回,不会阻塞到这些数据在CAN 总线上真正传递完毕。
    上层通过Read 接口,从对应ID 流缓冲结构中读取到指定长度的数据。如果流缓冲中数据长度不够待读长度,则调用此接口的上层线程即可以获取已有数据并立即返回;也可以把在对应流缓冲结构中记录下需要读取的范围,然后把自己挂起在任务挂起队列中,待模块从CAN 包接受队列中获取到足够长度数据后,会从任务挂起队列中按先进先出原则唤醒等待该ID 数据的任务。
    接口提供一些配置性操作。此接口可以获取CAN 控制器出错状态和出错原因,开启、关闭CAN 控制器以便控制本节点接入或脱离CAN总线CAN 驱动层主要由ISR(中断处理)、驱动层task 和两层buffer(收发包缓冲和收发流缓冲)构成,整个模块由中断下半部、中断上半部、接口层三个子层次构成。
    2.2 配置CAN 中断
    为了能使CAN 中断处理ISR 能够被正常触发,需要合理的设置VIC(中断向量控制器)。LPC2378中,CAN 控制器的中断号是23,设置CAN 中断ISR 为IRQ 方式(区别快速中断模式,在主板中FIQ 被timer0 独占,用来提供OS ticks 计数能力)。为了能让程序在ARM用户态下运行时,能够按照上图流程成功的配置相关VIC寄存器,必须在boot 阶段,ARM 处于特权态时,设置VICProtection 寄存器
bit1(VIC_access)清零。
    对VIC 和CAN 控制器相关寄存器配置完毕后,当CAN 控制器成功从上接收到一个CAN 包或是CAN 控制器成功发送CAN 包到CANBus
后,CAN 控制器会触发VIC 的CAN 中断,此时程序会跳转到VICVectAddr23 寄存器中保存的CAN ISR 入口处执行,此时便开始了CAN 中断的处理流程。
    当 CAN 控制器收发到CAN 包并触发ISR 后,CANxSR 寄存器RBS、TS1、TS2、位指明了CAN 控制器的接收、发送buffer 的状态。ISR可根据CANxSR 中的这四个标志位,分别判断CAN 控制器中接收buffer 是否接收到CAN 包、
3 个发送buffer 中待发送CAN 包是否成功发送到CANBus,然后执行相应处理流程。
    2.3 中断处理流程
    ISR(interupt service routine)介于CAN 控制器和CAN 包收发队列之间,每当CAN 控制器接收到一个CAN 包或是成功发送一个CAN包后,VIC 模块都会触发此ISR,并在状态寄存器(CANxSR)置相应标识位。哑光玻璃
    当 ISR 被触发执行后,首先检查CANxSR 的RBS 位(Receive Buffer Status bit),如果此位被置位,则从CAN 控制器接收
buffer(包括CAN1RFS、CAN1RID、CAN1RDA、)中读出包括包头和数据净荷在内的完整CAN 包,再把这个接收到的CAN 包写入接收包队列中。然后ISR 会检查CANxSR 的三个发送状态标志位(TSx),如果有任何发送状态标志位被置位,则表示对应的控制器内的发送buffer 中
的CAN 包已经成功通过总线发送出去,此时ISR 会从多优先级发送包队列中,按队列权值轮流调度队列中待发送的包到CAN 控制器的发送buffer 中,然后置对应请求发送标志位。
    ISR通过上述过程,完成了在CAN 控制器和CAN 包收发队列中传递CAN 包。
    对于 CAN 包收、发队列,各有一个互斥量。当ISR、task 需要读、写队列前均需要先申请相应队列的互斥量。对于task 可以阻塞式的申请互斥量,因为task 可以被挂起,直到申请到队列互斥量后才对队列操作。但ISR 无法被挂起,所以ISR 在操作队列前申请互斥量时,必须是立即返回的。当ISR 申请收、发队列互斥量失败后(此时必然是task 在操作队列),ISR 会去置相应队列的SIrqStartFlag 标志,然后略过从CAN 寄存器读、写CAN 包的操作。当task 操作队列完毕并释放队列互斥量后,需要检查该队列的SIrqStartFlag 的标志,如果该标志被置位,则由task 触发CAN soft irq,之后CAN 中断ISR 再次被软触发。当被软中断触发后,接着上次因为未申请到队列互斥量而未完成的操作:从CAN 寄存器接收中及时读出CAN 包写入接收队列、或是从接收队列中获取一个CAN 包写入CAN 寄存器的某个发送
buffer 并申请发送。
    2.4 CAN包接收队列
    根据LPC2378CAN 控制器接收buffer ( RFSRIDRDARDB ) 、发送(TFSTIDTDATDB)结构,相应的定义CAN 包数据结构CAN_MSG 为:   
数据长度(byte),取值为0 到8; Bit 30: 远程请求包标志,置1表示发送的包是请求远端发送要求MSGID 的包,置0 表示是正常的数据包发送; Bit 31:长ID(29bit)标志,置1 表示使用29bitID,置0 表示使用包接收队列包含CAN_MSG 数组以及控制信息,在驱动层中包含一个CAN 包接收队列。CAN 包接收队列结构为:
    其中 CANMsgBuf 指向动态申请的CAN_MSG_T 类型的包数组;hMutex 为队列互斥量;为CANMsgBuf 缓冲的总长度;ReadIndex 为队列读下标,标定task 下一次从接收队列中读包的位置;WriteIndex 为队列写下标,标定ISR 下一次向接收队列写包的位置;是个指示标志位,当ISR 操作队列前申请队列互斥量失败后会置该标志并略过对CAN 控制器的响应,当task 对队列读取一个包后均要检查该标志是否置位,如果该标志被置位,那么task 会立即结束对接收队列的操作转而触发CAN 软中断。CAN 软中断被置位后,会触发ISR 被执行,此时ISR 会再次去申请接收队列互斥量,然后把CAN 控制器中尚未被读出的CAN 包保存到接收队列中。
    是CAN 包接收队列中用来在ISR 和task 之间缓冲接收到的CAN 包的队列,整个队列按照环形缓冲操作,它有三个直接属性即队列总长(标定队列缓冲CAN 包的能力)、读下标ReadIndex、写下标WriteIndex。
    当 CAN 包接收队列满,且ISR 检查到CAN 控制器又新接收到CAN 包时,ISR 会直接释放CAN 控制器的接收buffer,这种情况下就产生了数据溢出,所以task 必须保证及时的从接收队列中接收CAN 包,并把CAN 包内的数据净荷放入对应ID 的ID 流缓冲中。
    2.5 CAN包发送队列
    为了保障CAN 节点发送CAN 包的实时性,驱动层包含了多个CAN 包发送队列,每个队列具有不同的优先级,以便指示ISR 按照各个队列的优先级,合理调度具有不同实时性要求的CAN 包的发送。
    包多优先级发送队列,避免了单队列会造成不同实时性要求的CAN 包的串行化发送,可以满足不同实时性需求的CAN 包发送。
    每个 CAN 优先级发送队列是在CAN 包接收队列的基础上的改进,增加了两个字段:
    和Counter。一个CAN 优先级发送队列结构为:
    其中 CANMsgBuf 指向动态申请的CAN_MSG_T 类型的包数组;hMutex 为队列互斥量;为CANMsgBuf 缓冲的总长度;ReadIndex 为队列读下标,标定
ISR 下一次从发送队列中读包的位置;WriteIndex 为队列写下标,标定task 下一次向发送队列中写包的位置;是个指示标志位,当ISR 操作队列前申请队列互斥量失败后会置该标志并略过对CAN 控制器的响应,当task 对发送队列每写一个包后均要检查该标志是否置位,如果该标志被置位,那么task 会立即结束对该发送队列的操作同时触发CAN 软中断。
    和Counter 字指示ISR 调度不同优先级包发送队列,ISR 结合这两个字段并按照一定的调度策略,实现对不同优先级队列不同权重的发送,同时尽量让每个队列均有机会发送。
    当 CAN 包发送队列满时,task 将停止从各个ID 流缓冲中抽取数据封装CAN 包并放入包发送队列的过程,此时task 等待CAN 控制器和ISR 对CAN 包发送队列的发送过程。
    2.6包发送队列调度策略
    负责从多个发送队列中选取CAN 包并写入CAN 控制器的发送缓冲中,然后请求控制器发送。ISR 是多优先级CAN 包发送队列调度发送的主体。
    对于不同优先级CAN 包发送队列调度的目的在于使得高优先级队列较低优先级队列有更多的机
会发送更多的包,但同时需要保证低优先级队列能有机会发送CAN 包,不会因为高优先级队列始终被TASK 填充而造成低优先级队列中的包无法发送。
    存在 3 个包发送队列Tx queue 1(Priority 恒为8)、Tx queue 2(Priority 恒为4)、(Priority 恒为2)。每个队列的Priority字段代表该队列的优先级权值,且这个权值在程序运行的整个过程中一直保持不变。每个发送队列还有一个Counter 字段,该字段的初始值为所属队列的Priority 值。
    当 ISR 需要从CAN 包发送队列中一个包填充CAN 控制器的发送buffer 并请求发送时:应该首先从高优先级队列中寻,如果当前发送队列的Counter 值不为零且该队列中有待发送的CAN 包,则从该队列中取一个CAN 包并写CAN 控制器,然后把该队列的值减一;如果当前发送队列的值为零或是队列中不存在待发送CAN 包时,ISR 转而到低一级的发送队列中继续上述过程,直到到合适发送的CAN 包或是全部队列中都无CAN 包为止。
    当 ISR 检查到所有队列的Counter 值均为零后,按照上述过程,ISR 无法从任何一个发送队列中读取CAN 包。此时由ISR 负责初始化所有队列的Counter 值,即把所有发送队列的Counter 值恢复成队列Priority 值,然后继续上述的CAN 包选取过程。
    上述 ISR 从多优先级CAN 包发送队列中选取CAN 包发送的过程。
蚕蛹虫草    每当CAN 中断ISR 被触发,需要从发送队列中选取CAN 包发送时,均按照上图流程,依次从高优先级队列到低优先级队列中寻合适
的包发送。
    当 ISR 从某个队列中取出一个CAN 包发送后,相应队列的Counter 值减一。当某个包发送队列的Counter 值递减到零后,该队列暂时退出ISR 的包调度过程。由于具有不同优先级Priority 包发送队列的初始Counter 值不一样,这样保证了不同优先级队列具有不同的发送包能力。同时当某个队列的Counter 值递减到零后退出调度的机制,保证了低优先级队列中的CAN 包同样有机会被选取发送,避免了高优先级队列在重载荷下抑制低优先级队列的发送的情况。
    当某个发送队列Counter 值即使未递减到零,当ISR 在该发送队列没有待发送的包时,也会对该队列的Counter 值减一。这可以有效避免某个队列因为其Counter 值为递减到零,却因为该队列长时间无待发送包,而阻塞其它队列的发送。
    这种多优先级CAN 包发送队列和上述的ISR 调度发送策略综合作用,可以保障上层不同实时性需求数据的有效、有序的发送。
    2.7 流缓冲结构
扎把机    流缓冲是介于接口层(read、write 接口)和task 之间,基于数据流的缓冲结构。
二维码打印设备    流缓冲结构由一个hash 索引表,索引出缓冲各个CAN message ID 对应数据流所使用的。
    该ID 流缓冲中包含了6 个ID 的steam buffer。Hash 索引表结构为:
    取ID 的低4 位作为hash 索引值。对于具有相同hash 索引值的采用链表方式链接。
    结构为:
    仅针对write 接口,指明请求发送数据流的实时性需求。
    还需读取、写入长度起始挂起时间允许挂起的时间信号量,用于挂起上层调用read、接口的线程上层当有数据需要接收/发送时,需要首先通过open 接口指明该发送数据对应的报文ID、CAN 报文ID 的类型(即是使用CAN2.0A 定义的11 位ID 还是CAN2.0B 
除垢器定义的位ID,对于LPC2378 的片上CAN 控制器同时支持这两种模式)、发送数据的实时性需求( 仅针对发送过程) , 然后由open 接口负责初始化该ID得流缓冲结构(CAN_ID_STREAM_BUFFER_T),并链入hash 表。
    当上层有实际数据需要接收/发送时,会分别通过read/write 接口,从该ID 对应的流缓冲结构中读取或写入数据。
    对于接收流缓冲结构,当task 从CAN 包接收缓冲中到该ID 对应的CAN 包后,负责把CAN 包中的数据净荷抽取出来,并保存到该ID得流缓冲中。对于接收流缓冲结构,当task 发现CAN 包发送优先级队列有空余空间时,会从ID 流缓冲中抽取数据净荷, 综合
CAN_ID_STREAM_BUFFER_T:: MsgID 、信息封装成CAN 包,并插入CAN 包发送队列中。
    从ID 流缓冲中抽取数据流封装CAN 包的过程为:把CAN_MSG_T:: Frame 低位(对应CANxTFI 的PRIO 字段)固定为0x80;根据
LongIdFlag 置第31 位(对应CANxTFI 的FF 标志);根据MsgID 置CAN_MSG_T:: MsgID;根据从读出的数据放入
投票机
CAN_MSG_T::DataA、CAN_MSG_T::DataB;然后根据CAN 包数据净荷长度置CAN_MSG_T:: Frame 第16 ̄19 位(对应CANxTFI 的DLC 字段)。然后把封装好的一个CAN 包放入CAN 包发送队列。
    的 CANxTFI(Transmit Frame Information Register)中的PRIO 字段标志着包的发送优先级,当CAN 控制器3 个发送buffer 有多余一个CAN 包等待发送时,CAN 控制器会根据PRIO 字段优先选择低值的CAN 包发送。TxPriority 字段是指发送实时需求,根据该字段的值,把从ID 流缓冲中封装好的CAN 包,放入相应优先级的CAN 包发送队列中。TxPriority 定义为:
    2.8 驱动层task 处理流程
    驱动层task 介于CAN 包收发缓冲和ID 流缓冲之间,主要负责中断上半部处理。对于发送过程,task 完成数据流到CAN 包的转换;对于接收过程,task 收取接收到的CAN 包内的数据净荷,并填充到对应ID 的流缓冲中。
    task 循环往复的在CAN 包接收队列和ID 接收流缓冲、CAN 包发送队列和ID 发送流缓冲间,进行封包、拆包、以及两层缓冲间传递数据。Task 乃至驱动层并不负责CAN 包的传输/接收乱序问题、CAN 包数据净荷获取的数据流正确性进行任何的保证。
    因此需要上层在必要的时候,需要对通过驱动层read 读取出来的数据流进行内容校验。
    3 结论
    通过设计基于流的CAN 驱动层,其上便可以直接被应用层使用,抑或添加设计一层传输层,完成应用层间透明的端到端传输。本设计通过对驱动的合理的结构设计,引入了中断上下半部分开处理的机制,具体实现时,辅以两个运行实体(ISR、task)和两层buffer(流缓冲和CAN 包收发队列),完全可以实现高效运行的面向数据流的CAN 驱动层。
    工程师职称论文资料,

本文发布于:2024-09-20 22:37:20,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/127689.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:队列   发送   缓冲   接收   数据   中断   控制器   驱动
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议