前面几篇详细 介绍了SPI的原理,并且实现了对flash芯片的写使能,读状态,擦除,页读,页写

​​​​​​FPGA——SPI总线详解(概念)_居安士的博客-CSDN博客_fpga芯片

FPGA——SPI总线控制flash(1)(含代码)_居安士的博客-CSDN博客

FPGA——SPI总线控制flash(2)(含代码)_居安士的博客-CSDN博客

接下来我们需要将各个模块汇合到一起:

目录

总线应答模块

SPI控制模块

SPI_FLASH总模块


总线应答模块

之前的总线应答都是写在TB文件里面,现在所以模块写齐了之后,需要将多个模块的总线应答汇总在一个模块里,根据请求总线的信号,回复ack。当接收到总线同意通信的信号后,将spi_cs ,spi_clk ,spi_dout ,spi_din传递给总线,传递结束后,请求总线关闭,回复ack。

总线控制模块需要完成的任务:

  1. 控制5个模块(写使能,读状态,擦除,页写,页读)的总线应答
  2. 根据模块给spi_bus信号(spi_cs ,spi_clk ,spi_dout ,spi_din)
  3. 流程图如下:

0:给5个模块分配标号

1:在请求总线开放信号到来时,根据标号给总线应答开放信号

2:在请求总线关闭信号到来时,采请求总线下降沿,给总线应答关闭信号

总线一次只能通信一个模块,根据分配的标号,将模块输出的spi_cs ,spi_clk ,spi_dout给总线,总线输出的spi_din给模块

module mux_top(
input clk,
input reset,
//写使能
input mux_wren           ,
output reg  mux_wren_done,
input spi_cs1            ,
input spi_clk1           ,
input spi_dout1          ,
output reg spi_din1      ,
//读状态
input mux_status           ,
output reg  mux_status_done,
input spi_cs2              ,
input spi_clk2             ,
input spi_dout2            ,
output reg spi_din2        ,
//擦除
input mux_earse            ,
output reg  mux_earse_done ,
input spi_cs3              ,
input spi_clk3             ,
input spi_dout3            ,
output reg spi_din3        ,
//页写
input mux_write            ,
output reg  mux_write_done ,
input spi_cs4              ,
input spi_clk4             ,
input spi_dout4            ,
output reg spi_din4        ,
//页读
input mux_read             ,
output reg  mux_read_done  ,
input spi_cs5              ,
input spi_clk5             ,
input spi_dout5            ,
output reg spi_din5        ,
//总线bus
input spi_din  ,
output spi_cs  ,
output spi_clk ,
output spi_dout);//输入打一拍reg mux_wren_dly  ;reg mux_status_dly;reg mux_earse_dly ;reg mux_write_dly ;reg mux_read_dly  ;always@(posedge clk)beginif(reset)beginmux_wren_dly   <=1'd0;mux_status_dly <=1'd0;mux_earse_dly  <=1'd0;mux_write_dly  <=1'd0;mux_read_dly   <=1'd0;endelse beginmux_wren_dly   <=mux_wren  ;mux_status_dly <=mux_status;mux_earse_dly  <=mux_earse ;mux_write_dly  <=mux_write ;mux_read_dly   <=mux_read  ;endendreg [2:0] mux_mode;//选择写、读、擦除等模式reg [1:0] state;//状态机always@(posedge clk)beginif(reset)beginmux_mode<=1'd0;state<=2'd0;endelse beginmux_wren_done  <=1'd0;mux_status_done<=1'd0;mux_earse_done <=1'd0;mux_write_done <=1'd0;mux_read_done  <=1'd0;case(state)2'd0:begin //根据请求总线的信号选择当前模式if(mux_wren_dly)beginmux_mode<=3'd1;state<=2'd1;endelse if(mux_status_dly)beginmux_mode<=3'd2;state<=2'd1;endelse if(mux_earse_dly)beginmux_mode<=3'd3;state<=2'd1;endelse if(mux_write_dly)beginmux_mode<=3'd4;state<=2'd1;endelse if(mux_read_dly)beginmux_mode<=3'd5;state<=2'd1;endelse beginmux_mode<=3'd0;state<=2'd0;endend2'd1:begin//回复同意开启总线case(mux_mode)3'd1:mux_wren_done<=1'd1;3'd2:mux_status_done<=1'd1;3'd3:mux_earse_done<=1'd1;3'd4:mux_write_done<=1'd1;3'd5:mux_read_done<=1'd1;endcasestate<=2'd2;end2'd2:begin//回复关闭总线if(~mux_wren&&mux_wren_dly)begin//在mux_wren下降沿mux_wren_done<=1'd1;state<=2'd0;endelse if(~mux_status&&mux_status_dly)beginmux_status_done<=1'd1;state<=2'd0;endelse if(~mux_earse&&mux_earse_dly)beginmux_earse_done<=1'd1;state<=2'd0;endelse if(~mux_write&&mux_write_dly)beginmux_write_done<=1'd1;state<=2'd0;endelse if(~mux_read&&mux_read_dly)beginmux_read_done<=1'd1;state<=2'd0;endendendcaseendend//总线经过选择之后,发送csassign spi_cs=(mux_mode==3'd1)?spi_cs1(mux_mode==3'd2)?spi_cs2(mux_mode==3'd3)?spi_cs3(mux_mode==3'd4)?spi_cs4(mux_mode==3'd5)?spi_cs51'd1;//总线经过选择之后,发送clk                       assign spi_clk =(mux_mode==3'd1)? spi_clk1 :(mux_mode==3'd2)? spi_clk2 :(mux_mode==3'd3)? spi_clk3 :(mux_mode==3'd4)? spi_clk4 :(mux_mode==3'd5)? spi_clk5 :1'd0;//总线经过选择之后,发送dout               assign spi_dout =(mux_mode==3'd1)? spi_dout1 :(mux_mode==3'd2)? spi_dout2 :(mux_mode==3'd3)? spi_dout3 :(mux_mode==3'd4)? spi_dout4 :(mux_mode==3'd5)? spi_dout5 :1'd1;
//把输出的din给模块
always@(*)beginif(mux_mode==3'd2)beginspi_din2=spi_din;endelse if (mux_mode==3'd5)beginspi_din5=spi_din;endelse beginspi_din2=1'd1;spi_din5=1'd1;endendendmodule

