理论学习:
SPI(串行外围设备接口)通信协议,同步串行接口技术,是一种高速,全双工,同步通信总线,只占用四根管脚用来控制及数据传输。
应用: FLASH,EEPROM
特点: 全双工通信,通讯方式简单,相对数据传输速率较快。 没有应答机制确认数据是否接收,数据可靠性上差于IIC。
物理层:
一主一从模式: 一主多从模式:
SCK: 时钟信号线,同步通讯数据。serial clock
MOSI: 主设备输出/从设备输入
MISO: 主设备输入/从设备输出 从机到主机
CS: 片选信号,CS_N。
一主多从:
从机并联,但片选CS每个从机都有单独的一个。
SPI 协议层:
CPOL: clock polarity 时钟极性
CPHA:clock phase 时钟相位
四种模式由 CPOL 和CPHA 决定
CPOL为0: 从设备处于空闲状态,SCK时钟信号处于低电平。
CPOL为1: 从设备处于空闲状态,sck 时钟信号处于高电平
0 : 奇数沿采样 1: 偶数沿采样
CPHA为0: 为奇数边沿采样
CPHA为1: 为偶数边沿采样
四种状态:
0: 0 0 1:0 1 2:1 0 3:1 1
通信过程:
SCK完成数据同步,MOSI,MISO同时进行,一般采用高位在前。上升沿被采样,下降沿变化。
基于SPI协议的FLash控制:全擦除
1 sof文件是编译(分析、综合、布线、生成、时序)过程中生成的一个文件。 生成的sof文件是可以直接通过JTAG口下载到FPGA的SRAM中去并直接执行。 断电之后程序消失。
2 jic文件不是在编译过程中生成的,而是将sof转化得到的。 程序的固化,通过covert programming file 转化。
FLASH的全擦除:
通过下载界面,erase实现数据的擦除。
spi——flash——be
顶层模块的框图:
子功能模块:
按键消抖模块: key——filter 全擦除控制模块:falsh——be——ctrl
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