一,SPI简介
SPI(Serial Peripheral Interface---串行外设接口),Motorola首先在MC68HCXX系列处理器上定义的。SPI接口主要用在EEPROM、FLASH、实时时钟、AD转换器、还有数字信号处理器和数字信号解码器之间等主从设备之间通信,一主一从,一主多从,多主多从等,同一时间只允许一个主机;可配置为主机模式侦测功能,避免多主机冲突。
SPI接口是在CPU和外围低速器件之间进行同步串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,低位在后,为全双工通信、高速、同步传输,数据传输速度总体来说要比I2C总线要快,速度可达几Mbps。
SPI主要使用4根线,SCLK、MOSI、MISO、NSS。
二,工作原理
1. 硬件的工作原理:(以单主单从为例)
现在很多主从设备都内置了SPI通信模块,可寄存器配置其工作速率、移位时钟的相位和极性、中断、溢出等工作状态;这里就不一一介绍,请读具体的SPC,以下主要介绍起数据传输的工作原理;
这里有两个参数需要注意:移位时钟的相位和极性;
极性---CPOL,决定其空闲时SCLK的电平,0为低;1为高。
相位---CPHA,决定其采样时间,0为第一个跳变沿采样;1为第二个跳变沿采样。
本文主要讲解空闲时高电平,第一个跳变沿采样的情况,其他情况简单叙述;
SPI发送端是单缓冲器,向数据寄存器中写时,不锁存直接并行写入移位寄存器中;
SPI接收端是双缓冲器,数据寄存器锁存数据,当读取完成后,移位寄存器才向数据寄存器中写数据。
参照网上,主机发送0b10110001,从机发送0b10110001。
每次都是主机发起传输,首先片选信号NSS使能,然后移位时钟振动;主机/从机将待发送的数据写入数据寄存器,如果SPI移位寄存器为空,发送缓冲器中的数据传入移位寄存器,数据开始传输。
1. 主机把移位寄存器中的MSB发送到从机并数据移位。要保证从机在第一个跳变沿采样并锁存MOSI的数据,主机需要在第一个下降沿前半个周期左右,将MSB发送出去,即MOSI=1;
2. 从机要把移位寄存器中的MSB发送到主机。同样,要保证主机在第一个跳变沿能采样到数据,从机需要在NSS使能的时候就把MSB发送出去,即MISO=0;
3. 第一个跳变沿,从机采样并锁存MOSI线,主机采样锁存MISO线;
4. 第二个跳变沿,数据移入移位寄存器中,主机/从机发送第二位数据到总线上;
5. 第一位发送完成,此时主机移位寄存器是0b01100011,从机为0b01100011;
6. 重复3、4、5过程,直到8位数据发送完成。
简单的,主机和从机的两个数据寄存器可被认为是一个16位的循环位移寄存器。主机向从机发数据,从机向主机推数据,实现数据的交换,即全双工通信;
其中,某些标志位,如传输完成标志位,是硬件置位的,需要手动软件清零,然后才开始下一次传输。
注意:
数据传输完成前保持低电平,如果SS变为高,SPI将强制进入空闲状态;如果传输过程中置高,传输被取消,同时接受数据的缓冲区也进入空闲状态。根据不同的设备,保存或清除数据;
写冲突错误,溢出错误等都需要根据具体设备的SPC来参考,大部分都是由于主从主频或相应速度相差太大,或受到外界干扰,造成发送端发送过快,或接收端接收过慢,使得数据被覆盖等,这里不一一叙述;
2. 软件模拟
此处为没有SPI接口的设备提供时序的软件模拟,单向传输。不同的设备,timing不同,需要各个击破;
void SPI_BIT_FORMAT(unsigned char Flag) { SPI_SCL_Low(); if(Flag){ SPI_SDI_Hi(); } else { SPI_SDI_Low(); } SPI_Delay(); SPI_SCL_Hi(); SPI_Delay(); }
void SPI_8b_Out_Data(unsigned char Byte) { unsigned char i, temp,tmp2; tmp2 = Byte; temp=tmp2; for(i=0;i<8;i++){ temp &= 0x80; if(temp == 0x80) SPI_BIT_FORMAT(1); else SPI_BIT_FORMAT(0); tmp2 <<= 1; temp = tmp2; } }
void SPI_3W_SET_CMD(unsigned char CMD) { SPI_8b_Out_Data(CMD); SPI_SDI_Hi(); }
三,优缺点
SPI: 高速同步串行通信,收发独立,可同步进行,实现简单;但是缺乏流控机制,无法对数据确认,并且主机无法知道从机的工作状态,需要软件弥补;主从设备的运行频率相差不应太大,会造成丢失数据。
IIC: 线少,但是需要双向IO口,使用上拉电阻,软件实现较复杂,速度较SPI慢;不能实现全双工。
UART: 需要固定的波特率;
(备注:个人心得,若有错误请指正,谢谢! 小V)