SPI控制模块

spi控制模块需要完成的任务是:

1 定义操作启动信号,利用操作启动信号来控制每种模块的启动信号

定义操作信号(0~9),根据操作指令来控制spi里面5个模块(写使能,读状态,擦除,页写,页读)的每种指令

2 输入想要控制spi里面模块的地址和突发长度

3 输出写类完成信号(写使能,擦除,页写)和读类完成信号(读状态,页读),

以及总线忙信号和总线不忙信号

4 控制写使能模块:输出启动写使能信号,输出写使能指令

5 控制读状态模块:输出启动读状态信号,输出读状态指令,输入读状态数据

6 控制擦除模块:输出启动擦除信号,输出擦除指令,输出擦除的地址

7 控制页写模块:输出页写擦除信号,输出页写指令,输出页写的地址,输出页写的突发长度

8 控制页读模块:输出页读擦除信号,输出页读指令,输出页读的地址,输出页读的突发长度,输入页读的数据

编写代码如下:

module spi_control(
input clk,
input reset,
//操作信号
input       op_en          ,//启动操作
input [3:0] op_cmd         ,//0:写使能04h 1:写使能06h 2:读状态05h 3:读状态35h 4:擦除20h 5:擦除52h 6:擦除D8h 7:擦除整片 8:页写 9:页读
input [23:0]op_addr        ,
input [8:0] op_brust_length,
output reg  wr_cmd_done    , //返回写类done:写使能,页写,擦除
output reg  rd_cmd_done    ,//返回读类done:读状态寄存器,页读
output reg  rd_cmd_fail    ,//读状态寄存器为忙
output reg  status_ok      ,//写使能
output reg start_wr        ,
output reg wren_cmd        ,
input      wren_done       ,
//读状态
output reg start_status    ,
output reg status_cmd      ,
input[7:0] status_data     ,
input      status_done     ,
//擦除
output reg       start_erase ,
output reg [1:0] erase_cmd   ,
output reg [23:0]erase_addr  ,
input            erase_done  ,
//页写
output reg       start_write      ,
output reg [8:0] wr_brust_length     ,
output reg [23:0]write_addr       ,
input            write_done       ,
//页读
output reg       start_read      ,
output reg [8:0] rd_brust_length    ,
output reg [23:0]read_addr       ,
input            read_done       );//输出start信号和对应的命令always@(posedge clk)beginif(reset)beginwr_cmd_done <=1'd0;rd_cmd_done <=1'd0;rd_cmd_fail <=1'd0;status_ok   <=1'd0;start_wr       <=1'd0;wren_cmd       <=1'd0;start_status   <=1'd0;status_cmd     <=1'd0;start_erase    <=1'd0;erase_cmd      <=2'd0;erase_addr     <=24'd0;start_write    <=1'd0;wr_brust_length<=8'd0;write_addr     <=24'd0;start_read     <=1'd0;rd_brust_length<=8'd0;read_addr      <=24'd0;endelse beginif(op_en)begincase(op_cmd)4'd0:begin//写使能04hstart_wr<=1'd1;wren_cmd<=1'd0;end4'd1:begin//写使能06hstart_wr<=1'd1;wren_cmd<=1'd1;end4'd2:begin//读状态05hstart_status<=1'd1;status_cmd<=1'd0;end4'd3:begin//读状态35hstart_status<=1'd1;status_cmd<=1'd1;end4'd4:begin//擦除20hstart_erase<=1'd1;erase_cmd<=2'd0;erase_addr  <=op_addr;end4'd5:begin//擦除52hstart_erase<=1'd1;erase_cmd<=2'd1;erase_addr  <=op_addr;end4'd6:begin//擦除D8hstart_erase<=1'd1;erase_cmd<=2'd2;erase_addr  <=op_addr;end4'd7:begin//擦除整片start_erase<=1'd1;erase_cmd<=2'd3;erase_addr  <=op_addr;end4'd8:begin//页写start_write<=1'd1;wr_brust_length<=op_brust_length;write_addr  <=op_addr;end4'd9:begin//页读start_read<=1'd1;rd_brust_length<=op_brust_length;read_addr  <=op_addr;endendcaseendelse beginstart_wr<=1'd0;start_status<=1'd0;start_erase<=1'd0;start_write<=1'd0;start_read<=1'd0;endendendalways@(posedge clk)begin//输出写类完成信号if(wren_done||erase_done||write_done)beginwr_cmd_done<=1'b1;endelse beginwr_cmd_done<=1'b0;endendalways@(posedge clk)begin//输出读类完成信号if(status_done||read_done)beginrd_cmd_done<=1'b1;endelse beginrd_cmd_done<=1'b0;endendalways@(posedge clk)beginif((status_data[0]==1'b0)&&status_done)begin//读状态总线不忙status_ok<=1'b1;endelse beginstatus_ok<=1'b0;end
endalways@(posedge clk)beginif((status_data[0]==1) &&status_done)begin//status_data_dly=1表示状态忙rd_cmd_fail<=1'b1;endelse beginrd_cmd_fail<=1'b0;end
endendmodule

