Linux内核中SPI总线驱动分析.doc_第1页
Linux内核中SPI总线驱动分析.doc_第2页
Linux内核中SPI总线驱动分析.doc_第3页
Linux内核中SPI总线驱动分析.doc_第4页
Linux内核中SPI总线驱动分析.doc_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux内核中SPI总线驱动分析本文主要有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程);另一个是SPI总线驱动的编写(不用研究具体的实现过程)。1SPI概述 SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口,是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。 SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要4根线,事实上3根也可以。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选)。 MOSI(SDO):主器件数据输出,从器件数据输入。 MISO(SDI):主器件数据输入,从器件数据输出。 SCLK :时钟信号,由主器件产生。 CS:从器件使能信号,由主器件控制。 其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个SPI设备成为可能。需要注意的是,在具体的应用中,当一条SPI总线上连接有多个设备时,SPI本身的CS有可能被其他的GPIO脚代替,即每个设备的CS脚被连接到处理器端不同的GPIO,通过操作不同的GPIO口来控制具体的需要操作的SPI设备,减少各个SPI设备间的干扰。 SPI是串行通讯协议,也就是说数据是一位一位从MSB或者LSB开始传输的,这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,MISO、MOSI则基于此脉冲完成数据传输。 SPI支持4-32bits的串行数据传输,支持MSB和LSB,每次数据传输时当从设备的大小端发生变化时需要重新设置SPI Master的大小端。2Linux SPI驱动总体架构 在2.6的linux内核中,SPI的驱动架构可以分为如下三个层次:SPI 核心层、SPI控制器驱动层和SPI设备驱动层。 Linux 中SPI驱动代码位于drivers/spi目录。2.1SPI核心层 SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。 Linux中,SPI核心层的代码位于driver/spi/ spi.c。由于该层是平台无关层,本文将不再叙述,有兴趣可以查阅相关资料。2.2SPI控制器驱动层 SPI控制器驱动层,每种处理器平台都有自己的控制器驱动,属于平台移植相关层。它的职责是为系统中每条SPI总线实现相应的读写方法。在物理上,每个SPI控制器可以连接若干个SPI从设备。 在系统开机时,SPI控制器驱动被首先装载。一个控制器驱动用于支持一条特定的SPI总线的读写。一个控制器驱动可以用数据结构struct spi_master来描述。 在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下:structspi_masterstructdevicedev; s16bus_num; u16num_chipselect; int(*setup)(structspi_device*spi); int(*transfer)(structspi_device*spi,structspi_message*mesg); void (*cleanup)(structspi_device*spi); ; bus_num为该控制器对应的SPI总线号。 num_chipselect控制器支持的片选数量,即能支持多少个spi设备 setup函数是设置SPI总线的模式,时钟等的初始化函数,针对设备设置SPI的工作时钟及数据传输模式等。在spi_add_device函数中调用。 transfer函数是实现SPI总线读写方法的函数。实现数据的双向传输,可能会睡眠 cleanup注销时候调用2.3SPI设备驱动层 SPI设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口。 SPI设备驱动层可以用两个模块来描述,struct spi_driver和struct spi_device。 相关的数据结构如下:structspi_driver int(*probe)(structspi_device*spi);int(*remove)(structspi_device*spi);void(*shutdown)(structspi_device*spi);int(*suspend)(structspi_device*spi,pm_message_tmesg);int(*resume)(structspi_device*spi);structdevice_driverdriver; Driver是为device服务的,spi_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定,probe函数用于驱动和设备匹配时被调用。从上面的结构体注释中我们可以知道,SPI的通信是通过消息队列机制,而不是像I2C那样通过与从设备进行对话的方式。structspi_devicestructdevicedev;structspi_master*master;u32max_speed_hz;u8chip_select;u8mode; u8bits_per_word;intirq;void*controller_state;void*controller_data;charmodalias32; ;.modalias = m25p10, .mode =SPI_MODE_0, /CPOL=0, CPHA=0 此处选择具体数据传输模式 .max_speed_hz = 10000000, /最大的spi时钟频率 /* Connected to SPI-0 as 1st Slave */ .bus_num = 0, /设备连接在spi控制器0上 .chip_select = 0, /片选线号,在S5PC100的控制器驱动中没有使用它作为片选的依据,而是选择了下文controller_data里的方法。 .controller_data = &smdk_spi0_csi0,通常来说spi_device对应着SPI总线上某个特定的slave。并且spi_device封装了一个spi_master结构体。spi_device结构体包含了私有的特定的slave设备特性,包括它最大的频率,片选那个,输入输出模式等等3OMAP3630 SPI控制器 OMAP3630上SPI是一个主/从的同步串行总线,这边有4个独立的SPI模块(SPI1,SPI2,SPI3,SPI4),各个模块之间的区别在于SPI1支持多达4个SPI设备,SPI2和SPI3支持2个SPI设备,而SPI4只支持1个SPI设备。SPI控制器具有以下特征: 1.可编程的串行时钟,包括频率,相位,极性。 2.支持4到32位数据传输 3.支持4通道或者单通道的从模式 4.支持主的多通道模式 4.1全双工/半双工 4.2只发送/只接收/收发都支持模式 4.3灵活的I/O端口控制 4.4每个通道都支持DMA读写 5.支持多个中断源的中断时间 6.支持wake-up的电源管理 7.内置64字节的FIFO4 spi_device以下一系列的操作是在platform板文件中完成!spi_device的板信息用spi_board_info结构体来描述:struct spi_board_info charmodaliasSPI_NAME_SIZE;const void*platform_data;void*controller_data;intirq;u32max_speed_hz;u16bus_num;u16chip_select;u8mode;这个结构体记录了SPI外设使用的主机控制器序号、片选信号、数据比特率、SPI传输方式等构建的操作是以下的两个步骤:1.spi_device就构建并注册static struct spi_board_info s3c_spi_devs _initdata = .modalias = m25p10a,.mode = SPI_MODE_0,.max_speed_hz = 1000000,.bus_num = 0,.chip_select = 0,.controller_data = &smdk_spi0_csiSMDK_MMCSPI_CS,;2.而这个info在init函数调用的时候会初始化:spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs);在板文件中添加spi_board_info,并在板文件的init函数中调用spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs);/注册spi_board_info。这个代码会把spi_board_info注册到链表board_list上。spi_device封装了一个spi_master结构体,事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,找到挂接在它上面的spi设备,然后创建并注册spi_device。至此spi_device就构建并注册完成了!5 spi_driver的构建与注册driver有几个重要的结构体:spi_driver、spi_transfer、spi_messagedriver有几个重要的函数 :spi_message_init、spi_message_add_tail、spi_sync(1)spi_driver的构建static struct spi_driver m25p80_driver = .driver = .name =m25p80, .bus =&spi_bus_type, .owner = THIS_MODULE, , .probe = m25p_probe, .remove =_devexit_p(m25p_remove),;(2)spi_driver的注册spi_register_driver(&m25p80_driver);/在有匹配的spi_device时,会调用m25p_probe(3)实现probe操作probe里完成了spi_transfer、spi_message的构建;spi_message_init、spi_message_add_tail、spi_sync、spi_write_then_read函数的调用。spi_transfer(里面集成了数据buf空间地址等信息)spi_message(是spi_transfer的集合)的构建)spi_message_init(初始化spi_message)spi_message_add_tail(将新的spi_transfer添加到spi_message队列尾部)spi_sync函数的调用(调用spi_master发送spi_message)spi_write_then_read(先写后读)例如:structspi_transferst=;/填充spi_transferstructspi_messagemeg;/定义messagespi_init_message(&meg);/初始化megspi_message_add_tail(&st,&meg);/将st放在message队列尾部Spi_sync(spi_device,&meg);/将message与spi_device关联,发送megstaticintm25p10a_read(structm25p10a*flash,loff_tfrom,size_tlen,char*buf)intr_count=0,i; structspi_transferst2; structspi_messagemsg;spi_message_init(&msg);memset(st,0,sizeof(st);flash-cmd0=CMD_READ_BYTES;flash-cmd1=from16;flash-cmd2=from8;flash-cmd3=from;st0.tx_buf=flash-cmd;st0.len=CMD_SZ;spi_message_add_tail(&st0,&msg);st1.rx_buf=buf;st1.len=len;spi_message_add_tail(&st1,&msg);mutex_lock(&flash-lock);/*Waituntilfinishedpreviouswritecommand.*/if(wait_till_ready(flash)mutex_unlock(&flash-lock);return-1;spi_sync(flash-spi,&msg);r_count=msg.actual_length-CMD_SZ;printk(in(%s):read%dbytesn,_func_,r_count);for(i=0;ilock);return0;staticintm25p10a_write(structm25p10a*flash,loff_tto,size_tlen,constchar*buf)intw_count=0,i,page_offset;structspi_transferst2;structspi_messagemsg;write_enable(flash);/写使能spi_message_init(&msg); memset(st,0,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论