基于FPGA的内存128Mflash芯片控制器设计

原创 FPGA技术江湖 2024-04-19 07:06

大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。


今天给大侠带来基于FPGA的内存128M flash芯片控制器设计,话不多说,上货。

设计原理及思路


FLASH闪存 闪存的英文名称是"Flash Memory",一般简称为"Flash",它属于内存器件的一种,是一种不挥发性( Non-Volatile )内存。

闪存的物理特性与常见的内存有根本性的差异:目前各类 DDR 、 SDRAM 或者 RDRAM 都属于挥发性内存,只要停止电流供应内存中的数据便无法保持,因此每次电脑开机都需要把数据重新载入内存;闪存在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘,这项特性正是闪存得以成为各类便携型数字设备的存储介质的基础。

本次设计使用的是 W25Q128FV 内存128M的flash芯片,大家可以自己在官网上下载器件手册。在这里为了方便,也提供给各位,需要使用的可以在公众号内部回复“W25Q128FV手册资料”,各位可以根据实际项目应用灵活设计。

这款flash芯片的的存储是一个扇区4KB,一个扇区可以存256个字,一个字是8位,一个块是64KB,一共有256个块组成一个存储flash内存。

在下面的讲解中,将主要讲实现一下字节的读写,本次设计使用的协议是SPI协议,这个芯片支持QSPI,双端口SPI等。flash有三个状态寄存器,每一个状态寄存器的每一位都有各自的功能。大家可以具体的看器件手册,首先给大家简单的讲一下第一个状态寄存器。


这个状态寄存器第一位是可读、忙和不忙的标志位,大家可以在我们的设计中判断芯片是否忙和不忙来是否进行下一步的操作。第二位是一个写标志的信号,当写使能打开的时候它1,只有它为1的时候我们才可以进行写,值得一说的不管是页操作,还是擦除等命令后都会使这个标志位变成0。然后前面的命令算的上的是保护命令,具体有使用的逻辑功能。

在flash中,写数据前先要擦除数据(想要擦除的地方),然后进行写,如果没有用过的flash芯片的话那么可以不用擦除,因为flash掉电不丢失数据。

设计思路大概是先读出器件厂商和芯片ID,然后写命令,写使能打开,页操作写入数据(值得说明的是我们FLASH是新的所以没进行擦除命令,建议擦除---关闭写使能 -- 打开写使能),然后读第一个寄存器判断芯片的第一位是否忙,不忙然后进行读操作之后再数码管上显示出我们写入的数据。

部分操作命令如下:


我们的发送格式为在时钟的上升沿写入命令,在时钟的下降沿读出命令,用的是标准的SPI协议,端口IO0,和IO1,都是单向的。

写使能时序:


读使能时序:

其他的时序在这里就不分别列举出来了,大家可以参考器件手册。


设计架构


本次的设计是用一个FSM控制器来控制发送什么命令,flash模块判断FSM发送过来的state信号来选择应该执行什么操作,当命令写入或者读出后,会发送一个flag_done命令,这个命令让我们判断上个指令是否完成,如果完成后FAM将发送下一个命令。总体架构图如下:


设计代码


顶层模块 flash_top 代码:

module flash_top(clk , rst_n, q0,  q1, sclk, cs, seg, sel);
input clk, rst_n; input q0; output q1; output sclk; output cs; output [5:0] sel; output [7:0] seg; wire [7:0] command; wire [23:0] addr; wire [2:0] state; wire [7:0] data; wire [23:0] show_data; wire flag_done; flash flash_dut( .clk(clk) , .rst_n(rst_n), .q0(q0), .q1(q1), .sclk(sclk), .cs(cs), .command(command), .addr(addr), .state(state), .data(data), .show_data(show_data), .flag_done(flag_done) ); fsm fsm_dut( .clk(clk), .rst_n(rst_n), .flag_done(flag_done), .command(command), .addr(addr), .state(state), .data(data) ); seg seg_dut( .clk(clk), .rst_n(rst_n), .sel(sel), .seg7(seg), .data_in(show_data) );

endmodule 


