N25Q00AA NOR SPIFLASH 的FPGA驱动开发

来源:互联网 发布:布尔教育java怎么样 编辑:程序博客网 时间:2024/06/14 16:45

    • N25Q00AA简介
    • 命令集
    • 读写寄存器
    • 读FLASH
    • 写FLASHPAGE PROGRAM
    • 擦除DIE 擦除
    • 附录一 SPI通信模块


N25Q00AA简介

该芯片是Micron公司的Serial NOR FLASH,主存储区为1Gbits,分为4个256Mb的die,基于SPI协议通信。支持3-byte和4-byte地址。支持4KB\64KB\32MB擦除。

命令集

这里写图片描述
这里写图片描述
本文主要实现了图中红框所示命令,以下所述是在EXTENDED SPI协议下

读写寄存器

-对于任意写操作(写寄存器或者PROGRAM)都需要执行WRITE ENABLE命令.
其时序为:
这里写图片描述
发送8比特命令0x06,之后片选拉高

-工程中使用Write extended address register命令
其时序为:
这里写图片描述
发送16比特,其中前8比特为命令0xC5,后8比特为扩展地址

-读寄存器相对写寄存器少了写使能操作,工程中使用了读状态寄存器命令,读标志状态寄存器命令和读扩展地址命令。
READ STATUS REG/READ FLAG STATUS REG/READ EXTENDED ADDRESS REG时序
这里写图片描述

读FLASH

-使用了3-byte寻址模式,根据该芯片的主存区划分,3-byte地址只能访问128Mb数据量,但是该芯片支持一次READ操作读取1个die(即256Mb数据量),需要配置extended address register来访问其他3个die的存储空间。也就是说读取完该芯片所有容量1Gb至少需要4次读操作。
READ操作时序
这里写图片描述

写FLASH(PAGE PROGRAM)

-擦除之后,存储区数据为1,也就是说写操作将1变成0.每一次写操作最多能够写256byte(one page),同时注意写之前需确认该区域已经擦除。
PROGRAM MEMORY时序
这里写图片描述

擦除(DIE 擦除)

-工程中需要一次性将整块颗粒擦除完,所以使用die擦除方式。
-擦除与read类似,如果要擦除整片,在3-byte寻址模式下,需要修改扩展地址。
-整片擦除操作步骤
-a)写使能
-b)写扩展地址addr_extend=0x00
-c)die erase命令0xC4
-d)轮询读取状态寄存器,直至bit0为0
-e)读取FLAG STATUS寄存器,同时判断是否擦除完整块芯片,如果没有:判断bit7若为1则跳转b)更改addr_extend+=2,否则跳转c);如果擦除完,擦除成功,退出擦除状态

附录一 SPI通信模块

module spi_flash_config
(
input rst_n,
input sys_clk,

input [31:0] send_data,input        send_trig, input [15:0] conf_data,output reg[15:0] rece_data,output reg       rece_data_valid,output reg       send_done,output       spi_sclk_o  ,output       spi_ncs_o   ,output       spi_mosi_o  ,input        spi_miso_i  

);

reg [2:0] spi_state;
parameter s_IDLE = 3’d0,
s_NCS = 3’d1,
s_CMD = 3’d2,
s_RECE_DATA = 3’d3,
s_DELAY = 3’d4,
s_END = 3’d5;

reg [7:0] cnt_delay;

reg [7:0] cnt_send ;
reg [7:0] cnt_sclk ;
reg[31:0] send_buff;

wire rece_en ;
reg [7:0] cnt_rece ;
reg [15:0] rece_buff;

reg spi_ncs ;
wire spi_mosi ;
wire spi_sclk ;

assign spi_sclk_o = spi_sclk;
assign spi_ncs_o = spi_ncs;
assign spi_mosi_o = spi_mosi;

//generate spi_ncs ,spi_sclk,spi_mosi
always@(posedge sys_clk)
begin
if(rst_n == 1’b0)
begin
spi_state <= 3’d0;
cnt_delay <= 8’h0;

    cnt_send        <= 8'h0;    cnt_rece            <= 8'h0;    cnt_sclk            <= 'h0;    send_buff      <= 32'h0;            spi_ncs         <= 1'b1;            send_done       <= 1'b0;endelsebegin    case(spi_state)    s_IDLE:        begin            if(send_trig)            begin                cnt_send  <= conf_data[7:0];                cnt_rece  <= conf_data[15:8];                send_buff <= send_data;                spi_state <= s_NCS;             end            else            begin                send_buff <= 32'h0;                spi_state <= s_IDLE;            end            spi_ncs <= 1'b1;            cnt_delay<= 8'd2;            send_done<= 1'b0;        end    s_NCS://1        begin            spi_ncs  <= 1'b0;            if(cnt_delay == 8'd0)                spi_state <= s_CMD;            else                cnt_delay <= cnt_delay - 1'b1;        end    s_CMD://2        begin            send_buff <= {send_buff[30:0],1'b0};            if(cnt_send == 0)            begin                if(cnt_rece == 'h0)                    spi_state <= s_DELAY;                else                    spi_state <= s_RECE_DATA;                cnt_sclk <= 'h0;            end            else                cnt_send <= cnt_send - 1'b1;        end    s_RECE_DATA://3        begin            cnt_delay<= 8'd2;            if(cnt_sclk == cnt_rece)            begin                cnt_sclk <= 'h0;                spi_state <= s_DELAY;            end            else                cnt_sclk <= cnt_sclk + 1'b1;        end    s_DELAY://4        begin            if(cnt_delay == 8'd0)            begin                send_done <= 1'b1;                spi_state <= s_END;                spi_ncs  <= 1'b1;            end            else                cnt_delay <= cnt_delay - 1'b1;        end    s_END://5        begin            send_done       <= 1'b0;            spi_state       <= s_IDLE;            spi_ncs         <= 1'b1;        end    default:        begin            send_done       <= 1'b0;            spi_state      <= s_IDLE;            spi_ncs         <= 1'b1;        end    endcaseend

end
assign spi_mosi = send_buff[31];
assign spi_sclk = ((spi_state == s_CMD) || (spi_state == s_RECE_DATA)) && (~sys_clk);

assign rece_en = (spi_state == s_RECE_DATA);
//receive data
initial begin rece_buff = ‘h0;end
always@(posedge spi_sclk or posedge send_trig)
begin
if(send_trig)
rece_buff <= ‘h0;
else
if(rece_en)
rece_buff <= {rece_buff[14:0],spi_miso_i};
else;
end
reg rece_en_r;
reg rece_en_rr;
reg rece_en_falling;

always@(posedge sys_clk)
begin
if(rst_n == 1’b0)
begin
rece_data <= ‘h0;
rece_data_valid <= 1’b0;

    rece_en_r        <= 1'b0;    rece_en_rr       <= 1'b0;    rece_en_falling <= 1'b0;endelsebegin    rece_en_r        <= rece_en;    rece_en_rr       <= rece_en_r;    rece_en_falling <= rece_en_rr &&(~rece_en_r);    if(rece_en_rr &&(~rece_en_r))    begin        rece_data <= rece_buff;        rece_data_valid <= 1'b1;    end    else    begin        rece_data <= rece_data;        rece_data_valid <= 1'b0;    endend

end

endmodule