xilinx在线升级+flash操作+N25Q128
因为使用xdc升级跳转方式,实际测试升级过程中掉电无法回退版本,开始了使用ICAP方式来进行跳转
这里使用的时钟是125MHz,是以太网时钟,
使用golden的bit和update的bit文件合成一个mcs文件,需要注意跳转地址,因为这里使用的容量大小是16M,所以取了中间位置;
把mcs文件先下载到flash,后通过以太网直接下发需要更新的bin文件覆盖到之前的update区,重新上电,重启,就可以实现升级了;
Flash操作:
说明:
擦除操作:收到擦除start命令--->读ID号匹配手册上的ID--->如果读ID成功--->开始进行擦除操作--->擦除一个块--->读状态寄存器不忙--->循环进行擦除操作
--->直到60个块擦完后--->IDLE
写操作:收到写start命令--->读ID号匹配手册上的ID--->如果读ID成功--->开始进行写操作--->1页写完后--->读状态寄存器不忙--->读出当前写入页数据--->循环写入读出(可验证数据是否写入)
--->直到4页完且读完--->IDLE
有的flash第一次擦不成功,所以得加一下读ID成功操作,
实际板子上使用:
module flash_top( // input wire sys_clk_p, //system clock positive // input wire sys_clk_n, //system clock negative input clk , input wire rst_n , //reset ,low active input erase_start, input write_start, input fl_data_en , input [7:0] fl_data , output erase_completed, //仿真 output four_pp_completed,//仿真 input cmd_reply_clear_finish, input miso , // output sck , output mosi , output cs_n ); // wire erase_completed;//调试 // wire four_pp_completed;//调试 wire sck; 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_spi ( .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(1'b0), // 1-bit input: User start-up clock input .GSR(1'b0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name) .GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name) .KEYCLEARB(1'b1), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM) .PACK(1'b1), // 1-bit input: PROGRAM acknowledge input .USRCCLKO(sck), // 1-bit input: User CCLK input .USRCCLKTS(1'b0), // 1-bit input: User CCLK 3-state enable input .USRDONEO(1'b1), // 1-bit input: User DONE pin output control .USRDONETS(1'b1) // 1-bit input: User DONE 3-state enable output ); // reg [5:0] cnt_clk=0; // wire add_cnt_clk; // wire end_cnt_clk; // always@(posedge sys_clk or negedge rst_n)begin // if(rst_n==1'b0)begin // cnt_clk<=0; // end // else if(add_cnt_clk)begin // if(end_cnt_clk) // cnt_clk<=0; // else // cnt_clk<=cnt_clk+1; // end // end // assign add_cnt_clk = 1; // assign end_cnt_clk = add_cnt_clk && cnt_clk == 2-1; // reg clk;//100MHz // always@(posedge sys_clk)begin // if(cnt_clk<1)begin // clk<=1'b1; // end // else begin // clk<=1'b0; // end // end // wire clk; // assign clk=sys_clk; // wire clk_out1; // wire clk_out2; // clk_wiz_0 clk_wiz_0_uut // ( // .clk_out1(clk_out1), // output clk_out1 // .clk_out2(clk_out2), // output clk_out2 // .reset(~rst_n), // input reset // .locked(locked), // output locked // .clk_in1(sys_clk)); // input clk_in1 // wire clk; // assign clk=clk_out2 & locked; //===========================vio========================================= // wire earse_start_vio; // wire write_start_vio; // wire read_start_vio; // vio_0 uut_vio_0 ( // .clk(clk), // .probe_out0(earse_start_vio), // .probe_out1(write_start_vio), // .probe_out2(read_start_vio) // ); // reg earse_start_r1; // always@(posedge clk)begin // earse_start_r1<=earse_start_vio; // end // wire earse_edge; // assign earse_edge= earse_start_r1 & ~earse_start_vio; // reg write_start_r1; // always@(posedge clk)begin // write_start_r1<=write_start_vio; // end // wire write_edge; // assign write_edge= write_start_r1 & ~write_start_vio; // reg read_start_r1; // always@(posedge clk)begin // read_start_r1<=read_start_vio; // end // wire read_edge; // assign read_edge= read_start_r1 & ~read_start_vio; //===========================test========================================= // reg I_fl_data_en ; // wire end_cnt0; // always @(posedge clk or negedge rst_n)begin // if(!rst_n)begin // I_fl_data_en <= 0; // end // else if(write_start) begin //仿真 // else if(write_edge)begin //实际 // I_fl_data_en <= 1; // end // else if(end_cnt0) begin // I_fl_data_en <= 0; // end // end // reg [15:0] cnt0; // wire add_cnt0; // always@(posedge clk or negedge rst_n)begin // if(rst_n==1'b0)begin // cnt0<='d0; // end // else if(add_cnt0)begin // if(end_cnt0) // cnt0<=0; // else // cnt0<=cnt0+1; // end // end // assign add_cnt0 = I_fl_data_en; // assign end_cnt0 = add_cnt0 && cnt0 == 1024-1;//256-1; // (*mark_debug="true", dont_touch="true"*)wire [7:0] wr_rd_state_spi_out ; (*mark_debug="true", dont_touch="true"*)wire [7:0] dout ;//读取数据 (*mark_debug="true", dont_touch="true"*)wire dout_vld ;//数据有效 (*mark_debug="true", dont_touch="true"*)wire spi_vld ; (*mark_debug="true", dont_touch="true"*)wire en ; (*mark_debug="true", dont_touch="true"*)wire [7:0] spi_dout ;//读取数据进入fifo (*mark_debug="true", dont_touch="true"*)wire spi_one_byte_done ; wr_control u_wr_control( /*input */.clk (clk ), /*input */.rst_n (rst_n ), // `ifdef simulation // `elsif .erase_start (erase_start),// erase_start 仿真 .write_start (write_start),//write_start // .erase_start (earse_edge ),//erase_start 调试 // .write_start (write_edge ),//write_start .erase_completed(erase_completed), .four_pp_completed(four_pp_completed), .cmd_reply_clear_finish(cmd_reply_clear_finish), .read_start(read_edge), // `endif /*input */.spi_one_byte_done (spi_one_byte_done ), /*input */.din_vld ( fl_data_en ),// (I_fl_data_en),//(rx_byte_vld ),// /*input [7:0] */.din ( fl_data),// (cnt0[7:0] ),//(rx_byte ),// /*input [7:0] */.read_data (spi_dout ), /*output reg [7:0] */.wr_rd_state_spi_out (wr_rd_state_spi_out ), /*output [7:0] */.read_flash_data_fifo_out (dout ), /*output */.read_flash_data_fifo_out_vld (dout_vld ), /*output */.en (en ), /*output */.spi_vld (spi_vld ) ); spi_master u_spi_master( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input */.en (en ), /*input [1:0] */.spi_mode (2'b00 ), /*input */.spi_vld (spi_vld ), /*input [7:0] */.spi_din (wr_rd_state_spi_out),//写入数据 /*input */.miso (miso ), /*output reg */.sck (sck ), /*output reg */.cs_n (cs_n ), /*output */.mosi (mosi ), /*output reg [7:0] */.spi_dout (spi_dout ),//读取数据 /*output reg */.busy ( ), /*output */.spi_one_byte_done (spi_one_byte_done ) ); endmodule
`include "param.v" module wr_control( input clk , input rst_n , input erase_start, (*mark_debug="true", dont_touch="true"*)output erase_completed, input write_start, (*mark_debug="true", dont_touch="true"*)output reg four_pp_completed, input cmd_reply_clear_finish, input read_start, input spi_one_byte_done , input [7:0] din , input din_vld , input [7:0] read_data , output reg [7:0] wr_rd_state_spi_out , output [7:0] read_flash_data_fifo_out , output read_flash_data_fifo_out_vld , output en , output reg spi_vld ); //参数定义 parameter DATA_WIDTH = 8'd12;//8'd15; parameter DATA_LENGTH = 1024;//'d10240; //中间信号定义 reg flag ; reg flag0 ; reg en_r ; wire en_dge_n ; reg read_data_vld ; //例化中间信号 wire read_id ; wire read_rdsr ; wire read_data_flag; wire read_only_data_flag; wire busy_read; wire data_req ; wire [7:0] write_state_spi_out ; wire [7:0] read_state_spi_out ; wire [1:0] en_ ; wire read_spi_one_byte_vld ; wire write_done ; wire read_done ; wire rxf_rdreq ; wire rxf_wrreq ; wire rxf_empty ; wire rxf_full ; wire [7:0] rxf_dout ; // wire [11:0] rxf_usedw ; wire [DATA_WIDTH-1:0] rxf_usedw ; wire txf_rdreq ; wire txf_wrreq ; (*mark_debug="true", dont_touch="true"*) wire txf_empty ; wire txf_full ; // (*mark_debug="true", dont_touch="true"*) wire [11:0] txf_usedw ; wire [DATA_WIDTH-1:0] txf_usedw ; reg [7:0] din_fifo; reg din_fifo_vld; //标志信号 //flag 1: uart 发送数据 0:停止发送数据 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag <= 0; end else if(txf_usedw >= DATA_LENGTH-1)begin // else if(txf_usedw >='d1023)begin flag <= 1; end else if(txf_empty)begin flag <= 0; end end //flag0 0:fish读模块输出数据(命令、地址)1:fish写模块发送数据(命令、地址、写入数据) always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag0 <= 0; end else if(en_[0])begin flag0 <= 1; end else if(en_[1])begin flag0 <= 0; end end //en_r 打拍 检测en信号边沿 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin en_r <= 0; end else begin en_r <= en; end end assign en_dge_n = !en & en_r; //read_data_vld always @(posedge clk or negedge rst_n)begin if(!rst_n)begin read_data_vld <= 0; end else begin read_data_vld <= read_spi_one_byte_vld;//读出数据有效 end end //输出 //wr_rd_state_spi_out 数据输出给spi_master模块 always @(*)begin if(flag0)begin wr_rd_state_spi_out = write_state_spi_out; end else if(flag0 == 0)begin wr_rd_state_spi_out = read_state_spi_out; end else begin wr_rd_state_spi_out = wr_rd_state_spi_out; end end //en assign en = en_[0] | en_[1]; //spi_vld always @(posedge clk or negedge rst_n)begin if(!rst_n)begin spi_vld <= 0; end else if(en_dge_n)begin spi_vld <= 1; end else if(write_done | read_done)begin spi_vld <= 0; end else begin spi_vld <= spi_vld; end end flash_write u_flash_write ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input */.erase_start (erase_start), .erase_completed(erase_completed), .cmd_reply_clear_finish(cmd_reply_clear_finish), /*input */.write_start (write_start), .read_id (read_id ), .read_rdsr (read_rdsr ), .read_data_flag(read_data_flag), /*input */.read_data (read_data), /*input */.read_data_vld(read_data_vld), /*input */.read_done (read_done), .busy_read(busy_read), /*input */.spi_one_byte_done (spi_one_byte_done ),//spi一个字节数据传输完成 /*input [7:0] */.din (rxf_dout ), /*output */.data_req (data_req ), //写入flash数据请求 /*output */.en (en_[0] ), /*output */.write_done (write_done ), /*output reg [7:0] */.write_state_spi_out (write_state_spi_out ) //给spi配置 ); flash_read u_flash_read ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), .read_id (read_id ), .read_rdsr (read_rdsr ), .read_data_flag(read_data_flag | read_start), .read_only_data_flag(read_only_data_flag), .busy_read(busy_read), /*input */.spi_one_byte_done (spi_one_byte_done ), /*output */.en (en_[1] ), /*output */.read_done (read_done ), /*output */.read_spi_one_byte_vld (read_spi_one_byte_vld ), /*output reg [7:0] */.read_state_spi_out (read_state_spi_out )//给spi配置 ); //fifo例化 // rx_fifo rx_fifo_inst ( // .aclr ( !rst_n ), // .clock ( clk ), // .data ( din ), //uart输入数据 // .rdreq ( rxf_rdreq ), // .wrreq ( rxf_wrreq ), // .empty ( rxf_empty ), // .full ( rxf_full ), // .q ( rxf_dout ), // .usedw ( rxf_usedw ) // ); flash_fifo rx_fifo ( .clk(clk), // input wire clk .srst(!rst_n), // input wire srst // .din(din), // input wire [7 : 0] din .din(din_fifo), .wr_en(rxf_wrreq), // input wire wr_en .rd_en(rxf_rdreq), // input wire rd_en .dout(rxf_dout), // output wire [7 : 0] dout .full(rxf_full), // output wire full .empty(rxf_empty), // output wire empty .data_count(rxf_usedw) // output wire [8 : 0] data_count ); // assign rxf_wrreq = !rxf_full && din_vld; assign rxf_wrreq = !rxf_full && din_fifo_vld; assign rxf_rdreq = !rxf_empty && data_req; // fifo_tx fifo_tx_inst ( // .aclr ( !rst_n ), // .clock ( clk ), // .data ( read_data ),//din_m从flash中读取数据 // .rdreq ( txf_rdreq ), // .wrreq ( txf_wrreq ), // .empty ( txf_empty ), // .full ( txf_full ), // .q ( read_flash_data_fifo_out ), //uart输出数据 // .usedw ( txf_usedw ) // ); flash_fifo fifo_tx ( .clk(clk), // input wire clk .srst(!rst_n), // input wire srst .din (read_data ), // input wire [7 : 0] din .wr_en(txf_wrreq), // input wire wr_en .rd_en(txf_rdreq), // input wire rd_en .dout(read_flash_data_fifo_out), // output wire [7 : 0] dout .full(txf_full), // output wire full .empty(txf_empty), // output wire empty .data_count(txf_usedw) // output wire [11 : 0] data_count ); assign txf_wrreq = !txf_full && read_data_vld && read_only_data_flag;//从flash中读取数据 data_vld数据有效 assign txf_rdreq = flag && (!txf_empty) ;//&& (!busy_t); assign read_flash_data_fifo_out_vld = txf_rdreq; //uart数据输出有效 (*mark_debug="true", dont_touch="true"*)reg [8:0] cnt_fifo; wire add_cnt_fifo; wire end_cnt_fifo; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_fifo<=0; end else if(add_cnt_fifo)begin if(end_cnt_fifo) cnt_fifo<=0; else cnt_fifo<=cnt_fifo+1; end end assign add_cnt_fifo = txf_wrreq; assign end_cnt_fifo = add_cnt_fifo && cnt_fifo == 256-1;//一页写字节 //--------------------比较----------------------- (*mark_debug="true", dont_touch="true"*)wire [7 : 0] original_dout; wire compare_fifo_full; (*mark_debug="true", dont_touch="true"*)wire compare_fifo_empty; // (*mark_debug="true", dont_touch="true"*)wire [11 : 0] compare_fifo_usedw; (*mark_debug="true", dont_touch="true"*)wire [DATA_WIDTH-1:0] compare_fifo_usedw; flash_fifo compare_fifo ( .clk(clk), // input wire clk .srst(!rst_n), // input wire srst // .din(din), // input wire [7 : 0] din .din(din_fifo), .wr_en(rxf_wrreq), // input wire wr_en .rd_en(txf_rdreq), // input wire rd_en .dout(original_dout), // output wire [7 : 0] dout .full(compare_fifo_full), // output wire full .empty(compare_fifo_empty), // output wire empty .data_count(compare_fifo_usedw) // output wire [11 : 0] data_count ); // (*mark_debug="true", dont_touch="true"*)reg [11:0] cnt_compare; (*mark_debug="true", dont_touch="true"*)reg [DATA_WIDTH-1:0] cnt_compare; wire add_cnt_compare; wire end_cnt_compare; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_compare<=0; end else if(add_cnt_compare)begin if(end_cnt_compare) cnt_compare<=0; else cnt_compare<=cnt_compare+1; end end assign add_cnt_compare = txf_rdreq&original_dout==read_flash_data_fifo_out/* &(~compare_fifo_empty) */; assign end_cnt_compare = add_cnt_compare && cnt_compare == DATA_LENGTH-1;//10240-1;//回读比较字节 // assign end_cnt_compare = add_cnt_compare && cnt_compare == 1024-1; // (*mark_debug="true", dont_touch="true"*)wire four_pp_completed; // assign four_pp_completed=end_cnt_compare; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin four_pp_completed <=1'b0; end else if(end_cnt_compare)begin four_pp_completed <= 1'b1; end else if(cmd_reply_clear_finish)begin four_pp_completed <= 1'b0; end end //不够1024字节后面都写ff reg din_vld_r; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin din_vld_r<=0; end else begin din_vld_r<=din_vld; end end wire din_vld_pos; assign din_vld_pos = din_vld & ~din_vld_r; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin din_fifo<='hff; end else if(din_vld)begin din_fifo<=din; end else begin din_fifo<='hff; end end // reg din_fifo_vld; wire end_cnt_din; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin din_fifo_vld<=1'b0; end else if(din_vld_pos)begin din_fifo_vld<=1'b1; end else if(end_cnt_din)begin din_fifo_vld<=0; end end reg [15:0] cnt_din; wire add_cnt_din; // wire end_cnt_din; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt_din<='d0; end else if(add_cnt_din)begin if(end_cnt_din) cnt_din<=0; else cnt_din<=cnt_din+1; end end assign add_cnt_din = din_fifo_vld; assign end_cnt_din = add_cnt_din && cnt_din == 1024-1;//256-1;//一页输入字节 //收包统计个数 (*mark_debug="true", dont_touch="true"*)reg [15:0] cnt_udp; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_udp<=0; end else if(din_vld_pos)begin cnt_udp<=cnt_udp+1'b1; end else begin cnt_udp<=cnt_udp; end end endmodule
`include "param.v" module flash_write( input clk , input rst_n , input erase_start, output reg erase_completed, input cmd_reply_clear_finish, input write_start, output reg read_id, (*mark_debug="true", dont_touch="true"*) output reg read_rdsr, (*mark_debug="true", dont_touch="true"*) output reg read_data_flag, (*mark_debug="true", dont_touch="true"*) input [7:0] read_data, (*mark_debug="true", dont_touch="true"*) input read_data_vld, (*mark_debug="true", dont_touch="true"*) input read_done, input busy_read, input spi_one_byte_done , input [7:0] din , output data_req , //写入flash数据请求 output en , output write_done , output reg [7:0] write_state_spi_out ); //参数定义 parameter M_IDLE =8'b0000_0001, M_RDID =8'b0000_0010, M_WREN =8'b0000_0100, M_SE =8'b0000_1000, M_RDSR =8'b0001_0000, M_WAIT =8'b0010_0000, M_RDDA =8'b0100_0000, M_PP =8'b1000_0000; parameter S_IDLE = 5'b00001, S_CMD = 5'b00010, S_ADDR = 5'b00100, S_DATA = 5'b01000, S_DELAY = 5'b10000; parameter INIT_ADDR = 24'h80_0000; //中间信号定义 reg [7:0] m_state_c ; reg [7:0] m_state_n ; (*mark_debug="true", dont_touch="true"*) reg [4:0] s_state_c ; reg [4:0] s_state_n ; reg [7:0] cnt_100ns ; wire add_cnt_100ns ; wire end_cnt_100ns ; reg [18:0] cnt_pp ; wire add_cnt_pp ; wire end_cnt_pp ; reg end_cnt_pp_r ; reg [10:0] cnt_se ; wire add_cnt_se ; wire end_cnt_se ; reg end_cnt_se_r ; reg [8:0] cnt_byte ; wire add_cnt_byte ; wire end_cnt_byte ; reg [8:0] byte_num ; (*mark_debug="true", dont_touch="true"*) reg [23:0] addr_wr ; (*mark_debug="true", dont_touch="true"*) reg [1:0] flag ; //主 wire m_idle2m_rdid ; wire m_rdid2m_wren ; wire m_rdid2m_idle ; wire m_wren2m_se ; wire m_wren2m_pp ; wire m_se2m_rdsr ; wire m_rdsr2m_rdda ; wire m_rdsr2m_idle ; wire m_rdsr2m_wren ; wire m_rdsr2m_wait ; wire m_wait2m_rdsr ; wire m_rdda2m_wren ; wire m_rdda2m_idle ; wire m_pp2m_rdsr ; //从 wire s_idle2s_cmd ; wire s_cmd2s_addr ; wire s_cmd2s_data ; wire s_cmd2s_delay ; wire s_addr2s_data ; wire s_addr2s_delay ; wire s_data2s_idle ; wire s_data2s_delay ; wire s_delay2s_idle ; reg [2:0] read_id_cnt; reg [7:0] first_id ; reg [7:0] second_id; reg [7:0] third_id ; reg read_done_r1; reg read_done_r2; reg read_done_r3; reg [1:0] read_id_flag; reg [11:0] erase_cnt; reg rdsr_sta_reg_vld ; reg [23:0] wait_time_cnt; reg [11:0] pp_cnt; reg second_erase_start; //状态机 //主状态机 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin m_state_c <= M_IDLE; end else begin m_state_c <= m_state_n; end end always @(*)begin case (m_state_c) M_IDLE: begin if(m_idle2m_rdid)begin m_state_n = M_RDID; end else begin m_state_n = m_state_c; end end M_RDID: begin if(m_rdid2m_wren)begin m_state_n = M_WREN; end else if(m_rdid2m_idle)begin m_state_n = M_IDLE; end else begin m_state_n = m_state_c; end end M_WREN: begin if(m_wren2m_se)begin m_state_n = M_SE; end else if(m_wren2m_pp)begin m_state_n = M_PP; end else begin m_state_n = m_state_c; end end M_SE: begin if(m_se2m_rdsr)begin m_state_n = M_RDSR; end else begin m_state_n = m_state_c; end end M_RDSR: begin if(m_rdsr2m_rdda)begin m_state_n = M_RDDA; end else if (m_rdsr2m_idle) begin m_state_n = M_IDLE; end else if (m_rdsr2m_wren) begin m_state_n = M_WREN; end else if (m_rdsr2m_wait) begin m_state_n = M_WAIT; end else begin m_state_n = m_state_c; end end M_WAIT:begin if(m_wait2m_rdsr)begin m_state_n = M_RDSR; end else begin m_state_n = m_state_c; end end M_RDDA:begin if(m_rdda2m_wren)begin m_state_n = M_WREN; end else if(m_rdda2m_idle)begin m_state_n = M_IDLE; end else begin m_state_n = m_state_c; end end M_PP: begin if (m_pp2m_rdsr) begin m_state_n = M_RDSR; end else begin m_state_n = m_state_c; end end default: m_state_n = m_state_c; endcase end //从状态机 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin s_state_c <= S_IDLE; end else begin s_state_c <= s_state_n; end end always @(*)begin case (s_state_c) S_IDLE : begin if (s_idle2s_cmd) begin s_state_n = S_CMD; end else begin s_state_n = s_state_c; end end S_CMD : begin if (s_cmd2s_addr) begin s_state_n = S_ADDR; end // else if (s_cmd2s_data) begin // s_state_n = S_DATA; // end else if (s_cmd2s_delay) begin s_state_n = S_DELAY; end else begin s_state_n = s_state_c; end end S_ADDR : begin if (s_addr2s_data) begin s_state_n = S_DATA; end else if(s_addr2s_delay) begin s_state_n = S_DELAY; end else begin s_state_n = s_state_c; end end S_DATA : begin // if (s_data2s_idle) begin // s_state_n = S_IDLE; // end // else if(s_data2s_delay)begin s_state_n = S_DELAY; end else begin s_state_n = s_state_c; end end S_DELAY : begin if(s_delay2s_idle)begin s_state_n = S_IDLE; end else begin s_state_n = s_state_c; end end default: s_state_n = s_state_c; endcase end //主状态机转换条件 assign m_idle2m_rdid = m_state_c == M_IDLE && (erase_start || write_start ||second_erase_start); assign m_rdid2m_wren = m_state_c == M_RDID && read_id_flag==2'b11; assign m_rdid2m_idle = m_state_c == M_RDID && read_id_flag==2'b10; assign m_wren2m_se = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b01; assign m_wren2m_pp = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b10; assign m_se2m_rdsr = m_state_c == M_SE && s_delay2s_idle; assign m_rdsr2m_rdda = m_state_c == M_RDSR && /* s_data2s_idle && */ rdsr_sta_reg_vld && flag == 2'b10; assign m_rdsr2m_idle = m_state_c == M_RDSR && /* s_data2s_idle && */ rdsr_sta_reg_vld && erase_cnt==12'd60 &&flag == 2'b01; assign m_rdsr2m_wren = m_state_c == M_RDSR && /* s_data2s_idle && */ rdsr_sta_reg_vld && erase_cnt <12'd60 &&flag == 2'b01; assign m_rdsr2m_wait = m_state_c == M_RDSR && /* s_data2s_idle */ read_done_r1 && read_data_vld && read_data[1:0] == 2'b11; assign m_wait2m_rdsr = m_state_c == M_WAIT && ((flag == 2'b01 && wait_time_cnt== 24'd250_0000) |(flag == 2'b10 && wait_time_cnt== 24'd150_000 )); assign m_rdda2m_wren = m_state_c == M_RDDA && /* read_done */ (~read_data_flag)&&read_done_r3 &&flag == 2'b10 && pp_cnt< 12'd4; assign m_rdda2m_idle = m_state_c == M_RDDA && /* read_done */ (~read_data_flag)&&read_done_r3 &&flag == 2'b10 && pp_cnt==12'd4;//1024字节4页 assign m_pp2m_rdsr = m_state_c == M_PP && s_delay2s_idle; //从状态机转换条件 assign s_idle2s_cmd = s_state_c == S_IDLE && (!(m_state_c == M_IDLE)) && (!(m_state_c == M_RDSR)) && (!(m_state_c == M_RDID)) && (!(m_state_c == M_RDDA)) ; assign s_cmd2s_addr = s_state_c == S_CMD && end_cnt_byte && (m_state_c == M_SE | m_state_c == M_PP); assign s_cmd2s_data = s_state_c == S_CMD && end_cnt_byte && (m_state_c == M_RDSR | m_state_c == M_RDID); assign s_addr2s_data = s_state_c == S_ADDR && end_cnt_byte && m_state_c == M_PP; assign s_addr2s_delay = s_state_c == S_ADDR && end_cnt_byte && m_state_c == M_SE; assign s_data2s_idle = s_state_c == S_DATA && read_done_r3 && (m_state_c == M_RDSR|| m_state_c == M_RDID); assign s_data2s_delay = s_state_c == S_DATA && end_cnt_byte && (m_state_c == M_PP); assign s_cmd2s_delay = s_state_c == S_CMD && end_cnt_byte && m_state_c == M_WREN; assign s_delay2s_idle = s_state_c == S_DELAY && ((( (m_state_c == M_SE)?end_cnt_se_r : end_cnt_pp_r) && (m_state_c == M_SE || m_state_c == M_PP)) || (end_cnt_100ns && m_state_c == M_WREN)); //计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_100ns <= 0; end else if(add_cnt_100ns)begin if(end_cnt_100ns)begin cnt_100ns <= 0; end else begin cnt_100ns <= cnt_100ns + 1; end end else begin cnt_100ns <= cnt_100ns; end end assign add_cnt_100ns = s_state_c == S_DELAY && m_state_c == M_WREN; assign end_cnt_100ns = add_cnt_100ns && cnt_100ns == 30; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_byte <= 0; end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte <= 0; end else begin cnt_byte <= cnt_byte + 1; end end else begin cnt_byte <= cnt_byte; end end assign add_cnt_byte = spi_one_byte_done && (s_state_c == S_CMD | s_state_c == S_ADDR | s_state_c == S_DATA ) && ~busy_read; assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_num-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_pp <= 0; end else if(add_cnt_pp)begin if(end_cnt_pp | s_delay2s_idle)begin cnt_pp <= 0; end else begin cnt_pp <= cnt_pp + 1; end end else begin cnt_pp <= cnt_pp; end end assign add_cnt_pp = s_state_c == S_DELAY && (m_state_c == M_PP || m_state_c == M_SE); assign end_cnt_pp = add_cnt_pp && cnt_pp == `DELAY_5MS-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_se <= 0; end else if(add_cnt_se)begin if(end_cnt_se)begin cnt_se <= 0; end else begin cnt_se <= cnt_se + 1; end end else begin cnt_se <= cnt_se; end end assign add_cnt_se= s_state_c == S_DELAY && end_cnt_pp && m_state_c == M_SE; assign end_cnt_se = add_cnt_se && cnt_se == 2-1; //flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag <=2'b00; end else if(erase_start)begin flag <=2'b01; end else if(write_start)begin flag <=2'b10; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)begin end_cnt_pp_r <= 0; end_cnt_se_r <= 0; end else begin end_cnt_pp_r <= end_cnt_pp; end_cnt_se_r <= end_cnt_se; end end //byte_num always @(posedge clk or negedge rst_n)begin if(!rst_n)begin byte_num <= 0; end else if(s_state_c == S_CMD)begin byte_num <= `CMD_BYTE; end else if(s_state_c == S_ADDR)begin byte_num <= `ADDR_BYTE; end else if(s_state_c == S_DATA)begin byte_num <= `DATA_BYTE; end else begin byte_num <= byte_num; end end reg [23:0] addr_erase; always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin addr_erase <= INIT_ADDR;//24'h40_0000; end else if(m_rdsr2m_wren & flag == 2'b01)begin addr_erase <= addr_erase +24'h01_0000; end else begin addr_erase <= addr_erase; end end reg [23:0] addr_pp; always @(posedge clk or negedge rst_n)begin if(!rst_n /* | m_state_c == M_IDLE */)begin addr_pp <=INIT_ADDR; end // else if(addr_pp ==24'h7a_607b)begin // addr_pp <=INIT_ADDR; // end else if(m_pp2m_rdsr & flag == 2'b10)begin addr_pp <= addr_pp +24'h00_0100; end else begin addr_pp <= addr_pp; end end //addr_wr always @(posedge clk or negedge rst_n)begin if(!rst_n)begin addr_wr <= INIT_ADDR; end else if(flag==2'b01)begin addr_wr <= addr_erase; end else if(flag==2'b10 )begin addr_wr <= addr_pp; end else begin addr_wr <= addr_wr; end end //输出 //write_state_spi_out always @(posedge clk or negedge rst_n)begin if(!rst_n)begin write_state_spi_out <= 0; end else if(s_state_c == S_CMD)begin if(m_state_c == M_WREN)begin write_state_spi_out <= `CMD_WREN; end else if(m_state_c == M_SE ) begin write_state_spi_out <= `CMD_SE; end else if (m_state_c == M_PP ) begin write_state_spi_out <= `CMD_PP; end else begin write_state_spi_out <= write_state_spi_out; end end else if(s_state_c == S_ADDR)begin write_state_spi_out <=addr_wr[23-cnt_byte*8-:8]; end else if (s_state_c == S_DATA && m_state_c == M_PP) begin write_state_spi_out <=din; end end //data_req en write_done read_data_vld busy // wire en_temp; assign data_req = m_state_c == M_PP && spi_one_byte_done && s_state_c == S_DATA; assign /* en_temp */ en = m_rdid2m_wren |m_rdsr2m_wren |m_wren2m_se |m_wren2m_pp |m_rdda2m_wren; assign write_done = s_data2s_delay | s_addr2s_delay | s_cmd2s_delay; // reg [7:0] en_r; // always @(posedge clk or negedge rst_n)begin // if(!rst_n)begin // en_r[7:0] <= 8'h0; // end // else begin // en_r[7:0] <= {en_r[6:0],en_temp}; // end // end // assign en=en_r[7]; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin read_id <= 1'b0; end else if(erase_start|write_start|second_erase_start)begin read_id <= 1'b1; end else begin read_id <= 1'b0; end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin read_id_cnt <= 'd0; end else if(m_state_c == M_RDID && read_data_vld)begin read_id_cnt <= read_id_cnt + 1'b1; end else begin read_id_cnt <= read_id_cnt; end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin first_id <= 'd0; second_id <= 'd0; third_id <= 'd0; end else if(m_state_c == M_RDID && read_data_vld &&read_id_cnt==0)begin first_id <= read_data; end else if(m_state_c == M_RDID && read_data_vld &&read_id_cnt==1)begin second_id <= read_data; end else if(m_state_c == M_RDID && read_data_vld &&read_id_cnt==2)begin third_id <= read_data; end else begin first_id <= first_id ; second_id <= second_id; third_id <= third_id ; end end always @(posedge clk or negedge rst_n)begin if(!rst_n )begin read_done_r1<=1'b0; read_done_r2<=1'b0; read_done_r3<=1'b0; end else begin read_done_r1<=read_done; read_done_r2<=read_done_r1; read_done_r3<=read_done_r2; end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin read_id_flag <= 2'b00; end else if(read_done_r3 && first_id==`MF_ID && second_id == `ID1 && third_id == `ID2)begin read_id_flag <= 2'b11; end else if(read_done_r3 && (first_id != `MF_ID || second_id != `ID1 || third_id != `ID2))begin read_id_flag <= 2'b10;//实际 // read_id_flag <= 2'b11;//仿真 end else if(m_state_c != M_RDID)begin read_id_flag <= 2'b00; end else begin read_id_flag <= read_id_flag; end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin erase_cnt <= 'd0; end else if(m_se2m_rdsr)begin erase_cnt <= erase_cnt + 1'b1; end else begin erase_cnt <= erase_cnt; end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin rdsr_sta_reg_vld <= 1'b0; end else if(m_state_c == M_RDSR && read_data_vld && read_data[1:0] == 2'b00)begin rdsr_sta_reg_vld <= 1'b1; end else if(m_state_c != M_RDSR)begin rdsr_sta_reg_vld <= 1'b0; end else begin rdsr_sta_reg_vld <= rdsr_sta_reg_vld ; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)begin read_rdsr <= 1'b0; end else if(m_se2m_rdsr|m_wait2m_rdsr|m_pp2m_rdsr)begin read_rdsr <= 1'b1; end else begin read_rdsr <= 1'b0; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)begin wait_time_cnt <= 24'd0; end else if(m_state_c == M_WAIT)begin wait_time_cnt <= wait_time_cnt+1'b1; end else if(m_state_c != M_WAIT)begin wait_time_cnt <= 24'd0; end else begin wait_time_cnt <= wait_time_cnt; end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)begin pp_cnt <= 'd0; end else if(m_pp2m_rdsr)begin pp_cnt <= pp_cnt + 1'b1; end else begin pp_cnt <= pp_cnt; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)begin read_data_flag <= 1'b0; end else if(m_rdsr2m_rdda)begin read_data_flag <= 1'b1; end else begin read_data_flag <= 1'b0; end end // reg erase_completed; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin erase_completed <= 1'b0; end else if(m_rdsr2m_idle)begin erase_completed <= 1'b1; end else if(cmd_reply_clear_finish)begin erase_completed <= 1'b0; end end // // reg second_erase_start; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin second_erase_start <= 1'b0; end else if(m_rdid2m_idle)begin second_erase_start <= 1'b1; end else if(m_idle2m_rdid)begin second_erase_start <= 1'b0; end end endmodule
`include "param.v" module flash_read( input clk , input rst_n , input read_id, input read_rdsr, input read_data_flag, (*mark_debug="true", dont_touch="true"*) output reg read_only_data_flag, output wire busy_read, input spi_one_byte_done , output en , output read_done , output read_spi_one_byte_vld , output reg [7:0] read_state_spi_out ); //参数定义 parameter IDLE =9'b00000_0001, RDID_CMD =9'b00000_0010, RDID_DATA =9'b00000_0100, RDSR_CMD =9'b00000_1000, RDSR_DATA =9'b00001_0000, RDAD_CMD =9'b00010_0000, RDAD_ADDR =9'b00100_0000, RDAD_DATA =9'b01000_0000, RD_DONE =9'b10000_0000; parameter INIT_ADDR = 24'h80_0000; //中间信号定义 (*mark_debug="true", dont_touch="true"*) reg [8:0] state_c ; reg [8:0] state_n ; reg [8:0] cnt_byte ; wire add_cnt_byte ; wire end_cnt_byte ; reg [8:0] byte_num ; (*mark_debug="true", dont_touch="true"*) reg [23:0] addr_rd ; wire idle2rdid_cmd ; wire idle2rdsr_cmd ; wire idle2rdad_cmd ; wire rdid_cmd2rdid_data ; wire rdsr_cmd2rdsr_data ; wire rdad_cmd2rdad_addr ; wire rdad_addr2rdad_data ; wire rdid_data2rd_done ; wire rdsr_data2rd_done ; wire rdad_data2rd_done ; wire rd_done2idle ; //状态机 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin state_c <= IDLE; end else begin state_c <= state_n; end end always @(*)begin case (state_c) IDLE : begin if (idle2rdid_cmd) begin state_n <= RDID_CMD; end else if(idle2rdsr_cmd) begin state_n <= RDSR_CMD; end else if(idle2rdad_cmd) begin state_n <= RDAD_CMD; end else begin state_n <= state_c; end end RDID_CMD : begin if(rdid_cmd2rdid_data)begin state_n <= RDID_DATA; end else begin state_n <= state_c; end end RDID_DATA : begin if (rdid_data2rd_done) begin state_n <= RD_DONE; end else begin state_n <= state_c; end end RDSR_CMD : begin if(rdsr_cmd2rdsr_data)begin state_n <= RDSR_DATA; end else begin state_n <= state_c; end end RDSR_DATA : begin if (rdsr_data2rd_done) begin state_n <= RD_DONE; end else begin state_n <= state_c; end end RDAD_CMD : begin if (rdad_cmd2rdad_addr) begin state_n <= RDAD_ADDR; end else begin state_n <= state_c; end end RDAD_ADDR : begin if (rdad_addr2rdad_data ) begin state_n <= RDAD_DATA; end else begin state_n <= state_c; end end RDAD_DATA : begin if(rdad_data2rd_done)begin state_n <= RD_DONE; end else begin state_n <= state_c; end end RD_DONE : begin if(rd_done2idle)begin state_n <= IDLE; end else begin state_n <= state_c; end end default: state_n <= state_c; endcase end assign idle2rdid_cmd = state_c == IDLE && read_id ; assign idle2rdsr_cmd = state_c == IDLE && read_rdsr ; assign idle2rdad_cmd = state_c == IDLE && read_data_flag ; assign rdid_cmd2rdid_data = state_c == RDID_CMD && end_cnt_byte; assign rdsr_cmd2rdsr_data = state_c == RDSR_CMD && end_cnt_byte; assign rdad_cmd2rdad_addr = state_c == RDAD_CMD && end_cnt_byte; assign rdad_addr2rdad_data = state_c == RDAD_ADDR && end_cnt_byte; assign rdid_data2rd_done = state_c == RDID_DATA && end_cnt_byte; assign rdsr_data2rd_done = state_c == RDSR_DATA && end_cnt_byte; assign rdad_data2rd_done = state_c == RDAD_DATA && end_cnt_byte; assign rd_done2idle = state_c == RD_DONE && 1'b1; //计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_byte <= 0; end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte <= 0; end else begin cnt_byte <= cnt_byte + 1; end end else begin cnt_byte <= cnt_byte; end end assign add_cnt_byte = (state_c == RDID_CMD | state_c == RDID_DATA |state_c == RDSR_CMD | state_c == RDSR_DATA | state_c == RDAD_CMD | state_c == RDAD_ADDR |state_c == RDAD_DATA) && spi_one_byte_done; assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_num-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin byte_num <= 0; end else if(state_c == RDID_CMD |state_c == RDSR_CMD | state_c == RDAD_CMD )begin byte_num <= `CMD_BYTE; end else if(state_c == RDID_DATA)begin byte_num <= `ID_BYTE; end else if(state_c == RDSR_DATA)begin byte_num <= `RDSR_BYTE; end else if (state_c == RDAD_ADDR) begin byte_num <= `ADDR_BYTE; end else if(state_c == RDAD_DATA)begin byte_num <= `DATA_BYTE; end end //addr_rd always @(posedge clk or negedge rst_n)begin if(!rst_n /* | addr_rd==24'h00_0400 */)begin addr_rd <= INIT_ADDR; end else if(rdad_data2rd_done)begin addr_rd <= addr_rd + 24'h00_0100; end else begin addr_rd <= addr_rd; end end //输出 //read_state_spi_out always @(posedge clk or negedge rst_n)begin if(!rst_n)begin read_state_spi_out <= 0; end else if(state_c == RDID_CMD)begin read_state_spi_out <= `CMD_RDID; end else if(state_c == RDSR_CMD)begin read_state_spi_out <= `CMD_RDSR; end else if(state_c == RDAD_CMD)begin read_state_spi_out <= `CMD_READ; end else if(state_c == RDAD_ADDR)begin if(cnt_byte == 0) begin read_state_spi_out <= addr_rd[23:16]; end else if(cnt_byte == 1) begin read_state_spi_out <= addr_rd[15:8]; end else if(cnt_byte == 2) begin read_state_spi_out <= addr_rd[7:0]; end end else begin read_state_spi_out <= read_state_spi_out; end end //en read_done dtat_m_vld assign en =(read_id |read_rdsr| read_data_flag) & state_c == IDLE; assign read_done = rdid_data2rd_done | rdsr_data2rd_done| rdad_data2rd_done; assign read_spi_one_byte_vld = spi_one_byte_done && (state_c == RDID_DATA | state_c == RDSR_DATA | state_c == RDAD_DATA); // assign read_only_data_flag=state_c == RDAD_DATA; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin read_only_data_flag<=1'b0; end else if(state_c == RDAD_DATA)begin read_only_data_flag<=1'b1; end else begin read_only_data_flag<=1'b0; end end assign busy_read= !(state_c==IDLE); endmodule
`include "param.v" module spi_master( input clk , input rst_n , input en , input [1:0] spi_mode, input spi_vld , input [7:0] spi_din , input miso , output reg sck , output reg cs_n , output mosi , output reg [7:0] spi_dout , output reg busy , output spi_one_byte_done ); //中间信号定义 reg [4:0] cnt_bit ; wire add_cnt_bit ; wire end_cnt_bit ; reg [8:0] cnt_sck ; wire add_cnt_sck ; wire end_cnt_sck ; reg end_cnt_sck_r ; //计数器 //cnt_sck always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_sck <= 0; end else if(add_cnt_sck)begin if(end_cnt_sck | en)begin cnt_sck <= 0; end else begin cnt_sck <= cnt_sck + 1; end end else begin cnt_sck <= cnt_sck; end end assign add_cnt_sck = spi_vld; assign end_cnt_sck = add_cnt_sck && cnt_sck == `SCK_PERIOD-1; //cnt_bit always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit <= 0; end else if(add_cnt_bit )begin if(end_cnt_bit | en)begin cnt_bit <= 0; end else begin cnt_bit <= cnt_bit + 1; end end else begin cnt_bit <= cnt_bit; end end assign add_cnt_bit = (cs_n == 0)&& end_cnt_sck; assign end_cnt_bit = add_cnt_bit && cnt_bit == 8-1; //sck always @(*)begin case (spi_mode) 0 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 0; end else if(cnt_sck > `SCK_HALF-1)begin sck <= 1; end else begin sck <= 0; end end 1 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 1; end else if(cnt_sck > `SCK_HALF-1)begin sck <= 0; end else begin sck <= 0; end end 2 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1 ))begin sck <= 1; end else if(cnt_sck > `SCK_HALF-1 )begin sck <= 0; end else begin sck <= 1; end end 3 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 0; end else if(cnt_sck > `SCK_HALF-1 )begin sck <= 1; end else begin sck <= 1; end end default: sck <= sck; endcase end //end_cnt_sck_r always @(posedge clk or negedge rst_n)begin if(!rst_n)begin end_cnt_sck_r <= 0; end else begin end_cnt_sck_r <= end_cnt_sck; end end //输出 //cs_n always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cs_n <= 1; end else if(en)begin cs_n <= 0; end else if(cs_n == 0 && (!spi_vld) && end_cnt_sck_r)begin cs_n <= 1; end end //mosi assign mosi = spi_din[7-cnt_bit]; //spi_dout always @(posedge clk or negedge rst_n)begin if(!rst_n)begin spi_dout <= 0; end else if(cs_n == 0 && cnt_sck == `SCK_PERIOD-1)begin spi_dout[7-cnt_bit] <= miso; end else begin spi_dout <= spi_dout; end end //spi_one_byte_done assign spi_one_byte_done = end_cnt_bit; //busy always @(posedge clk or negedge rst_n)begin if(!rst_n)begin busy <= 0; end else if(add_cnt_bit && end_cnt_bit == 0)begin busy <= 1; end else if(end_cnt_bit)begin busy <= 0; end end endmodule
//参数定义 //spi时钟参数 `define SCK_PERIOD 20 `define SCK_HALF 10 //spi command `define CMD_WREN 8'h06 // `define CMD_WRDI 8'h04 // `define CMD_RDID 8'h9f // `define CMD_RDSR 8'h05 // `define CMD_WRSR 8'h01 // `define CMD_READ 8'h03 // `define CMD_FAST_READ 8'h0b // `define CMD_PP 8'h02 // `define CMD_SE 8'hd8 // `define CMD_BE 8'hc7 // `define CMD_DP 8'hb9 // `define CMD_RES 8'hab // //spi byte `define CMD_BYTE 1 // 命令1字节数 `define ADDR_BYTE 3 // 地址3字节数 `define ID_BYTE 3 // 读取id字节数 `define DATA_BYTE 256 // 读取数据字节数 `define RDSR_BYTE 1 // 读状态寄存器字节数 // `define DELAY_5MS 250_000 // 5ms 数据写入后需要等待5ms才能读出 `define DELAY_5MS 50 // 5ms 数据写入后需要等待5ms才能读出 //波特率 `define BAUD_9600 5208 `define BAUD_19200 2604 `define BAUD_38400 1302 `define BAUD_115200 434 `define STOP_BIT 1'b1 //数据停止位 `define START_BIT 1'b0 //数据开始位 `define MF_ID 8'h20 `define ID1 8'hBA `define ID2 8'h18
这里的读第二个ID,手册写的BB,我实际测的一直是BA,所以就用了BA
仿真相关:
module top( input wire sys_clk_p, //system clock positive input wire sys_clk_n, //system clock negative input wire rst_n , //reset ,low active input erase_start, input write_start, // output erase_completed, //仿真 // output four_pp_completed,//仿真 input miso , // output sck , output mosi , output cs_n ); wire erase_completed;//调试 wire four_pp_completed;//调试 wire sck; IBUFGDS sys_clk_ibufgds ( .O (sys_clk ),//200MHz .I (sys_clk_p ), .IB (sys_clk_n ) ); 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_spi ( .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(1'b0), // 1-bit input: User start-up clock input .GSR(1'b0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name) .GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name) .KEYCLEARB(1'b1), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM) .PACK(1'b1), // 1-bit input: PROGRAM acknowledge input .USRCCLKO(sck), // 1-bit input: User CCLK input .USRCCLKTS(1'b0), // 1-bit input: User CCLK 3-state enable input .USRDONEO(1'b1), // 1-bit input: User DONE pin output control .USRDONETS(1'b1) // 1-bit input: User DONE 3-state enable output ); reg [5:0] cnt_clk=0; wire add_cnt_clk; wire end_cnt_clk; always@(posedge sys_clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt_clk<=0; end else if(add_cnt_clk)begin if(end_cnt_clk) cnt_clk<=0; else cnt_clk<=cnt_clk+1; end end assign add_cnt_clk = 1; assign end_cnt_clk = add_cnt_clk && cnt_clk == 2-1; // reg clk;//100MHz // always@(posedge sys_clk)begin // if(cnt_clk<1)begin // clk<=1'b1; // end // else begin // clk<=1'b0; // end // end wire clk; assign clk=sys_clk; // wire clk_out1; // wire clk_out2; // clk_wiz_0 clk_wiz_0_uut // ( // .clk_out1(clk_out1), // output clk_out1 // .clk_out2(clk_out2), // output clk_out2 // .reset(~rst_n), // input reset // .locked(locked), // output locked // .clk_in1(sys_clk)); // input clk_in1 // wire clk; // assign clk=clk_out2 & locked; //===========================vio========================================= wire earse_start_vio; wire write_start_vio; wire read_start_vio; vio_0 uut_vio_0 ( .clk(clk), .probe_out0(earse_start_vio), .probe_out1(write_start_vio), .probe_out2(read_start_vio) ); reg earse_start_r1; always@(posedge clk)begin earse_start_r1<=earse_start_vio; end wire earse_edge; assign earse_edge= earse_start_r1 & ~earse_start_vio; reg write_start_r1; always@(posedge clk)begin write_start_r1<=write_start_vio; end wire write_edge; assign write_edge= write_start_r1 & ~write_start_vio; reg read_start_r1; always@(posedge clk)begin read_start_r1<=read_start_vio; end wire read_edge; assign read_edge= read_start_r1 & ~read_start_vio; //===========================test========================================= reg I_fl_data_en ; wire end_cnt0; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin I_fl_data_en <= 0; end // else if(write_start) begin //仿真 else if(write_edge)begin //实际 I_fl_data_en <= 1; end else if(end_cnt0) begin I_fl_data_en <= 0; end end reg [15:0] cnt0; wire add_cnt0; // wire end_cnt0; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<='d0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = I_fl_data_en; assign end_cnt0 = add_cnt0 && cnt0 == 1024-1;//256-1; // (*mark_debug="true", dont_touch="true"*)wire [7:0] wr_rd_state_spi_out ; (*mark_debug="true", dont_touch="true"*)wire [7:0] dout ;//读取数据 (*mark_debug="true", dont_touch="true"*)wire dout_vld ;//数据有效 (*mark_debug="true", dont_touch="true"*)wire spi_vld ; (*mark_debug="true", dont_touch="true"*)wire en ; (*mark_debug="true", dont_touch="true"*)wire [7:0] spi_dout ;//读取数据进入fifo (*mark_debug="true", dont_touch="true"*)wire spi_one_byte_done ; // (*mark_debug="true", dont_touch="true"*) wire [1:0] key_out; // key_filter_fsm # (.KEY_W(2),.TIME_20MS(1_000_000))u_key_filter_fsm // ( // /*input */.clk (clk ), // /*input */.rst_n (rst_n ), // /*input [KEY_W - 1:0] */.key_in ({write_start,erase_start} ), // /*output [KEY_W - 1:0] */.key_out (key_out ) // ); wr_control u_wr_control( /*input */.clk (clk ), /*input */.rst_n (rst_n ), // `ifdef simulation // `elsif // .erase_start (erase_start),// erase_start 仿真 // .write_start (write_start),//write_start .erase_start (earse_edge ),//erase_start 调试 .write_start (write_edge ),//write_start .erase_completed(erase_completed), .four_pp_completed(four_pp_completed), .read_start(read_edge), // `endif /*input */.spi_one_byte_done (spi_one_byte_done ), /*input [7:0] */.din (cnt0[7:0]),//(rx_byte ),// /*input */.din_vld (I_fl_data_en),//(rx_byte_vld ),// /*input [7:0] */.read_data (spi_dout ), /*output reg [7:0] */.wr_rd_state_spi_out (wr_rd_state_spi_out ), /*output [7:0] */.read_flash_data_fifo_out (dout ), /*output */.read_flash_data_fifo_out_vld (dout_vld ), /*output */.en (en ), /*output */.spi_vld (spi_vld ) ); spi_master u_spi_master( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input */.en (en ), /*input [1:0] */.spi_mode (2'b00 ), /*input */.spi_vld (spi_vld ), /*input [7:0] */.spi_din (wr_rd_state_spi_out),//写入数据 /*input */.miso (miso ), /*output reg */.sck (sck ), /*output reg */.cs_n (cs_n ), /*output */.mosi (mosi ), /*output reg [7:0] */.spi_dout (spi_dout ),//读取数据 /*output reg */.busy ( ), /*output */.spi_one_byte_done (spi_one_byte_done ) ); endmodule
`timescale 1ns / 1ps // `define simulation module top_tb(); //时钟与复位 reg sys_clk_p; reg rst_n; //uut的输入信号 reg erase_start ; reg write_start ; reg miso; //时钟周期,单位为ns, parameter CYCLE = 5; //复位时间,此时表示复位3个时钟周期的时间 parameter RST_TIME = 3; //待测试的模块例化 top uut( .sys_clk_p(sys_clk_p), .sys_clk_n(~sys_clk_p), .rst_n (rst_n), .erase_start (erase_start ), .write_start (write_start ), .miso (miso), .mosi (mosi), .cs_n (cs_n) ); //生成本地时钟200M initial begin sys_clk_p =0; forever #(CYCLE/2) sys_clk_p =~sys_clk_p; end //产生复位信号 initial begin rst_n =1; #2; rst_n =0; #(CYCLE*RST_TIME) rst_n =1; end initial begin write_start=0; erase_start =0; #1000 erase_start =1; #100 erase_start =0; #35_0000 //擦除4块 write_start=1; #100 write_start=0; #180_0000 write_start=1; #100 write_start=0; // #10_0000 //擦除4块 // write_start=1; // #100 // write_start=0; // #180_0000 // write_start=1; // #100 // write_start=0; end initial begin miso =0; end endmodule
注意:里面代码延时部分没有使用,是通过读状态寄存器来判断忙不忙,来决定进行下一次操作;文末有参考原文连接将的更加详细;
xilinx在线升级相关:
这里icap控制跳转的代码,测试可用,以下是原文连接:
https://blog.csdn.net/qq_43557686/article/details/134750377?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522028715b643b80c588730a73e4c1310ae%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=028715b643b80c588730a73e4c1310ae&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-134750377-null-null.nonecase&utm_term=icap&spm=1018.2226.3001.4450
/* * file : multiboot_ctrl.v * author : 今朝无言 * Lab : WHU-EIS-LMSWE * date : 2023-11-30 * version : v1.0 * description : ICAP 原语实现程控 multiboot(多重启动),K7需要使用 ICAPE2 原语 * Copyright © 2023 WHU-EIS-LMSWE, All Rights Reserved. */ module multiboot_ctrl( input wire clk, input wire rst_n, input wire multiboot_start, //触发Multiboot, 上升沿有效 input wire [31:0] multiboot_addr, //要启动的Muliboot Image的起始地址 output reg busy ); //-------------------ICAPE2原语----------------------------- wire ICAPE2_CLK; wire [31:0] ICAPE2_O; reg ICAPE2_CSIB; wire [31:0] ICAPE2_I; reg ICAPE2_RDWRB; assign ICAPE2_CLK = clk; ICAPE2 #( .DEVICE_ID (32'h3631093), // Specifies the pre-programmed Device ID value to be used for simulation purposes. K7-100T的为32'h3631093 .ICAP_WIDTH ("X32"), // Specifies the input and output data width. .SIM_CFG_FILE_NAME ("NONE") // Specifies the Raw Bitstream (RBT) file to be parsed by the simulation model. ) ICAPE2_inst( .O (ICAPE2_O), // 32-bit output: Configuration data output bus .CLK (ICAPE2_CLK), // 1-bit input: Clock Input .CSIB (ICAPE2_CSIB), // 1-bit input: Active-Low ICAP Enable .I (ICAPE2_I), // 32-bit input: Configuration data input bus .RDWRB (ICAPE2_RDWRB) // 1-bit input: Read/Write Select input 1对应rd,0对应wr ); wire [31:0] Dummy = 32'hFFFFFFFF; wire [31:0] Sync_Word = 32'hAA995566; wire [31:0] NOOP = 32'h20000000; wire [31:0] WR_WBSTAR = 32'h30020001; /*When using ICAPE2 to set the WBSTAR address, the 24 most significant address bits should be written to WBSTAR[23:0]. For SPI 32-bit addressing mode, WBSTAR[23:0] are sent as address bits [31:8]. The lower 8 bits of the address are undefined and the value could be as high as 0xFF. Any bitstream at the WBSTAR address should contain 256 dummy bytes before the start of the bitstream.*/ wire [31:0] WBSTAR = {3'b000, 5'h0, multiboot_addr[31:8]}; wire [31:0] WR_CMD = 32'h30008001; wire [31:0] IPROG = 32'h0000000F; //ICAPE2位翻转 reg [31:0] wrdat; assign ICAPE2_I = {wrdat[24], wrdat[25], wrdat[26], wrdat[27], wrdat[28], wrdat[29], wrdat[30], wrdat[31], wrdat[16], wrdat[17], wrdat[18], wrdat[19], wrdat[20], wrdat[21], wrdat[22], wrdat[23], wrdat[8], wrdat[9], wrdat[10], wrdat[11], wrdat[12], wrdat[13], wrdat[14], wrdat[15], wrdat[0], wrdat[1], wrdat[2], wrdat[3], wrdat[4], wrdat[5], wrdat[6], wrdat[7]}; //------------------------FSM---------------------------------- localparam S_IDLE = 16'h0001; localparam S_DUMMY = 16'h0002; localparam S_SYN_WORD = 16'h0004; localparam S_NOOP1 = 16'h0008; localparam S_WR_WBSTAR = 16'h0010; localparam S_WBSTAR = 16'h0020; localparam S_WR_CMD = 16'h0040; localparam S_IPROG = 16'h0080; localparam S_NOOP2 = 16'h0100; localparam S_STOP = 16'h0200; (*mark_debug="true", dont_touch="true"*)wire multiboot_start_pe; reg multiboot_start_d0; reg multiboot_start_d1; assign multiboot_start_pe = multiboot_start_d0 & (~multiboot_start_d1); always @(posedge clk) begin multiboot_start_d0 <= multiboot_start; multiboot_start_d1 <= multiboot_start_d0; end (*mark_debug="true", dont_touch="true"*) reg [15:0] state = S_IDLE; reg [15:0] next_state; always @(posedge clk) begin if(~rst_n) begin state <= S_IDLE; end else begin state <= next_state; end end always @(*) begin case(state) S_IDLE: begin if(multiboot_start_pe) begin next_state <= S_DUMMY; end else begin next_state <= S_IDLE; end end S_DUMMY: next_state <= S_SYN_WORD; S_SYN_WORD: next_state <= S_NOOP1; S_NOOP1: next_state <= S_WR_WBSTAR; S_WR_WBSTAR: next_state <= S_WBSTAR; S_WBSTAR: next_state <= S_WR_CMD; S_WR_CMD: next_state <= S_IPROG; S_IPROG: next_state <= S_NOOP2; S_NOOP2: next_state <= S_STOP; S_STOP: next_state <= S_IDLE; default: next_state <= S_IDLE; endcase end always @(posedge clk) begin case(state) S_IDLE: begin wrdat <= 32'd0; ICAPE2_CSIB <= 1'b1; ICAPE2_RDWRB <= 1'b1; end S_DUMMY: begin wrdat <= Dummy; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_SYN_WORD: begin wrdat <= Sync_Word; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_NOOP1: begin wrdat <= NOOP; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_WR_WBSTAR: begin wrdat <= WR_WBSTAR; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_WBSTAR: begin wrdat <= WBSTAR; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_WR_CMD: begin wrdat <= WR_CMD; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_IPROG: begin wrdat <= IPROG; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_NOOP2: begin wrdat <= NOOP; ICAPE2_CSIB <= 1'b0; ICAPE2_RDWRB <= 1'b0; end S_STOP: begin wrdat <= 32'd0; ICAPE2_CSIB <= 1'b1; ICAPE2_RDWRB <= 1'b1; end default: begin wrdat <= 32'd0; ICAPE2_CSIB <= 1'b1; ICAPE2_RDWRB <= 1'b1; end endcase end always@(*)begin if(state==S_IDLE) busy <= 1'b0; else busy <= 1'b1; end endmodule
golden中icap
//上电初始化信号 // parameter STA_EN_DLY = 32'd399_999_999; parameter STA_EN_DLY = 32'd7_999_999_999;//64s (*mark_debug="true", dont_touch="true"*)reg [32:0] power_ini_cnt; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin power_ini_cnt<='d0; end else if(power_ini_cnt < STA_EN_DLY)begin power_ini_cnt<=power_ini_cnt+1'b1; end else begin power_ini_cnt<=power_ini_cnt; end end reg power_en; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin power_en<= 1'b0; end else if(power_ini_cnt == STA_EN_DLY) begin power_en<= 1'b1; end else begin power_en<= 1'd0; end end reg power_en_r1; reg power_en_r2; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin power_en_r1 <= 1'b0; power_en_r2 <= 1'b0; end else begin power_en_r1 <= power_en; power_en_r2 <= power_en_r1; end end // (*mark_debug="true", dont_touch="true"*)wire power_ini_pos; assign power_ini_pos = power_en_r1 & ~power_en_r2; // (*mark_debug="true", dont_touch="true"*)reg erase_write_start_reg; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin erase_write_start_reg<= 1'b0; end else if(erase_start|write_start) begin erase_write_start_reg<= 1'b1; end else begin erase_write_start_reg<= erase_write_start_reg; end end // (*mark_debug="true", dont_touch="true"*)reg multiboot_start; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin multiboot_start<= 1'b0; end else if(power_ini_pos&(~erase_write_start_reg)) begin multiboot_start<= 1'b1; end else if(update_end)begin multiboot_start<= 1'b0;//1'b0不跳//1'b1跳 end else begin multiboot_start<= 1'b0; end end // multiboot_ctrl multiboot_ctrl_inst( .clk (clk),//(sys_clk), .rst_n (rst_n), .multiboot_start (multiboot_start),//(~key_in[0]),//key_in[0]---key1 key_in[1]---key2 .multiboot_addr (32'h80000000), //实际是(32'h00800000),模块内部移动了8位 //加载0x01000000处的Multiboot Image .busy () );
update中icap
//CMD_START_UPDATE 接收开始升级指令/用于跳转到golden区 reg start_update; always @(posedge clk or negedge rst_n) begin if (~rst_n) start_update<= 1'b0 ; else if(~header[0] && header_argu == CMD_START_UPDATE && cmd_mac_addr == local_mac_addr) begin if (cmd_cnt == 'd12)// start_update<=udp_rec_ram_rdata[0] ; else start_update<=1'b0 ; end end // multiboot_ctrl multiboot_ctrl_inst( .clk (clk),//(sys_clk), .rst_n (rst_n), .multiboot_start (start_update),//(~key_in[0]),//key_in[0]---key1 key_in[1]---key2 .multiboot_addr (32'h00000000),//加载0x01000000处的Multiboot Image .busy () );
multiboot_addr的地址这里写的是0x8000_0000,实际上在multiboot_ctrl内部做了8位偏移,而我使用的FLASH型号的S25FL128,采用的是24位地址。实际上跳转地址是0x0080_0000,经过仿真输出的是0x0080_0000;
XDC相关:
############## NET - IOSTANDARD ###################### set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] #############SPI Configurate Setting################## #set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.TIMER_CFG 32'h0007A120 [current_design] ##for golden image set_property BITSTREAM.CONFIG.CONFIGFALLBACK ENABLE [current_design] #set_property BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 32'h00800000 [current_design] set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]
############## NET - IOSTANDARD ###################### set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] #############SPI Configurate Setting################## #set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.TIMER_CFG 32'h0007A120 [current_design] #for multiboot image set_property BITSTREAM.CONFIG.CONFIGFALLBACK ENABLE [current_design] set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]
使用icap跳转升级流程:
1.升级指令顺序:
第一步,首先发送第六条升级启动指令,该指令将update区跳转到golden区,(如果已再golden区则可不用)
第二步,获取golden版本号,如果获取到golden版本号说明跳转成功
第三步,golden区版本号获取成功,开始进行擦除操作,
第四步,收到擦除完成信号,可以发送写升级包数据命令;发一包(1024字节写4页)后,收到应答后再下发一包,直到所有包发完,
第五步,掉电,拔掉jtag下载线,重启
2.注意事项:
每次重启后,先进入golden版本,一分钟内如果未收到擦除写flash命令,一分钟后,自动跳转到update版本;如果update版本破坏,则回退至golden版本,
如果需要升级,则需要跳转到golden区,update版本不具有擦写flash权,防止升级掉电版本不回退;
这里有一个问题:当update区没有数据或者数据破坏时,可以退回golden区,如果没有升级操作,两个区会一直来回跳,如果此时想使用golden区,那么这里的方法是,当进入golden区,一分钟内,发送擦除指令,这样就会一直停留在golden区,
使用工具:
软件:vivado2019.1
使用的FPGA型号为XC7A100T-2FGG4841,属于Xilinx 公司 Artix-7 系列的产品,速度等级为 2,温度等级为工业级。此型号为 FGG484封装,484 个引脚。
使用了一片 容量16M的 QSPI FLASH 芯片,型号为 N25Q128,它使用 3.3V CMOS 电压标准。由于它的非易失特性,在使用中,QSPIFLASH 可以作为 FPGA 系统的启动镜像。
vivado可选Mt25ql128-spi-x1_x2_x4











合成mcs,


参考连接:
flash参考代码连接:
【FPGA】SPI协议详解及对flash读写操作(玩嵌入式谁会脱发呀)
https://blog.csdn.net/li_lys/article/details/123146497
K7系列FPGA多重启动(Multiboot)(今朝无言)
https://blog.csdn.net/qq_43557686/article/details/134750377?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522028715b643b80c588730a73e4c1310ae%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=028715b643b80c588730a73e4c1310ae&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-134750377-null-null.nonecase&utm_term=icap&spm=1018.2226.3001.4450
FPGA在线升级 -- Multiboot(热爱学习地派大星)
https://blog.csdn.net/weixin_51418325/article/details/144370219?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-5-144370219-blog-136070049.235^v43^pc_blog_bottom_relevance_base8&spm=1001.2101.3001.4242.4&utm_relevant_index=7
感谢各位前辈的指路,记录一下,
posted on 2025-11-21 15:04 taylorrrrrrrrrr 阅读(2) 评论(0) 收藏 举报
浙公网安备 33010602011771号