[RK3399][Android7.1]spi 重要的数据结构

平台 内核版本 安卓版本
RK3399 Linux4.4 Android7.1

硬件框图

在这里插入图片描述

spi 重要的数据结构

spi_board_info

该结构主要用来匹配 spi master

struct spi_board_info {和初始化 spi_device
    char modalias[SPI_NAME_SIZE];
    const void *platform_data;
    void *controller_data;
    int  irq;
    u32 max_speed_hz;
    u16 bus_num;
    u16 chip_select;
    u8  mode;
};

其中重要的是mode:
包括属于哪种传输模式,是否是三线模式,片选信号激活时候电平高低等

在这里插入图片描述
SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置

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

如果 CPOL=0,串行同步时钟的空闲状态为低电平;
如果 CPOL=1,串行同步时钟的空闲状态为高电平。

时钟相位(CPHA)能够配置用于选择两种不同的传
输协议之一进行数据传输。
如果 CPHA=0,在串行同步时钟的第一个跳变沿(上
升或下降)数据被采样;
如果 CPHA=1,在串行同步时钟的第二个跳变沿(上升
或下降)数据被采样。

SPI 主模块和与之通信的外设备时钟相位和极性应该一致。SPI 主模块和与之通信的外设备时钟相位和极性应该一致。

其一,主设备SPI 时钟和极性的配置应该由外设来决定;

扫描二维码关注公众号,回复: 8834267 查看本文章

其二,二者的配置应该保持一致,即主
设备的 SDO 同从设备的 SDO 配置一致,主设备的 SDI 同从设备的 SDI 配置一致。因为主从设备是在 SCLK 的控制下,同时发送和接收数据,并通过 2 个双向移位寄存器来交换数据。

boardinfo

struct boardinfo {
    struct list_head list;
    unsigned n_board_info;
    struct spi_board_info board_info[0];
};

spi_board_info 与 与 boardinfo的关系:
pi_board_info:每个 spi_board_info代表一个设备,spi_board_info以数组的形式组织
boardinfoboardinfo会将 spi_board_info[]的内容拷贝过来填充其board_info[]结构,相关函数为
spi_register_board_ino(struct spi_board_info const *info, unsigned n),其中 n 代表有多少个 spi_board_info
样的数组元素。系统里可能有多个board_info,所有的 boardinfo都会连接到一个全局 SPI设备链表。

在这里插入图片描述

spi_device

spi_device{}用于spi slave 和 和cpu 之间数据传输 ,其大部分成员由spi_board_info{}结构来初始化

struct spi_device {
    struct device  dev;
    struct spi_master  *master;
    u32 max_speed_hz;
    u8  chip_select;
    u8  mode;
    u8  bits_per_word;
    int  irq;
    void *controller_state;
    void *controller_data;
    char modalias[SPI_NAME_SIZE];//SPI_NAME_SIZE=32
};

成员变量 max_speed_hz;chip_select;mode;controller_data;modalias 都是来自spi_board_info{}
master 指向所属的 master 控制器

bits_per_word对于 SPI总线协议来说,传输单位可以是 4-32 之间的任意bits,但对于SPI控制器来说,
bits_per_word只能是 8/16/32,即需要取整,待收发的数据在内存里都是以主机字节序右对齐存储,SPI 控制
器会自动根据传输单位及大小端进行转换。

spi_master

struct spi_master {
	struct device  dev;
	s16 bus_num;
	u16 num_chipselect;
	u16 dma_alignment;
	u16 mode_bits;
	u16 flags;
	int  (*setup)(struct spi_device *spi);
	int  (*transfer)(struct spi_device *spi, struct 	spi_message *mesg);
	void (*cleanup)(struct spi_device *spi);
};

transfer添加一个msgspi控制器的队列.在进行 spi 通信的时候,会先将要传输的 msg先添加到一个
主控制器的一个队列,稍后再处理这些 msg。稍后的意思一般是指将这 msg交给一个工作队列处理。

spi_transfer

struct spi_transfer {
	const void *tx_buf;
	void *rx_buf;
	unsigned len;
	dma_addr_t  tx_dma;
	dma_addr_t  rx_dma;
	unsigned cs_change:1;
	u8  bits_per_word;
	u16 delay_usecs;
	u32 speed_hz;
	struct list_head transfer_list;
};

单个spi_transfer可表示一次读,一次写或者是一次读写。在SPI controller 驱动下,所有操作常是全双
工的。控制器驱动会先写入tx 的数据,然后读取同样长度的数据。长度指示是len。如果tx_buff是空指针,
填充 rx_buff的时候会输出 0(为了产生接收的时钟),如果rx_buffNULL,接收到的数据将被丢弃。

spi_message

struct spi_message {
	struct list_head transfers;
	struct spi_device *spi;
	unsigned is_dma_mapped:1;
	void (*complete)(void *context);
	void *context;
	unsigned actual_length;
	int  status;
	struct list_head queue;
	void *state;
};

message 里面有两个链表,其中第一个 transfer 表示将所有的 spi transfer 的链表头,而 queue 一
的 般是在使用具体的 spi master 的时候,可能同时会有多个 msg 要处理,但是同一时段不能处理这么多,
为了不使信息丢失,于是就将所有待处理的 msg

在这里插入图片描述

发布了247 篇原创文章 · 获赞 93 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_33487044/article/details/91347444