转至:https://blog.csdn.net/headogerz/article/details/82251175
1.擦除程序,程序擦除是可以用软件,但本文主要讨论用代码实现擦除。擦除已经固化好的程序需要对flash芯片(M25P94)的时序进行描述。时序原理如图所示:
这里主要是对flash的前8个扇区进行擦除,为了产生擦除标志,所以多家了一个wait_3s的标识,8个扇区总共需要24秒。
2.固化原理描述,fpga是没有存储程序的空间的。所以需要flash芯片来存储程序,可以用ise软件固化,也可以用verilog代码固化。这里就需要阅读M25P64 flash芯片的手册,主要是对时序的控制。
3.通过uart协议发送固化程序,需要在ise软件中生成bin文件,然后通过matlab实现进制转化。最终发送到fpga芯片中。
4.擦除与固化的代码为:
/***************************
spi协议控制flash扇区固化
****************************/
module flash_ctrl_wr(
input wire sclk,
input wire rst_n,
input wire pi_flag,
input wire [7:0] data_in,
output reg cs_n,
output reg sck,
output reg sdi
);
reg [9:0] 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 [4:0] sclk_cnt;
parameter SCLK_CNT=31;
reg [1:0] cnt_init_addr;
reg [1:0] cnt4;
reg [2:0] bit_cnt;
reg add_addr_flag;
reg [23:0] init_addr;
parameter INIT_ADDR_Location=6'h00_00_00;
parameter wr_en=8'h06;
parameter PP_en=8'h02;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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
[email protected](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;
[email protected](posedge sclk or negedge rst_n)
if(!rst_n)
sdi<=1'b1;
else if(state==WRITE)
sdi<=wr_en[7-bit_cnt];
else if(state==PP)
sdi<=PP_en[7-bit_cnt];
else if(state==INIT_ADDR&&cnt_init_addr==0)
sdi<=init_addr[23-bit_cnt];
else if(state==INIT_ADDR&&cnt_init_addr==1)
sdi<=init_addr[15-bit_cnt];
else if(state==INIT_ADDR&&cnt_init_addr==2)
sdi<=init_addr[7-bit_cnt];
else if(state==DATA_IN)
sdi<=data_in[7-bit_cnt];
else sdi<=1'b1;
endmodule
/***************************
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 [9:0] 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 [4:0] sclk_cnt;
parameter SCLK_CNT=31;
reg [1:0] cnt_init_addr;
reg [25:0] cnt_1s;
parameter ONE_S=49_9999_99;
reg [1:0] cnt_3s;
reg [1:0] cnt4;
reg [2:0] bit_cnt;
reg [3:0] cnt_wait_3s;
reg [23:0] 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;
//[email protected](posedge sclk or negedge rst_n)
// if(!rst_n)
// se_flag<=0;
// else if(pi_se_flag==1)
// se_flag<=1;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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;
[email protected](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
[email protected](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;
[email protected](posedge sclk or negedge rst_n) //低电平传输数据 上升沿采集数据
if(!rst_n)
sdi<=1'b1;
else if(state==WRITE)
sdi<=wr_en[7-bit_cnt];
else if(state==SE)
sdi<=se_en[7-bit_cnt];
else if(state==INIT_ADDR&&cnt_init_addr==0)
sdi<=init_addr[23-bit_cnt];
else if(state==INIT_ADDR&&cnt_init_addr==1)
sdi<=init_addr[15-bit_cnt];
else if(state==INIT_ADDR&&cnt_init_addr==2)
sdi<=init_addr[7-bit_cnt];
else sdi<=1'b1; //检查发现有问题
[email protected](posedge sclk or negedge rst_n)
if(!rst_n)
led<=0;
else if(cnt_3s_en==1)
led<=1;
else led<=0;
endmodule
5.需要说明的是擦除需要一个标志位,可以使用按键产生。