设计模块 fsm 代码

module fsm(clk, rst_n, flag_done, command, addr, state, data);
input clk, rst_n; input flag_done; //输入标志位 output reg [7:0] command; //输出命令 output reg [23:0] addr; //输出地址 output reg [2:0] state; //输出状态模式 output reg [7:0] data; //输出写入数据 reg [2:0] state_s; reg [20:0] count; always @ (posedge clk) if(!rst_n) begin state_s <= 0; data <= 8'd0; addr <= 24'd0; command <= 8'd0; state <= 0; count <= 0; end else case (state_s) 0 : begin if(count < 200) //延迟一段时间 count <= count + 1; else begin //发送读厂商ID的命令 command <= 8'h90; addr <= 24'd0; state <= 1; count <= 1; end if(flag_done) //检查是否完成 state_s <= 1; end 1 : begin if(count < 200) //延迟一段时间 count <= count + 1; else begin //写使能 command <= 8'h06; state <= 3; count <= 0; end if(flag_done) //检查是否完成 state_s <= 2; end 2 : begin if(count < 200) //延迟一段时间 count <= count + 1; else begin //页操作 command <= 8'h02; addr <= 24'd0; state <= 4; data <= 8'haa; count <= 0; end if(flag_done) //检查是否完成 state_s <= 3; end 3 : begin if(count < 200) //延迟一段时间 count <= count + 1; else begin //读寄存器 command <= 8'h05; count <= 0; state <= 5; end if(flag_done) //检查是否完成 state_s <= 4; end 4 : begin if(count < 200) //延迟一段时间 count <= count + 1; else begin //读数据 command <= 8'h03; addr <= 24'd0; state <= 2; count <= 0; end end default: state_s <= 0; endcase endmodule


中间模块flash代码:

module flash (clk , rst_n, q0,  q1, sclk, cs, command, addr, state, data, show_data, flag_done);    input clk, rst_n;          input q0;  output reg q1;  output reg sclk;  output reg cs;  input [7:0] command;      //输入命令  input [23:0] addr;      //地址  input [2:0] state;      //状态  input [7:0] data;        //数据  output reg [23:0] show_data;   //显示  output reg flag_done;    //命令完成标志
reg [5:0] count; reg [5:0] cnt; reg [31:0] temp; reg [15:0] d; reg [5:0] count_s; reg [7:0] dou; reg [39:0] xie; reg [7:0] r_reg; always @ (posedge clk) if(!rst_n) begin sclk <= 1; count_s <= 0; end else if(cs) begin count_s <= 0; sclk <= 1; end else begin if(count_s == 25 - 1) //产生1M的时钟 begin count_s <= 0; sclk <= ~sclk; end else count_s <= count_s + 1; end reg [1:0] signle_s; //边沿检测电路 always @ (posedge clk or negedge rst_n) if(!rst_n) begin signle_s <= 2'b11; end else begin signle_s[0] <= sclk; signle_s[1] <= signle_s[0]; end assign pose_dge = signle_s[0] && ~signle_s[1]; //上升沿脉冲 assign nege_dge = ~signle_s[0] && signle_s[1]; //下降沿脉冲 reg [1:0] s; reg [1:0] s1,s2,s3,s4; always @ (posedge clk or negedge rst_n) if(!rst_n) begin q1 <= 0; count <= 0; cs <= 1; temp <= 0; d <= 0; cnt <= 0; s <= 0; s1 <= 0; s2 <= 0; s3 <= 0; flag_done <= 0; s4 <= 0; end else begin if (state == 1) //state == 1进入读芯片的厂商和ID case (s) 0: begin cs <= 0; temp <= {command,addr}; s <= 1; end 1 : begin if(nege_dge) //下降沿发送数据 begin if(count < 32) begin q1 <= temp[31]; count <= count + 1; temp <= {temp[30:0],temp[31]}; end else begin count <= 0; s <= 2; end end else q1 <= q1; end 2 : begin if(pose_dge) //上升沿采集数据 begin if(count < 16) begin count <= count + 1; d <= {d[14:0],q0}; end else begin s <= 3; cs <= 1; count <= 0; flag_done <= 1; show_data <= d; end end else begin s <= 2; end end 3 : begin flag_done <= 0; end endcase else if(state == 2) //state == 2进入读模式 case (s1) 0: begin cs <= 0; temp <= {command,addr}; s1 <= 1; end 1 :begin if(nege_dge) begin if(count < 32) begin q1 <= temp[31]; count <= count + 1; temp <= {temp[30:0],temp[31]}; end else begin count <= 0; s1 <= 2; end end else q1 <= q1; end 2 : begin if(pose_dge) begin if(count < 8) begin count <= count + 1; dou <= {dou[6:0],q0}; s1 <= 2; end else begin s1 <= 3; cs <= 1; count <= 0; flag_done <= 1; show_data <= dou; end end else begin s1 <= 2; end end 3 : begin flag_done <= 0; end endcase else if(state == 3) //state == 3 进入写使能模式 case (s2) 0: begin cs <= 0; temp <= {command,addr}; s2 <= 1; end 1 :begin if(nege_dge) begin if(count < 8) begin q1 <= temp[31]; count <= count + 1; temp <= {temp[30:0],temp[31]}; end else begin count <= 0; s2 <= 2; cs <= 1; flag_done <= 1; end end else q1 <= q1; end 2 : flag_done <= 0; endcase else if(state == 4) //state == 4 进入页写操作 case (s3) 0: begin cs <= 0; xie <= {command,addr,data}; s3 <= 1; end 1 :begin if(nege_dge) begin if(count < 40) begin q1 <= xie[39]; count <= count + 1; xie <= {xie[38:0],xie[39]}; end else begin count <= 0; s3 <= 2; cs <= 1; flag_done <= 1; end end else q1 <= q1; end 2 : flag_done <= 0; endcase else if(state == 5) //state == 5 进入读第一个状态寄存器操作 case (s4) 0: begin cs <= 0; r_reg <= command; s4 <= 1; end 1 :begin if(nege_dge) begin if(count < 8) begin q1 <= r_reg[7]; count <= count + 1; r_reg <= {r_reg[6:0],r_reg[7]}; end else begin count <= 0; s4 <= 2; end end else q1 <= q1; end 2 : begin if(pose_dge) begin if(count < 8) begin count <= count + 1; d <= {d[14:0],q0}; end else begin cs <= 1; count <= 0; if(!d[8]) //判断BUSY位忙不忙,不忙进入下个状态 begin flag_done <= 1; s4 <= 3; end else //忙继续读第一个寄存器 s4 <= 0; end end else begin s4 <= 2; end end 3 : flag_done <= 0; endcase end endmodule


数码管模块seg代码:
module seg(clk,rst_n,sel,seg7,data_in);
input clk; input rst_n; input [23:0] data_in; output reg [5:0] sel; output reg [7:0] seg7; parameter s0 = 3'b000; parameter s1 = 3'b001; parameter s2 = 3'b010; parameter s3 = 3'b011; parameter s4 = 3'b100; parameter s5 = 3'b101; `define T1ms 50_000 //`define T1ms 5 reg [15:0] count; reg flag; always @ (posedge clk or negedge rst_n) if(!rst_n) begin count <= 16'd0; flag <= 1; end else if(count == (`T1ms / 2 - 1)) begin count <= 16'd0; flag <= ~ flag; end else begin count <= count + 1'b1; end reg [2:0] state; reg [3:0] num; always @ (posedge flag or negedge rst_n) if(!rst_n) begin sel <= 3'b0; state <= 3'b0; num <= 4'b0; end else begin case (state) s0:begin state <= s1; sel <= 6'b011111; num <= data_in[23:20]; end s1:begin state <= s2; sel <= 6'b101111; num <= data_in[19:16]; end s2:begin state <= s3; sel <= 6'b110111; num <= data_in[15:12]; end s3:begin state <= s4; sel <= 6'b111011; num <= data_in[11:8]; end s4:begin state <= s5; sel <= 6'b111101; num <= data_in[7:4]; end s5:begin state <= s0; sel <= 6'b111110; num <= data_in[3:0]; end default:state <= s0; endcase end
always @ (*) begin case (num) 0:seg7 = 8'b1100_0000; 1:seg7 = 8'b1111_1001; 2:seg7 = 8'b1010_0100; 3:seg7 = 8'b1011_0000; 4:seg7 = 8'b1001_1001; 5:seg7 = 8'b1001_0010; 6:seg7 = 8'b1000_0010; 7:seg7 = 8'b1111_1000; 8:seg7 = 8'b1000_0000; 9:seg7 = 8'b1001_0000; 10:seg7 = 8'b1000_1000; 11:seg7 = 8'b1000_0011; 12:seg7 = 8'b1100_0110; 13:seg7 = 8'b1010_0001; 14:seg7 = 8'b1000_0110; 15:seg7 = 8'b1000_1110; default:; endcase endendmodule


