Linux驱动学习--SPI驱动(一)

一、spi协议介绍

1、硬件连接

DO(MOSI):Master Output ,Slave Input;SPI主控用来发出数据,SPI从设备用来接受数据

DI(MISO):Master Input,Slave Output;SPI主控用来接受数据,SPI从设备用来发送数据

SCK:时钟

CS:芯片选择引脚

2、传输实例

假设现在主控芯片要传输一个0x56数据给SPI Flash,时序如下:

首先CS0先拉低选中SPI Flash,0x56的二进制就是0b0101 0110,因此在每个SCK时钟周期,DO输出对应的电平。SPI Flash会在每个时钟周期的上升沿读取DO上的电平。

3、SPI模式

在spi协议中,有两个值来确定SPI的模式。

CPOL:表示SPICLK的初始电平,0为低电平,1为高电平

CPHA:表示相位,即第一个还是第二个时钟沿采样数据,0为第一个时钟沿,1为第二个时钟沿

CPOLCPHA模式含义
000

SPICLK初始电平为低电平,

在第一个时钟沿采样数据

011

SPICLK初始电平为低电平,

在第二个时钟沿采样数据

102

SPICLK初始电平为高电平,

在第一个时钟沿采样数据

113

SPICLK初始电平为高电平,

在第二个时钟沿采样数据

我们常见的是模式0和,因为他们都是在上升沿采集数据,不用去在乎初始电平是什么,只要在上升沿采集数据就行

二、SPI总线设备

平台总线设备驱动模型我们前面已经有讲解:

左边注册一个platform_driver结构体,里面代码比较固定,通用;

右边注册一个platform_device结构体,里面书硬件资源;

可以在C文件中注册platform_device;

也可在设备树中创建一个节点,内核解析设备树时注册platform_device

有前面的硬件连接图我们可知,SPI控制器有驱动程序,提供SPI的传输能力。

SPI设备也有自己的驱动程序,提供SPI设备的访问能力:

        他知道怎么访问这个设备,这个设备的数据含义是什么

        他会调用SPI控制器的函数来收发数据。

1、spi控制器数据结构

Linux中使用spi_master结构体描述SPI控制器,里面最重要的成员就是transfer函数指针:

2、spi设备数据结构

Linux中使用spi_device结构体描述SPI设备,里面记录有设备的片选引脚、频率、挂载在那个SPI控制器下面:

3、SPI设备驱动

Linux中使用spi_driver结构体描述SPI设备驱动:

三、SPI驱动框架

1、spi控制器驱动程序

SPI控制器的驱动程序是基于平台总线设备驱动模型来实现:

在设备树里描述SPI控制器的硬件信息,在设备树子节点里描述挂在下面的SPI设备信息

在platform_driver中提供一个probe函数

        他会注册一个spi_master

        还会解析设备树子节点,创建spi_device结构体

2、SPI设备驱动程序

跟平台总线设备模型类似,Linux中也有一个SPI总线设备驱动模型:

左边是一个spi_driver,使用C文件实现,里面有id_table表示能支持哪些SPI设备,有probe函数

右边是spi_device,用来描述SPI设备,比如他的片选引脚、频率

        可以来自设备树:比如由SPI控制器驱动程序解析设备树后创建、注册spi_devcie

        可以来自C文件:比如使用spi_register_board_info创建、注册spi_device

四、SPI设备树处理过程

1、spi_device结构体

struct spi_device {
	struct device		dev;
	struct spi_master	*master;
	u32			max_speed_hz;
	u8			chip_select;
	u8			bits_per_word;
	u16			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 */
#define	SPI_NO_CS	0x40			/* 1 dev/bus, no chipselect */
#define	SPI_READY	0x80			/* slave pulls low to pause */
#define	SPI_TX_DUAL	0x100			/* transmit with 2 wires */
#define	SPI_TX_QUAD	0x200			/* transmit with 4 wires */
#define	SPI_RX_DUAL	0x400			/* receive with 2 wires */
#define	SPI_RX_QUAD	0x800			/* receive with 4 wires */
	int			irq;
	void			*controller_state;
	void			*controller_data;
	char			modalias[SPI_NAME_SIZE];
	int			cs_gpio;	/* chip select gpio */

	/* the statistics */
	struct spi_statistics	statistics;

	/*
	 * 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
	 *  - ...
	 */
};