SPI_FLASH总模块

接下来把所有的模块例化到一起;

module spi_flash(
input clk,
input reset  ,
input clk_wr ,
input clk_rd ,
//控制信号
input        op_en          ,
input [3:0]  op_cmd         ,
input [23:0] op_addr        ,
input [8:0]  op_brust_length,//done信号
output wr_cmd_done,
output rd_cmd_done,
output rd_cmd_fail,
//bus
output spi_cs  ,
output spi_clk ,
output spi_dout,
input  spi_din );
// 写使能
wire  start_wr         ;
// 读状态
wire start_status      ;
//擦
wire start_erase       ;
wire erase_cmd_out     ;
//写
wire start_write       ;
wire din               ;
//计时器
wire time_done         ;
wire write_en          ;
wire erase_en          ;
wire erase_cmd         ;
//spi控制
wire wren_cmd          ;
wire wren_done         ;wire status_cmd        ;
wire status_data       ;
wire status_done       ;wire erase_addr        ;
wire erase_done        ;wire write_addr        ;
wire write_done        ;wire read_addr         ;
wire read_done         ;
//总线模式选择
wire mux_wren          ;
wire mux_wren_done     ;
wire spi_cs1           ;
wire spi_clk1          ;
wire spi_dout1         ;
wire spi_din1          ;wire mux_status        ;
wire mux_status_done   ;
wire spi_cs2           ;
wire spi_clk2          ;
wire spi_dout2         ;
wire spi_din2          ;wire mux_earse         ;
wire mux_earse_done    ;
wire spi_cs3           ;
wire spi_clk3          ;
wire spi_dout3         ;
wire spi_din3          ;wire mux_write         ;
wire mux_write_done    ;
wire spi_cs4           ;
wire spi_clk4          ;
wire spi_dout4         ;
wire spi_din4          ;wire mux_read          ;
wire mux_read_done     ;
wire spi_cs5           ;
wire spi_clk5          ;
wire spi_dout5         ;
wire spi_din5          ;//-------------------------------------------写使能wr_enable inst_wr_enable(.clk       (clk),.reset         (reset)           ,.start_wr      (start_wr)        ,//开始写使能.wren_cmd      (wren_cmd)        ,//指令(0/1).mux_wren_done (mux_wren_done)   ,//总线返回.wren_done     (wren_done)       ,//写使能完成.mux_wren      (mux_wren)        ,//请求总线.spi_cs        (spi_cs1)          ,//总线发送的片选线.spi_clk       (spi_clk1)         ,//总线发送的clk线.spi_dout      (spi_dout1)         //总线发送的DI线);//----------------------------------------读状态read_status inst_read_status(.clk       (clk),.reset          (reset)       ,.start_status   (start_status)       ,//开始读状态.status_cmd     (status_cmd)       ,//读状态指令.mux_status_done(mux_status_done)       ,//总线返回.spi_din        (spi_din2)       ,//由总线输入.mux_status     (mux_status)  ,//请求总线.status_done    (status_done)  ,//读状态完成.status_data    (status_data)  ,//读状态返回8位数据.spi_cs         (spi_cs2)  ,//片选信号.spi_clk        (spi_clk2)  ,//时钟信号.spi_dout       (spi_dout2)   //总线输入);//--------------------------------------------------擦除erase_top  erase_top(.clk       (clk) ,.reset          (reset) ,.start_erase    (start_erase) ,.erase_cmd      (erase_cmd) ,//擦除指令.erase_addr     (erase_addr) ,//擦除地址.mux_erase_done (mux_erase_done) ,.time_done      (time_done) ,//计时完成.mux_erase      (mux_erase) ,.spi_cs         (spi_cs3) ,.spi_clk        (spi_clk3) ,.spi_dout       (spi_dout3) ,.erase_done     (erase_done) ,.erase_en     (erase_en));//-----------------------------------------------------页写write_top inst_write_top(.clk       (clk),    .reset       (reset)     ,.start_write (start_write)     ,//启动页写//fifo部分驱动接口.brust_length  (brust_length)   ,//突发长度.write_addr    (write_addr)     ,//初始地址.clk_wr        (clk_wr)         ,//fifo时钟.wr_fifo_en    (wr_fifo_en)     ,//fifo写使能.din           (wr_fifo_data)   ,//写数据.wr_fifo_empty (wr_fifo_empty)  ,//fifo空.wr_fifo_full  (wr_fifo_full)   ,//fifo满//总线接口.spi_cs          (spi_cs4)  ,//spi片选.spi_clk         (spi_clk4)  ,//spi时钟.spi_dout        (spi_dout4)  ,//spi输出.mux_write       (mux_write)  ,//请求总线.mux_write_done  (mux_write_done)  ,//总线应答.write_done      (write_done)  ,//页写完成//计时器.time_done (time_done)       ,//计时完成.write_en  (write_en)  //启动计时);//-------------------------------------------页读read_top inst_read_top(.clk       (clk),        .reset         (reset)         ,.rd_clk        (rd_clk)         ,.start_read    (start_read)         ,//开始页读.read_addr     (read_addr)         , //页读地址.brust_length  (brust_length)         ,//突发长度.rd_fifo_en    (rd_fifo_en)         ,//fifo读使能.rd_fifo_data  (rd_fifo_data)         ,//从fifo读出的数据.rd_fifo_empty (rd_fifo_empty)         ,.rd_fifo_full  (rd_fifo_full)         ,.spi_cs        (spi_cs5)           ,.spi_clk       (spi_clk5)           ,.spi_dout      (spi_dout5)           ,.spi_din       (spi_din5)           ,.mux_read      (mux_read)           ,.mux_read_done (mux_read_done)           ,.read_done     (read_done));//-------------------------------------------time_top模块erase_time inst_erase_time(.clk       (clk),.reset     (reset),.write_en  (write_en),//页写计时.erase_en  (erase_en),//擦除计时.erase_cmd (erase_cmd),//擦除模式选择.time_done (time_done));//------------------------------------------spi_control模块spi_control inst_spi_control(.clk            (clk),.reset          (reset),
//操作信号            .op_en          (op_en),.op_cmd         (op_cmd),//0:写使能04h 1:写使能06h 2:读状态05h 3:读状态35h 4:擦除20h 5:擦除52h 6:擦除D8h 7:擦除整片 8:页写 9:页读.op_addr        (op_addr),.op_brust_length(op_brust_length),.wr_cmd_done    (wr_cmd_done), //返回写类done:写使能,页写,擦除.rd_cmd_done    (rd_cmd_done),//返回读类done:读状态寄存器,页读.rd_cmd_fail    (rd_cmd_fail),//读状态寄存器为忙
//写使能              .start_wr       (start_wr) ,.wren_cmd       (wren_cmd) ,.wren_done      (wren_done) ,
//读状态             .start_status   (start_status) ,.status_cmd     (status_cmd) ,.status_data    (status_data) ,.status_done    (status_done) ,
//擦除                .start_erase    (start_erase) ,.erase_cmd      (erase_cmd) , .erase_addr     (erase_addr) ,.erase_done     (erase_done) ,
//页写                .start_write    (start_write)  ,.wr_brust_length   (wr_brust_length)  ,.write_addr     (write_addr)  ,.write_done     (write_done)  ,
//页读               .start_read     (start_read) ,.rd_brust_length(rd_brust_length) ,.read_addr      (read_addr) ,.read_done      (read_done) );//-------------------------------------------总线交互模块mux_top mux_top(.clk              (clk)  ,.reset            (reset)  ,
//写使能               .mux_wren         (mux_wren)  ,.mux_wren_done    (mux_wren_done)  ,.spi_cs1          (spi_cs1)  ,.spi_clk1         (spi_clk1)  ,.spi_dout1        (spi_dout1)  ,.spi_din1         (spi_din1 )  ,
//读状态               .mux_status      (mux_status)     ,.mux_status_done (mux_status_done)     ,.spi_cs2         (spi_cs2)     ,.spi_clk2        (spi_clk2)     ,.spi_dout2       (spi_dout2)     ,.spi_din2        (spi_din2)     ,
//擦除                 .mux_earse       (mux_earse)     ,.mux_earse_done  (mux_earse_done)     ,.spi_cs3         (spi_cs3)     ,.spi_clk3        (spi_clk3)     ,.spi_dout3       (spi_dout3)     ,.spi_din3        (spi_din3)     ,
//页写                 .mux_write      (mux_write)      ,.mux_write_done (mux_write_done)      ,.spi_cs4        (spi_cs4)      ,.spi_clk4       (spi_clk4)      ,.spi_dout4      (spi_dout4)      ,.spi_din4       (spi_din4)      ,
//页读                 .mux_read       (mux_read)      ,.mux_read_done  (mux_read_done)      ,.spi_cs5        (spi_cs5)      ,.spi_clk5       (spi_clk5)      ,.spi_dout5      (spi_dout5)      ,.spi_din5       (spi_din5)      ,
//总线bus              .spi_din        (spi_din)    ,.spi_cs         (spi_cs)    ,.spi_clk        (spi_clk)    ,.spi_dout       (spi_dout));
endmodule

