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

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;


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[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;

//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[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;							//检查发现有问题

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

endmodule

5.需要说明的是擦除需要一个标志位,可以使用按键产生。

猜你喜欢

转载自blog.csdn.net/Headogerz/article/details/82251175
今日推荐