版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
ADS8345驱动程序设计文档隶属项目高速多路数据采集板文件状态:/”/草稿文件//正式文件//修订版正式编写者:版本:V0.1修改审定:最后修改日期:2013-4-12版本历史版本作者参与者起始日期备注V0.12013-4-122013--草稿目录TOC\o"1-5"\h\z1弓1言 4\o"CurrentDocument"1.1编写日的 4\o"CurrentDocument"1.2实验环境 4\o"CurrentDocument"1.4术语和缩写词 4\o"CurrentDocument"2关于硬件的说明 4\o"CurrentDocument"ADS8345的简介 4\o"CurrentDocument"2驱动程序的组织结构 7\o"CurrentDocument"Linux的设备模型 7\o"CurrentDocument"Tiny210SPI移植 9\o"CurrentDocument"mini2440SPI驱动移植 11\o"CurrentDocument"SPI移植驱动验证 19\o"CurrentDocument"3ADS8345驱动实现 20\o"CurrentDocument"Linux设备模型 203.2驱动接口实现 26\o"CurrentDocument"4总结说明 331引言1.1编写目的本文档编写目的是:方便实验室内部交流、相同工作只做一遍、在不同届学生之间项目的快速交接之目的。1.2实验环境1.2.1内核版本:(mini2440) (Tiny210)1.2.2硬件平台:mini2440开发板,Tiny210开发板1.2.3参考资料:华清远见SPI讲解资料,2010级师兄政越伟论文1.4术语和缩写词2关于硬件的说明ADS8345的简介ADS8345是一款16位逐次逼近型8通道串行输出的内部采样型模数转换器。在100khz的转化速率,5v单电源供电的时候最大功耗为8mW。参考电压可在500mv到1/2电源电源范围内变化。输入电压范围根据参考电压而相适应。本设备包括休眠模式,在这个模式下最低功耗可达15uw。确保正常工作的最低电压是2.7v。低功耗,高速率,自带多路转换器。
Single-endedordifferentialanaloginputs.1CH0+^cc2CH1DCLK3Single-endedordifferentialanaloginputs.1CH0+^cc2CH1DCLK3CH2CS4CH3din5CH4BUSY6CH5Dow7CH6GND8CH7GND9COM+^cc10SHDNVrefADS8345+2.7VSerialDataOut\ChipSelect<SerialDataID+1.25Vto+2.5VAds8345是一款典型的逐次逼近型数模转换器。内部自带采样保持器(SHA)典型应用电路:管脚介绍:管脚名称说明1CH0模拟输入端通道02CH1模拟输入端通道13CH2模拟输入端通道24CH3模拟输入端通道35CH4模拟输入端通道46CH5模拟输入端通道57CH6模拟输入端通道68CH7模拟输入端通道79COM公共参考端,这个端口通10SHDN常接到Vref待机,到此管脚为低电11Vref平,设备进入超低功耗待机模式。12+Vcc参考电压输入端,输入范13GND围参考电气特性表14GND电源,2.7-5V。15Dout地16BUSY地17Din串仃数据输出18CS忙碌信号输出19DCLK串仃数据输入20+Vcc片选信号外部时钟输入电源工作时需要外部的参考电源,外部时钟。需要单端电源2.7-5V。外部参考电源可以是500mV到+Vcc/2。参考电源的电压直接决定转换器的模拟输入电压范围。参考电源平均输入电流大小取决于AD的转换速率。AD的模拟输入是差分的。通过8通道的多路器获得。输入电压可以根据COM端的电压设置。或者使用8路中的4路来组成差分信号。这些设置可以通过串口来选择。模拟输入模拟输入是双极的差分的。有两种方法来获得AD的模拟输入。单端型和差分型。当输入作为单端型的时候,COM端被保持在一个固定的电压。CHX各个通道的输入电压在这个固定的电压值上下变化,峰峰值为2倍的Vref。参考电压值决定COM端电压的变化范围。当输入作为差分输入方式,各通道的输入电压的振幅为CHX端与COM端输入的差值。每个通道的峰峰值为Vref。ConirrrDn-WodeConirrrDn-WodeVoltage{typicallyVref)NOTE:(1)Restivetcco-miTion-rr-odevotsge.CS―|_1□cmfinnr^LTLnj®_Din |S|A2|A1|a0XI律|PDl|PD。(START)BUSY―| |_1Dour'~|1S114I13I12I11I10I9I8I7]6I5I4|3I2I1I0| ZeroFilled.. | {MSB) (L5B)FIGURE8.ExternalClockMode,32ClocksPerConversion在第一个八个时钟周期内。可以通过Din端口向AD写入控制字符。一旦AD获得了足够的控制信息之后就对内部的输入多路器进行设置。AD就进入到采用模式。四个或四个以上的时钟周期之后。收到控制字符后,AD进入到转换模式。在这个时候,输入采样保持器进入保持模式。在之后的十六个时钟周期后完成实际的模拟数字转换。控制字符:上图中显示出控制字符的每位控制字的写入顺序。表中详细的给我这些控制字的说明。BIT7BIT7(MSB)BIT6BIT5BIT4SA2MAOBIT3BIT2BIT1BIT0(LSB}SGL/DIFP01PDO第一位“S”为控制字的起始位,必须为逻辑高。ADS8345会忽略所有的信息。直到Din端口收到“S”这个开始位。之后的三个位(A2-A0)可以用来选择模拟输入多路器的八个通道。A2A1A2A1AOCH。CH1CH2000+IN100*IN001+IN101010110011111CH3CH4CH5CH6CH7COM-IN-IN-IN+IN-IN+IN-IN+IN-IN+IN-IN+IN-IN2驱动程序的组织结构Linux的设备模型SPI接口是Motorola公司首先提出的全双工三线同步串行外围接口,采用主从模式(MasterSlave)架构;一般仅支持单Master,但可以支持多slave模式。时钟由Master控制,在时钟移位脉冲下,数据按位传输,高位在前(MSBfirst),低位在后(LSB);SPI接口有两根单向数据线,为全双工通信,目前应用中的数据速率可以达到Mbps级水平。SPI接口主要应用在EEPROM、FLASH、RTC、ADC、DSP以及数字信号解码器之间。它在芯片中只占用四根管脚用来控制以及进行数据传输,分别为SCK(时钟信号)、MOSI(主设备输出从设备输入)、MISO(主设备输入从设备输出),CS(片选信号,一般为低电平有效),节约了芯片的管脚数目,同时为PCB在布局上节省了空间。正是由于这种简单易用的特性,现在越来越多的芯片上都集成了SPI技术。其总线结构如图4.2所示:图4.2SPI总线结构首先,主从设备之间进行的通信,要确保两个设备之间时钟的一致性,要匹配否则就没有办法进行正常的通信了。对时钟(SCLK)来说,最重要的两个特性就是极性和相位了,只要保证两个设备的极性和相位保持一致,就可以保证两者正常通信。时钟(SCLK)的空闲时刻,就是当时钟在发送八个比特数据之前和之后的状态,与此对应的就是在时钟发送数据的时候,也就是SPI正常工作的时候。SPI的极性就是指,当时钟空闲的时候,其电平是高电平还是低电平。CPOL=0,表示时钟空闲的时候的电平是低电平;CPOL=1表示时钟空闲时候的电平是高电图4.3时钟极性从图中可以看出,时钟的波形(CPOL=0)在有输出八个脉冲,而在脉冲输出前和完成后都保持在低电平状态。此时的状态就是时钟空闲状态或无效状态,因为此时没有脉冲也就不会有数据传输。同理可以得出CPOL=1的图形,无效状态为高电平。时钟的相位就是表示当数据有效时刻,是在时钟的第几个条边沿进行采样,是在第一个或者第二个跳变沿进行采样。CPHA=0表示在时钟的第一个跳变沿进行采样,即读取数据。CPHA=1表示在时钟的第二个跳变沿进行数据采样。SPI接口的极性(CPOL)和相位(CPHA)分别可以是0或者是1,对应的组合可以实现SPI通信的四种模式:Mode0(CPOL=0,CPHA=0)、Mode1(CPOL=0,CPHA=1)、Mode2(CPOL=1,CPHA=0)、Mode3(CPOL=1,CPHA=1)。其详细对比如表4.1:
CycleSPICLKMOSIMISO1234CycleSPICLKMOSIMISO1234567SCPOL=0.CPHA=0(Format时钟空闲时刻电压低电平CPOL=0高电平CPOL=1数据采样时刻,时钟的第几个跳变沿采样第一个跳变沿CPHA=0上升沿采样(开始电压是低电平,而第一个跳变沿只能是从低到高,即上升沿)下降沿采样第二个跳变沿CPHA=1下降沿采样上升沿采样(开始电压是高电压,第二个跳变沿肯定是从低电平到高电平)其中Mode0和Mode3是最常用的模式,本系统采用的SPI接口协议即采用的Mode0,脉冲传输前和完成后都保持在低电平状态,所以CPOL=0即低电平是空闲时的电平。在第一个跳变沿(上升沿)进行数据采样,第二个跳变沿(下降沿)输出数据,对应着CPHA=0。其对应的时序图如4.4:图4.4SPI时序图(MODE0)Tiny210SPI移植Linux内核的内核源码中已经给出了三星s5pv210的SPI驱动,但是Tiny210核心板并没有启用这个驱动,因此需要在开发板中配置这个驱动,使得Tiny210支持SPI接口。通过对Linux内核相关的学习,得到在BSP包中添加添加SPI接口支持的方法:1)进入本开发板中的BSP相关的目录下,在Tiny210核心板中即是:/用户目录/Linux-/arch/arm/mach-s5pv210,打开Tiny210的板级支持包Mach-mini210.c,加入相关头文件的支持,因为s5pv210的SPI寄存器相关定义
和s3c64xx相同,故还是使用s3c64xx中SPI相关的寄存器,加入的头文件如下:#include<plat/s3c64xx-spi.h>#include<mach/spi-clocks.h>2)在平台相关设备中添加从设备相关结构体的定义,因为核心板有两个SPI控制器,需要填充设备结构体数组structspi_board_infos3c_spi_devs[],在本BSP中的代码如下:staticstructspi_board_infos3c_spi_devs[]_initdata={[0]={.mode.max_speed_hz.busnum.irq.chip_select="spidev",=SPI_MODE_0,=10000000,=0,=IRQ_SPI0,.mode.max_speed_hz.busnum.irq.chip_select="spidev",=SPI_MODE_0,=10000000,=0,=IRQ_SPI0,=0,},[1]={.modalias.mode.max_speed_hz.busnum.irq.chip_select="ads8345”,=SPI_MODE_0,=1000000,=1,=IRQ_SPI1,=0,};本系统运用的是SPI1控制器,设备名字为ads8345,数据采集模式应用为Mode0即是CPOL=0,CPHA=0,采集速率为1MHz,SPI总线为一号总线,片选为低电平有效。3)在structplatform_device*mini210_devices[]_initdata数组平台中添加SPI控制器设备相关代码,用以在开发板初始化代码中注册进开发板,所添加的代码如下:&s5pv210_device_spi0,&s5pv210_device_spi1,设备结构体初始化代码,也就是SPI控制器设备结构体,包括设备名字,所用的资源等,s5pv210_device_spi0对应SPI第一个控制器,s5pv210_device_spi1对应第2个SPI控制器:structplatform_devices5pv210_device_spi0={.name="s3c64xx-spi",.id=0,.num_resources=ARRAY_SIZE(s5pv210_spi0_resource),.resource=s5pv210_spi0_resource,.dev={.dma_mask=&spi_dmamask,.coherent_dma_mask=DMA_BIT_MASK(32),.platform_data=&s5pv210_spi0_pdata,},};structplatform_devices5pv210_device_spi1={.name="s3c64xx-spi”,.id=1,.num_resources=ARRAY_SIZE(s5pv210_spi1_resource),.resource=s5pv210_spi1_resource,.dev={.dma_mask=&spi_dmamask,.coherent_dma_mask=DMA_BIT_MASK(32),.platform_data=&s5pv210_spi1_pdata,},};4)在开发板的初始化代码中把上面步骤添加的相关代码,通过调用注册设备函数即在staticvoid__initmini210_machine_init(void)中通过调用spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs))函数进行注册。mini2440SPI驱动移植1,在LinuxSourceCode中修改arch/arm/mach-s3c2440/mach-mini2440.c文件,加入头文件:#include<linux/spi/spi.h>#include<../mach-s3c2410/include/mach/spi.h>然后加入如下代码:staticstructspi_board_infos3c2410_spi0_board[]=([0]=(.modalias="spidev",・bus_num=0,.chip_select=0,・irq=IRQ_EINT9,.max_speed_hz=500*1000,}};11.staticstructs3c2410_spi_infos3c2410_spi0_platdata={13..pin_cs=S3C2410_GPG(2),.num_cs=1,・bus_num=0,.gpio_setup=s3c24xx_spi_gpiocfg_bus0_gpe11_12_13,TOC\o"1-5"\h\z};18.staticstructspi_board_infos3c2410_spi1_board[]=([0]=(.modalias="spidev",.bus_num=1,.chip_select=0,25・.irq=IRQ_EINT2,.max_speed_hz=500*1000,}};29.30.staticstructs3c2410_spi_infos3c2410_spi1_platdata=(.pin_cs=S3C2410_GPG(3),.num_cs=1,.bus_num=1,.gpio_setup=s3c24xx_spi_gpiocfg_bus1_gpg5_6_7,};这里需要了解驱动架构,其中移植过程中容易出问题的地方时S3C2410_GPG(2)和S3C2410_GPG(3)两处地方,网上一般给的源代码是S3C2410_GPG2这在2.6.29中可行,但是在2.6.32源代码中没有定义S3C2410_GPG2宏定义,要使用S3C2410_GPG(2)宏定义。//注册SPI平台设备到虚拟平台总线上....在mini2440_devices[]平台数组中添加如下代码:&s3c_device_spi0,&s3c_device_spi1,最后在mini2440_machine_init函数中加入如下代码:s3c_device_spi0.dev.platform_data=&s3c2410_spi0_platdata;spi_register_board_info(s3c2410_spi0_board,ARRAY_SIZE(s3c2410_spi0_board));s3c_device_spi1.dev.platform_data=&s3c2410_spi1_platdata;spi_register_board_info(s3c2410_spi1_board,ARRAY_SIZE(s3c2410_spi1_board));最后需要修改arch/arm/plat-s3c24xx/KConfig文件找到如下代码段:configS3C24XX_SPI_BUS0_GPE11_GPE12_GPE13boolhelpSPIGPIOconfigurationcodeforBUS0whenconnectedtoGPE11,GPE12andGPE13.6.configS3C24XX_SPI_BUS1_GPG5_GPG6_GPG7boolhelpSPIGPIOconfigurationcodeforBUS1whenconnectedtoGPG5,GPG6andGPG7.修改为configS3C24XX_SPI_BUS0_GPE11_GPE12_GPE13bool"S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13helpSPIGPIOconfigurationcodeforBUS0whenconnectedtoGPE11,GPE12andGPE13.6.configS3C24XX_SPI_BUS1_GPG5_GPG6_GPG7bool"S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7"helpSPIGPIOconfigurationcodeforBUS1whenconnectedtoGPG5,GPG6andGPG7.最后我们配置编译文件:1.makemenuconfig
图2
图4最后编译内核makezImage至此,SPI驱动移植结束,2.4SPI移植驱动验证将编译好的内核导入开发板,并且编译LinuxSource自带的测试程序,在Documentation/spi下,修改spidev_test.c文件,将devicename改为/dev/spidev1.0交叉编译:arm-linux-gcc-I~/linux-/include/spidev_test.c将编译好的文件下载到开发板上,并且将开发板的SPIMOI和MIO短接,也就是让SPI自己发送自己接收,执行文件,我们看到如下结果:FFFFFFFFFFFF400000000095FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDEADBEEFBAADF00D到此移植完毕,但要注意,mini2440上的SPI1被K3K43ADS8345驱动实现3.1Linux设备模型随着计算机的外设越来越丰富,设备管理已经成为现代操作系统的一项重要的任务,对于Linux来说也是同样的情况。每次Linux内核新版本的发布,都会伴随着一批设备驱动进入内核。在Linux内核里,驱动程序的代码量占了相当大的比重。Linux2.6内核最初为了应付电源管理的需求,提出了一个设备模型来管理所有的设备。在物理上,外设之间是有一种层次关系,为了对计算机设备进行统一的表示和操作,包括设备本身和设备与主机之间的链接关系,人们通过分析PCI和USB这两个总线,它们能够代表当前系统中的大多数设备总线,有着完善的热插拔和电源管理机制,从而得出设备模型的结构。如在一个典型的计算机系统中,CPU能够直接控制的是PCI总线设备,而USB总线设备是以一个PCI设备的形式接入到PCI总线上的,外部的USB设备再入USB总线设备上;当计算机执行挂起操作时,Linux内核应该以“外部USB设备->USB总线设备->PCI总线设备”的顺序通知每一个设备的执行电源挂起;执行恢复时则以相反的顺序通知每一个设备。如果不按这样的顺序则将有设备因为没有得到正确的通知,而没有执行电源相关的操作,从而使设备不能正常的工作。因为有这样的需要,必须能够建立一个树状的结构可以把所有的外设组织起来。这样就提出了建立Linux设备模型的概念。当然,既然设备模型已经建立起来,已经有了一个可以组织所有设备和驱动的树状结构,我们就可以通过这棵树去遍历所有的设备,建立设备和驱动程序之间的联系,根据设备类型的不同还可以对设备进行分门别类,这样用户就可以通过不同的视角更清晰的去学习Linux的内核,认识Linux的外部设备。Linux设备模型把很多设备共有的一些操作属性进行抽象,从而大大的减少了重复代码的编写过程,让开发者能够更加安全快速的开发驱动程序。上文提到过Linux设备的外设之间有一种层次关系,在Linux内核的设计中频繁地用到了这种思想。在设备驱动的设计中往往为相似的设备构建一个框架,在框架的核心层实现了这类设备的通用功能。如果具体的设备驱动函数不想应用核心层提供的函数,还可以重新实现该函数。图4.7反应了设备驱动核心层与具
体设备驱动的关系。这种层次化的思想在Linux的SPI、TTY、USB等子系统中得到了普遍的应用。某类设备的核心某类设备的
子燹的核心层某类设备的
子龚的核心层某类设备的
子燹的核心层某类设备的
子龚的核心层某类设备子A的实例1某类设备子B»实例某类设备子B的实例图4.7驱动分层结构在Linux驱动框架的构建过程中,除了有分层设计的思想外,为了实现代码的重复利用,还充分利用了主机控制器和外设驱动分离的思想。如果不这样做,那么当同一个外设用在不同种类的CPU上,都需要不同的驱动程序,这将是不可接受的。所以最佳的办法就是外设驱动不关心主机控制器,而主机控制器也不关心外设驱动,他们之间的通信都是通过中间层来完成。而这个中间层就是核心层,通过调用核心层的API函数来完成两者之间的信息传递,外设和主机控制器之间可以进行任意的组合,实现代码的最大重用。具体的分离思想可以用图4.8表示:主机控制器B驱动七几区力甬-日主机控制器B驱动七几区力甬-日P亥、^3kf、H~IrA7一二一,aaIL一一----44一L-_z>Jrr/7J*rrf/x^/图4.8驱动分离结构Linux2.6的设备模型,是由总线、设备和设备驱动这三个部分构成。总线的作用就是将设备和设备驱动进行匹配和绑定,在系统每注册一个设备的时候,总线会寻找与之匹配的设备驱动,同时在注册每一个设备驱动时,总线也会匹配相应的设备。Linux内核一般的设备都会挂接在一种总线上,像SPI设备、I2C设备、USB设备等。对Linux内核中SPI设备模型的研究学习是编写基于SPI总线设备驱动的基础。在开发需要给用户层提供接口的驱动中,常用的方法有以下三种:注册虚拟的字符设备文件,以这个虚拟设备上的read/write/ioctl等接口与用户交互,许多子系统就是基于此种方式实现与用户的交互,其中包括SPI子系统;注册proc接口,接收用户的read/write/ioctl操作;注册sysfs属性,利用属性文件的show/store文件属性实现用户交互;其中,基于子系统开发驱动程序已经是Linux内核的普遍做法了。图4.9是针对Tiny210核心板中SPI控制系统的一个简单描述:图4.9SPI驱动层次结构图连接所有SPI设备和驱动的连接所有平台设备和驱动的PlatformbusSPI总线叮理解为连接所有SPI设备和驱动的连接所有平台设备和驱动的PlatformbusSPI总线叮理解为SPI控制器引山的总线WT设备对应的spi_deviceSPI控制器对应的platformdeviceSPT设备射应为spi_dri.verSPI控制器对陶的platforsidriver在Linux的设备模型中有些集成在芯片上的设备,挂接在片上系统的内存空间的外设等,不依赖于某种实体总线。为了统一Linux设备模型,Linux内核发明了一种虚拟总线,称为platform总线,相对应的设备称为platform_device,对应的驱动为plarform_driver。但是platform_device是Linux提供的一种虚拟方法,并不是和块设备、字符设备、网络设备并列的概念。在本系统s5pv210芯片中,把内部集成的I2C、SPI等都定义为platform_device设备,而他们本身都是字符设备。platform_bus对应的结构体是platform_bus_type,其定义在linux\driver\base\Platform.c文件中,这个在内核开始就是定义好的,其代码如下:structbus_typeplatform_bus_type={.name ="platform", 〃名称.dev_attrs =platform_dev_attrs,〃总线属性.match =platform_match, 〃匹配函数.uevent =platform_uevent,.pm=&platform_dev_pm_ops,};platform_device对应的即是s5pv210处理器对应的SPI控制器,其相关的定义在linux\arch\arm\mach-s5pv210\Dev-spi.c中,定义的代码如下:structplatform_devices5pv210_device_spi1={.name="s3c64xx-spi",//名称,要和platform_driver匹配.id=1, //第二个控制器,s5pv210中有三个SPI控制器.num_resources=ARRAY_SIZE(s5pv210_spi1_resource),〃占用资源的大小.resource=s5pv210_spi1_resource,//指向资源结构数组的指针.dev={.dma_mask =&spi_dmamask,//dma寻址范围.coherent_dma_mask=DMA_BIT_MASK(32),//DMA位掩码.platform_data=&s5pv210_spi1_pdata,〃特殊的平台数据,用于控制器管脚的IO配置},};3)platform_driver的定义文件为linux\driver\spi\Spi_s3c64xx.c,其定义代码如下:staticstructplatform_drivers3c64xx_spi_driver={.driver={.name="s3c64xx-spi",//驱动名称和platform_device一致.owner=THIS_MODULE,},.remove=s3c64xx_spi_remove,.suspend=s3c64xx_spi_suspend,.resume=s3c64xx_spi_resume,};总线把设备驱动程序和平台上注册的设备相匹配后,会根据下文注册进来的spi_device创建用于描述SPI控制器的结构体spi_master,用于描述控制器对象的属性比如序号(系统中存在多个控制器)、SPI模式、时钟设置和数据传输用到的函数等。结构体定义如下:structspi_master{structdevicedev;s16 bus_num;//SPI控制器的编号u16 num_chipselect;//支持的片选数量int(*setup)(structspi_device*spi);//针对SPI设备设置传输模式和时钟频率int (*transfer)(structspi_device*spi,structspi_message*mesg);//实现数据的双向传输void (*cleanup)(structspi_device*spi);};spi_bus可以理解为SPI控制器引出的总线,相当于platform_bus的下一级结构,体现着Linux的分层思想。其定义在linux\driver\spi\Spi.c,其定义代码:structbus_typespi_bus_type={ II_'!!.name = spi,.dev_attrs = spi_dev_attrs,.match = spi_match_device,.uevent=spi_uevent,.suspendsspi_suspend,.resume=spi_resume,};spi_device即是我们自己需要添加的设备,需要构建设备本身的特性,传输要求,以及挂接在哪条总线上等属性,并把设备注册进内核。因为这是和开发板相关的代码,一般需要在板级支持包相关的文件中添加代码。对于本系统主要是添加ADS8345模数转换模块的支持,需要在linux\arch\arm\mach_s5pv210\Mach_mini210.c中添加代码结构体如下:staticstructspi_board_infos3c_spi_devs[]__initdata={.modalias="ads8345",//设备名称.mode=SPI_MODE_0,//选择的传输模式.max_speed_hz=1000000,//最大的传输速率.bus_num=1, 〃连接的总线号.irq=IRQ_SPI1,//中断号.chip_select},=0, 〃片选线号};6)spi_driver即为设备对应的驱动,本系统中就是实现ADS8345的驱动程
序。3.2驱动接口实现ADS8345芯片相关的信息在上文已经进行了详细的介绍,本节通过编写驱动函数来为上层的Linux应用程序提供接口。主要的功能函数如表4.2:表4.2A/D驱动函数接口函数名称描述ads8345_init驱动加载时候执行的函数,驱动函数的初始化函数,包括注册字符设备驱动、注册类和注册SPI子系统设备驱动等ads8345_probeSPI总线匹配设备和驱动执行的函数,建立设备节点提供字符设备其他操作函设备节点ads8345_open设备驱动打开函数,给应用程序提供打开驱动的接口函数,创建设备结构体对象ads8345_write设备写函数,将应用程序的命令数据发送到设备,给应用程序提供写函数接口ads8345_read设备读函数,将设备转化后的结果返回给应用程序,给应用程序提供读函数接口ads8345_release设备关闭文件函数,当应用程序不再使用设备时,关闭已经打开的文件的函数接口ads8345_exit驱动卸载时系统调用执行的函数,释放申请的资源等做一些清理工作设备描述文件的的结构体,一般驱动程序编写者自己定义,把常用的变量、结构体及指针存入其中:structads8345_data{dev_t devt;〃保存设备主从设备号structspi_device*spi;//spi设备指针structlist_headdevice_entry;〃设备列表头structmutexbuf_lock;//互斥访问量u8 *buffer; 〃内核控件缓冲区};定义文件的入口操作数据结构,应用程序调用这些函数来调用驱动程序中的
函数:.owner=staticconststructfile_operationsads8345_fops={.owner=THIS_MODULE,.owner=.write=ads8345_write,.read=ads8345_read,.write=ads8345_write,.read=ads8345_read,.open=.release=.open=.release=ads8345_release,};本驱动是基于SPI子系统进行通信,利用SPI子系统实现模拟字符驱动的关键结构体代码为:staticstructspi_driverads8345_spi_driver={.driver={.name="ads8345",.owner=THIS_MODULE,},.probe=ads8345_probe,.remove=__devexit_p(ads8345_remove),};(1)ads8345_init为设备驱动加载后,Linux内核调用执行的第一个函数。该函数主要进行字符设备的注册,包括注册设备操作的结构体,创建设备对应的类,后续根据创建的类建立设备节点。把设备做为SPI子系统的驱动注册进内核。上述每个函数都有可能因资源被占用的等情况而失败,因此在失败的情况下,必须把已经申请到的资源还给内核。主要的函数为:register_chrdev(ADS8345_MAJOR,"ads8345",&ads8345_fops);class_create(THIS_MODULE,"ads8345");spi_register_driver(&ads8345_spi_driver);函数的执行流程如图4.10:失败失败成功失败失败成功注册字符设备"■■■■■(Register_chrdev)"成功创建设备类'''•...(class_creat)-"""移除注册字符设备(unregister_chrdeV失败 一注册SPI子系统驱动1""■■■■■.(spi_register_driver)"'取消建立类(classdestroy移除注册字符设备(unregister_chrdeV成功1— /返回状态: 图4.10ads8345_init流程图(2)ads8345_probe是SPI子系统比较重要的一个函数,在注册SPI设备后,SPI总线会匹配设备和驱动的名字,当有相同的名字的时候,系统会自动调用该函数。在函数中会执行对结构体ads8345_data分配内存,对数据进行一些初始化工作,并创建用于字符设备读写函数操作所用的节点/dev/ads8345,将增加的设备添加到spi总线设备列表中。主要的函数为:structads8345_data*spidev;kzalloc(sizeof(*spidev),GFP_KERNEL);device_create(ads8345_class,&spi->dev,spidev->devt,spidev,"ads8345");list_add(&spidev->device_entry,&device_list);函数的执行流程图如4.11:
失败分配内存 (kzalloc)成功失败初始化ads8345_data
结构体数据失败创建设备节点(devicecreatA'成功I增加到设备列表(list_ad)T返回状态—vy图4.11ads8345_probe流程图(3)ads8345_open主要是为应用层提供打开设备的接口,该函数中主要完成从SPI设备列表中遍历需要打开的文件,如果存在则为分配内核buffer,作为后续接收应用层数据的缓冲区,并且将设备结构体作为打开文件的私有数据存储起来,以后的读写函数都可以使用这个私有数据,如果不存在则返回错误状态信息。具体的函数如下:list_for_each_entry(spidev,&device_list,device_entry);kmalloc(bufsiz,GFP_KERNEL);filp->private_data=spidev;其执行流程如图4.12:失败添加到打开文件私有 打印出错信息数据(失败添加到打开文件私有 打印出错信息数据(Filp-> JeV—dbGprivate_data=spidev)图4.12ads8345_open流程图循环遍历设备节点 .(.listforeachentry ..)'".y匚二,....成功分配内核buffer(kmalloc)失败成功(4)ads8345_write和ads8345_read函数在内核中扮演着作用相反的角色,前一个用于为应用程序提供写函数接口,而后一个则是为应用程序提供一个读函数接口。但他们在内核中的执行流程是非常的相似,而且在Linux内核SPI子系统中的最终都是调用同一个函数spi_asys函数来完成最终的数据传输。与应用程序的交互是通过copy_to_user/copy_from_user两个函数来完成。在函数传输过程中有非常重要的两个结构体,spi_message和spi_transfer。spi_message描述了一次完整的读写过程,而spi_transfer代表一次单独的读或者写过程,多个spi_transfer组成一个spi_message。以ADS8345的典型工作读写时序图(图3.4)为例,从Din写入数据到Dout完成输出数据,24个时钟周期组成一个spi_message。但可以把它分为两个spi_transfer,前8个时钟写命令为一个spi_transfer,后16个时钟周期读数据为一个spi_transfer,在本驱动的写函数中表示为:staticinlinessize_tads8345_sync_write(structads8345_data*spidev,size_tlen){structspi_transfer t={.tx_buf =spidev->buffer,//驱动中要发送的数据括:copy_from_user(spidev->buffer,buf,count);ads8345_sync_write(spidev,count);ads8345_sync(spidev,&m);spi_async(spidev->spi,message);其执行流程如图4.13,开始应用程序调用括:copy_from_user(spidev->buffer,buf,count);ads8345_sync_write(spidev,count);ads8345_sync(spidev,&m);spi_async(spidev->spi,message);其执行流程如图4.13,开始应用程序调用(write)失败返回状态*参数传递到内核•••.(copy_from_us
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024各类设备采购协议总览
- 2024年新公司聘用劳动协议样式
- 2024年场地调查委托协议模板
- 2024届安徽江南十校高三数学试题毕业班4月质量检查试题
- 2024年劳务合作及就业保障协议
- 化信息技术硬件采购协议范本
- 2024年智能设备部署与维护协议
- 2024年蔬菜产业链战略合作协议
- DB11∕T 1603-2018 睡莲栽培技术规程
- 2024专业新风系统安装服务协议模板
- 音乐治疗服务行业发展趋势及前景展望分析报告
- 摊位入股合同范本
- 2024年人教版八年级地理上册全册基础知识点复习提纲
- 续保赠送活动方案
- 安全隐患排查检讨反思
- Advanced Operations Research智慧树知到答案2024年上海大学
- 音乐鉴赏(西安交通大学)智慧树知到期末考试答案2024年
- 主题班会-期中考试动员
- MOOC 数据挖掘与python实践-中央财经大学 中国大学慕课答案
- (2024)辅警招聘公安基础知识考试题库及答案
- 夸美纽斯完整版本
评论
0/150
提交评论