前言
本章可与I2C章节对比阅读,体会两种通讯总线差异。本章主要对SPI协议层进行总结。
一、介绍SPI通讯
基本概念
SPI通讯是一种串行数据传输接口,通常用于在数字系统中通过高速(Mbps)的方式进行短距离通信。它被广泛应用于嵌入式系统、传感器网络、外围设备等领域。
SPI通讯设备之间的常用连接方式见下图。
工作原理
SPI通讯使用3条总线及片选线,3条总线分别为SCK、MOSI、MISO,片选线为NSS ,它们的作用介绍如下:
SCK (Serial Clock):时钟信号线,用于通讯数据同步。
MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。
MISO(Master Input,Slave Output):主设备输入/从设备输出引脚。
NSS(Slave Select):从设备选择信号线,即有几个从设备就有几个NSS引脚。

二、总线结构
基本通讯过程
这是一个主机的通讯时序。NSS、SCK、MOSI信号都由主机控制产生,而MISO的信号由从机产生。
先发送高位再发送低位,发送完一个字节之后无需应答即可开始下个字节,NSS片选从设备作为起始/终止信号

数据有效性
- 在时钟线SCK上升沿/下降沿(CPOL=0/1)时,MOSI及MISO数据传输一位 数据传输时
- MSB先行或LSB先行并没有作硬性规定,但要保证两个SPI通讯设备之间使用同样的协定
- SPI每次数据传输可以8位或16位为单位,每次传输的单位数不受限制
CPOL/CPHA及通讯模式
SPI一共有四种通讯模式,如图
| CPOL | CPHA | 空闲时SCK时钟 | 采样时刻 |
|---|---|---|---|
| 0 | 0 | 低电平 | 奇数边沿 |
| 0 | 1 | 低电平 | 偶数边沿 |
| 1 | 0 | 高电平 | 奇数边沿 |
| 1 | 1 | 高电平 | 偶数边沿 |
代码分析
- 打开SPI 总线的设备文件
- 设置SPI 工作模式
- 设置SPI通信过程中一个字节所占的位数(8)
- 设置SPI通信的波特率(500K)
static uint32_t mode = SPI_MODE_2; //用于保存 SPI 工作模式
static uint8_t bits = 8; // 接收、发送数据位数
static uint32_t speed = 500000; // 发送速度
/*
* 初始化SPI
*/
void spi_init(void)
{
int ret = 0;
/*-------------------第一部分-------------------------*/
/*打开 SPI 设备*/
fd = open("/dev/spidev2.0", O_RDWR);
if (fd < 0)
{
pabort("can't open /dev/spidev2.0 ");
}
/*-------------------第二部分-------------------------*/
/*
* spi mode 设置SPI 工作模式
*/
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*-------------------第三部分-------------------------*/
/*
* bits per word 设置一个字节的位数
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*-------------------第四部分-------------------------*/
/*
* max speed hz 设置SPI 最高工作频率
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
}
SPI发送:将要发送的数据填入结构体spi_ioc_transfer,然后调用ioctl函数执行发送
void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
/*------------------第一部分--------------------*/
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.tx_nbits = 1,
.rx_nbits = 1
};
/*------------------第二部分--------------------*/
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
{
pabort("can't send spi message");
}
}
/*-------------------第一部分---------------------*/
/*SPI 接收 、发送 缓冲区*/
unsigned char tx_buffer[100] = "hello the world !";
unsigned char rx_buffer[100];
/*-------------------第二部分---------------------*/
int main(int argc, char *argv[])
{
/*初始化SPI */
spi_init();
/*执行发送*/
transfer(fd, tx_buffer, rx_buffer, sizeof(tx_buffer));
/*打印 tx_buffer 和 rx_buffer*/
printf("tx_buffer: \n %s\n ", tx_buffer);
printf("rx_buffer: \n %s\n ", rx_buffer);
close(fd);
return 0;
}
三、SPI与I2C对比
- I2C速率:标准: 100 KHz、快速: 400 KHz、快速+: 1 MHz、高速: 3.4 MHz。
SPI速率:主要取决于 CPU 的 SPI 控制器和时钟(clock)。常用设备比如STM32F103 最高支持 18 MHz、i.MX6ULL 最高支持 52 MHz、W25Q128 最高支持 80 MHz。
因此 I2C适用于低速外围设备,多用于传输命令;SPI适用于高速应用,如SD卡、液晶屏多用于传输数据。 - IIC为半双工,SPI为全双工
- IIC有应答机制、信号,SPI无
- IIC的时钟和极性是固定的(空闲时高电平,SCL为高电平时读取数据),SPI是可以变化设置的
- 寻址方式不同,IIC是发送一个字节去寻址,SPI通过片选位选择
本文详细介绍了SPI物理层的连接方式和功能,包括SCK、MOSI、MISO和NSS的作用。进一步阐述了SPI协议层的基本通讯过程、数据有效性、CPOL/CPHA设置以及与I2C的比较,指出SPI在高速应用中的优势和I2C在低速场景的适用性。
563

被折叠的 条评论
为什么被折叠?