SignalTap 采集图


图中显示的和我们的设计一样,发送的各个命令也是一样的,我们写入的是AA然后接收的也是AA,设计正确。

- THE END -

🍁


往期精选 

 
 

【免费】FPGA工程师人才招聘平台

FPGA人才招聘,企业HR,看过来!

系统设计精选 | 基于FPGA的实时图像边缘检测系统设计(附代码)

基于原语的千兆以太网RGMII接口设计

时序分析理论和timequest使用_中文电子版

求职面试 | FPGA或IC面试题最新汇总篇

资料汇总|FPGA软件安装包、书籍、源码、技术文档…(2024.01.06更新)

FPGA就业班,05.04开班,新增课程内容不加价,高薪就业,线上线下同步!

FPGA技术江湖广发江湖帖

无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,QQ微信双选,FPGA技术江湖打造最纯净最专业的技术交流学习平台。


FPGA技术江湖微信交流群

加群主微信,备注姓名+学校/公司+专业/岗位进群


FPGA技术江湖QQ交流群

备注姓名+学校/公司+专业/岗位进群

FPGA技术江湖 任何技术的学习就好比一个江湖,对于每一位侠客都需要不断的历练,从初入江湖的小白到归隐山林的隐世高人,需要不断的自我感悟自己修炼,让我们一起仗剑闯FPGA乃至更大的江湖。
评论 (0)
  • [初次发表 24-05-16  最后编辑:24-05-19] 额定功耗 / Rated Dissipation    根据 IEC 60115-1/GB 5729 的定义,额定功耗是指在 70摄氏度环境温度下进行耐久性试验,试验结束时,阻值变化不超过试验允许偏差范围所允许的最大功耗。有时也称为 P70。    上面这个定义没有给出具体的耐久性试验时间和允许的偏差范围。这两个参数可以引用另外一个标准—— EN 140401-801。对于一
    电子知识打边炉 2024-05-16 22:30 137浏览
  • 光耦技术作为一种高效的电气与光学信号隔离解决方案,在高端智能装配领域展现出了广阔的应用前景。本文将对光耦技术在该领域的应用进行深入分析,探讨其在提升装配设备性能和安全性方面的作用。光耦技术在高端智能装配领域的应用十分广泛。首先,在自动化装配系统中,光耦器件常用于隔离控制电路和传感器电路之间的信号传输,以确保系统的稳定运行。通过光耦技术,可以实现电气信号的隔离传输,避免由于电气干扰而导致的系统故障或误操作。同时,光耦器件具有响应速度快、抗干扰能力强的特点,能够满足高速装配线的需求,提高装配效率和精
    腾恩科技-彭工 2024-05-17 16:15 116浏览
  • 项目内容描述简略描述:细节需求:1.1.搭建一个开源物联网平台,设置好接受数据。2.上传传感器数据到物联网平台。3.直接传到服务器,通过WIFI,http或者mqtt协议上传。4.通过mqtt网关。5.时间周期为1天。费用为1000元左右。 ...指定区域接包方:无指定区域。项目分析: 1. 开源物联网平台搭建:    - 需要选择一个合适的开源物联网平台作为基础,如ThingWorx, Eclipse IoT, OpenIoT等。    -
    丙丁先生 2024-05-17 08:58 108浏览
  • 丝杆升降机作为一种常用的升降机构,升降机广泛应用于各种工业、建筑和自动化领域。它以其高精度、高稳定性、高承载能力和易于控制的特点,成为现代机械传动和定位技术中不可或缺的一部分。本文将详细解析丝杆升降机的工作原理及其结构特点,为读者提供深入的理解和应用指导。 丝杆升降机的工作原理 丝杆升降机的工作原理主要基于螺旋传动机构。其核心部件为丝杆(或称为螺杆)和螺母(或称为螺套)。丝杆上刻有螺旋状的齿纹(或称为螺纹),螺母则内嵌有与丝杆螺纹相匹配的螺旋槽。当丝杆旋转时,螺母会沿着丝杆的轴向方向进行直线
    MISUMI米 2024-05-16 16:03 129浏览
  • ALTERA Cyclone 10器件的使用-5:模块复用在导入时遇到的问题概述 复用模块导入时,该复用模块的输入端口在设计者侧被接入到物理I/O,而在使用者侧导入QDB文件后,FIT时报错。导入QDB后布局布线报错 使用者一侧导入设计者一侧传导来的QDB文件,然后进行工程全编译,在开始Fit不久后出现了如图1所示的错误提示。出错的是子模块中的一个16-bit的数据总线,从错误信息可以看出,编译器认为该总线在之前编译的时候是连接到器件I/O引脚上的,导入后该总线用于内部逻辑互联通讯,所以给出了冲
    coyoo 2024-05-19 10:42 68浏览
  • 步进电机,作为一种将电脉冲信号转化为角位移或线位移的执行元件,因其精确的定位和易于控制的特性,在现代工业控制、机器人技术、精密测量等领域得到了广泛应用。本文旨在深入探讨步进电机的工作原理,以及基于其特性的运动控制基础,为相关领域的工程师和技术人员提供参考。 步进电机的工作原理 步进电机的工作原理主要基于电磁感应和磁场相互作用。其内部包含多个定子磁极和转子磁极,通过控制定子磁极的电流方向和大小,可以产生旋转磁场,进而驱动转子磁极按照预定的角度进行旋转。 电磁感应 步进电机中的定子磁极通常采用
    MISUMI米 2024-05-16 16:02 121浏览
  • 在现代化的工业生产和机械设备中,电缆和管线的保护与管理是一项至关重要的任务。电缆和管线作为电能、信号和数据传输的媒介,其安全性和可靠性直接影响到整个系统的正常运行。拖链作为一种灵活高效的电缆与管线保护解决方案,广泛应用于各类机械设备和自动化系统中。本文将对拖链的原理进行详细解析,并探讨其在电缆与管线保护中的应用。 拖链的基本原理 拖链,又称为电缆拖链或电缆保护链,是一种用于保护电缆和管线的链式结构。它通过将电缆和管线放置在一个可弯曲的链状结构中,实现电缆和管线的灵活移动和有效保护。拖链的基本
    MISUMI米 2024-05-16 16:04 134浏览
  • 各大Logo更新汇报 | NEW百佳泰为ISO/IEC17025实验室,亦获得国际协会授权,可提供超过30种标准认证测试,特为您整理2024年5月各大Logo的最新规格信息。PCIe▶PCIe6.0 Preliminary FYI研讨会■ 日期:2024年6月3日至7日■ 旧金山机场大使套房酒店,南旧金山,加利福尼亚州Thunderbolt▶更新补贴计划■ TBT3/4 Device: 从2024年4月起, Intel将不再为TBT3/4 Device提供补贴。■ TBT5 Device:- 如
    百佳泰测试实验室 2024-05-16 17:36 143浏览
  • 车载以太网(Automotive Ethernet)是什么?Automotive Ethernet是指在汽车中使用Ethernet技术的网络。它的发展主要受益于汽车对更多数据和连接性的需求,以支持例如自动驾驶、车辆互联和娱乐系统等先进的车辆功能。其高带宽、低延迟和可扩展性的多项优势,使Automotive Ethernet成为支持复杂系统的理想选择,也让不同的汽车子系统(如传感器、摄像头、控制单元)能够更有效地共享信息。Automotive Ethernet的主要技术Automotive Eth
    百佳泰测试实验室 2024-05-17 10:45 138浏览
  • 光电耦合元件作为一种关键的电子元器件,在各种电气设备和系统中发挥着重要作用。然而,对于很多国家来说,依赖进口的情况依然存在。因此,对光电耦合元件的国产替代具有重要意义。本文将从现状和前景两个方面分析光电耦合元件的国产替代情况。光电耦合元件的国产替代现状光电耦合元件是一种将光学和电气两种信号进行隔离的器件,通常由发光二极管(LED)和光敏二极管(光电晶体管)组成。目前,全球光电耦合元件市场主要由一些发达国家的企业垄断,国内市场依赖进口情况较为普遍。然而,近年来,国内光电子领域的发展取得了长足的进步
    腾恩科技-彭工 2024-05-17 16:18 150浏览
  • 5月13日小米智能生态官方宣布推出小米人在传感器,并在小米有品众筹上价,众筹价格 119 元,预计零售价格为149元。据介绍,小米人在传感器是一台不用插电的人体存在感知设备,可以实现 " 人在灯不灭,人走关空调 "。主要亮点方面,该传感器采用磁吸设计可随心安装,并采用创新探索新技术,超低功耗毫米波雷达监测算法,1 节纽扣电池可以用 3 年。▲来源:小米有品创新传感器带来突破性家居体验!小米展示了传感器在智能家居中的感知地位传感器在智能化时代,扮演非常重要的角色,是所有感知的源头,在智能家居中更是
    传感器专家网 2024-05-17 10:05 128浏览
  • 键盘作为人机互动的重要接口之一,经过多年的演进已成为一个相当成熟的产品类别。制造商与用户开始更加注重键盘的设计美学、键帽材质与耐用性,以及敲击时的手感是否符合个人偏好等。对于游戏玩家来说,键盘的手感对于游戏体验有着关键性的影响。良好的键盘回馈不仅能提升操作的准确性,还能在游戏中为玩家提供实时的触感回馈,进而提升游戏表现,而在需要快速反应的竞技游戏中,手感好的键盘则可以成为决定胜负的关键。另一个常用键盘的办公族群,若有具备适中的按键行程、清晰的打字回馈以及舒适手感的键盘,不仅能够减少输入错误率,还
    百佳泰测试实验室 2024-05-16 17:04 139浏览
  • 熟悉消费电子市场的朋友或许了解到,最近一家国产CMOS图像传感器企业频频出现,那就是豪威科技——韦尔股份旗下子公司,也是全球第三大CMOS图像传感器企业。曾几何时,旗舰手机的图像传感器主要由索尼、三星提供,也以此为卖点,豪威科技等国产传感器企业的产品只能在低端手机中应用。而近一年来,豪威科技的CMOS图像传感器作为主摄像头,越来越多地出现在小米、荣耀等国产企业的旗舰手机中。而据近期,数码博主数码闲聊站爆料称,华为正在紧锣密鼓的测试豪威 OV50K,今年下半年登场的华为Mate 70系列,主摄传感
    传感器专家网 2024-05-17 10:22 168浏览
  • SOT-23和SOT-323都属于小型轮廓晶体管(Small Outline Transistor,SOT)封装系列,是表面贴装设备(SMD)中常见的封装类型。它们主要用于小功率器件,如晶体管、二极管等。尽管这两种封装在应用和外观上有诸多相似之处,但也有一些关键的区别。SOT-23封装SOT-23封装是一种非常流行的小型三引脚封装,它的引脚间距通常为0.95mm。由于其紧凑的尺寸和良好的性能,SOT-23广泛应用于各种低功率应用,如信号转换、放大和开关。SOT-323封装SOT-323封装相比于
    大鱼芯城 2024-05-17 11:36 144浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