gaochy1126 发表于 2022-3-31 22:57

FPGA的flash板卡程序擦除与固化

1.擦除程序,程序擦除是可以用软件,但本文主要讨论用代码实现擦除。擦除已经固化好的程序需要对flash芯片(M25P94)的时序进行描述。时序原理如图所示:https://www.pianshen.com/images/514/348da91c65d9e2f2e4015df27bd12032.png    这里主要是对flash的前8个扇区进行擦除,为了产生擦除标志,所以多家了一个wait_3s的标识,8个扇区总共需要24秒。2.固化原理描述,fpga是没有存储程序的空间的。所以需要flash芯片来存储程序,可以用ise软件固化,也可以用verilog代码固化。这里就需要阅读M25P64 flash芯片的手册,主要是对时序的控制。https://www.pianshen.com/images/454/b4d006d0df68a8d88042e537c0157616.png3.通过uart协议发送固化程序,需要在ise软件中生成bin文件,然后通过matlab实现进制转化。最终发送到fpga芯片中。

gaochy1126 发表于 2022-3-31 22:57

/***************************
spi协议控制flash扇区固化
****************************/
module flash_ctrl_wr(
               
                input        wire                        sclk,
                input        wire                        rst_n,
                input        wire                        pi_flag,
                input        wire                data_in,
               
                output        reg                cs_n,
                output        reg                sck,
                output        reg                sdi
);

reg                state;
parameter        idle                =10'b0000_0000_01;
parameter        WAIT1                =10'b0000_0000_10;
parameter        WRITE                =10'b0000_0001_00;
parameter        WAIT2                =10'b0000_0010_00;
parameter        WAIT3                =10'b0000_0100_00;
parameter        WAIT4                =10'b0000_1000_00;
parameter        PP                        =10'b0001_0000_00;
parameter        INIT_ADDR        =10'b0010_0000_00;
parameter        DATA_IN                =10'b0100_0000_00;
parameter        WAIT5                =10'b1000_0000_00;        
reg                sclk_cnt;
parameter        SCLK_CNT=31;
reg                cnt_init_addr;
reg                cnt4;
reg                bit_cnt;
reg                        add_addr_flag;
reg                init_addr;
parameter        INIT_ADDR_Location=6'h00_00_00;
parameter        wr_en=8'h06;
parameter        PP_en=8'h02;


always@(posedge sclk or negedge rst_n)
        if(!rst_n)
                add_addr_flag<=0;
        else if(state==WAIT5&&sclk_cnt==SCLK_CNT)
                add_addr_flag<=1;
        else add_addr_flag<=0;
always@(posedge        sclk or negedge rst_n)       
                if(!rst_n)       
                        init_addr<=INIT_ADDR_Location;
                else if(add_addr_flag==1)
                        init_addr<=init_addr+24'h0000_01;         //字节自动加一,加到255后页自动加一
                //else init_addr<=24'd0;
                                       
always@(posedge        sclk or negedge        rst_n)
                if(!rst_n)
                        cnt4<=2'd0;
                else if(cnt4==3)
                        cnt4<=2'd0;
                else if(state==WRITE||state==PP||state==INIT_ADDR||state==DATA_IN)
                       cnt4<=cnt4+1;
always@(posedge        sclk or negedge        rst_n)
                if(!rst_n)
                        bit_cnt<=3'd0;
                else if(bit_cnt==7&&cnt4==3)
                        bit_cnt<=3'd0;
                else if(cnt4==3)
                                bit_cnt<=bit_cnt+1;
                               
always@(posedge        sclk or negedge rst_n)
                if(!rst_n)
                        cs_n<=1;
                else if(pi_flag==1)
                        cs_n<=0;
                else if(state==WAIT2&&sclk_cnt==SCLK_CNT)
                        cs_n<=1;
                else if(state==WAIT3&&sclk_cnt==SCLK_CNT)
                        cs_n<=0;
                else if(sclk_cnt==SCLK_CNT&&state==WAIT5)
                        cs_n<=1;               
