SPI为串行外设接口的缩写,SPI为高速全双工同步通信总线,共使用4根线。SPI以主从方式工作,通常可以一个主设备和一个或多个从设备。需要至少4根线。MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。CS是从设备是否被主设备选中的引脚,当被选中时(通常以CS为低电平选中),主设备与从设备的操作才有效。
三、SPI总线
1、采用SPI总线的常用设备。
常用的设备有:①W25Qxx的大容量FLASH存储芯片。②SPI的小OLED屏幕。③RC522的射频RFID读卡器④MCP2515的CAN总线模块等等
2、SPI总线的优点。
①仅占用4个引脚,节约了芯片的管脚。②简单易用。③支持高速(100Mhz以上)④支持全双工
3、SPI的缺点
①没有应答机制确认是否接收到数据②没有寻址机制,只能靠片选选择不同设备③典型应用只支持单主控
4、SPI协议
SPI也为串行通讯协议,数据通过MISO和MOSI一位一位的传进传出,SCLK提供时钟脉冲,且该信号只由主设备控制,从设备不能控制。普通的串行通讯一次需连续传送8bit,而SPI允许一位一位的传送,且可暂停。
二、硬件连接
SPI总线定义两个及两个以上设备间的数据通信,提供时钟信号的为主机,接收时钟信号的设备为从机。
1、电路连接:
①单主机单从机,如下图
②单个主机和多个从机的连接
2、SPI相关寄存器
以STM32为例,与SPI相关寄存器有:
SPI控制寄存器1(SPI_CR1)
SPI控制寄存器2(SPI_CR2)
SPI状态寄存器 (SPI_SR)
SPI数据寄存器 (SPI_DR)
SPI_I2S配置寄存器(SPI_I2S_CFGR)
SPI_I2S预分频寄存器(SPI_I2SPR)
3、SPI传输模式
通过控制SPI控制寄存器1中的CPOL和CPHA位,将SPI分为4种传输模式。
Mode0 CPOL=0,CPHA=0
Mode1 CPOL=0,CPHA=1
Mode2 CPOL=1,CPHA=0
Mode3 CPOL=1,CPHA=1
时钟极性CPOL:SPI空闲时,时钟信号sclk的电平(1:空闲时高电平,0:空闲时低电平)
时钟相位CPHA:SPI在SCLK第几个边沿开始采样(0:第一个边沿开始,1:第二个边沿开始)
其中常用的为Mode0和Mode3。
4、以STM32为例,SPI初始化程序以及设置速度程序如下:
- void SPI1_Init(void)
- {
- RCC->APB2ENR|=1<<2; //PORTA时钟使能
- RCC->APB2ENR|=1<<12; //SPI1时钟使能
- //这里只针对SPI口初始化
- GPIOA->CRL&=0X000FFFFF;
- GPIOA->CRL|=0XBBB00000;//PA5.6.7复用
- GPIOA->ODR|=0X7<<5; //PA5.6.7上拉
- SPI1->CR1|=0<<10;//设置为双线双向全双工工作模式
- SPI1->CR1|=1<<9; //内部NSS信号管理:设置为软件管理
- SPI1->CR1|=1<<8;
- SPI1->CR1|=1<<2; //设置SPI为主机
- SPI1->CR1|=0<<11;//SPI发送接收8位帧数据
- SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1 空闲信号下的时钟极性
- SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1 时间相位
- SPI1->CR1|=7<<3; //Fsck=Fcpu/256 设置SPI分频系数
- SPI1->CR1|=0<<7; //定义数据以MSB位开始
- SPI1->CR1|=1<<6; //SPI设备使能
- SPI1_ReadWriteByte(0xff);//启动传输(主要作用:维持MOSI为高)
- }
- //SpeedSet:0~7
- //SPI速度=fAPB2/2^(SpeedSet+1)
- //APB2时钟一般为72Mhz
- void SPI1_SetSpeed(u8 SpeedSet)
- {
- SpeedSet&=0X07; //限制范围
- SPI1->CR1&=0XFFC7;
- SPI1->CR1|=SpeedSet<<3; //设置SPI1速度
- SPI1->CR1|=1<<6; //SPI设备使能
- }
5、SPI读写操作及时序
1、SPI的读取,以读取W25X16的ID为例,顺序为:主机拉低CS引脚,选中W25X16,主机控制SCLK引脚产生时钟信号。主机控制MOSI引脚,发送读取ID的指令0x90。
紧接着发送24位地址码。最后,读取MISO引脚,查看W25x16返回给主机的ID。
参考代码:
- u16 SPI_Flash_ReadID(void)
- {
- u16 Temp = 0;
- SPI_FLASH_CS=0;
- SPI1_ReadWriteByte(0x90);//发送读取ID命令
- SPI1_ReadWriteByte(0x00);
- SPI1_ReadWriteByte(0x00);
- SPI1_ReadWriteByte(0x00);
- Temp|=SPI1_ReadWriteByte(0xFF)<<8;
- Temp|=SPI1_ReadWriteByte(0xFF);
- SPI_FLASH_CS=1;
- return Temp;
- }
2、SPI的写入,同样以W25X16为例,指定地址写入数据的时序如下如所示,图中仅用16位数据位,可以更换为更长。
参考代码:
- void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
- {
- u16 i;
- SPI_FLASH_Write_Enable(); //SET WEL
- SPI_FLASH_CS=0; //使能器件
- SPI1_ReadWriteByte(W25X_PageProgram); //发送写页命令 (0x02)
- SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址
- SPI1_ReadWriteByte((u8)((WriteAddr)>>8));
- SPI1_ReadWriteByte((u8)WriteAddr);
- for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循环写数
- SPI_FLASH_CS=1; //取消片选
- SPI_Flash_Wait_Busy(); //等待写入结束
- }
注:文章转自电子芯客吧,侵权删。