1 SPI概述
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的大小端。
2 Linux SPI驱动总体架构
在2.6的linux内核中,SPI的驱动架构可以分为如下三个层次:SPI 核心层、SPI控制器驱动层和SPI设备驱动层。
Linux 中SPI驱动代码位于drivers/spi目录。
2.1 SPI核心层
SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。
Linux中,SPI核心层的代码位于driver/spi/ spi.c。由于该层是平台无关层,本文将不再叙述,有兴趣可以查阅相关资料。
2.2 SPI控制器驱动层
SPI控制器驱动层,每种处理器平台都有自己的控制器驱动,属于平台移植相关层。它的职责是为系统中每条SPI总线实现相应的读写方法。在物理上,每个SPI控制器可以连接若干个SPI从设备。
在系统开机时,SPI控制器驱动被首先装载。一个控制器驱动用于支持一条特定的SPI总线的读写。一个控制器驱动可以用数据结构struct spi_master来描述。
在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下:
- /**
- * struct spi_master - interface to SPI master controller
- * @dev: device interface to this driver
- * @bus_num: board-specific (and often SOC-specific) identifier for a
- * given SPI controller.
- * @num_chipselect: chipselects are used to distinguish individual
- * SPI slaves, and are numbered from zero to num_chipselects.
- * each slave has a chipselect signal, but it's common that not
- * every chipselect is connected to a slave.
- * @setup: updates the device mode and clocking records used by a
- * device's SPI controller; protocol code may call this. This
- * must fail if an unrecognized or unsupported mode is requested.
- * It's always safe to call this unless transfers are pending on
- * the device whose settings are being modified.
- * @transfer: adds a message to the controller's transfer queue.
- * @cleanup: frees controller-specific state
- *
- * Each SPI master controller can communicate with one or more @spi_device
- * children. These make a small bus, sharing MOSI, MISO and SCK signals
- * but not chip select signals. Each device may be configured to use a
- * different clock rate, since those shared signals are ignored unless
- * the chip is selected.
- *
- * The driver for an SPI controller manages access to those devices through
- * a queue of spi_message transactions, copying data between CPU memory and
- * an SPI slave device. For each such message it queues, it calls the
- * message's completion function when the transaction completes.
- */
- struct spi_master {
- struct device dev;
-
- /* other than negative (== assign one dynamically), bus_num is fully
- * board-specific. usually that simplifies to being SOC-specific.
- * example: one SOC has three SPI controllers, numbered 0..2,
- * and one board's schematics might show it using SPI-2. software
- * would normally use bus_num=2 for that controller.
- */
- s16 bus_num;
-
- /* chipselects will be integral to many controllers; some others
- * might use board-specific GPIOs.
- */
- u16 num_chipselect;
-
- /* setup mode and clock, etc (spi driver may call many times) */
- int (*setup)(struct spi_device *spi);
-
- /* bidirectional bulk transfers
- *
- * + The transfer() method may not sleep; its main role is
- * just to add the message to the queue.
- * + For now there's no remove-from-queue operation, or
- * any other request management
- * + To a given spi_device, message queueing is pure fifo
- *
- * + The master's main job is to process its message queue,
- * selecting a chip then transferring data
- * + If there are multiple spi_device children, the i/o queue
- * arbitration algorithm is unspecified (round robin, fifo,
- * priority, reservations, preemption, etc)
- *
- * + Chipselect stays active during the entire message
- * (unless modified by spi_transfer.cs_change != 0).
- * + The message transfers use clock and SPI mode parameters
- * previously established by setup() for this device
- */
- int (*transfer)(struct spi_device *spi,
- struct spi_message *mesg);
-
- /* called on release() to free memory provided by spi_master */
- void (*cleanup)(struct spi_device *spi);
- };
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
- /**
- * struct spi_device - Master side proxy for an SPI slave device
- * @dev: Driver model representation of the device.
- * @master: SPI controller used with the device.
- * @max_speed_hz: Maximum clock rate to be used with this chip
- * (on this board); may be changed by the device's driver.
- * The spi_transfer.speed_hz can override this for each transfer.
- * @chip_select: Chipselect, distinguishing chips handled by @master.
- * @mode: The spi mode defines how data is clocked out and in.
- * This may be changed by the device's driver.
- * The "active low" default for chipselect mode can be overridden
- * (by specifying SPI_CS_HIGH) as can the "MSB first" default for
- * each word in a transfer (by specifying SPI_LSB_FIRST).
- * @bits_per_word: Data transfers involve one or more words; word sizes
- * like eight or 12 bits are common. In-memory wordsizes are
- * powers of two bytes (e.g. 20 bit samples use 32 bits).
- * This may be changed by the device's driver, or left at the
- * default (0) indicating protocol words are eight bit bytes.
- * The spi_transfer.bits_per_word can override this for each transfer.
- * @irq: Negative, or the number passed to request_irq() to receive
- * interrupts from this device.
- * @controller_state: Controller's runtime state
- * @controller_data: Board-specific definitions for controller, such as
- * FIFO initialization parameters; from board_info.controller_data
- * @modalias: Name of the driver to use with this device, or an alias
- * for that name. This appears in the sysfs "modalias" attribute
- * for driver coldplugging, and in uevents used for hotplugging
- *
- * A @spi_device is used to interchange data between an SPI slave
- * (usually a discrete chip) and CPU memory.
- *
- * In @dev, the platform_data is used to hold information about this
- * device that's meaningful to the device's protocol driver, but not
- * to its controller. One example might be an identifier for a chip
- * variant with slightly different functionality; another might be
- * information about how this particular board wires the chip's pins.
- */
- struct spi_device {
- struct device dev;
- struct spi_master *master;
- u32 max_speed_hz;
- u8 chip_select;
- u8 mode;
- #define SPI_CPHA 0x01 /* clock phase */
- #define SPI_CPOL 0x02 /* clock polarity */
- #define SPI_MODE_0 (0|0) /* (original MicroWire) */
- #define SPI_MODE_1 (0|SPI_CPHA)
- #define SPI_MODE_2 (SPI_CPOL|0)
- #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
- #define SPI_CS_HIGH 0x04 /* chipselect active high? */
- #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
- #define SPI_3WIRE 0x10 /* SI/SO signals shared */
- #define SPI_LOOP 0x20 /* loopback mode */
- u8 bits_per_word;
- int irq;
- void *controller_state;
- void *controller_data;
- char modalias[32];
-
- /*
- * likely need more hooks for more protocol options affecting how
- * the controller talks to each chip, like:
- * - memory packing (12 bit samples into low bits, others zeroed)
- * - priority
- * - drop chipselect after each word
- * - chipselect delays
- * - ...
- */
- };
复制代码通常来说spi_device对应着SPI总线上某个特定的slave。OMAP3630上SPI是一个主/从的同步串行总线,这边有4个独立的SPI模块(SPI1,SPI2,SPI3,SPI4),各个模块之间的区别在于SPI1支持多达4个SPI设备,SPI2和SPI3支持2个SPI设备,而SPI4只支持1个SPI设备。
OMAP3630的SPI控制器模块图如下:
图3.1 OMAP3630 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字节的FIFO
一周热门 更多>