赞
踩
本篇文章所使用的Flash型号为M25P16,是ST公司的一款(好像还有一款同名的,是别的公司的)。容量为16Mbit,SPI接口,时钟速率可达50Mhz。要想完成对Flash的读写擦除操作,只需要弄懂两点即可:SPI时序 和 Flash操作指令。其他的细节和一些概念可以学习的过程中了解补充。
SPI一共有四种模式,分别由两个变量CPOL和CPHA控制。此Flash芯片下面两种模式
一般来说,都采用第二种模式对Flash进行读写。
Flash的全部指令如下,不算多,而且其中有些指令不会用到。下面就对必须要用到的指令进行说明
这两条指令一个是写使能,另外一个是写失能,一般情况下,只用WREN就可以看,至于为什么,后面相关写指令会给出答案。
用来读取Flash的设备ID号,通常用来测试SPI总线是否正确,写完SPI协议后,可以使用这条命令来进行测试。
发送指令和读取的首地址后,接下来就是读取数据,每读取一个数据,地址就会知道加一,当达到地址边界后,地址会自动跳转到0地址进行读取,读取数据的数量没有限制,可以无限读下去。读完最后一个字节后,只需要将S信号拉高即可结束本部读取操作。
对flash进行写入操作,以页为单位,每一页有256bytes,共8192页,具体如下。
然后时序图如下,
然后重点来了,意思就是,在执行PP命令的时候,需要先执行WREN命令,并且锁住,可能在PP命令结束后,WREN命令会失效,根据最后一行推测出来的,测试时确实如此。
擦除命令,很简单,给指令和地址后,就ok了,擦除完成后,再次读取的时候,应该是全FF。同样擦除命令和PP命令一样,需要先发送WREN命令才行。其他的就没了。
Tcsh : 表示两条指令间隔时间,
Tpp: 表示page program后,需要等待Tpp时间后,才能进行下一条指令的操作
Tse: 同Tpp一样。
写流程: WREN -> SE -> WREN -> PP(PP只能将1写为0 ,所以在PP之前要先擦除)
读流程: READ
SPI模块
`timescale 1ns/1ps //MODE : CPOL=1 CPHA=1 //spi_clk = sys_clk / 2 module SPI_Master ( //system interface input wire sys_clk, input wire sys_rstn, //user inferface //user read input wire read_req, output wire[7:0] read_data, output wire read_ack, //user write input wire write_req, input wire[7:0] write_data, output wire write_ack, //spi to external flash output wire spi_clk, output wire spi_mosi, input wire spi_miso //output wire spi_csn ); localparam SPI_IDLE = 4'b0001; localparam SPI_DATA = 4'b0010; localparam SPI_END = 4'b0100; localparam SPI_END2 = 4'b1000; reg[3:0] state , next_state; reg spi_clk_reg; reg spi_mosi_reg; reg spi_csn_reg; reg spi_clk_inverse_cnt; reg[3:0] spi_rev_send_bit_cnt; reg[7:0] write_data_reg; reg[7:0] read_data_reg; assign spi_clk = spi_clk_reg; assign spi_mosi = spi_mosi_reg; assign spi_csn = spi_csn_reg; assign read_data = read_data_reg; assign read_ack = (state == SPI_END) ? 1'b1 : 1'b0; assign write_ack = (state == SPI_END) ? 1'b1 : 1'b0; always @(posedge sys_clk or negedge sys_rstn) begin if (sys_rstn == 1'b0) state <= SPI_IDLE; else state <= next_state; end always@(*)begin case (state) SPI_IDLE: if( write_req == 1'b1 || read_req == 1'b1) next_state <= SPI_DATA; else next_state <= SPI_IDLE; SPI_DATA: if( spi_rev_send_bit_cnt == 'd7 && spi_clk_inverse_cnt == 1'b1) next_state <= SPI_END; else next_state <= SPI_DATA; SPI_END: next_state <= SPI_END2; SPI_END2: next_state <= SPI_IDLE; default: next_state <= SPI_IDLE; endcase end always @(posedge sys_clk or negedge sys_rstn) begin if( sys_rstn == 1'b0) spi_clk_inverse_cnt <= 1'b0; else if( state == SPI_DATA) spi_clk_inverse_cnt <= spi_clk_inverse_cnt + 1'b1; else spi_clk_inverse_cnt <= 1'b0; end //spi csn out // always @(posedge sys_clk or negedge sys_rstn) begin // if( sys_rstn == 1'b0 ) // spi_csn_reg <= 1'b1; // else if( state == SPI_IDLE && (write_req == 1'b1 || read_req == 1'b1)) // spi_csn_reg <= 1'b0; // else if( state == SPI_DATA) // spi_csn_reg <= 1'b0; // else // spi_csn_reg <= 1'b1; // end //spi write/read data bit cnt always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) spi_rev_send_bit_cnt <= 4'd0; else if( spi_clk_inverse_cnt == 1'b1) spi_rev_send_bit_cnt <= spi_rev_send_bit_cnt + 1'b1; else if( state == SPI_DATA) spi_rev_send_bit_cnt <= spi_rev_send_bit_cnt; else spi_rev_send_bit_cnt <= 4'd0; end //mosi data shift always @(posedge sys_clk or negedge sys_rstn) begin if( sys_rstn == 1'b0) write_data_reg <= 8'd0; else if( state == SPI_IDLE && (write_req == 1'b1 || read_req == 1'b1)) write_data_reg <= write_data; else if( state == SPI_DATA && spi_clk_inverse_cnt == 1'b1) write_data_reg <= {write_data_reg[6:0],write_data_reg[7]}; else write_data_reg <= write_data_reg; end //spi_clk_gen always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) spi_clk_reg <= 1'b1; else if(state == SPI_DATA) spi_clk_reg <= ~spi_clk_reg; else spi_clk_reg <= 1'b1; end //mosi data out always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) spi_mosi_reg <= 1'b1; else if(state == SPI_DATA && write_req == 1'b1) spi_mosi_reg <= write_data_reg[7]; else spi_mosi_reg <= 1'b1; end //miso data in always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) read_data_reg <= 1'b0; else if(state == SPI_DATA && spi_clk_inverse_cnt == 1'b1) read_data_reg <= {read_data_reg[6:0] , spi_miso}; else read_data_reg <= read_data_reg; end endmodule
Flash模块
//flash write/read control : M25P16 module flash_contorl ( //system interface input wire sys_clk, input wire sys_rstn, //user interface //read identification input wire read_id_req, output wire[23:0] flash_id, output wire read_id_end, //read data input wire read_req, input wire[23:0] read_addr, input wire[9:0] read_size, output wire[7:0] read_data, output wire read_ack, output wire read_end, //write enalbe input wire write_enable_req, output wire write_enable_end, //write disalbe //write data input wire write_req, input wire[23:0] write_page, //write num page input wire[8:0] write_size, //max equal 256 input wire[7:0] write_data, output wire write_ack, output wire write_end, //erase sector input wire erase_sector_req, input wire[23:0] erase_sector_addr, output wire erase_sector_end, //erase bulk input wire erase_bulk_req, output wire erase_bulk_end, //spi to external flash output wire spi_clk, output wire spi_mosi, input wire spi_miso, output wire spi_csn ); //control flash instruction `define Write_Enable 8'h06 `define Write_Disable 8'h04 `define Read_Identification 8'h9F `define Read_Status_Reg 8'h05 `define Write_Status_Reg 8'h01 `define Read_Data_Bytes 8'h03 `define Read_Data_At_Higher_Speed 8'h0B `define Page_Program 8'h02 `define Sector_Erase 8'hD8 `define Bulk_Erase 8'hC7 `define Read_Identification_Bytes 4'd4 `define Sector_Erase_Bytes 4'd4 `define Bulk_Erase_Bytes 4'd1 localparam Page_Size = 9'd256; localparam Write_Enable_Wait = 'd10; localparam Read_Data_Bytes_Wait = 'd10; //wait 60ns localparam Sector_Erase_Wait = 32'd35_000_000; //wait 640ms localparam Page_Program_Wait = 32'd350_000; //wait 640us localparam Bulk_Erase_Wait = 32'd650_000_000; //wait 13s localparam Flash_Idle = 13'b0_0000_0000_0001; localparam Flash_Write_Enable = 13'b0_0000_0000_0010; localparam Flash_Write_Disable = 13'b0_0000_0000_0100; localparam Flash_Read_Identification = 13'b0_0000_0000_1000; localparam Flash_Read_Status_Reg = 13'b0_0000_0001_0000; localparam Flash_Write_Status_Reg = 13'b0_0000_0010_0000; localparam Flash_Read_Data_Bytes = 13'b0_0000_0100_0000; localparam Flash_Read_Data_At_hSpeed = 13'b0_0000_1000_0000; localparam Flash_Page_Program = 13'b0_0001_0000_0000; localparam Flash_Sector_Erase = 13'b0_0010_0000_0000; localparam Flash_Bulk_Erase = 13'b0_0100_0000_0000; localparam Flash_Wait = 13'b0_1000_0000_0000; localparam Flash_End = 13'b1_0000_0000_0000; reg[12:0] state , next_state; reg[12:0] state_ts; //spi read reg spi_read_req; wire[7:0] spi_read_data; wire spi_read_ack; //spi write reg spi_write_req; reg[7:0] spi_write_data; wire spi_write_ack; reg spi_csn_reg; reg[9:0] spi_wr_byte_cnt; reg[23:0] flash_id_reg; reg[32:0] pp_erase_wait_cnt; assign spi_csn = spi_csn_reg; //to spi flash csn assign flash_id = flash_id_reg; assign read_id_end = ((spi_wr_byte_cnt == `Read_Identification_Bytes - 1'b1) && spi_read_ack == 1'b1) ? 1'b1 : 1'b0; assign read_data = spi_read_data; assign read_ack = ((state == Flash_Read_Data_Bytes) && (spi_wr_byte_cnt > 'd3) && spi_read_ack == 1'b1) ? 1'b1 : 1'b0; //读出数据有效 assign read_end = ((state == Flash_Read_Data_Bytes) &&(spi_wr_byte_cnt == read_size + 'd1 + 'd3 - 1'b1) && spi_read_ack == 1'b1) ? 1'b1 : 1'b0; assign write_enable_end = ((state == Flash_Write_Enable) &&(spi_wr_byte_cnt == 'd0) && spi_write_ack == 1'b1) ? 1'b1 : 1'b0; assign write_ack = ((state == Flash_Page_Program) && (spi_wr_byte_cnt > 'd3) && spi_write_ack == 1'b1) ? 1'b1 : 1'b0; //请求下一个数据 assign write_end = ((state == Flash_Page_Program) && (spi_wr_byte_cnt == write_size + 'd1 + 'd3 - 1'b1) && spi_write_ack == 1'b1) ? 1'b1 : 1'b0; assign erase_sector_end = ((state == Flash_Sector_Erase) && (spi_wr_byte_cnt == `Sector_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1 ) ? 1'b1 : 1'b0; assign erase_bulk_end = ((state == Flash_Bulk_Erase) && (spi_wr_byte_cnt == `Bulk_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1 ) ? 1'b1 : 1'b0; always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) state <= Flash_Idle; else state <= next_state; end always@(*)begin case (state) Flash_Idle: if( read_id_req == 1'b1) next_state <= Flash_Read_Identification; else if( write_enable_req == 1'b1) next_state <= Flash_Write_Enable; else if( write_req == 1'b1 ) next_state <= Flash_Page_Program; else if( read_req == 1'b1 ) next_state <= Flash_Read_Data_Bytes; else if( erase_sector_req == 1'b1) next_state <= Flash_Sector_Erase; else if( erase_bulk_req == 1'b1 ) next_state <= Flash_Bulk_Erase; else next_state <= Flash_Idle; Flash_Read_Identification: if( (spi_wr_byte_cnt == `Read_Identification_Bytes - 1'b1) && spi_read_ack == 1'b1) next_state <= Flash_End; else next_state <= Flash_Read_Identification; Flash_Write_Enable: if( spi_write_ack == 1'b1) next_state <= Flash_Wait; else next_state <= Flash_Write_Enable; Flash_Page_Program: if( (spi_wr_byte_cnt == write_size + 'd1 + 'd3 - 1'b1) && spi_write_ack == 1'b1) //写入指令 + 地址 + 数据 next_state <= Flash_Wait; else next_state <= Flash_Page_Program; Flash_Read_Data_Bytes: if( (spi_wr_byte_cnt == read_size + 'd1 + 'd3 - 1'b1) && spi_read_ack == 1'b1) //写入指令 + 地址 + 数据 next_state <= Flash_Wait; else next_state <= Flash_Read_Data_Bytes; Flash_Sector_Erase: if( (spi_wr_byte_cnt == `Sector_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1) next_state <= Flash_Wait; else next_state <= Flash_Sector_Erase; Flash_Bulk_Erase: if( (spi_wr_byte_cnt == `Bulk_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1) next_state <= Flash_Wait; else next_state <= Flash_Bulk_Erase; Flash_Wait: if( state_ts == Flash_Page_Program && pp_erase_wait_cnt == Page_Program_Wait) next_state <= Flash_End; else if(state_ts == Flash_Sector_Erase && pp_erase_wait_cnt == Sector_Erase_Wait) next_state <= Flash_End; else if(state_ts == Flash_Bulk_Erase && pp_erase_wait_cnt == Bulk_Erase_Wait) next_state <= Flash_End; else if(state_ts == Flash_Read_Data_Bytes && pp_erase_wait_cnt == Read_Data_Bytes_Wait) next_state <= Flash_End; else if(state_ts == Flash_Write_Enable && pp_erase_wait_cnt == Write_Enable_Wait) next_state <= Flash_End; else next_state <= Flash_Wait; Flash_End: next_state <= Flash_Idle; default: next_state <= Flash_Idle; endcase end always@(posedge sys_clk or negedge sys_rstn ) begin if( sys_rstn == 1'b0) state_ts <= Flash_Idle; else if( state == Flash_Idle ) if( write_req == 1'b1 ) state_ts <= Flash_Page_Program; else if( erase_sector_req == 1'b1) state_ts <= Flash_Sector_Erase; else if( erase_bulk_req == 1'b1 ) state_ts <= Flash_Bulk_Erase; else if( read_req == 1'b1) state_ts <= Flash_Read_Data_Bytes; else if( write_enable_req == 1'b1) state_ts <= Flash_Write_Enable; else state_ts <= Flash_Idle; else state_ts <= state_ts; end always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) pp_erase_wait_cnt <= 'd0; else if(state == Flash_Wait) pp_erase_wait_cnt <= pp_erase_wait_cnt + 1'b1; else pp_erase_wait_cnt <= 'd0; end // spi csn always@(posedge sys_clk or negedge sys_rstn )begin if( sys_rstn == 1'b0) spi_csn_reg <= 1'b1; else if( state == Flash_Idle || state == Flash_End || state == Flash_Wait) spi_csn_reg <= 1'b1; else spi_csn_reg <= 1'b0; end //spi read/write byte cnt always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0 ) spi_wr_byte_cnt <= 'd0; else if( state != next_state) spi_wr_byte_cnt <= 'd0; else if( spi_read_ack == 1'b1 || spi_write_ack == 1'b1) spi_wr_byte_cnt <= spi_wr_byte_cnt + 1'b1; else spi_wr_byte_cnt <= spi_wr_byte_cnt; end //spi read always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0 ) spi_read_req <= 1'b0; else if( state == Flash_Read_Identification && spi_wr_byte_cnt > 'd0) if((spi_wr_byte_cnt == `Read_Identification_Bytes - 1'b1) && spi_read_ack == 1'b1) spi_read_req <= 1'b0; else spi_read_req <= 1'b1; else if(state == Flash_Read_Data_Bytes && spi_wr_byte_cnt > 'd3) if((spi_wr_byte_cnt == read_size + 'd1 + 'd3 - 1'b1) && spi_read_ack == 1'b1) spi_read_req <= 1'b0; else spi_read_req <= 1'b1; else spi_read_req <= 1'b0; end //read flash identification always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0) flash_id_reg <= 'd0; else if( state == Flash_Read_Identification && spi_wr_byte_cnt > 'd0) if( spi_read_ack == 1'b1) flash_id_reg <= {flash_id_reg[15:0],spi_read_data}; else flash_id_reg <= flash_id_reg; else flash_id_reg <= flash_id_reg; end //spi write req always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0 ) spi_write_req <= 1'b0; else if( state == Flash_Write_Enable) spi_write_req <= 1'b1; else if( state == Flash_Read_Identification && spi_wr_byte_cnt == 'd0) spi_write_req <= 1'b1; else if( state == Flash_Page_Program) spi_write_req <= 1'b1; else if( state == Flash_Read_Data_Bytes && spi_wr_byte_cnt < 'd4) spi_write_req <= 1'b1; else if( state == Flash_Sector_Erase && spi_wr_byte_cnt < 'd4 ) spi_write_req <= 1'b1; else if( state == Flash_Bulk_Erase ) spi_write_req <= 1'b1; else spi_write_req <= 1'b0; end //spi write data always@(posedge sys_clk or negedge sys_rstn)begin if( sys_rstn == 1'b0 ) spi_write_data <= 8'd0; else if( state == Flash_Write_Enable ) spi_write_data <= `Write_Enable; else if( state == Flash_Read_Identification && spi_wr_byte_cnt == 'd0) spi_write_data <= `Read_Identification; else if( state == Flash_Page_Program) case(spi_wr_byte_cnt) 'd0: spi_write_data <= `Page_Program; 'd1: spi_write_data <= write_page[23:16]; 'd2: spi_write_data <= write_page[15:8]; 'd3: spi_write_data <= write_page[7:0]; default: spi_write_data <= write_data; endcase else if(state == Flash_Read_Data_Bytes) if( spi_wr_byte_cnt == 'd0) spi_write_data <= `Read_Data_Bytes; else if( spi_wr_byte_cnt == 'd1) spi_write_data <= read_addr[23:16]; else if( spi_wr_byte_cnt == 'd2) spi_write_data <= read_addr[15:8]; else spi_write_data <= read_addr[7:0]; else if( state == Flash_Sector_Erase) if( spi_wr_byte_cnt == 'd0) spi_write_data <= `Sector_Erase; else if( spi_wr_byte_cnt == 'd1) spi_write_data <= erase_sector_addr[23:16]; else if( spi_wr_byte_cnt == 'd2) spi_write_data <= erase_sector_addr[15:8]; else spi_write_data <= erase_sector_addr[7:0]; else if( state == Flash_Bulk_Erase) spi_write_data <= `Bulk_Erase; else spi_write_data <= 8'd0; end SPI_Master SPI_Master_hp( //system interface /*input wire sys_clk */ .sys_clk (sys_clk), /*input wire sys_rstn*/ .sys_rstn (sys_rstn), //user inferface //user read /*input wire read_req */ .read_req (spi_read_req), /*output wire[7:0] read_data*/ .read_data (spi_read_data), /* output wire read_ack*/ .read_ack (spi_read_ack), //user write /*input wire write_req */ .write_req (spi_write_req), /*input wire[7:0] write_data*/ .write_data (spi_write_data), /*output wire write_ack */ .write_ack (spi_write_ack), //spi to external flash /*output wire spi_clk */ .spi_clk (spi_clk), /*output wire spi_mosi*/ .spi_mosi (spi_mosi), /*input wire spi_miso*/ .spi_miso (spi_miso) /*output wire spi_csn */ //.spi_csn () ); endmodule
下面给出测试读取ID的值
完整工程 可以 关注 回复 FPGA读写Flash 获取
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。