基于FPGA和python烧录flash(W25Q128JV)方法

1. 所需材料

  • FPGA
  • W25Q128JV
  • 根据需要自行编写FPGA端口约束文件
  • 需要烧录的数据文件

2.实现原理

每一次烧录操作会对flash一个扇区(sector 4096byte)依次进行擦除,写入,读取的操作。

python脚本会自动对数据文件进行数据分割,将一个sector的数据通过UART传给FPGA,FPGA会对当前所操作的扇区进行擦除,写入,读取的操作,并将读取的数通过UART传给上位机。上位机的python脚本会自动比较读回的数和预先写入的数,判断写入是否成功。如果当前sector烧录失败,则会重新尝试对此sector进行烧录。以此类推,python脚本会对后续的扇区进行同样的操作,直到数据文件全部被写入FLASH。

3. 数据文件格式

如下图,数据文件是16进制文本文件。数据从左到右从上到下,依次对应低位地址和高位地址。在编写文件时,任意两个数据通过空格或换行进行风格,python脚本会自动按照sector对数据进行分割。

在编写数据文件时,数据量可以是任意数量(不超过flash最大容量)。如果分割后最后一个sector块数据量不满4096字节,python脚本会自动在后面补0xff。

4. FPGA 代码

module top(
  input     clk,
  input     rst_n,
  input     rx,
  output    tx,

  output    sclk,
  output    csn,
  inout     io0,
  inout     io1,
  inout     io2,
  inout     io3
);

  wire [7:0] uart_rdata;
  wire       uart_rvalid;
  wire [11:0] ram_waddr;
  wire [7:0] ram_wdata;
  wire       ram_wen;
  wire      start_pg;
  wire [23:0] flash_addr;
  wire [7:0] ram_rdata;
  wire [11:0] ram_raddr;
  wire spi_vld;
  wire [7:0] spi_wdata;
  wire  spi_wr;
  wire  spi_ready;
  wire  spi_valid;
  wire [7:0] spi_rdata;
  wire spi_rvalid;
  wire fifo_wen;
  wire [7:0] fifo_wdata;
  wire uart_tx_en;
  wire [7:0] uart_tx_data;
  wire uart_tx_ready;


  uart_rx u_uart_rx(
    .clk      (clk),
    .rst_n    (rst_n),
    .uart_rxd (rx),
  
    .rx_data  (uart_rdata),
    .rx_valid (uart_rvalid)
  );

  uart_decode u_uart_decode(
    .clk          (clk    ),
    .rst_n        (rst_n  ),
    .uart_rdata   (uart_rdata),
    .uart_vld     (uart_rvalid),
    .ram_addr     (ram_waddr),
    .ram_wdata    (ram_wdata),
    .ram_wen      (ram_wen),
    .start_pg     (start_pg),
    .addr         (flash_addr)
  );

  ram u_ram(
    .clk     (clk),
    .waddr   (ram_waddr),
    .wdata   (ram_wdata),
    .wen     (ram_wen),
    .rdata   (ram_rdata),
    .raddr   (ram_raddr)
  );

  flash_ctr_fsm u_flash_ctr_fsm(
    .clk        (clk        ),
    .rst_n      (rst_n      ),
    .start_pg   (start_pg   ),
    .ram_raddr  (ram_raddr  ),
    .ram_data   (ram_rdata  ),
    .flash_addr (flash_addr ),
    .spi_vld    (spi_vld),
    .spi_ready  (spi_ready),
    .spi_rd_vld (spi_rvalid),
    .spi_rdata  (spi_rdata),
    .spi_wdata  (spi_wdata),
    .csn        (csn),
    .spi_wr     (spi_wr),
    .fifo_wen   (fifo_wen),
    .fifo_wdata (fifo_wdata)
  );

  qspi u_qspi(
    .clk      (clk    ),
    .rst_n    (rst_n  ),
    .en       (spi_vld),
    .wdata    (spi_wdata),
    .wr       (spi_wr),
    .spi_mode (2'b00), //00:spi 01: dual spi 10/11: quad spi
    .dtr      (1'b0),
    .ready    (spi_ready),
    .rdata    (spi_rdata),
    .rdata_vld(spi_rvalid),
    .sclk     (sclk),
    .d0       (io0),
    .d1       (io1),
    .d2       (io2),
    .d3       (io3) 
  );

  fifo_ctrl u_fifo_ctrl(
    .rst_n      (rst_n),
    .clk        (clk),
    .fifo_wr    (fifo_wen),
    .fifo_wdata (fifo_wdata),
    .tx_ready   (uart_tx_ready),
    .tx_en      (uart_tx_en),
    .tx_data    (uart_tx_data)
  );

  uart_tx u_uart_tx
  (
    .clk   (clk   ),
    .rst_n (rst_n ),
    .valid (uart_tx_en),
    .data  (uart_tx_data),
    .ready (uart_tx_ready),
    .tx    (tx)
  );

endmodule
module uart_tx
#(
    parameter BAUDRATE = 1_000_000,
    parameter CLKRATE = 50_000_000
)
(
    input           clk   ,
    input           rst_n ,
    input           valid ,
    input   [7:0]   data  ,
    output  reg     ready ,
    output  reg     tx    
    );

//**********definitions**********************//
parameter BAUD_MAX = CLKRATE/BAUDRATE - 1; // the maximum of baud_count

reg [5:0] baud_cnt;

reg [1:0] st_cr,st_nx; //state machine
parameter   IDLE  = 2'd0,
             START = 2'd1,
             TRS   = 2'd2,
             STOP  = 2'd3;
reg [7:0] data_r;
reg [2:0] data_cnt;

//********behavior of state machine******//
always@(posedge clk or negedge rst_n) begin
    if(~rst_n)
        st_cr <= IDLE;
    else
        st_cr <= st_nx;
end

always@(*) begin
    if(~rst_n)
        st_nx = IDLE;
    else begin
        case(st_cr)
            IDLE:
                if(ready & valid)
                    st_nx = START;
                else
                    st_nx = IDLE;
            START:
                if(baud_cnt == BAUD_MAX)
                    st_nx = TRS;
                else
                   st_nx = START;
            TRS:
                if(baud_cnt == BAUD_MAX && data_cnt == 3'd7)
                    st_nx = STOP;
                else
                    st_nx = TRS;
            STOP:
                if(baud_cnt == BAUD_MAX)
                    st_nx = IDLE;
                 else
                    st_nx = STOP;
            default:
                st_cr = IDLE;
        endcase
    end
end

//*********behavior of ready*******//
always@(posedge clk or negedge rst_n) begin
    if(~rst_n)
        ready <= 1'b1;
    else if(valid & ready)
        ready <= 1'b0;
    else if(st_cr == IDLE)
        ready <= 1'b1;
end

//********bahavior of baud_cnt******//
always@(posedge clk or negedge rst_n) begin
    if(~rst_n)
        baud_cnt  <= 6'b0;
    else if(baud_cnt == BAUD_MAX || st_cr == IDLE)
        baud_cnt <= 6'b0;
    else
        baud_cnt <= baud_cnt + 1'b1;
end


//********bahavior of data_cnt*****//
always@(posedge clk or negedge rst_n) begin
    if(~rst_n)
        data_cnt <= 3'b0;
    else if(st_cr == IDLE)
        data_cnt <= 3'b0;
    else if(baud_cnt == BAUD_MAX && st_cr == TRS)
        data_cnt <= data_cnt + 1'b1;
end

//********behavior of tx**********//
always@(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        tx <= 1'b1;
    end
    else if(st_cr == TRS && baud_cnt == 13'd0) begin
        tx <= data_r[data_cnt];
    end
    else if(st_cr == START) begin
        tx <= 1'b0;
    end
    else if(st_cr == IDLE || st_cr == STOP) begin
        tx <= 1'b1;
    end
end
//********behavior of data_r******//
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        data_r <= 8'b0;

    end
    else if (valid & ready) begin
        data_r <= data;
    end
end





endmodule
module  uart_rx(
  input             clk,
  input             rst_n,
  input             uart_rxd,
  
  output  reg[7:0]  rx_data,
  output  reg       rx_valid
);
  parameter       BPS   =   1_000_000;
  parameter       FREQ  =   50000000;
  localparam      BPS_CNT =   FREQ / BPS;

  reg [5:0] baud_cnt;
  reg [3:0] bit_cnt;
   
  parameter IDLE  = 2'd0,
            START = 2'd1,
            BITS  = 2'd2,
            STOP  = 2'd3;
 
  reg [1:0] st_cr, st_nx;

  reg uart_rxd_r;
  reg uart_rxd_2r;
  reg uart_rxd_3r;

  wire start_flag;

  //state machine
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      st_cr <= IDLE;
    end else begin
      st_cr <= st_nx;
    end
  end

  always @(*) begin
    if(~rst_n) begin
      st_nx = IDLE;
    end
    else begin
      case(st_cr)
        IDLE: 
          if(start_flag)
            st_nx = START;
          else
            st_nx = IDLE;
        START: 
          if(baud_cnt == BPS_CNT-1)
            st_nx = BITS;
          else
            st_nx = START;
        BITS:
          if(baud_cnt == BPS_CNT-1 && bit_cnt == 3'd7)
            st_nx = STOP;
          else
            st_nx = BITS;
        STOP: 
          if(baud_cnt == BPS_CNT / 2)
            st_nx = IDLE;
          else
            st_nx = STOP;
        default: 
          st_nx = IDLE;
      endcase
    end
  end


  //rx input
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      uart_rxd_r <= 1'b1;
      uart_rxd_2r <= 1'b1;
      uart_rxd_3r <= 1'b1;
    end 
    else begin
      uart_rxd_r <= uart_rxd;
      uart_rxd_2r <= uart_rxd_r;
      uart_rxd_3r <= uart_rxd_2r;
    end
  end

  assign start_flag = uart_rxd_3r & ~uart_rxd_2r;

  //baudcnt
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      baud_cnt <= 6'b0;
    end else if(st_cr == IDLE) begin
      baud_cnt <= 6'd0;
    end
    else if(baud_cnt > BPS_CNT-1) begin
      baud_cnt <= 6'd0;
    end
    else begin
      baud_cnt <= baud_cnt + 1'b1;
    end
  end

  //bit_cnt
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      bit_cnt <= 3'd0;
    end
    else if(st_cr ==IDLE) begin
      bit_cnt <= 3'd0;
    end
    else if(baud_cnt == BPS_CNT-1 && st_cr == BITS) begin
      bit_cnt <= bit_cnt + 1'b1;
    end
  end

  //
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      rx_data <= 8'b0;
    end else if(st_cr == BITS  && baud_cnt == BPS_CNT / 2) begin
      rx_data <= {uart_rxd_2r, rx_data[7:1]};
    end
  end

  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      rx_valid <= 1'b0;
    end else if(st_cr == BITS  && baud_cnt == BPS_CNT / 2 && bit_cnt == 3'd7) begin
      rx_valid <= 1'b1;
    end
    else begin
      rx_valid <= 1'b0;
    end
  end

endmodule
module uart_decode(
	input 		         clk    ,
	input 		         rst_n  ,
  input   [7:0]      uart_rdata,
  input              uart_vld,
  output reg [11:0]   ram_addr,
  output     [7:0]   ram_wdata,
  output             ram_wen,
  output             start_pg,
  output    [23:0]   addr
);
  parameter SYNC   = 8'h00,
            ESCAPE = 8'h01;

  reg [2:0] st_cr, st_nx;
  reg [7:0] addr0, addr1, addr2;
  reg [7:0] addr0_l, addr1_l, addr2_l;
  wire isdata;
  wire restart;

  reg escap_on;

  assign addr = {addr0_l, addr1_l, addr2_l};

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      escap_on <= 1'b0;
    else if(uart_vld) begin
      escap_on <= escap_on == 1'b0 && uart_rdata == ESCAPE;
    end
  end

  assign isdata = uart_vld && (uart_rdata != SYNC && uart_rdata != ESCAPE || escap_on);
  assign restart = uart_vld && escap_on == 1'b0 &&  uart_rdata == SYNC;


  parameter IDLE = 3'd0,
            ADDR0 = 3'd1,
            ADDR1 = 3'd2,
            ADDR2 = 3'd3,
            DATA  = 3'd4;

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      st_cr <= IDLE;
    else
      st_cr <= st_nx;
  end

  always @(*) begin
    case(st_cr)
      IDLE:
        if(restart)
          st_nx = ADDR0;
        else
          st_nx = IDLE;
      ADDR0:
        if(isdata)
          st_nx = ADDR1;
        else
          st_nx = ADDR0;
      ADDR1:
        if(restart)
          st_nx = ADDR0;
        else if(isdata)
          st_nx = ADDR2;
        else
          st_nx = ADDR1;
      ADDR2:
        if(restart)
          st_nx = ADDR0;
        else if(isdata)
          st_nx = DATA;
        else
          st_nx = ADDR2;
      DATA:
        if(restart)
          st_nx = ADDR0;
        else if(isdata & (&ram_addr))
          st_nx = IDLE;
        else
          st_nx = DATA;
      default:
        st_nx = IDLE;
    endcase
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      ram_addr <= 8'd0;
    else if(st_cr == IDLE)
      ram_addr <= 8'd0;
    else if(ram_wen)
      ram_addr <= ram_addr + 1'd1;
  end

  assign ram_wen = st_cr == DATA && isdata;
  assign ram_wdata = uart_rdata;
  assign start_pg = st_cr == DATA && isdata && (&(ram_addr));

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      addr0 <= 8'd0;
    end
    else if(st_cr == ADDR0 && isdata)
      addr0 <= uart_rdata;
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      addr1 <= 8'd0;
    end
    else if(st_cr == ADDR1 && isdata)
      addr1 <= uart_rdata;
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      addr2 <= 8'd0;
    end
    else if(st_cr == ADDR2 && isdata)
      addr2 <= uart_rdata;
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      addr0_l <= 8'd0;
      addr1_l <= 8'd0;
      addr2_l <= 8'd0;
    end
    else if(start_pg) begin
      addr0_l <= addr0;
      addr1_l[7:4] <= addr1[7:4];
      //addr2_l <= addr2;
    end
  end

endmodule
module ram(
  input         clk,
  input [11:0]   waddr,
  input [7:0]   wdata,
  input         wen,
  output [7:0]  rdata,
  input  [11:0]  raddr
  );


  reg [7:0] ram_reg [0:4095];

  always @(posedge clk)
    if(wen)
      ram_reg[waddr] <= wdata;

  assign rdata = ram_reg[raddr];

endmodule
module qspi(
	input          clk,
	input          rst_n,
  input          en,
  input [7:0]    wdata,
  input          wr,
  input [1:0]    spi_mode, //00:spi 01: dual spi 10/11: quad spi
  input          dtr,
  output reg     ready,
  output reg [7:0]   rdata,
  output reg      rdata_vld,

  output reg     sclk,
  inout          d0,
  inout          d1,
  inout          d2,
  inout          d3	
);

  reg drv_d0, drv_d1, drv_d2, drv_d3;
  reg d0_i, d1_i, d2_i, d3_i;
  wire d0_o, d1_o, d2_o, d3_o;

  reg [1:0] baud_cnt;
  reg [2:0] bit_cnt;
  reg [2:0] BIT_CNT_MAX;

  reg [7:0] wdata_r;
  reg       wr_r;
  reg [1:0] spi_mode_r;
  reg       dtr_r;

  wire [7:0] wdata_d;
  wire       wr_d;
  wire [1:0] spi_mode_d;
  wire       dtr_d;


  pullup(d0);
  pullup(d1);
  pullup(d2);
  pullup(d3);
  assign d0 = drv_d0 ? d0_i : 1'bz;
  assign d1 = drv_d1 ? d1_i : 1'bz;
  assign d2 = drv_d2 ? d2_i : 1'bz;
  assign d3 = drv_d3 ? d3_i : 1'bz;
  assign d0_o = d0;
  assign d1_o = d1;
  assign d2_o = d2;
  assign d3_o = d3;


  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      wdata_r     <= 8'd0;
      wr_r        <= 1'd0;
      spi_mode_r  <= 2'd0;
      dtr_r       <= 1'd0;
    end
    else if(en & ready) begin
      wdata_r     <= wdata;
      wr_r        <= wr;
      spi_mode_r  <= spi_mode;
      dtr_r       <= dtr;
    end
  end

  assign wdata_d    = (en & ready) ? wdata    : wdata_r;
  assign wr_d       = (en & ready) ? wr       : wr_r;
  assign spi_mode_d = (en & ready) ? spi_mode : spi_mode_r;
  assign dtr_d      = (en & ready) ? dtr      : dtr_r;


  always@(*) begin
    if(spi_mode_d == 2'd0) begin //spi
      BIT_CNT_MAX = dtr_d ? 3'd3 : 3'd7;
    end
    else if(spi_mode_d == 2'd1) begin //dual spi
      BIT_CNT_MAX = dtr_d ? 3'd1 : 3'd3;
    end
    else begin
      BIT_CNT_MAX = dtr_d ? 3'd0 : 3'd1; //quad spi
    end
  end
  
  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      baud_cnt <= 2'd0;
    else if(en & ready)
      baud_cnt <= 2'd1;
    else if(ready == 1'b0)
      baud_cnt <= baud_cnt + 2'd1;
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      bit_cnt <= 3'd0;
    else if(en & ready)
      bit_cnt <= 3'd0;
    else if(baud_cnt == 2'd3)
      bit_cnt <= bit_cnt + 1'd1;
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      ready <= 1'b1;
      rdata_vld <= 1'b0;
    end
    else if(en & ready) begin
      ready <= 1'b0;
    end
    else if(bit_cnt == BIT_CNT_MAX && baud_cnt == 2'd3) begin
      ready <= 1'b1;
      rdata_vld <= ~wr_r;
    end
    else
      rdata_vld <= 1'b0;
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      drv_d0 <= 1'b0;
      drv_d1 <= 1'b0;
      drv_d2 <= 1'b0;
      drv_d3 <= 1'b0;
    end
    else if(en & ready & wr == 1'b0) begin
        drv_d0 <= 1'b0;
        drv_d1 <= 1'b0;
        drv_d2 <= 1'b0;
        drv_d3 <= 1'b0;
    end
    else if(en & ready & wr == 1'b1) begin
      if(spi_mode == 2'b0) begin
        drv_d0 <= 1'b1;
        drv_d1 <= 1'b0;
        drv_d2 <= 1'b0;
        drv_d3 <= 1'b0;
      end
      else if(spi_mode == 2'd1) begin
        drv_d0 <= 1'b1;
        drv_d1 <= 1'b1;
        drv_d2 <= 1'b0;
        drv_d3 <= 1'b0;
      end
      else begin
        drv_d0 <= 1'b1;
        drv_d1 <= 1'b1;
        drv_d2 <= 1'b1;
        drv_d3 <= 1'b1;
      end
    end
    else if(ready) begin
      drv_d0 <= 1'b0;
      drv_d1 <= 1'b0;
      drv_d2 <= 1'b0;
      drv_d3 <= 1'b0;
    end
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      d0_i <= 1'b0;
      d1_i <= 1'b0;
      d2_i <= 1'b0;
      d3_i <= 1'b0;
    end
    else if(en & ready & wr == 1'b1) begin
      if(spi_mode == 2'd0) begin
        d0_i <= wdata[7];
      end
      else if(spi_mode == 2'd1) begin
        d0_i <= wdata[6];
        d1_i <= wdata[7];
      end
      else begin
        d0_i <= wdata[4];
        d1_i <= wdata[5];
        d2_i <= wdata[6];
        d3_i <= wdata[7];
      end
    end
    else if(wr_r == 1'b1) begin
      if(dtr_r == 1'b0 && baud_cnt == 2'd3) begin //dtr off
        if(spi_mode_r == 2'd0) begin
          d0_i <= wdata_r[3'd6 - bit_cnt];
        end
        else if(spi_mode_r == 2'd1) begin
          d0_i <= wdata_r[3'd5 - {bit_cnt[1:0], 1'b1}];
          d1_i <= wdata_r[3'd5 - {bit_cnt[1:0], 1'b0}];
        end
        else begin
          d0_i <= wdata_r[3'd3 - {bit_cnt[0], 2'd3}];
          d1_i <= wdata_r[3'd3 - {bit_cnt[0], 2'd2}];
          d2_i <= wdata_r[3'd3 - {bit_cnt[0], 2'd1}];
          d3_i <= wdata_r[3'd3 - {bit_cnt[0], 2'd0}];
        end
      end
      else if(dtr_r == 1'b1 && baud_cnt == 2'd0) begin //dtr on, first data
        if(spi_mode_r == 2'd0) begin
          d0_i <= wdata_r[3'd7 - {bit_cnt, 1'b0}];
        end
        else if(spi_mode_r == 2'd1) begin
          d0_i <= wdata_r[3'd6 - {bit_cnt[0], 2'b0}];
          d1_i <= wdata_r[3'd7 - {bit_cnt[0], 2'b0}];
        end
        else begin
          d0_i <= wdata_r[3'd4];
          d1_i <= wdata_r[3'd5];
          d2_i <= wdata_r[3'd6];
          d3_i <= wdata_r[3'd7];
        end
      end
      else if(dtr_r == 1'b1 && baud_cnt == 2'd2) begin //dtr on, second data
        if(spi_mode_r == 2'd0) begin
          d0_i <= wdata_r[3'd7 - {bit_cnt, 1'b1}];
        end
        else if(spi_mode_r == 2'd1) begin
          d0_i <= wdata_r[3'd6 - {bit_cnt[0], 2'b10}];
          d1_i <= wdata_r[3'd7 - {bit_cnt[0], 2'b10}];
        end
        else begin
          d0_i <= wdata_r[3'd0];
          d1_i <= wdata_r[3'd1];
          d2_i <= wdata_r[3'd2];
          d3_i <= wdata_r[3'd3];
        end
      end
    end
  end


  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      rdata <= 8'd0;
    end
    else if(wr_r == 1'b0) begin
      if(baud_cnt == 2'd1 || dtr_r == 1'b1 && baud_cnt == 2'd3) begin
        if(spi_mode_r == 2'd0)
          rdata <= {rdata[6:0], d1_o};
        else if(spi_mode_r == 2'd1)
          rdata <= {rdata[6:0], d1_o, d0_o};
        else
          rdata <= {rdata[3:0], d3_o, d2_o, d1_o, d0_o};
      end
    end
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      sclk <= 1'b0;
    else if(en & ready)
      sclk <= 1'b0;
    else if(baud_cnt == 2'd1)
      sclk <= 1'b1;
    else if(baud_cnt == 2'd3)
      sclk <= 1'b0;
  end

endmodule
module flash_ctr_fsm(
  input             clk     ,
  input             rst_n   ,
  input             start_pg,
  output reg [11:0] ram_raddr,
  input      [7:0]  ram_data,
  input      [23:0]  flash_addr,

  output reg        spi_vld,
  input             spi_ready,
  input             spi_rd_vld,
  input [7:0]       spi_rdata,
  output reg [7:0]  spi_wdata,
  output reg        csn,
  output reg        spi_wr,

  output            fifo_wen,
  output [7:0]      fifo_wdata
  );

  reg [3:0] csn_cnt;


  parameter S0 =  6'd0, //IELD
            S1 =  6'd1, //pull down csn
            S2 =  6'd2, //WEL on, send 0x06
            S3 =  6'd3, //wait WEL on finish, pull up csn
            S4 =  6'd4, //pull down csn
            S5 =  6'd5, //send 0x20, sector erase
            S6 =  6'd6, //send addr[23:16]
            S7 =  6'd7, //send addr[15:8]
            S8 =  6'd8, //send addr[7:0]
            S9 =  6'd9, //wait send finish
            S10 = 6'd10, //pull up csn
            S11 = 6'd11, //pull down csn,
            S12 = 6'd12, //send 0x05, read status reg1
            S13 = 6'd13, //read cmd
            S14 = 6'd14, //wait send done and judge whether busy,
            S15 = 6'd15, //pull up csn

            S16 = 6'd16, //pull down csn
            S17 = 6'd17, //send 0x06
            S18 = 6'd18, // wait send down

            S19 = 6'd19, //pull up csn
            S20 = 6'd20,  //pull down csn
            S21 = 6'd21, //send 0x02, page program
            S22 = 6'd22, //send addr[23:16]
            S23 = 6'd23, //send addr[16:8]
            S24 = 6'd24, //send addr[7:0]

            S25 = 6'd25, //send nx data
            S26 = 6'd26, //wait send done and pull up csn
            S27 = 6'd27, //pull down csn,
            S28 = 6'd28, //send 0x05, read status reg1
            S29 = 6'd29, //read cmd
            S30 = 6'd30, //wait send done and judge whether busy, judge whether the whole sector is programed
            S31 = 6'd31, //pull up csn
            S32 = 6'd32, //pull down csn
            S33 = 6'd33, //send 0x03, read data
            S34 = 6'd34, //send addr[23:16]
            S35 = 6'd35, //send addr[15:8]
            S36 = 6'd36, //send addr[7:0]
            S37 = 6'd37, //read data
            S38 = 6'd38; // wait send done and pull up csn

  reg [5:0] st_cr, st_nx;

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      st_cr <= S0;
    else
      st_cr <= st_nx;
  end

  always @(*) begin
    case(st_cr)
    S0 :begin 
      if(start_pg) 
        st_nx = S1; 
      else 
        st_nx = S0; 
      end
    S1 :begin 
          if(&csn_cnt) 
            st_nx = S2; 
          else 
            st_nx = S1; 
        end
    S2 :begin 
          if(spi_vld & spi_ready)
            st_nx = S3;
          else
            st_nx = S2;
        end
    S3 :begin
          if(spi_ready)
            st_nx = S4;
          else
            st_nx = S3;
        end
    S4 :begin 
          if(&csn_cnt) 
            st_nx = S5; 
          else 
            st_nx = S4; 
        end
    S5 :begin
          if(spi_vld & spi_ready)
            st_nx = S6;
          else
            st_nx = S5;
        end
    S6 :begin
          if(spi_vld & spi_ready)
            st_nx = S7;
          else
            st_nx = S6;
        end
    S7 :begin
          if(spi_vld & spi_ready)
            st_nx = S8;
          else
            st_nx = S7;
        end
    S8 :begin
          if(spi_vld & spi_ready)
            st_nx = S9;
          else
            st_nx = S8;
        end
    S9 :begin
          if(spi_ready)
            st_nx = S10;
          else
            st_nx = S9;
        end
    S10:begin st_nx = S11; end
    S11:begin 
          if(&csn_cnt) 
            st_nx = S12; 
          else 
            st_nx = S11; 
        end
    S12:begin
          if(spi_vld & spi_ready)
            st_nx = S13;
          else
            st_nx = S12;
        end
    S13:begin
          if(spi_vld & spi_ready)
            st_nx = S14;
          else
            st_nx = S13;
        end
    S14:begin
          if(spi_rd_vld)
            st_nx = spi_rdata[0] ? S13 : S15;
          else
            st_nx = S14;
        end
    S15:begin st_nx = S16; end
    S16:begin 
          if(&csn_cnt) 
            st_nx = S17; 
          else 
            st_nx = S16; 
        end
    S17:begin
          if(spi_vld & spi_ready)
            st_nx = S18;
          else
            st_nx = S17;
        end
    S18:begin
          if(spi_ready)
            st_nx = S19;
          else
            st_nx = S18;
        end
    S19:begin st_nx = S20; end
    S20:begin 
          if(&csn_cnt) 
            st_nx = S21; 
          else 
            st_nx = S20; 
        end
    S21:begin 
          if(spi_vld & spi_ready)
            st_nx = S22;
          else
            st_nx = S21;
        end
    S22:begin 
          if(spi_vld & spi_ready)
            st_nx = S23;
          else
            st_nx = S22;
        end
    S23:begin 
          if(spi_vld & spi_ready)
            st_nx = S24;
          else
            st_nx = S23;
        end
    S24:begin 
          if(spi_vld & spi_ready)
            st_nx = S25;
          else
            st_nx = S24;
        end
    S25:begin 
          if(spi_vld & spi_ready)
            st_nx = S26;
          else
            st_nx = S25;
        end
    S26:begin
          if(spi_ready)
            st_nx = ram_raddr[7:0] == 8'd0 ? S27 : S25;
          else
            st_nx = S26;
    end
    S27:begin 
          if(&csn_cnt) 
            st_nx = S28; 
          else 
            st_nx = S27; 
        end
    S28:begin
      if(spi_vld & spi_ready)
        st_nx = S29;
      else
        st_nx = S28;
    end
    S29:begin
      if(spi_vld & spi_ready)
        st_nx = S30;
      else
        st_nx = S29;
    end
    S30:begin
      if(spi_rd_vld)
        st_nx = spi_rdata[0] ? S29 : S31;
      else
        st_nx = S30;
    end
    S31:begin st_nx = ram_raddr == 12'd0 ? S32 : S16; end
    S32:begin 
          if(&csn_cnt) 
            st_nx = S33; 
          else 
            st_nx = S32; 
        end
    S33:begin
          if(spi_vld & spi_ready)
            st_nx = S34;
          else
            st_nx = S33;
        end
    S34:begin
          if(spi_vld & spi_ready)
            st_nx = S35;
          else
            st_nx = S34;
        end
    S35:begin
          if(spi_vld & spi_ready)
            st_nx = S36;
          else
            st_nx = S35;
        end
    S36:begin
          if(spi_vld & spi_ready)
            st_nx = S37;
          else
            st_nx = S36;
        end
    S37:begin
          if(spi_vld & spi_ready)
            st_nx = S38;
          else
            st_nx = S37;
        end
    S38: if(spi_ready) 
            st_nx = ram_raddr == 12'b0 ? S0 : S37;
          else
            st_nx = S38;
    default: st_nx = S0;
    endcase
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      csn <= 1'b1;
    end
    else if((&csn_cnt) & (st_cr == S1 || 
            st_cr == S4 || 
            st_cr== S11 || 
            st_cr == S16 ||
            st_cr == S20 || 
            st_cr == S27 || 
            st_cr == S32)) begin
      csn <= 1'b0;
    end
    else if((spi_ready && st_cr == S3) ||
     st_cr == S10 || 
     st_cr == S15 ||
     st_cr == S19 ||
     (st_cr == S26 &&  spi_ready && ram_raddr[7:0] == 8'd0) ||
     st_cr == S31  ||
     (st_cr == S38 &&  spi_ready && ram_raddr == 12'b0))
      csn <= 1'b1;
  end

  always @(*) begin
    case(st_cr)
      S2, S17 : spi_wdata = 8'h06;
      S6, S34 : spi_wdata = flash_addr[23:16];
      S7, S35 : spi_wdata = flash_addr[15:8];
      S8, S36 : spi_wdata = flash_addr[7:0];
      S5: spi_wdata = 8'h20;
      S12, S28: spi_wdata = 8'h05;
      S21: spi_wdata = 8'h02;
      S22: spi_wdata = flash_addr[23:16];
      S23: spi_wdata = {flash_addr[15:12], ram_raddr[11:8]};
      S25: spi_wdata = ram_data;
      S33: spi_wdata = 8'h03;
      default: spi_wdata = 8'h00;
    endcase
  end

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      ram_raddr <= 12'd0;
    end
    else if((st_cr == S25 || st_cr == S37) && spi_vld && spi_ready)
      ram_raddr <= ram_raddr + 1'd1;
  end

  always @(*) begin
    case(st_cr)
      S2, S5, S6, S7, S8, S12, S13, S17, S21, S22, S23, S24, S25, S28, S29, S33, S34, S35, S36, S37: spi_vld = 1'b1;
      default: spi_vld = 1'b0;
    endcase
  end

  always @(*) begin
    case(st_cr)
      S2, S5, S6, S7, S8, S12, S17, S21, S22, S23, S24, S25, S28, S33, S34, S35, S36: spi_wr = 1'b1;
      default : spi_wr = 1'b0; 
    endcase
  end

  assign fifo_wen = spi_rd_vld && st_cr == S38;
  assign fifo_wdata = spi_rdata;

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      csn_cnt <= 4'd0;
    else if(st_cr == S1 ||
      st_cr == S4 ||
      st_cr == S11 ||
      st_cr == S16 ||
      st_cr == S20 ||
      st_cr == S27 ||
      st_cr == S32)
      csn_cnt <= csn_cnt + 1'd1;
    else
      csn_cnt <= 4'd0;
  end
  
endmodule
module fifo_ctrl(
  input         rst_n,
  input         clk,
  
  input         fifo_wr,
  input [7:0]   fifo_wdata,

  input         tx_ready,
  output        tx_en,
  output [7:0]  tx_data    
);

  wire empty;
  wire fifo_rd;
  wire [7:0] fifo_rdata;

  parameter IDLE = 2'd0,
            GET = 2'd1,
            SEND = 2'd2;
  
  reg [1:0] st_cr;
  reg [1:0] st_nx;

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      st_cr <= 2'd0;
    else
      st_cr <= st_nx;
  end
  
  always @(*) begin
    case(st_cr)
      IDLE:
        if(empty == 1'b0)
          st_nx = GET;
        else
          st_nx = IDLE;
      GET:
        if(empty == 1'b0 && fifo_rd == 1'b1)
          st_nx = SEND;
        else
          st_nx = GET;
      SEND:
          if(tx_ready & tx_en) begin
              st_nx = GET;
          end
          else begin
            st_nx = SEND;
          end
      default:
        st_nx = IDLE;
    endcase
  end
  

  assign tx_data = fifo_rdata;
  assign fifo_rd = (st_cr == GET) && (empty == 1'b0);
  assign tx_en = (st_cr == SEND);

  fifo u_fifo(
    .clk          (clk),
    .rst_n         (rst_n),
    .data_in          (fifo_wdata   ),
    .wr_en        (fifo_wr      ),
    .rd_en        (fifo_rd      ),
    .data_out         (fifo_rdata ),
    .full         (),
    .empty        (empty)
  );



endmodule
module	fifo
(
	input										clk		,
	input										rst_n	,
	input	[7:0]			    		data_in	,
	input										rd_en	, 
	input										wr_en	,
						                                        
	output	reg	[7:0]				data_out,
	output									empty	,
	output									full
);                                                              
 

reg [7:0]			fifo_buffer[4095: 0];	
reg [12:0]		wr_ptr;
reg [12:0]		rd_ptr;
 
//wire define
wire [11:0]	wr_ptr_true;
wire [11:0]	rd_ptr_true;
wire					wr_ptr_msb;
wire					rd_ptr_msb;
 
assign {wr_ptr_msb, wr_ptr_true} = wr_ptr;
assign {rd_ptr_msb, rd_ptr_true} = rd_ptr;
 
always @ (posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0)
		rd_ptr <= 'd0;
	else if (rd_en && !empty)begin
		data_out <= fifo_buffer[rd_ptr_true];
		rd_ptr <= rd_ptr + 1'd1;
	end
end

always @ (posedge clk or negedge rst_n) begin
	if (!rst_n)
		wr_ptr <= 0;
	else if (!full && wr_en)begin
		wr_ptr <= wr_ptr + 1'd1;
		fifo_buffer[wr_ptr_true] <= data_in;
	end	
end
 

assign	empty = ( wr_ptr == rd_ptr ) ? 1'b1 : 1'b0;
assign	full  = ( (wr_ptr_msb != rd_ptr_msb ) && ( wr_ptr_true == rd_ptr_true ) )? 1'b1 : 1'b0;
 
endmodule

5. Python代码

import serial
import binascii
import sys

def split_string(s, n):
    return [s[i:i+n] for i in range(0, len(s), n)]

port = 'COM4'
err_flag = 0
ser = serial.Serial(port, 1000000, 8, timeout=20, stopbits=1)
fw = open('flash_wdata.txt','r')
wdatas = fw.readlines()
byts = []
a = 0
a = 0
tmp = ''
tmp = tmp.join(wdatas)
tmp = tmp.replace('\n','')
tmp = tmp.replace(' ','')
tmp = tmp.lower()
byts = split_string(tmp,2)
if len(byts) > 16777216:
    byts = byts[:16777216]
if len(byts) % 4096 != 0:
    for i in range(4096 - (len(byts) % 4096)):
        byts.append('ff')
byts_sect = [byts[i:i+4096] for i in range(0,len(byts),4096)]

# print(len(byts_sect[0]))

addr = 0
cnt = 0
while addr < len(byts_sect):
    # if err_flag == 1:
    #     addr = addr - 1
    addr_msb = bin(addr)[2:].zfill(12)
    addr_lsb = '000000000000'
    addr_bin = addr_msb + addr_lsb
    addr_hi_hex = hex(int(addr_bin[0:8],2))[2:].zfill(2)
    addr_mi_hex = hex(int(addr_bin[8:16], 2))[2:].zfill(2)
    addr_lo_hex = hex(int(addr_bin[16:24], 2))[2:].zfill(2)
    print("start to erase and pg sector 0x" + addr_hi_hex + addr_mi_hex + addr_lo_hex + '...')
    ser.write(bytes.fromhex('00'))
    ser.write(bytes.fromhex('00')) #sync
    if addr_hi_hex == '00' or addr_hi_hex == '01':
        ser.write(bytes.fromhex('01'))
    ser.write(bytes.fromhex(addr_hi_hex))
    if addr_mi_hex == '00' or addr_mi_hex == '01':
        ser.write(bytes.fromhex('01'))
    ser.write(bytes.fromhex(addr_mi_hex))
    if addr_lo_hex == '00' or addr_lo_hex == '01':
        ser.write(bytes.fromhex('01'))
    ser.write(bytes.fromhex(addr_lo_hex))
    for i, bt in enumerate(byts_sect[addr]):
        #print('%d/%d' % (i, len(byts_sect)))
        if bt == '00' or bt == '01':
            ser.write(bytes.fromhex('01'))
        ser.write(bytes.fromhex(bt))
    flash_rb = ser.read(4096)
    rec_data = str(binascii.b2a_hex(flash_rb))[2:-1]
    rec_data = [rec_data[i:i+2] for i in range(0, len(rec_data), 2)]
    if(rec_data != byts_sect[addr]):
        cnt = cnt + 1
        print('sector pg error, err count is %d' % cnt)
        err_flag = 1
        if(cnt == 20):
            print("have tried 20 times, sector is still programmed fail!!")
            sys.exit()
        else:
            print(rec_data)
            print(byts_sect[addr])
            continue
    else:
        print('sector pg pass')
        err_flag = 0
        cnt = 0
    addr = addr + 1

if(err_flag == 0):
    print('all sectors are successfully programed')
else:
    print('some sectors are programed fail')

6. 实验结果

在烧录过程中,python脚本会实时打印当前烧录的扇区地址,以及烧录结果。烧录完成后,python会打印烧录过程中,是否会出现回读数据不匹配的情况。

### FPGA与W25Q128JVPIQ闪存芯片的烧录方法 对于希望利用FPGA来实现对W25Q128JVPIQ闪存芯片编程的需求,通常涉及通过SPI接口进行通信。具体来说,在设计阶段需考虑几个方面: #### 设计准备 为了确保能够顺利地将数据写入到W25Q128JVPIQ中,首先要准备好硬件环境以及软件配置文件。这包括但不限于选择合适的FPGA型号并完成其基本设置;编写或获取用于控制SPI总线操作的Verilog/VHDL代码片段。 #### SPI协议交互逻辑构建 由于W25Q128系列采用标准SPI通讯方式工作,因此需要在FPGA内部建立相应的控制器模块负责处理读取命令、发送指令序列给目标设备等功能[^1]。此部分可以通过调用现成IP核或者自行编码实现。 ```verilog // Verilog示例:简单的SPI Master初始化 module spi_master ( input wire clk, input wire rst_n, output reg sclk, // SPI Clock output reg mosi, // Master Out Slave In input wire miso, // Master In Slave Out output reg cs // Chip Select ); ... endmodule ``` #### 数据传输流程说明 当一切就绪之后,则可以按照如下顺序执行实际的数据传送过程: - 设置片选信号低电平激活存储器; - 发送特定的操作码告知即将发生的动作(如擦除扇区、页编程等); - 如果有必要的话还需附加地址参数指明作用范围; - 接着便是正式传递待记录的信息流直至结束标志到来为止; - 最终释放CS使能端口恢复正常状态等待下一次请求的到来。 值得注意的是上述每一步骤都应当严格遵循官方文档给出的时间窗口限制以保障可靠性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值