在linux内核中单独实现tty、i2c、spi、isa、usb等多种总线驱动时,每一种总线的实现都有各自的特点,如参数设置不同,实现的结构不同等。以tty、i2c为例,tty采用的是基于线路规程的三层结构,而i2c则是基于用户句柄和适配器的三层结构。当然,这些驱动都是功能齐全而强大的,但对于并不复杂的应用而言,这样的控制是比较繁琐的,而且,对于移植也是不利的。例如,某个应用系统原先使用一款i2c接口的时钟芯片,但后来系统升级换成了一款spi接口的时钟芯片,这时就不得不对程序做较大的改动了。本文给出了一种多种串行总线统一接口的实现方法,并以arm9为平台,以i2c、1-wire、spi为例验证了方法的可行性。
1 总线协议及其工作过程
多数的串行总线都基于主从结构,如果总线中包含了时钟信号线,那么,该时钟信号就由主机提供,而如果还包含了片选信号,通常也由主机来控制。也就是说,主机发起通信,从机处于被动状态,所以,对于总线时序的分析,只需讨论主控制器端的时序,而从设备的时序就是它的逆向过程。
1.1 spi协议及其工作过程
spi总线是摩托罗拉公司提出的一种串行总线协议,该总线由4根基本的信号线组成,分别是cs、si、so、sck。其中sck是串行总线时钟,由主设备提供;而si、so分别对应于数据输入和数据输出信号。在一主多从的系统中,片选信号决定当前有效的从设备。
spi总线的工作过程是:首先,主机发起通信,通过片选信号激活从设备;然后,主机在串行时钟sck信号的同步下,将地址、命令、数据信息从串行数据输出信号(相对主机而言)si送出;而从设备则在sck信号的同步下接收主机发送来的数据,并作出相应反应,最后将结果从数据输入信号(相对主机而言)so送出。
s3c2440中对spi总线的控制,就是集中于对rspconn、rspstan、rsppinn、rsppren、rsptdatn和rsprdatn的控制。其中rspconn用于dma设置、工作模式选择、时钟相位选择,rspstan用于控制器状态查询,rsppinn用于多主机下出错检测和片选释放,rsppren用于控制预分频状态寄存器,rsptdatn是数据发送寄存器,rsprdatn是数据接收寄存器。
1.2 i2c协议及其工作过程
i2c总线是由飞利浦公司提出的一种接口标准,该总线由sda、scl两根信号线组成。其中scl为时钟信号,由主机提供,最大传输速率为400kb/s;而sda为数据信号。连接到总线上的每一个设备都有一个唯一的地址,通过这个地址使得主机能够找到目标从机并与之进行通信。
以主机发送为例,i2c总线的工作过程是:首先,主机控制时钟信号scl为高电平时,数据信号sda产生一个下降沿,作为起始条件。然后,主机发出7位的从设备地址和1位r/w标志,并激活将要与之通信的从设备,而从设备则会产生一个应答信号。对于写数据,主机紧接着就将一个字符或一串数据写入到从设备;而对于读数据,则紧接着读取从设备输出的数据。
i2c总线中的s3c2440对i2c的控制主要集中于对riiccon、riicstat、riicadd和riicds的控制。其中riiccon用于时钟源选择、中断控制和i2c控制器使能,riicstat用于工作模式选择、控制器状态查询,riicadd是从设备地址(当s3c2440设置为从设备模式时使用),riicds是发送接收移位寄存器。
1.3 1-wire协议及其工作过程
1-wire总线是maxim全资子公司dallas提出的一种总线接口。1-wire总线与其他的串行总线有比较大的区别:普通的串行总线通常由两根或两根以上的信号线组成;而1-wire总线仅有一根信号线,同时用于时钟、数据、命令的传输,具有资源利用率高、结构简单、成本低廉、易于总线扩展等优点。
1-wire总线工作过程:1-wire总线包含复位、读、写三种基本时序。在复位状态下,主机将总线拉低480~960 μs后释放总线,由于上拉电阻的作用,此时的电平为高,等待15~60 μs之后,从设备将总线拉低表示复位成功。写操作时,若写入数据位为0,则主机将总线拉低60μs后释放;若写入数据位为1,则主机将总线拉低1~15 μs后释放。由于很少有控制器集成了1-wire总线控制器,所以,一般使用gpio模拟的方式,这时,对于时序的控制就要求得比较精确。
2 linux下的统一驱动
这些总线有一些共性,也就是驱动要实现的内容,主要包括单字节数据收发、数据流收发以及工作模式控制等。在这些共性的基础上,一般都需要向上层提供一个统一的接口,以使得对使用这些api的应用程序而言(下层总线无论是rs-232、spi、i2c,还是1-wire)都不需要做任何改变。同时,还要对下层也提供一个通用接口,使得不同的总线都能与上层统一接口协调通信。该驱动的结构框架如图1所示。
本文主要讨论的是总线驱动部分,而应用层和物理层在测试的时候,也可用两个简单的例子来验证设计结果。
2.1 注册一个新设备号
首先可为统一接口的总线定义一个新的设备号240,而且以后注册的总线子设备都以此为主设备号。假如现在注册了一个1-wire和一个i2c总线接口,那么,它们两者的主设备号都为240,而次设备号不同。如果1-wire的次设备号为0,而i2c的次设备号为1,那么就可将两条总线区分开来了。此时的程序如程序片段一所示。
程序片段一:
2.2 设备接口层
为了实现统一的接口,有必要定义一个统一的字符设备接口buses_ops,应用程序访问总线都通过这个接口,这样,所讨论的统一接口问题也就实现了。该接口的主要函数成员如程序片段二所示。
程序片段二:
应用程序打开设备的时候,利用子设备号可以找到总线对应的底层适配器,也就是说,子设备号兼具了适配器索引的功能,其具体实现如程序片段三所示。
程序片段三:
事实上,buses_dev是设备层和适配器层的桥梁,在open操作里被赋值给文件指针的私有数据域。那么,在读与写函数中,就可以反其道而行,通过文件指针的私有数据域就可获得buses_dev数据结构体。
2.3 适配器接口层
适配器负责对底层数据的操作,由于不同的总线之间存在共性,所以,一般来说,它们都包含了单字节读、单字节写、多字节读、多字节写以及一些特殊控制。综上所述,该数据结构如程序片段四所示。
程序片段四:
所谓适配器注册,就是将适配器添加到全局链表buses_list_head中,只有这样,才能在字符设备接口的open操作中通过子设备号索引找到适配器,具体如程序片段五所示。
程序片段五:
3 实验测试
这里分别以1-wire、spi、i2c总线为例来初始化三条总线适配器,同时实现适配器的单字节写、单字节读、特殊控制等三种基本操作。具体操作如下面的程序所示:
程序片段六:
完成设备驱动加载之后,就会在/dev目录下生成如图2所示的文件节点。通过打开节点,就可以打开总线的统一接口,从而实现对总线的读、写和控制操作。
同时,还会在/sys目录下生成关于注册的总线属性目录和文件,主要包含有设备号的属性文件、电源管理属性目录、到类目录的链接、特殊事件属性文件等,具体如图3所示。
这里分别对i2c接口的e2prom芯片at24c02、1-wire接口的eeprom芯片ds2433和spi接口的eeprom芯片25aa010进行测试。其测试结果如图4所示。
其测试过程是:通过打开/dev/bus-0、/dev/bus-1、/dev/bus-2节点,调用写操作写一段数据到eeprom,然后,再调用读操作读出刚才写入的数据,并验证两者是否一致,从而判断本文的接口函数的正确性。
4 结语
实践证明,使用设备接口层与适配器接口层的这种分层方式,能够让应用程序进一步忽略底层的接口操作,实现接口的统一。而且,该方法具有适应性强,易于系统升级,占用资源少等特点,能有效提高应用程序的开发效率。
主机电源的主要输出接口
十月八家车企创新高!比亚迪、理想表现亮眼,新能源渗透率突破40%!
人工智能温度控制器的功能特点
jvm metaspacesize大小设置
全球电子工程名校,中国仅有两所大学入围
基于Linux系统多种总线驱动统一接口的实现方法
常见的模拟信号处理技术有哪些?
GNU/Linux和Linux的区别在哪?
电容充电中的高压电源各项参数如何计算?
针对边缘设备的人工智能处理器Ergo
背靠大树的T3出行会成为下一个滴滴吗?
燧原科技获2023第十八届“中国芯”最高奖
助力未来通信:是德科技于2023世界5G大会展示5G端到端测试解决方案
京东推出了针对普通消费者的5G体验官活动
美国科技巨头合计10万员工开启在家办公模式 iPhone 11全球供应紧张
加密货币在乌克兰仍不受监管并且不合法
AI现在到底处于什么水平
厂商基于CXL上面做文章的案例
未来的运动鞋长这样?
基于LH7A404和LPC2214 CPU芯片实现绣花机控制系统的软硬件设计