always@(posedge        sclk or negedge rst_n)
                if(!rst_n)       
                        sclk_cnt<=5'd0;
                else if        (sclk_cnt==SCLK_CNT&&state==WAIT5)
                        sclk_cnt<=5'd0;
                else if(sclk_cnt==SCLK_CNT)       
                        sclk_cnt<=5'd0;
                else if(cs_n==0)
                        sclk_cnt<=sclk_cnt+1;
                else if(state==WAIT3)
                        sclk_cnt<=sclk_cnt+1;
always@(posedge        sclk or negedge rst_n)
                if(!rst_n)
                cnt_init_addr<=2'd0;
                else if(cnt_init_addr==2'd2&&sclk_cnt==SCLK_CNT)
                        cnt_init_addr<=2'd0;
                else if(sclk_cnt==SCLK_CNT&&state==INIT_ADDR)
                        cnt_init_addr<=cnt_init_addr+1;
                       
always@(posedge        sclk or negedge rst_n)
                if(!rst_n)
                        state<=idle;
                else case(state)
                                idle:                if(pi_flag==1)
                                                                state<=WAIT1;
                                                        else        state<=idle;
                                WAIT1:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WRITE;
                                                        else        state<=WAIT1;
                                WRITE:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT2;
                                                        else state<=WRITE;
                                WAIT2:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT3;
                                                        else         state<=WAIT2;
                                WAIT3:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT4;
                                                        else        state<=WAIT3;
                                WAIT4:                if(sclk_cnt==SCLK_CNT)
                                                                state<=PP;
                                PP:                        if(sclk_cnt==SCLK_CNT)
                                                                state<=INIT_ADDR;
                                                        else state<=PP;
                                INIT_ADDR:        if(cnt_init_addr==2'd2&&sclk_cnt==SCLK_CNT)
                                                                state<=DATA_IN;
                                                                else state<=INIT_ADDR;
                                DATA_IN:        if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT5;
                                                        else        state<=DATA_IN;
                                WAIT5:                if(sclk_cnt==SCLK_CNT)
                                                                        state<=idle;
                                                        else state<=WAIT5;
                                default:        state<=idle;
                                endcase
                                                               
always@(posedge        sclk or negedge rst_n)        //时钟传递
                if(!rst_n)               
                  sck<=0;
               else if(state==WRITE &&cnt4==1)       
                               sck<=1;
               else if(state==WRITE&&cnt4==3)
                               sck<=0;
               else if (state==PP&&cnt4==1)       
                               sck<=1;
               else if(state==PP&&cnt4==3)
                               sck<=0;
               else if (state==INIT_ADDR&&cnt4==1)       
                               sck<=1;
               else if(state==INIT_ADDR&&cnt4==3)
                               sck<=0;
               else if (state==DATA_IN&&cnt4==1)       
                               sck<=1;
               else if(state==DATA_IN&&cnt4==3)
                               sck<=0;
                              
always@(posedge        sclk or negedge rst_n)       
                if(!rst_n)
                        sdi<=1'b1;
                else if(state==WRITE)       
                        sdi<=wr_en;
                else if(state==PP)       
                        sdi<=PP_en;
                else if(state==INIT_ADDR&&cnt_init_addr==0)
                        sdi<=init_addr;
                else if(state==INIT_ADDR&&cnt_init_addr==1)
                        sdi<=init_addr;
                else if(state==INIT_ADDR&&cnt_init_addr==2)
                        sdi<=init_addr;
                else if(state==DATA_IN)
                       sdi<=data_in;
                else sdi<=1'b1;                                                       
endmodule

gaochy1126 发表于 2022-3-31 22:57

/***************************
spi协议控制flash扇区擦除
****************************/
module se_ctrl(
               
                input        wire        sclk,
                input        wire        rst_n,
                input        wire        pi_se_flag,
               
                output        reg                led,
                output        reg                cs_n,
                output        reg                sck,
                output        reg                sdi
               

);

reg                state;
parameter        idle                =10'b0000_0000_01;
parameter        WAIT1                =10'b0000_0000_10;
parameter        WRITE                =10'b0000_0001_00;
parameter        WAIT2                =10'b0000_0010_00;
parameter        WAIT3                =10'b0000_0100_00;
parameter        WAIT4                =10'b0000_1000_00;
parameter        SE                        =10'b0001_0000_00;
parameter        INIT_ADDR        =10'b0010_0000_00;
parameter        WAIT5                =10'b0100_0000_00;
parameter        WAIT_3S                =10'b1000_0000_00;        
reg                sclk_cnt;
parameter        SCLK_CNT=31;
reg                cnt_init_addr;
reg                cnt_1s;
parameter        ONE_S=49_9999_99;
reg                cnt_3s;
reg                cnt4;
reg                bit_cnt;
reg                cnt_wait_3s;
reg                init_addr;
//parameter        INIT_ADDR_Location=6'h00_00_00;
parameter        wr_en=8'h06;                //信号差了一个时钟周期
parameter        se_en=8'hd8;
parameter        CNT_wait_3s=7;
reg                        cnt_3s_en;

//always@(posedge        sclk or negedge        rst_n)
//                if(!rst_n)
//                        se_flag<=0;
//                else if(pi_se_flag==1)
//                        se_flag<=1;



always@(posedge        sclk or negedge rst_n)        //循环擦除
                if(!rst_n)       
                        cnt_wait_3s<=3'd0;
                else if(cnt_wait_3s==CNT_wait_3s&&cnt_1s==ONE_S&&cnt_3s==2)
                        cnt_wait_3s<=3'd0;
                else if(state==WAIT_3S&&cnt_1s==ONE_S&&cnt_3s==2)
                        cnt_wait_3s<=cnt_wait_3s+1'b1;

always@(posedge        sclk or negedge rst_n)        //扇区地址变换
                if(!rst_n)       
                init_addr<=24'd0;
                else if(state==WAIT_3S&&cnt_1s==ONE_S&&cnt_3s==2)
                        init_addr<=init_addr+24'h01_0000;
                else if(state==idle)
                        init_addr<=24'd0;
                                       
always@(posedge        sclk or negedge        rst_n)                //为输出时钟计数
                if(!rst_n)
                        cnt4<=2'd0;
                else if(cnt4==3)
                        cnt4<=2'd0;
                else if(state==WRITE||state==SE||state==INIT_ADDR)
                       cnt4<=cnt4+1;
always@(posedge        sclk or negedge        rst_n)   //        bit位计数
                if(!rst_n)
                bit_cnt<=3'd0;
                else if(bit_cnt==7&&cnt4==3)
                bit_cnt<=3'd0;
                else if(cnt4==3)
                                bit_cnt<=bit_cnt+1;
                               
always@(posedge        sclk or negedge        rst_n)
                if(!rst_n)
                cnt_1s<=26'd0;
                else if(cnt_1s==ONE_S)
                        cnt_1s<=26'd0;
                else if(cnt_3s_en==1)
                        cnt_1s<=cnt_1s+1;
always@(posedge        sclk or negedge        rst_n)
                if(!rst_n)
                cnt_3s<=2'd0;
                else if(cnt_1s==ONE_S&&cnt_3s==2)
                        cnt_3s<=2'd0;
                else if(cnt_1s==ONE_S)
                        cnt_3s<=cnt_3s+1;
always@(posedge        sclk or negedge rst_n)        //3秒使能信号
                if(!rst_n)       
                cnt_3s_en<=0;
                else if(cnt_1s==ONE_S&&cnt_3s==2)
                        cnt_3s_en<=0;
                else if(state==WAIT_3S)
                        cnt_3s_en<=1;
always@(posedge        sclk or negedge rst_n)
                if(!rst_n)
                        cs_n<=1;
                else if(pi_se_flag==1)
                        cs_n<=0;
                else if(state==idle)
                        cs_n<=1;
                else if(state==WAIT2&&sclk_cnt==SCLK_CNT)                //片选信号没有描述对
                        cs_n<=1;
                else if(state==WAIT3&&sclk_cnt==SCLK_CNT)
                        cs_n<=0;
                else if(state==WAIT5&&sclk_cnt==SCLK_CNT)
                        cs_n<=1;
                else if(state==WAIT_3S&&cnt_1s==ONE_S&&cnt_3s==2)
                        cs_n<=0;
                //else if(cnt_wait_3s==CNT_wait_3s)
                        //cs_n<=1;               

always@(posedge        sclk or negedge rst_n)
                if(!rst_n)       
                        sclk_cnt<=5'd0;
                else if        (sclk_cnt==SCLK_CNT&&cnt_wait_3s==CNT_wait_3s)
                        sclk_cnt<=5'd0;
                else if(sclk_cnt==SCLK_CNT)
                                sclk_cnt<=5'd0;
                else if(cs_n==0)
                        sclk_cnt<=sclk_cnt+1;
                else if(state==WAIT3)
                        sclk_cnt<=sclk_cnt+1;                               
always@(posedge        sclk or negedge rst_n)   //3位状态计数
                if(!rst_n)
                cnt_init_addr<=2'd0;
                else if(cnt_init_addr==2'd2&&sclk_cnt==SCLK_CNT)
                        cnt_init_addr<=2'd0;
                else if(sclk_cnt==SCLK_CNT&&state==INIT_ADDR)
                        cnt_init_addr<=cnt_init_addr+1;
                       
always@(posedge        sclk or negedge rst_n)
                if(!rst_n)
                        state<=idle;
                else case(state)
                                idle:                if(pi_se_flag==1)
                                                                state<=WAIT1;
                                                        else state<=idle;                                                               
                                WAIT1:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WRITE;
                                                        else        state<=WAIT1;
                                WRITE:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT2;
                                                        else state<=WRITE;
                                WAIT2:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT3;
                                                        else         state<=WAIT2;
                                WAIT3:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT4;
                                                        else        state<=WAIT3;
                                WAIT4:                if(sclk_cnt==SCLK_CNT)
                                                                state<=SE;
                                SE:                        if(sclk_cnt==SCLK_CNT)
                                                                state<=INIT_ADDR;
                                                        else state<=SE;
                                INIT_ADDR:        if(cnt_init_addr==2'd2&&sclk_cnt==SCLK_CNT)
                                                                state<=WAIT5;
                                                                else state<=INIT_ADDR;
                                WAIT5:                if(sclk_cnt==SCLK_CNT)
                                                                state<=WAIT_3S;
                                                        else        state<=WAIT5;
                                WAIT_3S:        if(cnt_1s==ONE_S&&cnt_3s==2)
                                                                        state<=WAIT1;
                                                        else if(cnt_wait_3s==CNT_wait_3s)
                                                                        state<=idle;
                                default:        state<=idle;
                                endcase

                                                               
always@(posedge        sclk or negedge rst_n)        //时钟传递
                if(!rst_n)               
                  sck<=0;
               else if(state==WRITE &&cnt4==1)       
                               sck<=1;
               else if(state==WRITE&&cnt4==3)
                               sck<=0;
               else if (state==SE&&cnt4==1)       
                               sck<=1;
               else if(state==SE&&cnt4==3)
                               sck<=0;
               else if (state==INIT_ADDR&&cnt4==1)       
                               sck<=1;
               else if(state==INIT_ADDR&&cnt4==3)
                               sck<=0;
                              
always@(posedge        sclk or negedge rst_n)        //低电平传输数据 上升沿采集数据
                if(!rst_n)
                        sdi<=1'b1;
                else if(state==WRITE)       
                        sdi<=wr_en;
                else if(state==SE)       
                        sdi<=se_en;
                else if(state==INIT_ADDR&&cnt_init_addr==0)
                        sdi<=init_addr;
                else if(state==INIT_ADDR&&cnt_init_addr==1)
                        sdi<=init_addr;
                else if(state==INIT_ADDR&&cnt_init_addr==2)
                        sdi<=init_addr;
                else sdi<=1'b1;                                                        //检查发现有问题

always@(posedge        sclk or negedge        rst_n)
                        if(!rst_n)
                                led<=0;
                else if(cnt_3s_en==1)
                                led<=1;
                else        led<=0;

endmodule

gaochy1126 发表于 2022-3-31 22:58

5.需要说明的是擦除需要一个标志位,可以使用按键产生。
页: [1]
查看完整版本: FPGA的flash板卡程序擦除与固化