SPI通信协议 1

302 阅读5分钟

理论学习:

SPI(串行外围设备接口)通信协议,同步串行接口技术,是一种高速,全双工,同步通信总线,只占用四根管脚用来控制及数据传输。

应用: FLASH,EEPROM

特点: 全双工通信,通讯方式简单,相对数据传输速率较快。 没有应答机制确认数据是否接收,数据可靠性上差于IIC。

物理层:

image.png

image.png

一主一从模式: 一主多从模式:

SCK: 时钟信号线,同步通讯数据。serial clock

MOSI: 主设备输出/从设备输入

MISO: 主设备输入/从设备输出 从机到主机

CS: 片选信号,CS_N。

一主多从:

从机并联,但片选CS每个从机都有单独的一个。

SPI 协议层:

image.png

CPOL: clock polarity 时钟极性

CPHA:clock phase 时钟相位

四种模式由 CPOL 和CPHA 决定

CPOL为0: 从设备处于空闲状态,SCK时钟信号处于低电平。

CPOL为1: 从设备处于空闲状态,sck 时钟信号处于高电平

image.png

0 : 奇数沿采样 1: 偶数沿采样

CPHA为0: 为奇数边沿采样

CPHA为1: 为偶数边沿采样

四种状态:

0: 0 0 1:0 1 2:1 0 3:1 1

通信过程:

image.png

SCK完成数据同步,MOSI,MISO同时进行,一般采用高位在前。上升沿被采样,下降沿变化。

基于SPI协议的FLash控制:全擦除

1 sof文件是编译(分析、综合、布线、生成、时序)过程中生成的一个文件。 生成的sof文件是可以直接通过JTAG口下载到FPGA的SRAM中去并直接执行。 断电之后程序消失。

2 jic文件不是在编译过程中生成的,而是将sof转化得到的。 程序的固化,通过covert programming file 转化。

FLASH的全擦除:

通过下载界面,erase实现数据的擦除。

spi——flash——be

顶层模块的框图: image.png

子功能模块:

按键消抖模块: key——filter 全擦除控制模块:falsh——be——ctrl

image.png

image.png

flash_be_ctrl:

波形图绘制:

1 IDLE: 空闲状态

需要做一个大于等于5ns的等待。

2 WREN:写使能状态 8bit,8个时钟周期,640ns

需要做一个等待大于等于5ns

3 DELAY: 延时状态 大于等于100ns

需要做一个等待大于等于5ns

4 BE:全擦除指令的写入 640ns

需要做一个等待大于等于5ns

回到IDLE状态,片选信号拉高。

综上所述 需要三个时间,5 100 640 .我们使用通用的640ns来简化。使用640ns的一个计数器作为通用计数器。

640ns 计数器 系统时钟为50mhz 20ns,所以要完成32个时钟周期的计数。才能实现计数器640ns。

需要计数7个周期。 每个周期640ns。

cnt_clk; //时钟计数器 计数0-31

cnt_byte: 字节计数器,当计数器完成计数器一个周期的计数后,字节计数器加一。 0-6 七个状态

cnt_sck: 640ns实现8个byte的采样,则50mhz四分频实现。12.5mhz。此处为数据的采样时钟。 0123 三位即可

cnt_bit: 数据的存储,一个时钟周期传输一个比特。 当字节计数器为时候,sck计数器为 时候,比特计数器自加1,0-7 8个bit.

全擦除控制模块:

module flash_be_ctrl( input wire sys_clk,input wire sys_rst_n,input wire key_flag,output  cs_n,output sck,output  mosi);

parameter IDLE = 4’b0001, WREN = 4'b0010,DELAY = 4'b0100,BE = 4'b1000;

//mosi 的指令 BE_IN为全擦除指令
parameter WREN_IN = 8'B0000_0010;
          BE_IN = 8'B1100_0111;




reg mosi;
reg sck;
reg cs_n;

reg [3:0] state;

