文章目录
- flash读写数据的特点
- 1. 扇擦除SE(Sector Erase)
- 1.1 flash_se 模块设计
- 1.1.1 信号连接示意图:
- 1.1.2 SE状态机
- 1.1.3 波形图设计:
- 1.1.4 代码
- 2. 页写PP(Page Program)
- 2.1 flash_pp模块设计
- 2.1.1 信号连接示意图:
- 2.1.2 PP状态机
- 2.1.3 波形图设计(WE部分和DELAY部分和上述一致)
- 2.1.4 代码
- 3.读flash操作
- 3.1 flash_rd模块设计
- 3.1.1 信号连接示意图
- 3.1.2 波形图设计
- 3.1.3 代码
- 4.模块整合
- 4.1 state_ctrl模块设计
- 4.1.1 信号连接示意图
- 4.1.2 状态机转换
- 4.1.3 波形图设计
- 4.1.4 代码
- 5.下板操作:
开始之前需要先了解一下SPI通信协议的特点: spi协议
本篇内容要实现FPGA芯片通过SPI总线与flash芯片进行通信,连接如下图所示:
信号线解释:
- Cs_n:片选线,为 FPGA 的输出信号,Flash 的输入信号,低电平有效;
- Sck:时钟线,为 FPGA 的输出信号,Flash 的输入信号,Flash 根据该信 号的上升沿锁存 sdi 发来的数据,根据该信号的下降沿通过 sdo 输出数据;
- sdi:mosi,数据线,为 FPGA 的输出信号,Flash 的输入信号,FPGA 可通过 sdi总线串行的传输数据到 Flash;
- sdo:miso,数据线,为 FPGA 的输入信号,Flash 的输出信号,Flash 可通过 sdo总线串行的传输数据到 FPGA。
flash读写数据的特点
这里以 M25p16 型号的 flash 为例进行介绍。
M25p16 最大的时钟频率为 50Mhz,在此我们进行擦除时采用 12.5Mhz 的时钟,即 sck 的时钟频率为 12.5Mhz。该款 Flash 芯片的存储空间16Mbit,每个地址内存储 1byte(8bit)的数据,共 2M 的存储深度,其地址分为 32 扇区(sector)、每个扇区包含 256 页(page)、每一页包含 256字节(byte),因此该 Flash 芯片需要用到 21 位地址线,加上扩展的 3bit 地址线,
一共用到== 24bit 地址线==,具体如下图 3所示。
1. 扇擦除SE(Sector Erase)
通过前面的项目我们知道,ram存储器的特点是:,在同一个地址写入新的数据时,旧数据会被覆盖。而flash则不同,在对 Flash 进行写入数据时,首先需要将 Flash内部现有的数据进行擦除,Flash 的擦除分为扇区擦除(sector erase)和全擦除(bulk erase)。下面将以扇区擦除为例进行讲解.
在进行 SE 之前需要给出一个写使能指令
(WREN),然后进行扇区擦除,WREN的指令为8’h06。SE时序图如下:
注意:
- 在 WREN 结束后,cs_n 需要被拉高,为了确保 WREN 被 Flash 存储,因此 cs_n 拉高的时间至少需要 100ns(官方文档虽然没写拉高 100ns 但是为了稳定一定要 拉高 cs_n),之后再次拉低 cs_n 为发送 SE 指令做准备。
- 由于是扇区擦除,因此给出的地址位只有高 8bit有效,低 16bit 无论是何值都对该扇区的擦除没有影响。
1.1 flash_se 模块设计
1.1.1 信号连接示意图:
1.1.2 SE状态机
1.1.3 波形图设计:
1.1.4 代码
module flash_se(input wire sclk,input wire rst,input wire se_flag,input wire [23:0] se_addr,output wire sck,output wire cs_n,output wire sdi);parameter IDLE = 4'b0001;
parameter WE = 4'b0010;
parameter DELAY = 4'b0100;
parameter SE = 4'b1000;parameter DIV_END_NUM = 4-1;
parameter DELAY_END =16-1;
parameter WRITE_EN =8'h06;
parameter SECTOR_E =8'hD8;reg [3:0] state;
reg [7:0] div_cnt;
reg [7:0] bit_cnt;
reg [7:0] delay_cnt;
reg cs_n_r;
reg sck_r;
reg sdi_r;
reg [7:0] we_inst_shift;
reg [31:0] se_inst_shift;assign sck = sck_r;
assign cs_n = cs_n_r;
assign sdi = sdi_r;
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginstate <= IDLE;endelse case (state)IDLE : if(se_flag == 1'b1 )state <= WE;WE : if(div_cnt == DIV_END_NUM && bit_cnt == 'd8)state <= DELAY;DELAY: if (delay_cnt == DELAY_END)state <= SE;SE : if(div_cnt == DIV_END_NUM && bit_cnt == 'd32)state <= IDLE;default : state <= IDLE;endcase
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begindiv_cnt <= 'd0;endelse if(div_cnt == DIV_END_NUM) begindiv_cnt <='d0;endelse if (state == WE || state == SE) begindiv_cnt <= div_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginbit_cnt <= 'd0;endelse if (state == WE && bit_cnt == 'd8 && div_cnt == DIV_END_NUM) beginbit_cnt <='d0;endelse if (state == WE && div_cnt == DIV_END_NUM) beginbit_cnt <= bit_cnt + 1'b1;endelse if (state == SE && bit_cnt == 'd32 && div_cnt == DIV_END_NUM) beginbit_cnt <='d0;endelse if (state == SE && div_cnt == DIV_END_NUM) beginbit_cnt <= bit_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begindelay_cnt <='d0;endelse if (state == DELAY) begindelay_cnt <= delay_cnt + 1'b1;endelse begindelay_cnt <= 'd0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begincs_n_r <= 1'b1;endelse if(state == WE && div_cnt == DIV_END_NUM && bit_cnt == 'd8) begincs_n_r <= 1'b1;endelse if (state == IDLE && se_flag == 1'b1) begincs_n_r <= 1'b0;endelse if(state == SE && div_cnt == DIV_END_NUM && bit_cnt == 'd32) begincs_n_r <= 1'b1;endelse if(state == DELAY && delay_cnt == DELAY_END) begincs_n_r <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginsck_r <= 1'b0;endelse if (state == WE && div_cnt == (DIV_END_NUM >>1) && bit_cnt != 'd8) beginsck_r <= 1'b1;endelse if (state == WE && div_cnt == (DIV_END_NUM ) && bit_cnt != 'd8) beginsck_r <= 1'b0;endelse if (state == SE && div_cnt == (DIV_END_NUM >>1) && bit_cnt != 'd32) beginsck_r <= 1'b1;endelse if (state == SE && div_cnt == (DIV_END_NUM ) && bit_cnt != 'd32) beginsck_r <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginwe_inst_shift <= 'd0;endelse if (se_flag == 1'b1) beginwe_inst_shift <= WRITE_EN;endelse if(state == WE && div_cnt == DIV_END_NUM) beginwe_inst_shift <= {we_inst_shift[6:0],1'b0};end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginse_inst_shift <= 'd0;endelse if (se_flag == 1'b1 && state == IDLE) beginse_inst_shift <= {SECTOR_E,se_addr};endelse if (state == SE && div_cnt == DIV_END_NUM) beginse_inst_shift <= {se_inst_shift[30:0],1'b0};end
endalways @* beginif (state == WE) beginsdi_r <= we_inst_shift[7];endelse if(state == SE) beginsdi_r <= se_inst_shift[31];endelse beginsdi_r <= 1'b0;end
endendmodule
2. 页写PP(Page Program)
Flash 页写功能,简称 PP,Page Program 命令 8’h02。同样与擦除指令一样,需要再发送 PP 指令之前,执行 Write EN 操作,当执行完 PP 后 Write EN 会自动复位,所以每次 PP 之前必须发送 Write EN 操作。PP时序图如下:
2.1 flash_pp模块设计
说明:这里:这里pp进去的256byte数据是提前存在fifo的,因此开始向flash里pp数据的时候需要产生读fifo使能(rd_en)。
Fifo的位宽设置为8,fifo一次读出8bit数据,而sdi传输1bit数据,所以需要考虑fifo读使能拉高的时机以及读出的数据移位的时机
2.1.1 信号连接示意图:
2.1.2 PP状态机
2.1.3 波形图设计(WE部分和DELAY部分和上述一致)
rd_en和rd_data数据移位实现并转串细节:
2.1.4 代码
module flash_pp( input wire sclk,input wire rst,input wire pp_flag,input wire [23:0] pp_addr,input wire wr_en,input wire [7:0] wr_data,output wire sck,output wire cs_n,output wire sdi);parameter IDLE = 4'b0001;
parameter WE = 4'b0010;
parameter DELAY = 4'b0100;
parameter PP = 4'b1000;parameter DIV_END_NUM = 4-1;
parameter DELAY_END =16-1;
parameter WRITE_EN =8'h06;
parameter PAGE_P =8'h02;reg [3:0] state;
reg [7:0] div_cnt;
reg [11:0] bit_cnt;
reg [7:0] delay_cnt;
reg cs_n_r;
reg sck_r;
reg sdi_r;
reg [7:0] we_inst_shift;
reg [31:0] pp_inst_shift;
reg read_fifo_en;
reg pp_shift_flag;
wire [7:0] read_fifo_data;assign sck = sck_r;
assign cs_n = cs_n_r;
assign sdi = sdi_r;
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginstate <= IDLE;endelse case (state)IDLE : if(pp_flag == 1'b1 )state <= WE;WE : if(div_cnt == DIV_END_NUM && bit_cnt == 'd8)state <= DELAY;DELAY: if (delay_cnt == DELAY_END)state <= PP;PP : if(div_cnt == DIV_END_NUM && bit_cnt == 'd2080)state <= IDLE;default : state <= IDLE;endcase
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begindiv_cnt <= 'd0;endelse if(div_cnt == DIV_END_NUM) begindiv_cnt <='d0;endelse if (state == WE || state == PP) begindiv_cnt <= div_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginbit_cnt <= 'd0;endelse if (state == WE && bit_cnt == 'd8 && div_cnt == DIV_END_NUM) beginbit_cnt <='d0;endelse if (state == WE && div_cnt == DIV_END_NUM) beginbit_cnt <= bit_cnt + 1'b1;endelse if (state == PP && bit_cnt == 'd2080 && div_cnt == DIV_END_NUM) beginbit_cnt <='d0;endelse if (state == PP && div_cnt == DIV_END_NUM) beginbit_cnt <= bit_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begindelay_cnt <='d0;endelse if (state == DELAY) begindelay_cnt <= delay_cnt + 1'b1;endelse begindelay_cnt <= 'd0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begincs_n_r <= 1'b1;endelse if(state == WE && div_cnt == DIV_END_NUM && bit_cnt == 'd8) begincs_n_r <= 1'b1;endelse if (state == IDLE && pp_flag == 1'b1) begincs_n_r <= 1'b0;endelse if(state == PP && div_cnt == DIV_END_NUM && bit_cnt == 'd2080) begincs_n_r <= 1'b1;endelse if(state == DELAY && delay_cnt == DELAY_END) begincs_n_r <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginsck_r <= 1'b0;endelse if (state == WE && div_cnt == (DIV_END_NUM >>1) && bit_cnt != 'd8) beginsck_r <= 1'b1;endelse if (state == WE && div_cnt == (DIV_END_NUM ) && bit_cnt != 'd8) beginsck_r <= 1'b0;endelse if (state == PP && div_cnt == (DIV_END_NUM >>1) && bit_cnt != 'd2080) beginsck_r <= 1'b1;endelse if (state == PP && div_cnt == (DIV_END_NUM ) && bit_cnt != 'd2080) beginsck_r <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginwe_inst_shift <= 'd0;endelse if (pp_flag == 1'b1) beginwe_inst_shift <= WRITE_EN;endelse if(state == WE && div_cnt == DIV_END_NUM) beginwe_inst_shift <= {we_inst_shift[6:0],1'b0};end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginpp_inst_shift <= 'd0;endelse if (pp_flag == 1'b1 && state == IDLE) beginpp_inst_shift <= {PAGE_P,pp_addr};endelse if (state == PP && div_cnt == DIV_END_NUM && bit_cnt < 'd31) beginpp_inst_shift <= {pp_inst_shift[30:0],1'b0};endelse if (read_fifo_en == 1'b1) beginpp_inst_shift <= {read_fifo_data,24'd0};endelse if (pp_shift_flag == 1'b1 ) beginpp_inst_shift <= {pp_inst_shift[30:24],25'd0};end
endalways @* beginif (bit_cnt >='d31 && bit_cnt <'d2079 && div_cnt == 'd3 && state == PP && bit_cnt[2:0]==3'b111) beginread_fifo_en <= 1'b1;endelse beginread_fifo_en <= 1'b0;end
endalways @* beginif (bit_cnt >='d31 && bit_cnt <'d2079 && div_cnt == 'd3 && state == PP && bit_cnt[2:0]!=3'b111) beginpp_shift_flag <= 1'b1;endelse beginpp_shift_flag <= 1'b0;end
endalways @* beginif (state == WE) beginsdi_r <= we_inst_shift[7];endelse if(state == PP) beginsdi_r <= pp_inst_shift[31];endelse beginsdi_r <= 1'b0;end
endfifo_1024x8 fifo_1024x8_inst (.clk(sclk), // input clk.din(wr_data), // input [7 : 0] din.wr_en(wr_en), // input wr_en.rd_en(read_fifo_en), // input rd_en.dout(read_fifo_data), // output [7 : 0] dout.full(full), // output full.empty(empty) // output empty
);
endmodule
3.读flash操作
Read data byte 读数据字节指令,简称 RDB 指令,指令码为 8’h03,读指令可以读取 Flash 地址空间的任何一个byte 数据,不受扇区,页的限制,而且可以连续读取出所有数据。
读数据的必要条件:给出读命令码,然后紧跟 24bit 的起始地址,之后会在 SDO 总线串行输出读出数据,直到 Cs_n 信号拉高中断读出数据操作,否则地址在 flash 内部递增读出数据。
flash_rd操作时序图:
3.1 flash_rd模块设计
读控制器要能满足以下功能:
给定读起始地址和需要读取的数据长度,控制器自动启动读 flash, 并把读出数据缓存到 fifo 中,以供其他模块读取调用。
3.1.1 信号连接示意图
3.1.2 波形图设计
sdo是1bit ,而fifo的wr_data为8bit,因此要合理设计sdo的移位标志,与wr_en的标志,实现串转并写入fifo中。
3.1.3 代码
module flash_rd(input wire sclk,input wire rst,input wire rd_flag,input wire [23:0] rd_addr,input wire [10:0] rd_len,output wire rd_ready,input wire rd_en,output wire [7:0] rd_data,output wire sck,output wire cs_n,input wire sdo,output wire sdi);parameter DIV_END_NUM = 4-1;
parameter READ_P = 8'h03;reg [15:0] bit_cnt_end;
reg cs_n_r,sdi_r,sck_r;
reg [7:0] div_cnt;
reg [15:0] bit_cnt;
reg [31:0] rd_inst_shift;
reg shift_flag;
reg wr_en;
reg [7:0] sdo_data_shift;
reg flash_read_end;
wire full,empty;assign sdi = sdi_r;
assign sck = sck_r;
assign cs_n = cs_n_r;always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginbit_cnt_end <='d0;endelse if (rd_flag == 1'b1) beginbit_cnt_end <= 32 + (rd_len<<3);end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begincs_n_r <= 1'b1;endelse if (div_cnt == DIV_END_NUM && bit_cnt == bit_cnt_end) begincs_n_r <= 1'b1;endelse if (rd_flag == 1'b1) begincs_n_r <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begindiv_cnt <='d0;endelse if(div_cnt == DIV_END_NUM) begindiv_cnt <= 'd0;endelse if (cs_n_r == 1'b0) begindiv_cnt <= div_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginbit_cnt <='d0;endelse if (cs_n_r == 1'b0 && div_cnt == DIV_END_NUM && bit_cnt == bit_cnt_end) beginbit_cnt <= 'd0;endelse if (cs_n_r == 1'b0 && div_cnt == DIV_END_NUM) beginbit_cnt <= bit_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginsck_r <= 1'b0;endelse if (cs_n_r == 1'b0 && div_cnt == (DIV_END_NUM>>1) && bit_cnt != bit_cnt_end) beginsck_r <= 1'b1;endelse if (cs_n_r == 1'b0 && div_cnt == DIV_END_NUM && bit_cnt != bit_cnt_end) beginsck_r <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginrd_inst_shift <='d0;endelse if (rd_flag == 1'b1 && cs_n_r == 1'b1) beginrd_inst_shift <= {READ_P,rd_addr};endelse if (cs_n_r == 1'b0 && bit_cnt < 31 && div_cnt== DIV_END_NUM) beginrd_inst_shift <= {rd_inst_shift[30:0],1'b0};end
endalways @*sdi_r <= rd_inst_shift[31];always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginshift_flag <= 1'b0;endelse if (bit_cnt >31 && bit_cnt != bit_cnt_end && div_cnt == (DIV_END_NUM>>1)) beginshift_flag <= 1'b1;endelse beginshift_flag <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginwr_en <= 1'b0;endelse if (bit_cnt > 31 && bit_cnt != bit_cnt_end && div_cnt == ((DIV_END_NUM >>1)+1) && bit_cnt[2:0] == 3'b111) beginwr_en <= 1'b1;endelse beginwr_en <= 1'b0;endendalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginsdo_data_shift <= 'd0;endelse if (shift_flag == 1'b1) beginsdo_data_shift <= {sdo_data_shift[6:0],sdo};end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginflash_read_end <= 1'b0;endelse if(flash_read_end == 1'b1 && empty == 1'b1)beginflash_read_end <= 1'b0;endelse if (cs_n_r == 1'b0 && bit_cnt == bit_cnt_end && div_cnt == DIV_END_NUM) beginflash_read_end <= 1'b1;end
endassign rd_ready = flash_read_end & (~empty);fifo_1024x8 fifo_1024x8_inst (.clk(sclk), // input clk.din(sdo_data_shift), // input [7 : 0] din.wr_en(wr_en), // input wr_en.rd_en(rd_en), // input rd_en.dout(rd_data), // output [7 : 0] dout.full(full), // output full.empty(empty) // output empty
);endmodule
4.模块整合
到目前为止,我们分别完成了flash_se、flash_pp、flash_rd三个对flash进行操作的模块,如何将他们整合在一起,实现:
我们通过串口给 fpga 发送指令,fpga 解析指令之后,转化为对 flash_se、flash_pp、flash_rd 的控制时序(即fpga能根据接收到的指令产生控制对应模块需要的输入信号),实现对 flash 的读or写or擦除操作。
4.1 state_ctrl模块设计
既然要与上位机串口交互,我们必须制定一个协议,我们制定三种数据包类型,擦除命令包、写命令包、读命令包,当fpga接收到对应的命令包后可以跳转到对应模块。
4.1.1 信号连接示意图
4.1.2 状态机转换
4.1.3 波形图设计
4.1.4 代码
关键代码:
module state_ctrl(input wire sclk,input wire rst,output reg cs_n,output reg sck,output reg sdi,input wire sdo,/*************uart rx****************************/input wire rx_flag,input wire [7:0] rx_data,/************uart tx ***************************/output wire tx_flag,output wire [7:0] tx_data,/************flash se interface*******************/output wire se_flag,output wire [23:0] se_addr,input wire se_sck,input wire se_cs_n,input wire se_sdi,/************flash pp interface******************/output wire pp_flag,output wire [23:0] pp_addr,output wire wr_en,output wire [7:0] wr_data,input wire pp_sck,input wire pp_cs_n,input wire pp_sdi,/************flash rd interface******************/output wire rd_flag,output wire [23:0] rd_addr,output wire [10:0] rd_len,input wire rd_ready,output wire rd_en,input wire [7:0] rd_data,input wire rd_sck,input wire rd_cs_n,output wire rd_sdo,input wire rd_sdi);
parameter IDLE =4'b0001;
parameter WRITE =4'b0010;
parameter SERASE=4'b0100;
parameter READ =4'b1000;parameter DIV_CNT_END = 4340;//52082;reg [3:0] state;
reg write_end,serase_end,read_end;
reg [15:0] byte_cnt;
reg [23:0] flash_addr_shift;
reg wr_fifo_en;
reg [7:0] wr_fifo_data;
reg [15:0] rd_len_shift;
reg rd_flash_req;//rd_flag
reg [15:0] div_cnt;
reg rd_fifo_en;
reg [15:0] tx_d_cnt;always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginstate <= IDLE;endelse case(state)IDLE : if(rx_flag == 1'b1 && rx_data == 8'hcc)beginstate <= WRITE;endelse if(rx_flag == 1'b1 && rx_data == 8'hee) beginstate <= SERASE;endelse if (rx_flag == 1'b1 && rx_data == 8'hdd) beginstate <= READ;endWRITE : if (write_end == 1'b1 ) beginstate <= IDLE;endSERASE : if (serase_end == 1'b1 ) beginstate <= IDLE;endREAD : if (read_end == 1'b1) beginstate <= IDLE;enddefault : state <= IDLE;endcase
end//write state and flash pp
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginbyte_cnt <= 'd0;endelse if (state == IDLE) beginbyte_cnt <='d0;endelse if (state != IDLE && rx_flag == 1'b1) beginbyte_cnt <= byte_cnt + 1'b1;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginflash_addr_shift <= 'd0;endelse if (state != IDLE && byte_cnt < 3 && rx_flag == 1'b1 ) beginflash_addr_shift <= {flash_addr_shift[15:0],rx_data};end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginwr_fifo_en <= 1'b0;endelse if (state == WRITE && byte_cnt >2 && rx_flag == 1'b1) beginwr_fifo_en <= 1'b1;endelse beginwr_fifo_en <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginwr_fifo_data <= 'd0;endelse if (state == WRITE) beginwr_fifo_data <= rx_data;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginwrite_end <=1'b1;endelse if (state == WRITE && byte_cnt == 'd258 && rx_flag == 1'b1) beginwrite_end <= 1'b1;endelse beginwrite_end <= 1'b0;end
endassign pp_flag = write_end;
assign pp_addr = flash_addr_shift;
assign wr_en = wr_fifo_en;
assign wr_data = wr_fifo_data;
//write state end
//serase state start
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginserase_end <= 1'b0;endelse if (state == SERASE && rx_flag == 1'b1 && byte_cnt == 2) beginserase_end <= 1'b1;endelse beginserase_end <= 1'b0;end
end
assign se_flag = serase_end;
assign se_addr = flash_addr_shift;
//serase state end
//read state startalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginrd_len_shift <='d0;endelse if (state == READ && (byte_cnt == 3 || byte_cnt == 4) && rx_flag == 1'b1 ) beginrd_len_shift <= {rd_len_shift[7:0],rx_data};end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginrd_flash_req<= 1'b0;endelse if (state == READ && byte_cnt == 4 && rx_flag == 1'b1 ) beginrd_flash_req <= 1'b1;endelse beginrd_flash_req <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begindiv_cnt <='d0;endelse if(state == READ && rd_ready == 1'b1 && div_cnt == DIV_CNT_END)begindiv_cnt <= 'd0;endelse if (state == READ && rd_ready == 1) begindiv_cnt <= div_cnt + 1'b1;endelse if (rd_ready == 1'b0) begindiv_cnt <='d0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginrd_fifo_en <= 1'b0;endelse if (state == READ && rd_ready == 1'b1 && div_cnt ==0) beginrd_fifo_en <= 1'b1;endelse beginrd_fifo_en <= 1'b0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) begintx_d_cnt <='d0;endelse if (state == READ && rd_fifo_en == 1'b1 ) begintx_d_cnt <= tx_d_cnt + 1'b1;endelse if(state != READ) begintx_d_cnt <='d0;end
endalways @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginread_end <= 1'b0;endelse if (state == READ && tx_d_cnt == (rd_len_shift-1)&&rd_fifo_en == 1'b1 ) beginread_end <= 1'b1;endelse beginread_end <= 1'b0;end
endassign rd_flag = rd_flash_req;
assign rd_addr = flash_addr_shift;
assign rd_len = rd_len_shift[10:0];
assign rd_en = rd_fifo_en;assign tx_flag = rd_fifo_en;
assign tx_data = rd_data;//read state end
//flash spi signal routealways @* beginif(state == READ) beginsdi <= rd_sdi;cs_n <= rd_cs_n;sck <= rd_sck;endelse beginsdi <= se_sdi | pp_sdi;sck <= se_sck | pp_sck;cs_n <= se_cs_n & pp_cs_n;end
endassign rd_sdo =sdo ;endmodule
5.下板操作:
实现将一个呼吸灯的程序固化到flash中
1.先将flash_ctrl设计的bit文件通过JTAG下载线下载到fpga板子上(保证fpga有读写flash的功能,这是往flash中烧写文件的前提)
2.打开老师提供的fpga_update软件(这个软件是简化版本的,目前只能对flash进行写数据),将呼吸灯的bin文件下载到flash中
3.烧写完成后,板卡重新上电,发现板子开始执行呼吸灯的程序了。