各个成员含义如下:

  • max_speed_hz:该设备能支持的SPI时钟最大值
  • chip_select:是这个spi_master下的第几个设备
    • 在spi_master中有一个cs_gpio数组,里面存放有下面各个spi设备的片选引脚
    • spi_device的片选引脚就是:cs_gpio[spi_device.chip_select]
  • cs_gpio:这是可选项,也可以把spi_device的片选引脚记录在这里
  • bits_per_word:每个基本的SPI传输涉及多少位
    • word:我们使用SPI控制器时,一般是往某个寄存器里写入数据,SPI控制器就会把这些数据一位一位地发送出去
    • 一个寄存器是32位的,被称为一个word(有时候也称为double word)
    • 这个寄存器里多少位会被发送出去?使用bits_per_word来表示
    • 扩展:bits_per_word是可以大于32的,也就是每次SPI传输可能会发送多于32位的数据,这适用于DMA突发传输
  • mode:含义广泛
    • SPI_CPHA:在第一个周期采样,还是在第2个周期采样?
    • SPI_CPOL:平时时钟极性
      • SPI_CPHA和SPI_CPOL组合起来就可以得到4种模式
      • SPI_MODE_0:平时SCK为低(SPI_CPOL为0),在第1个周期采样(SPI_CPHA为0)
      • SPI_MODE_1:平时SCK为低(SPI_CPOL为0),在第2个周期采样(SPI_CPHA为1)
      • SPI_MODE_2:平时SCK为高(SPI_CPOL为1),在第1个周期采样(SPI_CPHA为0)
      • SPI_MODE_3:平时SCK为高(SPI_CPOL为1),在第2个周期采样(SPI_CPHA为1)
    • SPI_CS_HIGH:一般来说片选引脚时低电平有效,SPI_CS_HIGH表示高电平有效
    • SPI_LSB_FIRST:
      • 一般来说先传输MSB(最高位),SPI_LSB_FIRST表示先传LSB(最低位);
      • 很多SPI控制器并不支持SPI_LSB_FIRST
    • SPI_3WIRE:SO、SI共用一条线
    • SPI_LOOP:回环模式,就是SO、SI连在一起
    • SPI_NO_CS:只有一个SPI设备,没有片选信号,也不需要片选信号
    • SPI_READY:SPI从设备可以拉低信号,表示暂停、表示未就绪
    • SPI_TX_DUAL:发送数据时有2条信号线
    • SPI_TX_QUAD:发送数据时有4条信号线
    • SPI_RX_DUAL:接收数据时有2条信号线
    • SPI_RX_QUAD:接收数据时有4条信号线

2、SPI Master设备树

在设备树中,对于SPI Master,必须的属性如下:

  • #address-cells:这个SPI Master下的SPI设备,需要多少个cell来表示它的片选引脚
  • #size-cell:必须设置为0
  • compatible:根据他找到SPI Master驱动

可选属性如下:

  • cs-gpio:SPI Master可以使用多个GPIO当做片选,可以在这个属性列出那些GPIO
  • num-cs:片选引脚总数

其他属性都是驱动程序相关的,不同的SPI Master驱动程序要求的属性可能不一样。

3、SPI Device设备树

在SPI Master对应的设备树节点下,每一个子节点都对应一个SPI设备,这个SPI设备连接在该SPI Master下面。

  • compatible:根据他找到SPI Device驱动
  • reg:用来表示它使用哪个片选引脚
  • spi-max-frequency:必选,该SPI设备支持的最大SPI时钟

可选属性:

  • spi-cpol:这是一个空属性,表示CPOL为1,即平时SPI时钟为低电平
  • spi-cpha:这是一个空属性,表示CPHA为1,即在时钟的第二个边沿采样数据
  • spi-cs-high:这是一个空属性,表示片选引脚高电平有效
  • spi-3wire:这是一个空属性,表示使用SPI三线模式
  • spi-lsb-first:这是一个空属性,表示使用SPI传输数据时先传输最低位(LSB)
  • spi-tx-bus-width:表示有几条MOSI引脚;没有这个属性时默认只有1条MOSI引脚
  • spi-rx-bus-width:表示有几条MISO引脚;没有这个属性时默认只有1条MISO引脚
  • spi-rx-delay-us:单位是毫秒,表示每次读传输后要延时多久
  • spi-tx-delay-us:单位是毫秒,表示每次写传输后要延时多久

4、设备树实例

使用GPIO模拟的SPI控制器

IMX6ULL SPI控制器

以上就是SPI的协议和驱动框架,以及驱动的设备在设备树中的实现

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux内核版本2.6是一个较早的版本,对于SPI总线的支持相对较为简单。SPI(Serial Peripheral Interface)是一种同步的全双工串行通信总线,可用于连接微控制器与外围设备,例如传感器、存储器等。 在Linux 2.6版本中,对于SPI总线的驱动代码主要涉及以下几个方面: 1. 初始化SPI硬件:SPI总线的初始化包括选择SPI设备、配置SPI寄存器、设置传输速率、设置SPI模式等。这通常在驱动模块的probe函数中完成。 2. 定义SPI设备:在驱动代码中,需要定义SPI设备的一些基本信息,如设备名称、ID、SPI模式、位宽等。这些信息在驱动模块中进行定义,并通过spi_register_driver函数进行注册。 3. 数据传输:SPI驱动代码需要实现与SPI设备的数据传输功能,包括发送数据和接收数据。对于发送数据,驱动代码通过spi_write函数将数据发送给SPI设备;对于接收数据,驱动代码通过spi_read函数从SPI设备接收数据。 4. 中断处理:SPI驱动代码可以通过中断处理函数来处理SPI设备发生的中断事件,以便实时响应设备的数据传输情况。中断处理函数通常与硬件平台相关,需要根据具体的硬件平台进行编写。 5. 设备节点的创建和注册:驱动代码需要创建设备节点,并通过sysfs接口将设备节点注册到/sys/class/spi目录下,以提供给用户空间进行访问和控制。 需要注意的是,以上是对于Linux 2.6版本中SPI驱动代码大致的介绍,实际的驱动代码会根据具体的硬件平台和需求进行适配和实现。对于较新的Linux内核版本,SPI驱动代码的实现可能会有所不同,更加灵活和强大。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值