1.写在前面
FPGA内部不具有掉电存储程序的功能,所以都需要外置的flash存储器来存储程序,上电后从flash加载程序到FPGA中运行。外置的flash可以存储程序,也可以存储任何用户数据,可以更有效的利用flash的存储空间。
值得注意的是,用于存储程序的flash和fpga连接用的是fpga的专用引脚,flash时钟信号不可以直接驱动,这个信号是fpga硬件直接管理的,需要使用原语才可以驱动时钟信号,这个原语叫STARTUPE2。
STARTUPE2 #(
.PROG_USR("FALSE"), // Activate program event security feature. Requires encrypted bitstreams.
.SIM_CCLK_FREQ(0.0) // Set the Configuration Clock Frequency(ns) for simulation
)
STARTUPE2_inst
(
.CFGCLK(), // 1-bit output: Configuration main clock output
.CFGMCLK(), // 1-bit output: Configuration internal oscillator clock output
.EOS(), // 1-bit output: Active high output signal indicating the End Of Startup.
.PREQ(), // 1-bit output: PROGRAM request to fabric output
.CLK(0), // 1-bit input: User start-up clock input
.GSR(0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name)
.GTS(0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name)
.KEYCLEARB(1), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM)
.PACK(1), // 1-bit input: PROGRAM acknowledge input
.USRCCLKO(flash_clk), // 1-bit input: User CCLK input
.USRCCLKTS(0), // 1-bit input: User CCLK 3-state enable input
.USRDONEO(1), // 1-bit input: User DONE pin output control
.USRDONETS(1) // 1-bit input: User DONE 3-state enable output
)
里边的flash_clk就是要约束的flash时钟信号,通过这个原语才能约束用于配置程序的flash的时钟信号。
不想这么麻烦也可以,在硬件上再加一片flash接到通用管脚上就完了,但是想做远程程序更新功能就必须这么干,通过串口或者网口或者什么其他通信接口将要更新的程序发送至fpga,fpga存储空间不够的话就暂存到ddr或者外置sram里,再按顺序操作flash烧入,扯远了,有机会一定要搞一下这个功能肯定有用,只是我现在还不会写上位机。
2.FPGA实现qspi flash读写
前面扯了很多没用的,直接上源码,自己写的,为了省事没搞qspi只用了spi,智商感人的领导把时间全给硬件开发了,硬件平台搭了一年多,软件只给了3个月,交货前2个月才知道具体需求,之前全是含糊其辞,没办法全是赶工出来的,凑活看吧,改改就能用,你问我为啥敢吐槽,已经被辞了,项目干的甲方无比懊恼,钱都不想给了,领导肯定是没错的,所以嘛只能这样了,硬件做的一言难尽时间全耽误了硬件平台到我手里连4个月都没有中间还反复改硬件,硬件做不到了就拿程序填,硬件做的垃圾最后全是做软件的背了锅,所以最后只有我走人,做垃圾的还好好的呢,说多了直接上码,前面发的牢骚各位直接忽略。
顶层命令控制
///
/* Document info
document class : RES
module name : flash
module purpose : n25q256 256byte per page
version : V1.0
author : mayidianzi
*/
///
module flash_ctrl(
input I_clk , // clk
input I_TEST_CLK ,
input I_reset_n , // module reset signal
input I_read_en ,
input I_write_en ,
input I_ID_en ,
input I_erase_en ,
input [63:0] I_wr_data ,
input I_wraddr_clear ,
input I_rdaddr_clear ,
output reg O_flash_ready,
output reg O_flash_end ,
input I_SDO , // flash D1信号
output O_SDI , // flash D0信号
output O_SCK , // flash SCK信号
output O_CS ,
input I_flash_dq3 ,
input I_flash_dq2 ,
output reg [63:0] O_rd_data,
output reg [23:0] O_flash_id
);
/ parameter set \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
parameter READ_STATUS_REGISTER = 16'h05_00,
READ_ID = 48'h9F_00_00_00_00_00,
WRITE_ENABLE = 8'h06,
BULK_ERASE = 8'hC7;
parameter C_empty = 8'd12,
C_READID_idle = 8'd0,
C_READID_valid = 8'd1,
C_erase_idle = 8'd2,
C_erase_valid = 8'd3,
C_check_idle = 8'd4,
C_check_valid = 8'd5,
C_write_idle = 8'd6,
C_write_valid = 8'd7,
C_read_idle = 8'd8,
C_read_valid = 8'd9,
C_wrenable_idle = 8'd10,
C_wrenable_valid= 8'd11;
internal signal \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
reg [23:0] S_rd_addr ;
reg [23:0] S_wr_addr ;
wire [95:0] S_rd_data ;
reg [63:0] S_wr_data ;
wire [15:0] S_rd_status ;
wire [95:0] READ_Command ;
wire [95:0] WRITE_Command ;
reg [7:0] S_status ;
reg [1:0] S_w_e_flag ;
reg S_readID_start ;
reg S_read_start ;
reg S_write_start ;
reg S_erase_start ;
reg S_wrenable_start ;
reg S_check_start ;
wire S_end ;
wire S_busy ;
wire [31:0] S_read_id ;
reg S_rdaddr_clear, S_wraddr_clear;
assign READ_Command = {8'h03,S_rd_addr,64'h00_00_00_00_00_00_00_00};
assign WRITE_Command = {8'h02,S_wr_addr,S_wr_data};
assign S_busy = S_rd_status[0];
instance \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//ila_1 ila_1_i(
//.clk(I_clk),
//.probe0(S_rd_addr),
//.probe1(S_wr_addr),
//.probe2(I_wraddr_clear),
//.probe3(I_rdaddr_clear),
//.probe4(O_rd_data),
//.probe5(I_wr_data),
//.probe6(I_write_en)
//);
spi_port spi_port_i(
.I_CLK(I_clk),
.I_reset(I_reset_n),
.I_wrcmd(WRITE_Command),
.I_rdcmd(READ_Command),
.I_erasecmd(BULK_ERASE),
.I_rdIDcmd(READ_ID),
.I_wrencmd(WRITE_ENABLE),
.I_checkcmd(READ_STATUS_REGISTER),
.I_wrstart(S_write_start),
.I_rdstart(S_read_start),
.I_readID_start(S_readID_start),
.I_erase_start(S_erase_start),
.I_wrenable_start(S_wrenable_start),
.I_check_start(S_check_start),
.I_SDO(I_SDO),
.O_end(S_end),
.O_SCK(O_SCK),
.O_CS(O_CS),
.O_SDI(O_SDI),
.I_flash_dq2(I_flash_dq2),
.I_flash_dq3(I_flash_dq3),
.O_rddata(S_rd_data),
.O_rd_status(S_rd_status),
.O_rd_id(S_read_id)
);
main programe \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
/* config procedure */
always @(posedge I_clk or negedge I_reset_n)
begin
if(!I_reset_n)
begin
S_status <= C_check_idle;
O_flash_ready <= 0;
S_w_e_flag <= 0;
O_flash_end <= 0;
end
else
beg