SPi通信详解-以W25QXX系列为编程实例

1 篇文章 0 订阅

目录

为了更好地理解什么的SPI首先可以先探讨一下这几个问题:

问题一:什么是SPI通信呢?

问题二:相对于其他通信方式,SPI通信的优缺点在哪里呢?

问题三:SPI通信主要在什么地方应用呢?

SPI的讲解:

1.SPI的引脚定义

2.SPI的连接图示

3.SPI的数据收发过程

4.SPI的四种工作模式

5.SPI通信时序的分析

SPI通信实例:

1.写移位寄存器函数分析

2.测试主机与flash的SPI通信是否正常

3.主机读flash

4.主机擦除flash扇区


为了更好地理解什么的SPI首先可以先探讨一下这几个问题:

问题一:什么是SPI通信呢?

定义:SPI 的英文全称为 Serial Peripheral Interface,顾名思义为串行外设接口。SPI 是一种同步串行通信接口规范,主要应用于嵌入式系统中的短距离通信。该接口由摩托罗拉在20世纪80年代中期开发,后发展成了行业规范。--------->SPI是一种通信规范


问题二:相对于其他通信方式,SPI通信的优缺点在哪里呢?


问题三:SPI通信主要在什么地方应用呢?

        基于其数据传输速度相对较快,但通信距离相对较近的特点。SPI主要应用于EEPROM、FLASH、ADC、DAC 等芯片,还有数字信号处理器和数字信号解码器之间。本文举例的就是主控MCU与外扩flash进行的SPI通信。


SPI的讲解:

1.SPI的引脚定义

MISO: 主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
MOSI: 主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
SCLK:串行时钟信号,由主设备产生。
CS/SS:从设备片选信号,由主设备控制。它的功能是用来作为“片选引脚”,也就是选择指定的从设备,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。

2.SPI的连接图示

SPI除了支持一对一通信以外,还支持一主多从的通信:

SPI一对一:

SPI一对多:

3.SPI的数据收发过程

        SPI主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。

1.首先拉低对应SS/CS信号线,表示与该设备进行通信。
2.主机通过发送SCLK时钟信号,来告诉从机写数据或者读数据,这里要注意,SCLK时钟信号可能是低电平有效,也可能是高电平有效,因为SPI有四种模式,这个我们在下面会介绍。
3.主机(Master)将要发送的数据写到发送数据缓存区(Menory),缓存区经过移位寄存器(0~7),串行移位寄存器通过MOSI信号线将字节一位一位的移出去传送给从机,同时MISO接口接收到的数据经过移位寄存器一位一位的移到接收缓存区。
4.从机(Slave)也将自己的串行移位寄存器(0~7)中的内容通过MISO信号线返回给主机。同时通过MOSI信号线接收主机发送的数据。这样,两个移位寄存器中的内容就被交换。

4.SPI的四种工作模式

SPI的工作模式是由CPOL(时钟极性)和CPHA(时钟相位)来控制的。

那么为什么要对工作模式进行设置呢?

        不同的从设备可能在出厂是就是配置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来控制我们主设备的通信模式。

1.时钟极性(CPOL)定义了时钟空闲状态电平:

    CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
    CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时

2.时钟相位(CPHA)定义数据的采集时间:

    CPHA=0,在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。,在第2个边沿发送数据
    CPHA=1,在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。,在第1个边沿发送数据

        

对应的工作模式如下图所示:

对应的有效采样点如下图所示:

5.SPI通信时序的分析

如下图所示:

从这张时序图我们能获取什么信息呢?

1.不管是主机发送数据到从机还是从机发送数据到主机,实际上是一个字节交换的过程。

2.数据交互过程中,需要注意的是数据是高位先行还是低位先行。(通常是高位先行)

3.根据工作模式确定采样点,也可以通过时序图的采样点来确定工作模式。

4.在主机从机进行数据交换的时候CS/NSS片选线一定要拉低。

SPI通信实例:

1.写移位寄存器函数分析

        函数在写一个字节到移位寄存器后,会接收一个字节,符合字节交换原则.

unsigned char SPI_Write(uint8_t data)
{
    unsigned char i,RX_Data = 0,Byte_Num = 0x80;
    
    for(i=0;i<0x08;i++)
    {
        FLASH_CLK(0);
        if(data & Byte_Num)
        {
            FLASH_MOSI(1);
        }
        else
        {
            FLASH_MOSI(0);
        }
        
        if(Byte_Num > 0x01)
        {
            Byte_Num = Byte_Num >> 1;
        }
        FLASH_CLK(1);
        if(SPI_MISO)
        {
            RX_Data |= 0x01;
        }
        if(i < 7)
        {
            RX_Data = RX_Data << 1;
        }
    }
    return RX_Data;
}

2.测试主机与flash的SPI通信是否正常

        在我们正式开始写入读取前,我们要先测试单片机与w25qxx是否正常通信,我们通过读取w25qxx的ID号来判断是否连接正常,我们发送0x90,然后dummy代表任意的数字,但我们按这个格式发送后,他会自动返回ID值。

u16 W25QXX_ReadID(void)
{
    u16 Temp = 0;      
    W25QXX_CS=0;                    
    SPI2_ReadWriteByte(0x90);//发送读取ID命令        
    SPI2_ReadWriteByte(0x00);         
    SPI2_ReadWriteByte(0x00);         
    SPI2_ReadWriteByte(0x00);                     
    Temp|=SPI2_ReadWriteByte(0x00)<<8;  
    Temp|=SPI2_ReadWriteByte(0x00);     
    W25QXX_CS=1;                    
    return Temp;

}

3.主机读flash

        要读取flash的值,首先使能器件,然后发送读取的命令,由图我们可以知道指令为0x90,发送需要读取的地址后,便能读取到flash上的数据。

void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{
     u16 i;                                               
    W25QXX_CS=0;                                //使能器件   
    SPI2_ReadWriteByte(W25X_ReadData);             //发送读取命令   
    SPI2_ReadWriteByte((u8)((ReadAddr)>>16));      //发送24bit地址    
    SPI2_ReadWriteByte((u8)((ReadAddr)>>8));   
    SPI2_ReadWriteByte((u8)ReadAddr);   
    for(i=0;i<NumByteToRead;i++)
    {
        pBuffer[i]=SPI2_ReadWriteByte(0XFF);       //循环读数  0xff可以为任何数,只是为了产生时钟信号
    }
    W25QXX_CS=1;                                
}

4.主机擦除flash扇区

        在写入之前,我们先把扇区的数据擦除干净,也是和上面一样,先使能片选线,然后发送指令,发送擦除地址,w25q开始擦除,擦除后通过busy位来判断是否擦除完成。

void W25QXX_Erase_Sector(u32 Dst_Addr)   
{  
    //监视falsh擦除情况,测试用   
     printf("fe:%x\r\n",Dst_Addr);      
     Dst_Addr*=4096;
    W25QXX_Write_Enable();                      //SET WEL      
    W25QXX_Wait_Busy();   
      W25QXX_CS=0;                                //使能器件   
    SPI2_ReadWriteByte(W25X_SectorErase);          //发送扇区擦除指令
    SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));      //发送24bit地址    
    SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));   
    SPI2_ReadWriteByte((u8)Dst_Addr);  
    W25QXX_CS=1;                                //取消片选               
    W25QXX_Wait_Busy();                              //等待擦除完成
}  
 
//等待空闲
void W25QXX_Wait_Busy(void)   
{   
    while((W25QXX_ReadSR()&0x01)==0x01);          // 等待BUSY位清空
}  

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值