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会打印烧录过程中,是否会出现回读数据不匹配的情况。