reg [5:0] cnt_clk;   //时钟计数器 计数0-31
reg [3:0] cnt_byte;  //字节计数器  时钟计数器一个周期后加一  0 -6   刚好七个周期
reg [10] cnt_sck;  // 比特计数器为1时候为1,每个时钟周期加一,实现四分频,0123,0123. 
reg [2:0] cnt_bit;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state <= IDLE;
     else
         case(state)
             IDLE: if(flag == 1'b1)
                 state <= WREN;
             WREN: if(cnt_byte == 4'b2 && cnt_clk == 6'd31)
                 state <= DELAY;
             
             DELAY:  if(cnt_byte == 4'd3 && cnt_clk == 6'd31)
                 state <= BE;
             
             BE:    if(cnt_byte == 4'd6 && cnt_clk == 6'd31)
                 state <= IDLE;

            default: state <= IDLE;
                   
        endcase
always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0)
            cnt_clk <= 5'd0;   // 5位宽会自动清零
       else if(state != IDLE)
           cnt_clk <= cnt_clk + 1'b1;
        
 always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0)          
            cnt_byte <= 4'd0;
       
       else if(cnt_byte == 4'd6 && cnt_clk == 6'd31)
           cnt_byte  <= 4'd0;
       else if(cnt_clk == 5'd31)
           cnt_byte <= cnt_byte + 1'b1;
        
always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0) 
            cnt_sck <= 2'd0;   //计满自动清零了
      else if(state ==WREN && cnt_byte == 4'd1)
          cnt_sck <= cnt_sck + 1'b1;
      else if(state ==BE& cnt_byte == 4'd5)
          cnt_sck <= cnt_sck + 1'b1;


always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0) 
            cnt_bit <= 3'd0;
       else if(cnt_sck == 2'd2)
           cnt_bit <= cnt_bit + 1'b1;
     
     
     
  // 输出信号的赋值
  always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0) 
          cs_n <= 1'b1;
      else if(key_flag == 1'b1)
          cs_n <= 1'b0;
        
       else if(cnt_byte ==4 'd2 && cnt_clk == 5'd31 && state == WREN)
             cs_n <= 1'b1;
       else if(cnt_byte ==4 'd3&& cnt_clk == 5'd31 && state == DELAY)
             cs_n <= 1'b0
       else if(cnt_byte ==4 'd2 && cnt_clk == 5'd31 && state == BE)
             cs_n <= 1'b1;

  always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0) 
            mosi <= 1'b0;
       else if(state == WREN && cnt_byte == 4'd2)
           mosi <= 1'b0;
         else if(state == BE&& cnt_byte == 4'd6 )
              mosi <= 1'b0;
         else if(state == WREN && cnt_byte == 4'd1 && cnt_sck == 2'd0)
              mosi <= WREN_IN[7-cnt_byte];   //先写入高位方法
            else if(state == BE&& cnt_byte == 4'd5&& cnt_sck == 2'd0)
              mosi <= BE_IN[7-cnt_byte];   
        
     always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0) 
          sck <= 1'b0;
      
      else if(cnt_sck == 1'b0)
          sck <= 1'b0;
      else if(cnt_sck == 2'd2)
          sck <= 1'b1;
      
 
endmodule



仿真程序:

`timescale 1ns/1ns
module tb_flash_be_ctrl();
    reg sys_clk;
    reg sys_rst_n;
    reg key_flag;
    
    
    wire cs_n;
    wire sck;
    wire mosi;
    
    
    
    
    initial 
        begin
            sys_clk = 1'b1;
            sys_rst_n <= 1'b0;
            key_flag <= 1'b0;
            
            #30
            sys_rst_n <= 1'b1;
            #1000
            key_flag <= 1'b1;
            #20
            key_flag <=1'b0;

        end
  always #10 sys_clk =~sys_clk;
    



    flash_be_ctrl flash_be_ctrl_inst(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.key_flag(key_flag), .cs_n(cs_n), .sck(sck),.mosi(mosi) );

endmodule



需要一个flash的仿真模型来验证。

顶层模块spi_flash_be

module spi_flash_be(input wire sys_clk, input wire sys_rst_n,input wirekey_in,input wire miso,output reg cs_n,output reg sck,output reg mosi);


wire key_flag;







key_filter#(.CNT_MAX(20'd999_999)   key_filter_inst
(
   .sys_clk(sys_clk),
   .sys_rst_n(sys_rst_n),
   .key_in(key_in),
   .key_flag(key_flag)

);



flash_be_ctrl flash_be_ctrl_inst(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.key_flag(key_flag), .cs_n(cs_n), .sck(sck),.mosi(mosi) );




endmodule