赞
踩
大多数FPGA内部不具有掉电存储程序的功能,所以都是外置flash存储器来存储程序,上电后加载flash中的程序到FPGA中,在运行。外置flash不仅可以作为存储程序使用,也可以存储任何你想存储的用户数据,这样可以更有效的利用flash的存储空间,本文不讲其寄存器及原理,这个网上很多。
flash_spi:
`timescale 1ns / 1ps // // Company: // Engineer: QSJ // // Create Date: 2021/03/26 9:02:44 // Design Name: // Module Name: flash_spi // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module flash_spi( input wire sys_clk, input wire i_rst_n, // ---------- spi port --------- output wire o_spi_clk, output wire o_spi_cs, output wire o_spi_mosi, input wire i_spi_miso, // --------- data port ----------- input wire [7:0] iv_write_data , output reg o_wr_1_byte_ok , input wire [15:0] iv_write_num, input wire [15:0] iv_read_num, input wire [3:0] iv_cmd_type, output reg o_flash_done, input wire [7:0] iv_flash_cmd, input wire [31:0] iv_flash_addr, output reg [7:0] ov_read_data, output wire o_read_data_vld ); wire spi_clk; reg spi_cs; reg spi_mosi; wire spi_miso; assign o_spi_clk = spi_clk; assign o_spi_cs = spi_cs; assign o_spi_mosi = spi_mosi; assign spi_miso = i_spi_miso; reg read_data_vld; reg [7:0] read_data; reg [2:0] spi_state; reg spi_clk_en=1'b0; reg data_come; assign o_read_data_vld=read_data_vld; assign spi_clk=spi_clk_en?sys_clk:0; parameter IDLE = 3'b000; parameter CMD_SEND = 3'b001; parameter ADDRESS_SEND = 3'b010; parameter READ_WAIT = 3'b011; parameter WRITE_DATA = 3'b101; parameter FINISH_DONE = 3'b110; reg [7:0] cmd_reg; reg [31:0] address_reg; reg [7:0] wr_bit_cnt; reg [15:0] write_cnt; reg [7:0] rd_bit_cnt; reg [15:0] read_cnt; reg [15:0] read_num_inner; reg read_finish; always @(negedge sys_clk) begin if(!i_rst_n) begin spi_cs<=1'b1; spi_state<=IDLE; cmd_reg<=0; address_reg<=0; spi_clk_en<=1'b0; wr_bit_cnt<=0; write_cnt<=0; read_num_inner<=0; o_flash_done<=1'b0; data_come<=1'b0; o_wr_1_byte_ok <= 1'b0; end else begin case(spi_state) IDLE: begin spi_clk_en<=1'b0; spi_cs<=1'b1; spi_mosi<=1'b1; cmd_reg<=iv_flash_cmd; address_reg<=iv_flash_addr; o_flash_done<=1'b0; if(iv_cmd_type[3]==1'b1) begin spi_state<=CMD_SEND; wr_bit_cnt<=7; write_cnt<=0; read_num_inner<=0; end end CMD_SEND: begin spi_clk_en<=1'b1; spi_cs<=1'b0; if(wr_bit_cnt>0) begin spi_mosi<=cmd_reg[wr_bit_cnt]; wr_bit_cnt<=wr_bit_cnt-1'b1; end else begin spi_mosi<=cmd_reg[0]; if ((iv_cmd_type[2:0]==3'b001) | (iv_cmd_type[2:0]==3'b100)) begin spi_state<=FINISH_DONE; end else if (iv_cmd_type[2:0]==3'b011) begin spi_state<=READ_WAIT; wr_bit_cnt<=7; read_num_inner<=1; end else if (iv_cmd_type[2:0]==3'b000) begin spi_state<=READ_WAIT; wr_bit_cnt<=7; read_num_inner<=17; end else begin spi_state<=ADDRESS_SEND; wr_bit_cnt<=31; end end end ADDRESS_SEND: begin if(wr_bit_cnt>0) begin spi_mosi<=address_reg[wr_bit_cnt]; wr_bit_cnt<=wr_bit_cnt-1; end else begin spi_mosi<=address_reg[0]; if(iv_cmd_type[2:0]==3'b010) begin spi_state<=FINISH_DONE; end else if (iv_cmd_type[2:0]==3'b101) begin spi_state<=WRITE_DATA; wr_bit_cnt<=7; end else begin spi_state<=READ_WAIT; read_num_inner<=iv_read_num; end end end READ_WAIT: begin if(read_finish) begin spi_state<=FINISH_DONE; data_come<=1'b0; end else data_come<=1'b1; end WRITE_DATA: begin if(write_cnt<iv_write_num) begin if(wr_bit_cnt>0) begin spi_mosi<=iv_write_data[wr_bit_cnt]; wr_bit_cnt<=wr_bit_cnt-1'b1; o_wr_1_byte_ok <= 1'b0; end else begin spi_mosi<=iv_write_data[0]; wr_bit_cnt<=7; o_wr_1_byte_ok <= 1'b1; write_cnt<=write_cnt+1'b1; end end else begin spi_state<=FINISH_DONE; spi_clk_en<=1'b0; o_wr_1_byte_ok <= 1'b0; write_cnt <= 0; end end FINISH_DONE: begin spi_cs<=1'b1; spi_mosi<=1'b1; spi_clk_en<=1'b0; o_flash_done<=1'b1; spi_state<=IDLE; end default:spi_state<=IDLE; endcase end end always @(posedge sys_clk) begin if(!i_rst_n) begin read_cnt<=0; rd_bit_cnt<=0; read_finish<=1'b0; read_data_vld<=1'b0; read_data<=0; ov_read_data<=0; end else if(data_come) begin if(read_cnt<read_num_inner) begin if(rd_bit_cnt<7) begin read_data_vld<=1'b0; read_data<={read_data[6:0],spi_miso}; rd_bit_cnt<=rd_bit_cnt+1'b1; end else begin read_data_vld<=1'b1; ov_read_data<={read_data[6:0],spi_miso}; rd_bit_cnt<=0; read_cnt<=read_cnt+1'b1; end end else begin read_cnt<=0; read_finish<=1'b1; read_data_vld<=1'b0; end end else begin read_cnt<=0; rd_bit_cnt<=0; read_finish<=1'b0; read_data_vld<=1'b0; read_data<=0; end end endmodule
flash_cmd:
`timescale 1ns / 1ps // // Company: // Engineer: QSJ // // Create Date: 2021/03/26 9:04:02 // Design Name: // Module Name: flash_cmd // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module flash_cmd( input sys_clk, input i_rst_n, input i_wr_flash_start, input i_rd_flash_start, input i_rd_device_id_start, input i_subsector_erase_start, input wire [7:0] iv_write_data , output wire o_wr_1_byte_ok , input wire [15:0] iv_write_num, input wire [15:0] iv_read_num, input wire [31:0] iv_base_addr , output o_spi_clk , output o_spi_cs , output o_spi_mosi , input i_spi_miso , output [7:0] ov_rd_data, output o_rd_data_vld ); reg [7:0] flash_cmd_def; reg [3:0] cmd_type; wire flash_done; wire [7:0] read_data; wire read_data_vld; reg [4:0] curr_state = 'd15; always @ ( posedge sys_clk ) begin if( !i_rst_n ) begin curr_state <= 'd15; flash_cmd_def <= 8'd0; cmd_type <= 4'b0000; end else begin case( curr_state ) 'd0://idle if(i_wr_flash_start) curr_state <= 'd8 ; else if(i_rd_flash_start) curr_state <= 'd13; else if(i_rd_device_id_start) curr_state <= 'd1 ; else if(i_subsector_erase_start) curr_state <= 'd3 ; else curr_state <= 'd0; // -------------- read device ID ------------------ 'd1://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd2; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd2:// Read Device ID:9FH if( flash_done ) begin flash_cmd_def <= 8'h00; if(read_data == 8'hFF) // if the device id is error curr_state <= 'd1; else curr_state <= 'd0; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h9f; curr_state <= curr_state; cmd_type <= 4'b1000; end // -------------- Erase ------------------ 'd3://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd4; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd4://Write Enable:06H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd5; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h06; curr_state <= curr_state; cmd_type <= 4'b1001; end 'd5://4-byte address mode Sector Erase:DCH Subsector Erase:21H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd6; cmd_type<=4'b0000; end else begin flash_cmd_def <= 8'h21; curr_state <= curr_state; cmd_type <= 4'b1010; end 'd6://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd7; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd7://Write disable: 04H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd0; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h04; cmd_type <= 4'b1100; end // -------------- write Data ------------------ 'd8://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd9; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd9://Write Enable:06H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd10; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h06; cmd_type <= 4'b1001; end 'd10://4-byte address page program: write data to flash if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd11; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h12; cmd_type <= 4'b1101; end 'd11://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd12; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd12://Write disable: 04H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd0; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h04; cmd_type <= 4'b1100; end // -------------- read Data ------------------ 'd13://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd14; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd14://4-byte address read flash data if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd0; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h13; cmd_type <= 4'b1110; end // -------------- enter 4-byte mode ------------------ 'd15://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd16; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd16://Write Enable:06H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd17; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h06; cmd_type <= 4'b1001; end 'd17://Enter 4-byte address mode:B7H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd18; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'hB7; cmd_type <= 4'b1001; end 'd18://Read Status Register:05H if( flash_done ) begin if (read_data[0]==1'b0) begin flash_cmd_def <= 8'h00; curr_state <= 'd19; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end end else begin flash_cmd_def <= 8'h05; cmd_type <= 4'b1011; end 'd19://Write disable: 04H if( flash_done ) begin flash_cmd_def <= 8'h00; curr_state <= 'd1; cmd_type <= 4'b0000; end else begin flash_cmd_def <= 8'h04; cmd_type <= 4'b1100; end endcase end end reg [31:0] base_addr; always @ ( posedge sys_clk) begin if( !i_rst_n ) begin base_addr <= 'd0; end else begin if(curr_state == 0) begin if(i_wr_flash_start|i_rd_flash_start|i_subsector_erase_start) base_addr <= iv_base_addr ; else base_addr <= 'd0; end else base_addr <= base_addr ; end end flash_spi U_flash_spi( .sys_clk( sys_clk ), .i_rst_n( i_rst_n ), .o_spi_clk ( o_spi_clk ), .o_spi_cs ( o_spi_cs ), .o_spi_mosi ( o_spi_mosi ), .i_spi_miso ( i_spi_miso ), .iv_write_data ( iv_write_data ), .o_wr_1_byte_ok ( o_wr_1_byte_ok ), .iv_write_num ( iv_write_num ), .iv_read_num ( iv_read_num ), .iv_cmd_type ( cmd_type ), .o_flash_done ( flash_done ), .iv_flash_cmd ( flash_cmd_def ), .iv_flash_addr ( base_addr ), .ov_read_data ( read_data ), .o_read_data_vld( read_data_vld ) ); assign ov_rd_data = read_data; assign o_rd_data_vld = (curr_state == 'd14) ? read_data_vld : 0; endmodule
以上就是全部内容,仅做个人记录,若需要对flash进行更多操作,可阅读flash对应的datasheet。
有完整的VIVADO FPGA测试工程。
工程未经过全面的调试,有问题请指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。