SPI总线

Hntea bio photo By Hntea

概念:

SPI(Serial Peripheral Interface,串行外围设备接口)总线,串行 主-从接口;很多集成与微控制器内部。

四线制,全双共模式,速度达到几兆,四线分别为:

  • SCLK(Serial Clock):串行时钟

  • CS(Chip Select):片选,有些写着SS

  • MISO(Master In Slave out):主设备输入,从设备输出

  • MOSI(Master Out Slave in):主设备输出,从设备输入

架构图解

硬件线路图

数据传输过程

SPI传输

主节点通过 MOSI 线输出数据,从节点在SIMO 处从主节点读取数据。同时,也在通过SOMI 输出MSB(最高位),主节点会在MISO处读取从节点的数据,整个过程将一直持续,直至交换完所有数据;也就是所主从实现数据交换既为一次传输过程

总线时序:

时序

  • CPOL极性:决定时钟空闲时为高电平还是低电平
  • CPOL=0:CLK空闲时是低电平,CLK有效时是高电平
  • CPOL=1: CLK空闲时是高电平,CLK有效时是低电平
  • 决定何时进行数据采样(读取)
    • CPHA=0:第一个时钟的上升沿采样
    • CPHA=1:第一个时钟的下降沿采样

根据CPOL和CPHA的不同组合,SPI被分为4种模式 模式

SPI0传输时序

SPI0

TQ210 SPI控制器编程步骤:芯片手册900页 data

Linux SPI总线子系统

架构

架构

SPI核心

SPI控制器驱动和设备驱动之间的纽带,它提供了SPI控制器驱动和设备驱动的注册、 注销方法等。

SPI控制器驱动

对 SPI控制器的驱动实现。

SPI设备驱动

对 SPI从设备的驱动实现。

典型客户驱动程序

向SPI核心注册设备驱动:如在prob函数中:

#include<linux/spi/spi.h>

static struct spi_driver my_spidriver =

{

	.driver =
	{
		.name = myspi,
		.bus = &spi_bus_type,
		.owner = THIS_MODULE,
	}

	.prob = myspidevice_prob,
	.remove = _devexit_p(myspidevice_remove),
};

spi_register_driver(my_spidriver ); /*向SPI核心注册,在SPI总线挂载驱动*/

SPI核心创建对应于此设备的spi_device结构,当调用注册的驱动方法时,将此结构作为调用参数。

数据传输结构

 * I/O INTERFACEbetween SPI controller and protocol drivers

 * Protocol drivers use a queue of spi_messages, each transferring data

 * between the controller and memory buffers.

struct spi_transfer

 * struct spi_message - one multi-segment SPI transaction

struct spi_message

关系图解

图解

SPI消息构造

  • spi_message_init(struct spi_message m) /分配一条消息空间,并初始化 链表头*/

  • spi_message_add_tail(struct spi_transfer t, struct spi_message *m) /将数据加入链表*/

数据通讯

  • spi_sync():等待操作完成

  • spi_async():当数据传输完成时,异步触发对注册的回调程序的调用,如SPI中断处理函数、sysf方法或者定时器处理程序

## SPI数据传输例子

#include<linux/spi/spi.h>

struct spi_device *spi;
struct spi_transfer *t;
struct spi_message sm;

unsigned char *command_buff; /*数据传输空间*/

int len; /*数据长度*/

/*1、初始化SPI消息链表*/

spi_message_init(&sm);

/*2、填充传输数据*/

t.tx_buf = command_buff;

t.len = len;

/*3、把传输数据加入SPI消息队列*/

spi_message_add_tail(t, &sm);

/*4、阻塞请求传输,将数据提交给SPI控制器*/

spi_sync(spi,&sm);

SPI控制器驱动:spi_s3c64xx.c,移植和I2C类似,不过这次比较简单,将内核配置,选择64XX的SPI驱动就行了

配置

平台型驱动,控制器初始化在捕获函数中进行,数据传输在中断中进行,桥接控制器和设备的数据结构,平台资源初始化对应在:dev-spi.c文件中,和6410使用同一个驱动


struct s3c24xx_spi {

	/* bitbang has to be first */
	struct spi_bitbang  bitbang;
	struct completion  done;
	void __iomem *regs;
	int  irq;
	int  len;
	int  count;
	struct fiq_handler  fiq_handler;
	enum spi_fiq_mode  fiq_mode;
	unsigned char  fiq_inuse;
	unsigned char  fiq_claimed;	 

	void (*set_cs)(struct s3c2410_spi_info *spi,
	  int cs, int pol);	 

	/* data buffers */
	const unsigned char *tx;
	unsigned char *rx;	
	struct clk *clk;
	struct resource *ioarea;
	struct spi_master *master;
	struct spi_device *curdev;
	struct device *dev;
	struct s3c2410_spi_info *pdata;
};

SPI控制器和SPI设备驱动的函数联系

关系图

(国嵌入图)