N25Q00AA NOR SPIFLASH 的FPGA驱动开发

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

N25Q00AA简介

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

命令集

N25Q00AA NOR SPIFLASH 的FPGA驱动开发_第1张图片
N25Q00AA NOR SPIFLASH 的FPGA驱动开发_第2张图片
本文主要实现了图中红框所示命令,以下所述是在EXTENDED SPI协议下

读写寄存器

-对于任意写操作(写寄存器或者PROGRAM)都需要执行WRITE ENABLE命令.
其时序为:
N25Q00AA NOR SPIFLASH 的FPGA驱动开发_第3张图片
发送8比特命令0x06,之后片选拉高

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

-读寄存器相对写寄存器少了写使能操作,工程中使用了读状态寄存器命令,读标志状态寄存器命令和读扩展地址命令。
READ STATUS REG/READ FLAG STATUS REG/READ EXTENDED ADDRESS REG时序
N25Q00AA NOR SPIFLASH 的FPGA驱动开发_第4张图片

读FLASH

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

写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;
end
else
begin

    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

    endcase

end

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;
end
else
begin
    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;
    end
end

end

endmodule

你可能感兴趣的:(FPGA接口,驱动开发,芯片,存储,FPGA)