spi总线之通信原理及linux驱动读写实现

一、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);
}

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

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeAmmon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值