基于FPGA 外置qspi Flash的读写

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
  • 10
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mayidianzi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值