FPGA——SPI总线控制flash(3)含代码相关推荐

  1. FPGA——SPI总线控制flash(1)(含代码)

    上一篇写了SPI总线的原理,建议先看原理,链接如下: FPGA--SPI总线详解(概念)_居安士的博客-CSDN博客 这一篇分别来实现SPI总线的flash写使能,读状态 目录 flash写使能 fl ...

  2. Xilinx-Spartan6-学习笔记(24):通过SPI总线读写FLASH

    Xilinx-Spartan6-学习笔记(24):通过SPI总线读写FLASH 利用SPI总线实现对FLASH进行读写,写入255个数据再读出255个数据.(这里为了模拟SDO信号,随机生成了0~1信 ...

  3. FPGA SPI总线协议简介

    1.1 FPGA SPI总线协议简介 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA SPI总线协议简介: 5)结束语. 1.1.2 本节引言 "不积 ...

  4. 操作系统实验二进程的创建控制实验(含代码及实验心得)

    实现工具:PC机 实现环境:Linux 实习内容(功能.目标): 实验目的:  创建进程,体会进程间的并发特征. 实验内容:  编写一段程序,使用系统调用 fork() 创建两个子进程 p1 和 p2 ...

  5. 使用EFM8微控制器进行项目开发:SPI总线控制LCD

    基于微控制器的嵌入式设计从硬件开始,然后从低级到高级的固件开发.我们将在一个简单的程序中探索这个设计过程,该程序使用Silicon Labs EFM8微控制器在128x128像素的LCD上显示滚动水平 ...

  6. FPGA verilog 基于SPI总线协议控制flash的项目升级

    项目一:SPI总线控制Flash的擦除功能 SPI(Serial Peripheral Interface,串行外设接口)是Motorola公司提出的一种同步串行数据传输标准,是一种高速的,全双工,同 ...

  7. 固件远程更新之STARTUPE2原语(fpga控制flash)

    转至: https://blog.csdn.net/jiuzhangzi/article/details/79471365 有的项目需要远程更新固件,更新完成后断电.重启即可.那远程更新是如何实现的呢 ...

  8. spi总线 上层调用_spi总线的mmc卡驱动调试总结 | 学步园

    这周调试挂载在spi总线sd卡驱动,总结一下 因为这个涉及到2个驱动,spi总线驱动和sd卡驱动,sd卡设备挂载在spi总线上并不像设备挂载在i2c总线上, i2c总线提供设备挂载需要的借口函数att ...

  9. FPGA接口_N25Q128型号的spi flash驱动verilog代码编写

    # N25Q128型号的spi flash驱动verilog代码编写 提示:使用正点原子达芬奇pro做的小例子,由于教程中无flash的读写,因此撰写记录 文章目录 # N25Q128型号的spi f ...

