SPI协议
SPI是一种高速,全双工,同步的通信总线,在芯片上主要占用四根线(CS、MOSI、MISO、SCK),极大的节约了芯片的引脚。
CS:片选信号,空闲状态为高电平
MOSI(master output slave input):主机输出数据,从机输入数据
MISO(master input slave output):主机输入数据,从机输出数据
SCK:用于输出时钟(在从模式下,SPI相对于该时钟传输数据)或接收时钟。
基本结构如下图:
SPI总线主要有四种工作状态,SPI0,SPI1,SPI2,SPI3,其中常用的为了SPI0和SPI3。SPI的工作状态主要由CPOL(时钟极性)和CPHA(时钟相位)决定。
CPOL=0时,SCK空闲时为低电平,CPOL=1时,SCK空闲时为高电平;
CPHA=0时,SCK的第一个跳变沿为采样数据即读取发送的数据,第二个跳变沿为输出数据,CPHA=1时,SCK的第一个跳变沿为输出数据,第二个跳变沿为采样数据。
SPI举例
当CPOL=1,CPHA=1时,即SCK空闲为高电平,第二个跳变沿为采集数据;
当主机需要发送的spi_data=8’b10101010时,在第一个跳变沿会发送mosi=1,从最高位开始输出,第二个跳变沿会读取0,第三个跳变沿输出mosi=0,以此类推;
在这个通信过程中需要三个组成部分:
计数器:计数16次,每次代表一个跳变沿;
移位器:将spi_data不断向左移,输出最高位到mosi;
分频器:生成sck波形,当空闲时拉高,启动时拉低,然后有规律的波动;
在top顶层文件中需要对状态切换进行定义,在三个子模块中,对于计数器,移位器和分频器进行编写;
SPI的输入主要有clk,rst,spi_data,spi_start;
SPI的输出主要有sck,spi_done,mosi,cs;
RTL代码
module top(
input clk,
input rst,
input [7:0] spi_data,
input spi_start,
output sck,
output mosi,
output reg cs,
output reg spi_done
);
reg a,en_a;//计数器清零和启动信号
reg b,en_b;//分频器,拉高和使能信号
reg c,en_c;//移位器,读取spi_data和移位标志信号
wire [4:0] i;//跳变沿计数;
reg [5:0] state='b0;//当前状态
reg [5:0] next_state='b0;//下一个状态
parameter s0='b000001;
parameter s1='b000010;
parameter s2='b000100;
parameter s3='b001000;
parameter s4='b010000;
parameter s5='b100000;
always@(posedge clk or negedge rst)
begin
if(!rst)
state<=s0;
else
state<=next_state;
end
always@(*)
begin
case(state)
s0: begin
if(spi_start)
next_state<=s1;
else
next_state<=s0