1.硬件环境
FPGA型号SPARTAN-6 XS6SLX9TQG144I
FLASH型号W25Q64FV
FPGA启动方式配置为主串模式(M[1:0] = 0x01)。
Spartan-6 FPGA Configuration User Guide(ug380)中对FPGA配置为主串模式的说明如下表所示。
2.实现过程
3.FLASH相关操作指令
3.1 芯片擦除
因为该片FLASH仅仅是用来作为FPGA程序的存储介质,故而在重构是采用直接芯片擦除的方式。若是FLASH还有不可擦除的扇区,则需要选择扇区擦除的方式。W25Q64FV对芯片擦除的时序如下图。
3.2 页编程
每页最大写入256个字节,即地址范围需是0xXXXX00~0xXXXXFF。所以本人上位机每次发送256个字节,直至最后一帧。最后一帧是有多少写多少。
3.3 写使能/写不使能
在执行PROGRAM和ERASE操作之前应先进行写使能,执行完后进行写不使能操作。
3.4 读状态寄存器
读状态寄存器的目的是判断当前ERASE和PROGRAM操作是否完成。状态寄存器Bit0位等于1则表示忙,等于0表示操作已完成。
状态寄存器1说明
4 程序设计
//instruction_type == 4'd1: program
//instruction_type == 4'd2: read data
//instruction_type == 4'd3: chip erase
//instruction_type == 4'd4: write disable
//instruction_type == 4'd5: write enable
//instruction_type == 4'd6: read status register
//instruction_type == 4'd7: read device ID
reg [15:0] read_length,write_length;
reg [15:0] write_count;
reg spi_valid;
reg [3:0] state;
assign flash_clk = spi_valid ? CLK : 1'b0;
//assign fifo_rd_clk = fifo_rd_en? CLK : 1'b0;
assign fifo_rd_clk = CLK;
parameter idle = 4'd0,
send_inst = 4'd1,
send_addr = 4'd2,
send_data = 4'd3,
wait_data = 4'd4,
send_done = 4'd5;
always @(negedge CLK or negedge RSTn)
if(!RSTn) begin
flash_csn <= 1'b1;
flash_dataout <= 1'b0;
frame_done <= 1'b0;
cnt_cmd <= 5'd7;
fifo_rd_en <= 1'b0;
read_cmd <= 1'b0;
write_length <= 16'd0;
read_length <= 16'd0;
write_count <= 16'd0;
spi_valid <= 1'b0;
state <= idle;
end else begin
case(state)
idle: begin
flash_csn <= 1'b1;
cnt_cmd <= 5'd7;
frame_done <= 1'b0;
write_count <= 16'b0;
if(instruction_type[3] == 1'b1) begin
state <= send_inst;
end else begin
state <= idle;
end
end
send_inst: if(cnt_cmd > 4'd0) begin
flash_csn <= 1'b0;
spi_valid <= 1'b1;
flash_dataout <= flash_instruction[cnt_cmd];
cnt_cmd <= cnt_cmd - 1'b1;
end else begin
flash_dataout <= flash_instruction[0];
if((instruction_type[2:0] == 3'd3) || (instruction_type[2:0] == 3'd4) || (instruction_type[2:0] == 3'd5)) begin
cnt_cmd <= 5'd7;
state <= send_done;
end else if(instruction_type[2:0] == 3'd6) begin
read_length <= 16'd2;
state <= wait_data;
end else begin
cnt_cmd <= 5'd23;
state <= send_addr;
end
end
send_addr: if(cnt_cmd > 4'd0) begin
flash_dataout <= flash_address[cnt_cmd];
cnt_cmd <= cnt_cmd - 1'b1;
end else begin
flash_dataout <= flash_address[0];
if(instruction_type[2:0] == 3'd1) begin
cnt_cmd <= 5'd7;
//write_length <= 16'd20;
write_length <= frame_write_length;
fifo_rd_en <= 1'b1;
state <= send_data;
end else if(instruction_type[2:0] == 3'd2) begin
read_length <= 16'd256;
cnt_cmd <= 5'd7; //unused
state <= wait_data;
end else begin
read_length <= 16'd2;
cnt_cmd <= 5'd7; //unused
state <= wait_data;
end
end
send_data: if(write_count < write_length - 1'b1) begin
if(cnt_cmd == 5'd0) begin
cnt_cmd <= 5'd7;
fifo_rd_en <= 1'b1;
write_count <= write_count + 1'b1;
flash_dataout <= flash_data_i[0];
end else begin
fifo_rd_en <= 1'b0;
flash_dataout <= flash_data_i[cnt_cmd];
cnt_cmd <= cnt_cmd - 1'b1;
end
end else begin
if(cnt_cmd == 5'd0) begin
cnt_cmd <= 5'd7;
//fifo_rd_en <= 1'b1;
//write_count <= write_count + 1'b1;
write_count <= 16'd0;
flash_dataout <= flash_data_i[0];
//spi_valid <= 1'b0;
fifo_rd_en <= 1'b0;
state <= send_done;
end else begin
fifo_rd_en <= 1'b0;
flash_dataout <= flash_data_i[cnt_cmd];
cnt_cmd <= cnt_cmd - 1'b1;
end
//
// spi_valid <= 1'b0;
// fifo_rd_en <= 1'b0;
// state <= send_done;
end
wait_data: if(read_count < read_length) begin
read_cmd <= 1'b1;
state <= wait_data;
end else begin
read_cmd <= 1'b0;
spi_valid <= 1'b0;
state <= send_done;
end
send_done: begin
flash_csn <= 1'b1;
spi_valid <= 1'b0;
frame_done <= 1'b1;
state <= idle;
end
default: state <= idle;
endcase
end
reg [15:0] read_count;
reg [3:0] j;
reg [7:0] recv_data;
assign flash_data_o = (read_cmd && (j == 4'd7))? recv_data : flash_data_o;
always @(posedge CLK or negedge RSTn)
if(!RSTn) begin
read_over <= 1'b0;
read_count <= 16'd0;
recv_data <= 8'h00;
flash_data_valid <= 1'b0;
end else begin
if(read_cmd) begin
if(j == 4'd0) begin
j <= 4'd7;
recv_data[j] <= flash_datain;
read_count <= read_count + 1'b1;
flash_data_valid <= 1'b1;
end else begin
j <= j - 1'b1;
recv_data[j] <= flash_datain;
flash_data_valid <= 1'b0;
end
end else begin
j <= 4'd7;
read_count <= 16'd0;
read_over <= 1'b0;
flash_data_valid <= 1'b0;
end
end
endmodule
//instruction_type == 4'd1: program
//instruction_type == 4'd2: read data
//instruction_type == 4'd3: chip erase
//instruction_type == 4'd4: write disable
//instruction_type == 4'd5: write enable
//instruction_type == 4'd6: read status register
//instruction_type == 4'd7: read device ID
always @(posedge CLK or negedge RSTn)
if(!RSTn) begin
instruction_type <= 4'b0000;
flash_instruction <= 8'h00;
flash_address <= 24'd0;
flash_address_r <= 24'd0;
frame_write_address <= 24'd0;
erase_finish <= 1'b0;
flash_program_finish <= 1'b0;
DeviceID <= 8'h00;
counter <= 32'd0;
state <= 5'd0;
end else begin
case(state)
5'd0: if(counter == 32'd1000) begin //wait a moment
counter <= 32'd0;
state <= state + 1'b1;
end else begin
counter <= counter + 1'b1;
state <= state;
end
5'd1: if(frame_done) begin //read device ID
DeviceID <= flash_data_o;
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1111;
flash_address <= 24'd0;
flash_instruction <= 8'h90;
state <= state;
end
5'd2: if(erase_start) begin //erase chip
frame_write_address <= 24'd0;
state <= state + 1'b1;
end else if(pos_frame_valid) begin //program
flash_address_r <= frame_write_address;
frame_write_address <= frame_write_address + 24'h000100;
state <= 5'd9;
end else if(pos_send_valid) begin //read data
state <= 5'd15;
end else begin
erase_finish <= 1'b0;
flash_program_finish <= 1'b0;
state <= state;
end
//chip erase sequency
5'd3: if(frame_done) begin //write enable instruction
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1101;
flash_address <= 24'd0;
flash_instruction <= 8'h06;
state <= state;
end
5'd4: if(frame_done) begin //erase chip
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1011;
flash_address <= 24'd0;
flash_instruction <= 8'hC7;
state <= state;
end
5'd5: if(counter == 32'd1000000) begin //wait one second
counter <= 32'd0;
state <= state + 1'b1;
end else begin
counter <= counter + 1'b1;
state <= state;
end
5'd6: if(frame_done) begin //read status register 1
if(flash_data_o[0] == 1'b0) begin
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
5'd7: if(frame_done) begin //write disable
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1100;
flash_address <= 24'd0;
flash_instruction <= 8'h04;
state <= state;
end
5'd8: if(frame_done) begin //read status register 1
if(flash_data_o[0] == 1'b0) begin
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= 5'd2;
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
end else begin
erase_finish <= 1'b1;
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
//write sequency
5'd9: if(frame_done) begin //write enable instruction
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1101;
flash_address <= 24'd0;
flash_instruction <= 8'h06;
state <= state;
end
5'd10: if(counter == 32'd10) begin //wait a moment
counter <= 32'd0;
state <= state + 1'b1;
end else begin
counter <= counter + 1'b1;
state <= state;
end
5'd11: if(frame_done) begin //program 256 data
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1001;
//flash_address <= 24'h800000;
flash_address <= flash_address_r;
flash_instruction <= 8'h02;
state <= state;
end
5'd12: if(counter == 32'd1000) begin //wait a moment
counter <= 32'd0;
state <= state + 1'b1;
end else begin
counter <= counter + 1'b1;
state <= state;
end
5'd13: if(frame_done) begin //read status register 1
if(flash_data_o[0] == 1'b0) begin
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
5'd14: if(frame_done) begin //write disable
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= 5'd2;
end else begin
flash_program_finish <= 1'b1;
instruction_type <= 4'b1101;
flash_address <= 24'd0;
flash_instruction <= 8'h04;
state <= state;
end
//read sequency
5'd15: if(frame_done) begin //read status register 1
if(flash_data_o[0] == 1'b0) begin
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
end else begin
instruction_type <= 4'b1110;
flash_address <= 24'd0;
flash_instruction <= 8'h05;
state <= state;
end
5'd16: if(frame_done) begin //read 256
instruction_type <= 4'b0000;
flash_address <= 24'd0;
flash_instruction <= 8'h00;
state <= state + 1'b1;
end else begin
instruction_type <= 4'b1010;
// flash_address <= 24'h023000;
flash_address <= flash_address_r;
flash_instruction <= 8'h03;
state <= state;
end
5'd17: state <= 5'd2;
default: state <= 5'd0;
endcase
end
程序链接:
链接:https://pan.baidu.com/s/1YxvZhcjUr5azazlGKVrD4Q
提取码:gb8e