SPI通讯的个人理解

SPI一共有四根信号线CS、CLK、MOSI、MISO  从设备选择信号线、串行SPI通信的时钟信号、主设备输出从设备输入、主设备输入从设备输出信号线。在硬件上主设备和从设备的两条数据线MOSI和MISO要相互交叉连接(个人理解成串口通信时的TX发接RX,RX接TX)。SPI的数据采集和传输依赖于CLK,一个周期的时钟移动一个位的数据。下面是SPI的时序图,从图中可以看出CPHA和CPOL的作用和意义。

SPI通讯的个人理解
SPI的时序图

 从SPI的时序图可以明显的看出CPHA的作用是控制数据采样的点如CPHA=1时数据在跳变后一个时钟采样,上升沿采样还是下降沿采样数据由CPOL决定(也决定了CLK空闲时刻的电平情况)。所以我们在使用单片机自带的硬件SPI的时候这些配置就很重要了,这关系到是否能通讯成功。

SPI的配置一般有以下步骤:1、配置SPI的硬件SPI相应的引脚。2、开启GPIO时钟和SPI时钟。3、配置SPI的主从模式。4、配置SPI的CPHA和CPOL。5、配置SPI的数据宽度。6、配置SPI的移位是LSB或者是MSB。7、配置SPI的传输速度。8、如有多个SPI的一半还有SPI的选择配置。一般大致就是这些就基本OK了。

下面是谋产品的SPI的通信时序图。

SPI通讯的个人理解

 从该图给出的时序图就知道需要配置CPHA=1,CPOL=0;即时钟空闲的时候为低电平状态,当被主设备选中CS拉低之后的时钟在跳变后的下降沿采样数据。

当然在编写SPI的读写程序的时候也需要注意一点,写数据的时候将数据放到SPI的发送寄存器的时候会自动产生硬件的时钟CLK和数据写的电平。但是读数据的时候需要SPI主设备的发送空数据来产生时钟使从设备的数据移位到主设备中。

SPI的读写程序:

void SPI_write(u8 addr, u32 data,u8 len)
{
    uint8_t i,B;
    GPIO->PBCLR =1<<4;
    SPI->STA |=0<<0; 
    SPI->TX = (1<<7)|(0XFF&addr);  //起始第一位为1是写数据
    while(SPI->STA&0X10);
    
    for(i=len;i>0;i--)
    {
        B=(data>>8*(i-1));
        SPI->STA |=0<<0; 
        SPI->TX = 0XFF&B;
        while(SPI->STA&0X10);    
    }
    
    GPIO->PBSET = 1<<4;
}


u32 SPI_Read(u8 addr,u8 len)
{
    uint32_t ReadData,B;
    uint8_t i;
    
    GPIO->PBCLR =1<<4;
    SPI->STA |=0<<0; 
    SPI->TX = 0Xff&addr;
    while(SPI->STA&0X10);
    
    for(i=0;i<len;i++)
    {
        SPI->STA |=0<<0; 
        SPI->TX = 0Xff;  //读从设备数据的时候发送空数据产生时钟CLK
        while(SPI->STA&0X10);
        ReadData = (ReadData <<8)|(SPI->RX &0XFF);  //数据移位
    }
    
    GPIO->PBSET = 1<<4;
    return ReadData;
}

记录自己对SPI的理解。