FPGA——SPI总线控制flash(3)含代码
前面几篇详细 介绍了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。
总线控制模块需要完成的任务:
- 控制5个模块(写使能,读状态,擦除,页写,页读)的总线应答
- 根据模块给spi_bus信号(spi_cs ,spi_clk ,spi_dout ,spi_din)
- 流程图如下:
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)含代码相关推荐
- FPGA——SPI总线控制flash(1)(含代码)
上一篇写了SPI总线的原理,建议先看原理,链接如下: FPGA--SPI总线详解(概念)_居安士的博客-CSDN博客 这一篇分别来实现SPI总线的flash写使能,读状态 目录 flash写使能 fl ...
- Xilinx-Spartan6-学习笔记(24):通过SPI总线读写FLASH
Xilinx-Spartan6-学习笔记(24):通过SPI总线读写FLASH 利用SPI总线实现对FLASH进行读写,写入255个数据再读出255个数据.(这里为了模拟SDO信号,随机生成了0~1信 ...
- FPGA SPI总线协议简介
1.1 FPGA SPI总线协议简介 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA SPI总线协议简介: 5)结束语. 1.1.2 本节引言 "不积 ...
- 操作系统实验二进程的创建控制实验(含代码及实验心得)
实现工具:PC机 实现环境:Linux 实习内容(功能.目标): 实验目的: 创建进程,体会进程间的并发特征. 实验内容: 编写一段程序,使用系统调用 fork() 创建两个子进程 p1 和 p2 ...
- 使用EFM8微控制器进行项目开发:SPI总线控制LCD
基于微控制器的嵌入式设计从硬件开始,然后从低级到高级的固件开发.我们将在一个简单的程序中探索这个设计过程,该程序使用Silicon Labs EFM8微控制器在128x128像素的LCD上显示滚动水平 ...
- FPGA verilog 基于SPI总线协议控制flash的项目升级
项目一:SPI总线控制Flash的擦除功能 SPI(Serial Peripheral Interface,串行外设接口)是Motorola公司提出的一种同步串行数据传输标准,是一种高速的,全双工,同 ...
- 固件远程更新之STARTUPE2原语(fpga控制flash)
转至: https://blog.csdn.net/jiuzhangzi/article/details/79471365 有的项目需要远程更新固件,更新完成后断电.重启即可.那远程更新是如何实现的呢 ...
- spi总线 上层调用_spi总线的mmc卡驱动调试总结 | 学步园
这周调试挂载在spi总线sd卡驱动,总结一下 因为这个涉及到2个驱动,spi总线驱动和sd卡驱动,sd卡设备挂载在spi总线上并不像设备挂载在i2c总线上, i2c总线提供设备挂载需要的借口函数att ...
- FPGA接口_N25Q128型号的spi flash驱动verilog代码编写
# N25Q128型号的spi flash驱动verilog代码编写 提示:使用正点原子达芬奇pro做的小例子,由于教程中无flash的读写,因此撰写记录 文章目录 # N25Q128型号的spi f ...
最新文章
- X265整体流程-Create
- 微软将人工智能嵌入Windows 10更新
- 新经济、新选择——人才流动与迁徙2021
- mysql noinstall 5.5_安装配置MYSQL5.5
- GitLab的CICD配置文件.gitlab-ci.yml
- 洛谷——P1652 圆
- 实战:基于Node的控制台记事本开发
- MySQL命令行乱码问题的解决
- 插桩java_字节码插桩技术
- 若依前后端分离版+vue图片上传
- TuscanySCA5-理解SCA Domian
- 卸载Visual Studio 2015并安装Visual Studio 2019
- 计算机考研--科普篇
- 致命打击:携号转网马上要实施,移动吐血!
- 从1,3,5,7,9,11,13,15中选3个数(选择可重复)作和得30
- 【视频格式】m3u8格式视频下载
- 中国式家长计算机科学家攻略,中国式家长特长图鉴一览表 Q版图表讲解各特长发展路线...
- 统计学中均值、方差、标准差、协方差、欧式距离、马氏距离等概念透彻理解
- Arduino 串口发送数据代码
- C++一些常见的面试题
热门文章
- Hive 统计连续天数
- NFS配置(RHCE考试题)
- 水晶苍蝇拍-微薄投资感悟
- intel RDT (Resource Director Technology) 管理LLC和内存带宽
- weblogic服务器日志记录说明
- python 视频加字幕_【小技巧】用Python给你的视频添加字幕
- 多元相关分析与多元回归分析
- 为什么一定要掌握自学能力?
- series not exists. Legend data should be same with series name or data name. 问题VUE ECHARTS
- 【go】ssa和调用链分析