在数字存储技术的领域中,闪存(Flash)是一种非易失性存储器,以其高速读写、低功耗和较高的可靠性而备受关注。相比于传统的磁盘存储技术,闪存具有更小的体积、更高的数据密度和更长的寿命,因此在各种应用中得到了广泛的应用。闪存最初应用于便携式设备和嵌入式系统中,如手机、平板电脑和闪存卡等。随着技术的不断进步,闪存逐渐取代了传统的硬盘驱动器,成为许多计算机系统的首选存储介质。
闪存的工作原理与传统的存储技术有所不同。它采用了一种称为“浮体栅结构”的技术,通过在晶体管中添加控制门、浮动门和栅极等元件,实现了数据的存储和擦除。这种浮体栅结构使得闪存能够在无电源供应的情况下保持数据的稳定性,同时具有较快的读写速度和较低的功耗。
闪存的应用领域包括但不限于:
1. 便携式设备和嵌入式系统:如手机、平板电脑、存储卡和嵌入式系统模块等。
2. 个人电脑和服务器:闪存固态硬盘(SSD)已经成为替代传统硬盘驱动器的首选存储介质。
3. 汽车电子:闪存被用于车载娱乐系统、导航系统和车载通信系统等。
4. 云存储和大数据中心:闪存被用于高速缓存、快速存储和大规模数据处理等。
闪存的存储密度和容量是一个重要的问题。随着技术的不断发展,闪存的存储密度和容量不断增加,但如何保持稳定的性能和可靠性仍然是一个挑战。如何平衡存储密度和容量与数据可靠性和读写速度之间的关系,是一个需要解决的问题。
闪存的读写速度和性能是另一个重要的问题。闪存的读取速度通常比写入速度更快,而写入速度受到擦除操作的限制。如何提高闪存的读写速度,并解决擦除操作带来的延迟和性能问题,是一个需要解决的挑战。
闪存的寿命和耐久性是一个关键问题。闪存存储单元在重复擦写操作后会逐渐损耗,导致寿命减少。如何提高闪存的耐久性,减少擦写操作对存储单元的损耗,是一个需要解决的问题。
在闪存中,数据的正确性和完整性是至关重要的。由于闪存存储单元的损耗和环境因素的影响,数据可能会发生错误或丢失。如何设计合适的错误校正和纠正机制,以确保数据的正确性和完整性,是一个需要解决的问题。
闪存中的垃圾回收和空间管理是一个关键问题。在闪存中,擦除操作是一个相对较慢的过程,而闪存存储单元的擦除前必须是空白的。如何高效地进行垃圾回收和空间管理,以充分利用闪存空间并减少擦除操作次数,是一个需要解决的挑战。
为了提高存储密度和容量,可以采用更高密度的闪存芯片和多级存储技术,如多层堆叠存储器(MLC)和三级堆叠存储器(TLC)。此外,可以采用更高级别的错误校正码(ECC)来增加数据的存储密度。
为了提高读写速度和性能,可以采用并行读写和多通道设计,以实现并发的数据访问。同时,可以优化闪存控制器的算法和数据缓存机制,以减少读写操作的延迟。
为了提高闪存的寿命和耐久性,可以采用动态均衡和可编程的擦写算法,以均衡存储单元的使用和减少擦写操作的次数。此外,可以实施写放大和数据分散技术,以减少对特定存储单元的过度擦写。
为了确保数据的正确性和完整性,可以采用强大的错误校正和纠正机制,如BCH(Bose-Chaudhuri-Hocquenghem)码和LDPC(低密度奇偶校验)码。这些机制可以检测和纠正数据传输过程中可能出现的错误。
为了高效地进行垃圾回收和空间管理,可以采用闪存控制器中的智能算法和策略。这些算法和策略可以根据存储单元的使用情况和数据访问模式,动态地进行垃圾回收和数据迁移,以减少擦除操作的次数并提高空间利用率。
该程序利用FPGA实现了对Flash存储器的多项功能,包括写入使能、整片擦除、全片写入和全片数据读取。通过使用FPGA作为控制器,程序能够有效地控制Flash存储器的写入操作,实现数据的可靠存储。同时,通过整片擦除和全片写入功能,可以在需要时快速清除和写入整个Flash存储器。而全片数据读取功能使得程序能够高效地读取Flash存储器中的全部数据。这些功能的实现,为Flash存储器的使用提供了更大的灵活性和便利性。
`timescale 1 ps/ 1 ps
//
// Company:
// Engineer:
//
// Create Date: 11-08-2022 16:06:19
// Design Name:
// Module Name: flash_control
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Additional Comments:
//
//
module flash_control(
input wire clk ,
input wire rst_n ,
input [7:0] O_data_out ,
input O_tx_done ,
input O_rx_done ,
input Clock_open ,
output reg I_rx_en ,
output reg I_tx_en ,
output reg [7:0] I_data_in ,
output reg O_spi_cs ,
output reg strswitch ,
output reg flash_done ,
output reg response ,
output reg control_done /*synthesis noprune*/,
output reg Register_error , //无法写入寄存器
output reg DATA_error , //数据错误
output reg [9:0] record ,
output reg [20:0] Erase_count
);
//------------------------------------------------------------------------------
//----------- Registers Declarations -------------------------------------------
//------------------------------------------------------------------------------
reg [7:0] state/* synthesis preserve */;
reg [63:0] cnt/* synthesis preserve */;
reg [7:0] DATA/* synthesis preserve */;
reg [7:0] DATA_out/* synthesis preserve */;
reg [23:0] addr2/* synthesis preserve */;
reg [23:0] addr;
reg [2:0] count/* synthesis preserve */;
reg d0,d1;
reg [7:0] state_reg/* synthesis preserve */;
reg a;
reg Sector_ER_DONE;
wire pos_Clock_open;
assign pos_Clock_open = d0 & (!d1);
//写启动 写禁止
parameter Write_Enable = 8'h06; //写启动
parameter Write_Disable = 8'h04; //写禁止
parameter Read_Data = 8'h03; //读数据
parameter Sector_Erase = 8'h20; //扇区擦除
parameter Chip_Erase = 8'hc7; //芯片擦除
parameter Power_down = 8'hb9; //芯片断电
parameter Quad_Input_Page_Program = 8'h32; //页写入
parameter Block_Erase_64KB = 8'hd8; //64K块擦除
parameter Page_Program = 8'h02; //页编程
parameter Fast_Read = 8'h0b; //快速读取
parameter Fast_Read_Quad_Output = 8'h6b; //读取4页数据
parameter Write_Enable_Register = 8'h50; //写状态寄存器
//写入状态 读取状态
parameter Read_Status_Register_1 = 8'h05; //读状态寄存器1
parameter Read_Status_Register_2 = 8'h35; //读状态寄存器2
parameter Read_Status_Register_3 = 8'h15; //读状态寄存器2
parameter Write_Status_Register_1 = 8'h01; //写状态寄存器1
parameter Write_Status_Register_2 = 8'h31; //写状态寄存器2
parameter Write_Status_Register_3 = 8'h11; //写状态寄存器3
always @ (posedge clk ) begin
state_reg <= state;
end
always @ (posedge clk ) begin
if (!rst_n)
begin
d0 <= 1'b0;
d1 <= 1'b0;
end
else
begin
d0 <= Clock_open;
d1 <= d0;
end
end
always @ (posedge clk ) begin
if (!rst_n)
a <= 1'b0;
else
a <= 1'b1;
end
always @ (posedge clk) begin
if (!rst_n)
begin
state <= 8'd0 ;
cnt <= 64'd0 ;
I_rx_en <= 1'b0 ;
I_tx_en <= 1'b0 ;
I_data_in <= 8'd0 ;
DATA <= 8'd0 ;
O_spi_cs <= 1'b1 ;
strswitch <= 1'b1 ;
addr2 <= 24'd0 ;
addr <= 24'd0 ;
DATA_out <= 8'd0 ;
count <= 3'd0 ;
flash_done <= 1'b0 ;
response <= 1'b0 ;
Register_error <= 1'b0 ;
DATA_error <= 1'b0 ;
control_done <= 1'b0 ;
record <= 10'd0 ;
Erase_count <= 21'd0 ;
Sector_ER_DONE <= 1'b0 ;
end
else
case (state)
0:begin
if (cnt == 5000000-1)//5000000-1
begin //5秒
addr <= 24'd0 ;
Erase_count <= 21'd0;
cnt <= 64'd0;
state <= state + 1'b1;
count <= 3'd0;
response <= 1'b0;
Register_error <= Register_error;
DATA_error <= DATA_error;
control_done <= 1'b0;
record <= record;
end
else if (a)
begin
addr <= 24'd0 ;
cnt <= cnt + 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
strswitch <= 1'b1;
control_done <= 1'b0;
record <= record;
end
else
begin
cnt <= 64'd0;
end
end
//***********************写启动
1:begin
DATA <= 8'hff;
Erase_count <= Erase_count;
state <= state + 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
I_data_in <= Write_Enable;
strswitch <= 1'b1;
addr2 <= 24'd0;
count <= count + 1'b1;
control_done <= 1'b0;
end
2:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
//***********************全片擦除
3:begin
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
state <= state + 1'b1;
end
4:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Chip_Erase;
record <= record + 1'b1;
control_done <= 1'b0 ;
end
5:begin
if (O_tx_done)
begin
control_done <= 1'b0;
state <= state + 1'b1;
end
else
begin
control_done <= 1'b0;
state <= state;
end
end
6:begin
O_spi_cs <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
DATA_out <= 8'haa;
end
//***********************读取状态寄存器
7:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Read_Status_Register_1;
end
8:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
9:begin //读写切换
I_rx_en <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
//***********************读数据
10:begin
if (O_rx_done)
begin
DATA <= O_data_out;
state <= state + 1'b1;
end
else
state <= state;
end
//***********************判断读取数据
11:begin
if (DATA[0] == 0)
begin
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
state <= state + 1;
cnt <= 64'd0;
Register_error <= 1'b0;
end
else
begin
Register_error <= 1'b1;
state <= state - 1;
end
end
12:begin //全片擦除完成 进行写操作
Sector_ER_DONE <= 1'b0;
O_spi_cs <= 1'b1;
state <= state + 1;
Erase_count <= Erase_count +1;
end
//***********************写启动
13:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Write_Enable;
end
14:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
15:begin
O_spi_cs <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
//***********************写状态寄存器
16:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Write_Enable_Register;
end
17:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
18:begin
O_spi_cs <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
//***********************写状态
19:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Write_Status_Register_2;
end
20:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
21:begin
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
//***********************写状态数据
22:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= 8'h02;
end
23:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
24:begin
O_spi_cs <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
//***********************读状态
25:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Read_Status_Register_2;
end
26:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
27:begin
// DATA <= 8'hff;
control_done <= 1'b0;
I_rx_en <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
//***********************读数据
28:begin
if (O_rx_done)
begin
DATA <= O_data_out;
state <= state + 1'b1;
end
else
state <= state;
end
//***********************判断读取数据
29:begin
if (DATA[1:0] == 2'b10)
begin
O_spi_cs <= 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
state <= state + 1;
cnt <= 64'd0;
Register_error <= 1'b0;
end
else
begin
Register_error <= 1'b1;
state <= state + 1;
end
end
30:begin
if (cnt >= 500000-1)
begin
cnt <= 64'd0;
state <= state + 1'b1;
end
cnt <= cnt + 1'b1;
end
//***********************等待buf时间缓存
31:begin
if (cnt >= 500)//5000000-1
begin
cnt <= 64'd0;
state <= state + 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
I_data_in <= Write_Enable;
strswitch <= 1'b1;
// count <= 25'd0;
end
else
begin
cnt <= cnt + 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
strswitch <= 1'b1;
end
end
32:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
33:begin
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
state <= state + 1'b1;
end
//***********************页写入
34:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
I_data_in <= Quad_Input_Page_Program;
state <= state + 1'b1;
end
35:if (O_tx_done)
begin
I_data_in <= addr2[23:16];
state <= state + 1'b1;
end
else
state <= state;
36:begin
if (O_tx_done)
begin
I_data_in <= addr2[15:8];
state <= state + 1'b1;
end
else
state <= state;
end
37:begin
if (O_tx_done)
begin
I_data_in <= addr2[7:0];
state <= state + 1'b1;
end
else
state <= state;
end
38:begin //提前切换
if (O_tx_done)
begin
strswitch <= 1'b0; //使用并行
state <= state + 1'b1;
end
else
state <= state;
end
39:begin
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
40:begin
I_tx_en <= 1'b1;
I_data_in <= DATA_out;
state <= state + 1'b1;
cnt <= cnt + 1'b1;
end
41:begin
if (cnt >= 257)
begin
cnt <= 64'd0;
state <= state + 2;
end
else if (O_tx_done)
begin
strswitch <= 1'b0;
I_tx_en <= 1'b0;
I_data_in <= DATA_out;
state <= state + 1'b1;
cnt <= cnt + 1'b1;
end
else
begin
I_tx_en <= 1'b1;
state <= state;
end
end
42:begin
if (O_tx_done)
begin
strswitch <= 1'b0;
I_tx_en <= 1'b0;
I_data_in <= DATA_out;
state <= state - 1'b1;
cnt <= cnt + 1'b1;
end
else
begin
I_tx_en <= 1'b1;
state <= state;
end
end
43:begin
if (Sector_ER_DONE)
begin
state <= state + 1'b1;
end
else if (addr2 >= 8388608-1)
begin
state <= state + 1'b1;
addr2 <= 24'd0;
end
else
begin
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
state <= 8'd31;
addr2 <= addr2 + 128;
end
end
44:begin
strswitch <= 1'b1 ;
state <= state + 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
end
//**************************************开时读取
//***********************写启动
45:begin
if (cnt == 25000000-1)
begin
cnt <= 32'd0;
state <= state + 1'b1;
end
else
begin
cnt <= cnt + 1'b1;
state <= state;
end
end
46:begin
state <= state + 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
I_data_in <= Write_Enable; //启动状态寄存器
strswitch <= 1'b1;
addr2 <= addr;
end
47:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
48:begin
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
state <= state + 1'b1;
end
//***********************读状态
49:begin
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
strswitch <= 1'b1;
I_data_in <= Read_Status_Register_2;
end
50:begin
if (O_tx_done)
state <= state + 1'b1;
else
state <= state;
end
51:begin
I_rx_en <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
52:begin
if (O_rx_done)
begin
DATA <= O_data_out;
state <= state + 1'b1;
end
else
state <= state;
end
//***********************判读读取数据
53:begin
if (DATA[1:0] == 2'b10)
begin
O_spi_cs <= 1'b1;
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
state <= state + 2;
cnt <= 64'd0;
Register_error <= 1'b0;
end
else
begin
Register_error <= 1'b1;
state <= state + 2;
end
end
54:begin
if (cnt >= 500000-1)
begin
cnt <= 64'd0;
state <= state + 1'b1;
end
cnt <= cnt + 1'b1;
end
//***************增加缓存时间读取数据
55:begin
if (cnt >= 500-1)
begin
cnt <= 64'd0;
state <= state + 1'b1;
end
begin
strswitch <= 1'b1;
cnt <= cnt + 1'b1;
// DATA <= 8'hff;
end
end
//********************四线制读取
56:begin
cnt <= 64'd0;
I_tx_en <= 1'b1;
O_spi_cs <= 1'b0;
state <= state + 1'b1;
I_data_in <= Fast_Read_Quad_Output;
end
57:if (O_tx_done)
begin
I_data_in <= addr2[23:16];
state <= state + 1'b1;
end
else
state <= state;
58:begin
if (O_tx_done)
begin
I_data_in <= addr2[15:8];
state <= state + 1'b1;
end
else
state <= state;
end
59:begin
if (O_tx_done)
begin
I_data_in <= addr2[7:0];
state <= state + 1'b1;
end
else
state <= state;
end
60:begin //提前切换
if (O_tx_done)
begin
strswitch <= 1'b0; //使用并行
state <= state + 1'b1;
end
else
state <= state;
end
//***************读取数据
61:begin
I_tx_en <= 1'b0;
I_rx_en <= 1'b1;
state <= state + 1'b1;
end
62:begin
if (cnt >= 257)
begin
cnt <= 64'd0;
state <= state + 2;
end
else if (O_rx_done)
begin
DATA <= O_data_out;
state <= state + 1'b1;
end
else
state <= state;
end
63:begin
if (DATA == DATA_out)
begin
cnt <= cnt + 1'b1;
state <= state - 1'b1;
DATA_error <= 1'b0;
end
else
begin
DATA_error <= 1'b1;
state <= state - 1'b1;
end
end
//换页读取数据判断
64:begin
if (Sector_ER_DONE)
begin
state <= 80;
end
else if (addr2 >= 8388608-1)
begin
state <= state + 1'b1;
addr2 <= 24'd0;
end
else
begin
addr2 <= addr2 + 128;
state <= 8'd55;
end
end
// 全片擦除10次 , 两个扇区擦除 1w次
65:begin
if (Erase_count == 10 - 1)
begin
O_spi_cs <= 1'b1 ;
state <= state + 1'b1;
I_tx_en <= 1'b0 ;
I_rx_en <= 1'b0 ;
strswitch <= 1'b1 ;
addr <= 24'd0 ;
end
else
begin
O_spi_cs <= 1'b1 ;
state <= 8'd1 ;
I_tx_en <= 1'b0 ;
I_rx_en <= 1'b0 ;
strswitch <= 1'b1 ;
end
end
//**********************************************************************启动两个扇区各擦除 1w次
//*******************写启动
66:begin
O_spi_cs <= 1'b0;
I_tx_en <= 1'b1;
state <= state + 1'b1;
I_data_in <= Write_Enable;
end
67:begin
if (O_tx_done)
begin
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
else
state <= state;
end
//*******************延迟等待
68:begin
if (cnt == 2)
begin
cnt <= 23'd0;
O_spi_cs <= 1'b1;
state <= state + 1'b1;
end
else
begin
cnt <= cnt + 1'b1;
state <= state;
end
end
//*******************扇区擦除指令
69:begin
O_spi_cs <= 1'b0;
I_tx_en <= 1'b1;
state <= state + 1'b1;
I_data_in <= Sector_Erase;
end
70:begin
if (O_tx_done)
begin
I_data_in<= addr[23:16];
state <= state + 1'b1;
end
else
state <= state;
end
71:begin
if (O_tx_done)
begin
I_data_in<= addr[15:8];
state <= state + 1'b1;
end
else
state <= state;
end
72:begin
if (O_tx_done)
begin
I_data_in<= addr[7:0];
state <= state + 1'b1;
end
else
state <= state;
end
73:begin
if (O_tx_done)
begin
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
else
state <= state;
end
//*******************延迟等待
74:begin
if (cnt == 2)
begin
cnt <= 23'd0;
O_spi_cs <= 1'b1;
state <= state + 1'b1;
end
else
begin
cnt <= cnt + 1'b1;
state <= state;
end
end
//*******************读取状态寄存器
75:begin
O_spi_cs <= 1'b0;
I_tx_en <= 1'b1;
state <= state + 1'b1;
I_data_in <= Read_Status_Register_1;
end
76:begin
if (O_tx_done)
begin
I_rx_en <= 1'b1;
I_tx_en <= 1'b0;
state <= state + 1'b1;
end
else
state <= state;
end
77:begin
if (O_rx_done)
begin
DATA <= O_data_out;
state <= state + 1'b1;
end
else
state <= state;
end
78:begin
if (DATA[0] == 0)
state <= state + 1'b1;
else
state <= state - 1'b1;
end
// 扇区擦除完成,进行写操作 , (跳转到13状态进行写数据与读取数据操作)
79:begin
Sector_ER_DONE <= 1'b1;
state <= 13;
addr2 <= addr;
end
80:begin //20000
if (Erase_count == 20000-10)
begin
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
state <= state + 2;
O_spi_cs <= 1'b1;
Erase_count <= Erase_count;
end //10000
else if (Erase_count == 10000-10)
begin
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
state <= state + 1;
O_spi_cs <= 1'b1;
Erase_count <= Erase_count + 1'b1;
end
else
begin
O_spi_cs <= 1'b1;
Erase_count <= Erase_count + 1'b1;
state <= 66;
end
end
//切换扇区
81:begin
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
addr <= addr + 128;
state <= 66;
end
//完成
82:begin
I_rx_en <= 1'b0;
I_tx_en <= 1'b0;
O_spi_cs <= 1'b1;
addr <= addr;
state <= state;
end
default : ;
endcase
end
endmodule
`timescale 1 ps/ 1 ps
//
// Company:
// Engineer:
//
// Create Date: 11-08-2022 16:06:06
// Design Name:
// Module Name: SPI
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Additional Comments:
//
//
module SPI(
input I_clk , // 鍏ㄥ眬鏃堕挓1MHz
input I_rst_n , // 澶嶄綅淇″彿锛屼綆鐢靛钩鏈夋晥
input I_rx_en , // 璇讳娇鑳戒俊鍙
input I_tx_en , // 鍙戦€佷娇鑳戒俊鍙
input [7:0] I_data_in , // 瑕佸彂閫佺殑鏁版嵁
input strswitch , // 涓茶涓庡苟琛屽垏鎹1浣跨敤涓茶 0浣跨敤骞惰
output reg [7:0] O_data_out , // 鎺ユ敹鍒扮殑鏁版嵁
output reg O_tx_done /*synthesis preserve*/, // 鍙戦€佷竴涓瓧鑺傚畬姣曟爣蹇椾綅
output reg O_rx_done , // 鎺ユ敹涓€涓瓧鑺傚畬姣曟爣蹇椾綅
// 鍥涚嚎鏍囧噯SPI淇″彿瀹氫箟
output reg O_spi_sck , // SPI鏃堕挓
inout O_spi_mosi , // SPI杈撳嚭锛岀敤鏉ョ粰浠庢満鍙戦€佹暟鎹 IO0
inout I_spi_miso , // SPI涓茶杈撳叆锛岀敤鏉ユ帴鏀朵粠鏈虹殑鏁版嵁 IO1
inout WP , // IO2
inout HOLD // IO3
);
//------------------------------------------------------------------------------
//----------- Registers Declarations -------------------------------------------
//------------------------------------------------------------------------------
reg [3:0] R_tx_state ;
reg [3:0] R_rx_state ;
reg [4:0] R_tx_state_c ;
reg [3:0] R_rx_state_c ;
reg fag_IO0 ;
reg fag_IO1 ;
reg fag_IO2 ;
reg fag_IO3 ;
reg [5:0] cnt ;
// 1鍙戦€佺粰鑺墖鏁版嵁 0鎺ユ敹鑺墖鏁版嵁
assign O_spi_mosi = I_tx_en==0 ? 1'hz : fag_IO0;
assign I_spi_miso = I_tx_en==0 ? 1'hz : fag_IO1;
assign WP = I_tx_en==0 ? 1'hz : fag_IO2;
assign HOLD = I_tx_en==0 ? 1'hz : fag_IO3;
always @(posedge I_clk )
begin
if(!I_rst_n)
begin
R_tx_state <= 4'd0 ;
R_rx_state <= 4'd0 ;
R_tx_state_c<= 5'd0 ;
R_rx_state_c<= 4'd0 ;
O_spi_sck <= 1'b0 ;
O_tx_done <= 1'b0 ;
O_rx_done <= 1'b0 ;
O_data_out <= 8'd0 ;
fag_IO0 <= 1'b0 ;
fag_IO1 <= 1'b0 ;
fag_IO2 <= 1'b0 ;
fag_IO3 <= 1'b0 ;
cnt <= 6'd0 ;
end
else if(I_tx_en && strswitch) // 鍙戦€佷娇鑳戒俊鍙锋墦寮€鐨勬儏鍐典笅
begin
case(R_tx_state_c)
0: // 鍙戦€佺7浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[7] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
1:
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
2: // 鍙戦€佺6浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[6] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
3: //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
4: // 鍙戦€佺5浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[5] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
5: //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
6: // 鍙戦€佺4浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[4] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
7: //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
8: // 鍙戦€佺3浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[3] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
9: //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
10: // 鍙戦€佺2浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[2] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
11: //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
12: // 鍙戦€佺1浣
if (cnt >= 25-1)
begin
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[1] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
13: //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
14: // 鍙戦€佺0浣
if (cnt >= 25-1)
begin
O_tx_done <= 1'b0 ;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_tx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[0] ;
fag_IO1 <= 1'hz ;
fag_IO2 <= 1'hz ;
fag_IO3 <= 1'hz ;
O_spi_sck <= 1'b0 ;
R_tx_state_c <= R_tx_state_c ;
end
15 : //鏁村悎濂囨暟鐘舵€
if (cnt >= 25-1)
begin
O_tx_done <= 1'b0 ;
O_rx_done <= 1'b0;
cnt <= 6'd0;
R_tx_state_c <= R_tx_state_c + 1'b1;
end
else
begin
O_rx_done <= 1'b0;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state_c <= R_tx_state_c ;
O_tx_done <= 1'b0 ;
end
16:begin
if (cnt >= 25-1)
begin
O_rx_done <= 1'b0;
cnt <= 6'd0 ;
O_tx_done <= 1'b1 ;
R_tx_state_c <= 0 ;
end
else
begin
O_spi_sck <= 1'b0 ;
O_rx_done <= 1'b0;
O_tx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
end
end
default: ;
endcase
end
else if(I_rx_en && strswitch) // 鎺ユ敹浣胯兘淇″彿鎵撳紑鐨勬儏鍐典笅
begin
case(R_rx_state_c)
4'd0, 4'd2 , 4'd4 , 4'd6 ,
4'd8, 4'd10, 4'd12, 4'd14 : //鏁村悎鍋舵暟鐘舵€
if (cnt == 25-1)
begin
O_tx_done <= 1'b0 ;
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
O_tx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b0 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
end
4'd1: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[7] <= I_spi_miso ;
end
4'd3: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[6] <= I_spi_miso ;
end
4'd5: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[5] <= I_spi_miso ;
end
4'd7: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[4] <= I_spi_miso ;
end
4'd9: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[3] <= I_spi_miso ;
end
4'd11: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[2] <= I_spi_miso ;
end
4'd13: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
cnt <= 6'd0;
R_rx_state_c <= R_rx_state_c + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_rx_done <= 1'b0 ;
O_data_out[1] <= I_spi_miso ;
end
4'd15: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
O_rx_done <= 1'b1 ;
cnt <= 6'd0;
R_rx_state_c <= 0;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state_c <= R_rx_state_c ;
O_data_out[0] <= I_spi_miso ;
end
default:R_rx_state_c <= 4'd0 ;
endcase
end
else if(I_tx_en && strswitch==0) // 鍙戦€佷娇鑳戒俊鍙锋墦寮€鐨勬儏鍐典笅
begin
case(R_tx_state)
4'd0: // 鍙戦€佺0浣
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_tx_state <= R_tx_state + 1'b1;
end
else
begin
O_rx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[4] ;
fag_IO1 <= I_data_in[5] ;
fag_IO2 <= I_data_in[6] ;
fag_IO3 <= I_data_in[7] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state ;
O_tx_done <= 1'b0 ;
end
4'd1:
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_tx_state <= R_tx_state + 1'b1;
end
else
begin
O_rx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state <= R_tx_state ;
O_tx_done <= 1'b0 ;
end
4'd2: // 鍙戦€佺1浣
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_tx_state <= R_tx_state + 1'b1;
end
else
begin
O_rx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
fag_IO0 <= I_data_in[0] ;
fag_IO1 <= I_data_in[1] ;
fag_IO2 <= I_data_in[2] ;
fag_IO3 <= I_data_in[3] ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state ;
O_tx_done <= 1'b0 ;
end
4'd3:
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_tx_state <= R_tx_state + 1'b1;
end
else
begin
O_rx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_tx_state <= R_tx_state ;
O_tx_done <= 1'b0 ;
end
4'd4:
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
O_tx_done <= 1'b1 ;
R_tx_state <= 4'd0 ;
end
else
begin
O_rx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b0 ;
R_tx_state <= R_tx_state ;
end
default: ;
endcase
end
else if(I_rx_en && strswitch==0) // 鎺ユ敹浣胯兘淇″彿鎵撳紑鐨勬儏鍐典笅
begin
case(R_rx_state)
4'd0:
if (cnt == 25-1)
begin
O_tx_done <= 1'b0 ;
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_rx_state <= R_rx_state + 1'b1;
end
else
begin
O_tx_done <= 1'b0 ;
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b0 ;
R_rx_state <= R_rx_state ;
O_rx_done <= 1'b0 ;
end
4'd1: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_rx_state <= R_rx_state + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state ;
O_rx_done <= 1'b0 ;
O_data_out[4] <= O_spi_mosi ;
O_data_out[5] <= I_spi_miso ;
O_data_out[6] <= WP ;
O_data_out[7] <= HOLD ;
end
4'd2:
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_rx_state <= R_rx_state + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b0 ;
R_rx_state <= R_rx_state ;
O_rx_done <= 1'b0 ;
end
4'd3: // 鎺ユ敹绗浣
if (cnt == 25-1)
begin
O_rx_done <= 1'b0 ;
cnt <= 6'd0 ;
R_rx_state <= R_rx_state + 1'b1;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b1 ;
R_rx_state <= R_rx_state ;
O_rx_done <= 1'b0 ;
O_data_out[0] <= O_spi_mosi ;
O_data_out[1] <= I_spi_miso ;
O_data_out[2] <= WP ;
O_data_out[3] <= HOLD ;
end
4'd4:
if (cnt == 25-1)
begin
O_rx_done <= 1'b1 ;
cnt <= 6'd0 ;
R_rx_state <= 4'd0 ;
end
else
begin
cnt <= cnt + 1'b1 ;
O_spi_sck <= 1'b0 ;
R_rx_state <= R_rx_state ;
end
default: ;
endcase
end
else
begin
R_tx_state <= 4'd0 ;
R_rx_state <= 4'd0 ;
R_tx_state_c<= 5'd0 ;
R_rx_state_c<= 4'd0 ;
O_tx_done <= 1'b0 ;
O_rx_done <= 1'b0 ;
O_spi_sck <= 1'b0 ;
O_data_out <= 8'd0 ;
cnt <= 6'd0 ;
end
end
endmodule
综上所述,通过利用FPGA实现的该程序,成功实现了Flash存储器的写入使能、整片擦除、全片写入和全片数据读取功能。这些功能的实现为Flash存储器的使用带来了更大的便利性和灵活性,使得数据的存储和访问更加可靠和高效。通过该程序,用户能够有效地控制Flash存储器的操作,并实现对整个存储器的快速擦除和写入,以及高效的数据读取。这些功能的结合为各种应用场景提供了更多的选择和解决方案。