一、SPI简介
1.SPI,全称SerialPerripheral Interface,也就是串行外围设备接口,是一种高速全双工穿的同步通信总线,SPI时钟频率相比I2C要高得多,最高可以达到上百MHz,SPI以主从方式工作,通常是一个主设备和一个或多个从设备,一般SPI需要4根线,也可以使用3根线(单向传输),下面介绍标准的4线通信:

  • CS/SS,Slave Select/Chip Select,这个是片选信号线,用于选择需要进行通信的从设备。
    I2C 主机是通过发送从机设备地址来选择需要进行通信的从机设备的,SPI 主机不需要发送从机
    设备,直接将相应的从机设备片选信号拉低即可。
  • SCK,串行时钟(Serial Clock),和I2C的SCL一样,为SPI通信提供时钟。
  • MOSI/SDO,主出从入信号线(Master Out Slave In/Serial Data Output),此数据线智能用于主机向从机发送数据,也就是主机输出,从机输入。
  • MISO/SDI,主入从出信号线(Master In Slave Out/Serial Data Input),此数据线智能用户从机向主机发送数据,也就是主机输入,从机输出。
    SPI通信都是由主机发起的,主机提供时钟信号,
    在这里插入图片描述

SPI四种工作模式,串行时钟极性(CPOL)和相位(CPHA)的搭配来得到四种工作模式,如图:
在这里插入图片描述

  • CPOL(极性)=0,串行时钟空闲状态为低电平。
  • CPOL(极性)=1,串行时钟空闲状态为高电平,此时可以通过配置时钟相位(CPHA)来选择具体的传输协议。
  • CPHA(相位)=0,串行时钟的第一个跳变沿(上升沿或下降沿)采集数据。
  • CPHA(相位)=1,串行时钟的第二个跳变沿(上升沿或下降沿)采集数据。

SPI全双工通信时序图,CPOL=0,CPHA=0。
在这里插入图片描述
片选(CS)信号拉低,即选中进行通信的从设备,SCLK时钟CPOL=0(极性为0是低电平),CPHA=0(相位为0,第一个跳变沿),然后MOSI发送数据0xD2(1101 0010)给从设备,同时从设备也通过MISO数据线给主设备返回0x66(110 0110)。

二、linux驱动中SPI读写代码实现

#include <linux/spi/spi.h>

struct spi_test_data{
	struct spi_device *spi_dev;
	char *tx_buf;
	char *rx_buf;
	//int tx_len;
	//int rx_len;
};
static u32 bit_per_word = 8; //每个字长的比特数
int demo_spi_read(struct spi_test_data *st,size_t len)
{
	struct spi_message msg;
	struct spi_transfer xfer = {
		.rx_buf = st->rx_buf,
		.len 	= len,
	};
	spi_message_init(&msg);
	//将spi_transfer添加到spi_message队列
	spi_message_add_tail(&xfer,&msg);
	//同步传输
	return spi_sync(st->spi_dev, &m);
}
int demo_spi_write(struct spi_test_data *st,size_t  len)
{
	struct spi_message msg;
	struct spi_transfer xfer = {
		.tx_buf = st->tx_buf,
		.len 	= len,
	};	
	spi_message_init(&msg);
	//将spi_transfer添加到spi_message队列
	spi_message_add_tail(&xfer,&msg);
	return spi_sync(st->spi_dev, &m);
}
int spi_write_then_read_demo(struct spi_test_data *st,unsigned tx_len,unsigned rx_len)
{
	int ret = -1;
	ret = spi_write_then_read(st->spi,st->tx_buf,tx_len,st->rx_buf,rx_len);
	return ret;
}
int spi_write_and_read_demo(struct spi_test_data *st,size_t len)
{
	struct spi_message msg;
	struct spi_transfer xfer = {
		.tx_buf = st->tx_buf,
		.rx_buf = st->rx_buf,
		.len 	= len,
	};	
	spi_message_init(&msg);
	//将spi_transfer添加到spi_message队列
	spi_message_add_tail(&xfer,&msg);
	return spi_sync(st->spi_dev, &m);
}

以上代码只提供思路验证,如有错误请多多批评指正

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