文章目录
- 一、SPI 简介
- 二、SPI四线
- 三、SPI四种工作模式
- 3.1 CPOL与CPHA
- CHOL
- CPHA
- 3.2 四种工作模式
- 四、多种传输速率
- 五、SPI时序图
- 六、使用IO口模拟SPI代码
一、SPI 简介
SPI 全称是 Serial Perripheral Interface,也就是串行外设接口。 SPI 是 Motorola 公司推出的一种同步串行接口技术,是一种高速、全双工的同步通信总线, SPI 时钟频率相比 I2C 要高很多,最高可以工作在上百 MHz。 SPI 以主从方式工作,通常是有一个主设备和一个或多个从设备, SPI 一般需要4 根线,但是也可以使用三根线(单向传输)。一般由SCLK、CS、MOSI,MISO四根线组成,有的地方可能是:SCK、SS、SDI、SDO等名称,都是一样的含义,当有多个从机存在时,通过CS来选择要控制的从机设备。
二、SPI四线
- CS/SS, Slave Select/Chip Select,这个是片选信号线,用于选择需要进行通信的从设备。SPI 由主机控制,直接将相应的从机设备片选信号拉低,使能从设备通信。
- SCK, Serial Clock,串行时钟信号,由主设备产生,为 SPI 通信提供时钟。
- MOSI/SDO, Master Out Slave In/Serial Data Output,主设备数据输出,从设备数据输入。
- MISO/SDI, Master In Slave Out/Serial Data Input,主设备数据输入,从设备数据输出。
SPI 通信都是由主机发起的,主机需要提供通信的时钟信号。主机通过 SPI 线连接多个从设备的结构如下图所示:
三、SPI四种工作模式
既然是进行数据传输,双方就要明确从机在什么时刻去采样主机发出的数据,主机在什么时刻去读取从机发来的数据。对于MCU自带的硬件SPI外设来说,只需要配置工具中配置一下模式就行了,但是对于使用使用GPIO模拟或者FPGA来实现SPI的时序,这一点是非常重要的,这就涉及到SPI标准协议的工作模式了,通过CPOL(Clock Polarity)时钟极性和CPHA(Clock Phase)时钟相位的不同组合,可以分为4种模式。
3.1 CPOL与CPHA
CHOL
CPOL即Clock Polarity,就是时钟信号的极性。
时钟的极性是什么概念呢?
通信的整个过程分为空闲时间和通信时间,如果SCLK在数据发送之前和之后的空闲状态是高电平,那么就是CPOL=1;如果空闲状态SCLK是低电平,那么就是 CPOL=0。
CPHA
CPHA即Clock Phase,就是时钟的相位。
主机和从机要交换数据,牵涉到一个问题:主机在什么时刻输出数据到MOSI上而从机在什么时刻采样这个数据?
同步通信的一个特点就是所有数据的变化和采样都是伴随着时钟沿进行的,也就是说数据总是在时钟的边沿附近变化或被采样。而一个时钟周期必定包含了一个上升沿和一个下降沿,这是周期的定义所决定的,只是这两个沿的先后并无规定。
又因为数据从产生的时刻到它的稳定是需要一定时间的,那么,如果主机在上升沿输出数据到MOSI上,从机就只能在下降沿去采样这个数据了。反之如果一方在下降沿输出数据,那么另一方就必须在上升沿采样这个数据。
CPHA=1,就表示数据的输出是在一个时钟周期的第一个沿上,至于这个沿是上升沿还是下降沿,这要视CPOL的值而定,CPOL=1 那就是下降沿,反之就是上升沿。那么数据的采样自然就是在第二个沿上了。
CPHA=0,就表示数据的采样是在一个时钟周期的第一个沿上,同样它是什么沿由 CPOL 决定。那么数据的输出自然就在第二个沿上了。
仔细想一下,这里会有一个问题:就是当一帧数据开始传输第一个 bit 时,在第一个时钟沿上就采样该数据了,那么它是在什么时候输出来的呢?有两种情况:一是 SSEL 使能的边沿,二是上一帧数据的最后一个时钟沿,有时两种情况还会同时生效。
3.2 四种工作模式
一般从机器件的工作模式是固定的,主机需要采用一样的工作模式,双方才能正常“交流”。
SPI 有四种工作模式,通过串行时钟极性(CPOL)和相位(CPHA)的搭配来得到四种工作模式:
- CPOL=0,串行时钟空闲状态为低电平。
- CPOL=1,串行时钟空闲状态为高电平,此时可以通过配置时钟相位(CPHA)来选择具体的传输协议。
- CPHA=0,串行时钟的第一个跳变沿(上升沿或下降沿)采集数据。
- CPHA=1,串行时钟的第二个跳变沿(上升沿或下降沿)采集数据。
这四种工作模式如下图所示:
模式速记方法:
| 模式 | CPOL | CPHA | 二进制数 |
|---|---|---|---|
| 0 | 0 | 0 | 00 |
| 1 | 0 | 1 | 01 |
| 2 | 1 | 0 | 10 |
| 3 | 1 | 1 | 11 |
每种模式与CPOL和CPHA也很好记,即CPOL和CPHA组成的二进制数的大小。例如,模式1,1对应的二进制数为01,则CPOL=0, CPHA=1,串行时钟空闲状态为低电平,时钟的第二个跳变沿进行信号采样。
这四种模式中,应用最广泛的是模式0和3,大多数SPI器件都同时支持这两种工作模式,其实这些都不重要,具体采用什么模式,看器件手册就知道了。
四、多种传输速率
SCK的速率就是SPI的传输速率,SPI协议没有一个固定的速率,不像IIC标准模式100K,快速模式400K,高速模式3.4M,SPI的传输速率取决于器件本身支持多高的速率
五、SPI时序图
以 CPOL=0, CPHA=0 这个工作模式为例, SPI 进行全双工通信的时序如下图所示:
从上图可以看出, SPI 的时序图很简单,不像 I2C 那样还要分为读时序和写时序,因为 SPI 是全双工的,所以读写时序可以一起完成。图中CS 片选信号先拉低,选中要通信的从设备,然后通过 MOSI 和 MISO 这两根数据线进行收发数据, MOSI 数据线发出了0XD2 这个数据给从设备,同时从设备也通过 MISO 线给主设备返回了 0X66 这个数据。这个就是 SPI 时序图。
六、使用IO口模拟SPI代码
/* CPOL = 0, CPHA = 0, MSB first */ uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat ) { uint8_t i, read_dat; for( i = 0; i < 8; i++ ) { if( write_dat & 0x80 ) MOSI_H; else MOSI_L; write_dat <<= 1; delay_us(1); SCK_H; read_dat <<= 1; if( MISO ) read_dat++; delay_us(1); SCK_L; __nop(); } return read_dat; } /* CPOL=0,CPHA=1, MSB first */ uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) { uint8_t i,Temp=0; for(i=0;i<8;i++) // 循环8次 { SCK_H; //拉高时钟 if(byte&0x80) { MOSI_H; //若最到位为高,则输出高 } else { MOSI_L; //若最到位为低,则输出低 } byte <<= 1; // 低一位移位到最高位 delay_us(1); SCK_L; //拉低时钟 Temp <<= 1; //数据左移 if(MISO) Temp++; //若从从机接收到高电平,数据自加一 delay_us(1); } return (Temp); //返回数据 } /* CPOL=1,CPHA=0, MSB first */ uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) { uint8_t i,Temp=0; for(i=0;i<8;i++) // 循环8次 { if(byte&0x80) { MOSI_H; //若最到位为高,则输出高 } else { MOSI_L; //若最到位为低,则输出低 } byte <<= 1; // 低一位移位到最高位 delay_us(1); SCK_L; //拉低时钟 Temp <<= 1; //数据左移 if(MISO) Temp++; //若从从机接收到高电平,数据自加一 delay_us(1); SCK_H; //拉高时钟 } return (Temp); //返回数据 } /* CPOL = 1, CPHA = 1, MSB first */ uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat ) { uint8_t i, read_dat; for( i = 0; i < 8; i++ ) { SCK_L; if( write_dat & 0x80 ) MOSI_H; else MOSI_L; write_dat <<= 1; delay_us(1); SCK_H; read_dat <<= 1; if( MISO ) read_dat++; delay_us(1); __nop(); } return read_dat; }