最新文章

  1. X265整体流程-Create
  2. 微软将人工智能嵌入Windows 10更新
  3. 新经济、新选择——人才流动与迁徙2021
  4. mysql noinstall 5.5_安装配置MYSQL5.5
  5. GitLab的CICD配置文件.gitlab-ci.yml
  6. 洛谷——P1652 圆
  7. 实战:基于Node的控制台记事本开发
  8. MySQL命令行乱码问题的解决
  9. 插桩java_字节码插桩技术
  10. 若依前后端分离版+vue图片上传
  11. TuscanySCA5-理解SCA Domian
  12. 卸载Visual Studio 2015并安装Visual Studio 2019
  13. 计算机考研--科普篇
  14. 致命打击:携号转网马上要实施,移动吐血!
  15. 从1,3,5,7,9,11,13,15中选3个数(选择可重复)作和得30
  16. 【视频格式】m3u8格式视频下载
  17. 中国式家长计算机科学家攻略,中国式家长特长图鉴一览表 Q版图表讲解各特长发展路线...
  18. 统计学中均值、方差、标准差、协方差、欧式距离、马氏距离等概念透彻理解
  19. Arduino 串口发送数据代码
  20. C++一些常见的面试题

热门文章

  1. Hive 统计连续天数
  2. NFS配置(RHCE考试题)
  3. 水晶苍蝇拍-微薄投资感悟
  4. intel RDT (Resource Director Technology) 管理LLC和内存带宽
  5. weblogic服务器日志记录说明
  6. python 视频加字幕_【小技巧】用Python给你的视频添加字幕
  7. 多元相关分析与多元回归分析
  8. 为什么一定要掌握自学能力?
  9. series not exists. Legend data should be same with series name or data name. 问题VUE ECHARTS
  10. 【go】ssa和调用链分析