verilog bug记录——正点原子spi_drive存在的问题

verilog bug记录------正点原子spi_drive存在的问题

问题概述

因为项目需求,需要利用spi对flash进行擦除和写入操作,所使用的开发板是正电原子的达芬奇开发板,我事先往Flash里面存了两个bit,分别对应LED0和LED1的点亮,但是我使用了正点原子的spi_dirve进行全擦除操作之后发现了很奇怪的现象:

1、没擦完,因为明显的看到LED1的灯亮了,说明擦除操作或许有效,但是可能只是破坏了第一个bit,第二个bit没有做修改;

2、时序不对,通过ila抓波形可以发现,全擦除之后的轮询寄存器,竟然只查了一次就自动跳出轮询的状态了,但是全擦除怎么说也不至于这么快吧。

我的flash_contol部分的指令操作顺序如下:

c 复制代码
always @(*)begin
	case(cmd_cnt)
		0 : spi_cmd = WEL_CMD		;			//写使能
        1 : spi_cmd = R_STA_REG_CMD	;			//轮询
		2 : spi_cmd = WEL_CMD		;			//写使能
		3 : spi_cmd = R_STA_REG_CMD	;			//轮询
		4 : spi_cmd = BE_CMD		;			//全擦除
		5 : spi_cmd = R_STA_REG_CMD		;	    //轮询
		6 : spi_cmd = WEL_CMD	;			//轮询
		7 : spi_cmd = R_STA_REG_CMD		;			//读数据
	default:;
	endcase
end

我只执行了0~5步,另外原代码中指令运行是一上电就会自动运行,但是我改成了只有我按键按下的时候才会执行。

出问题的时序如下:

从图中黄线部分可以看到,CS信号在spi_clk信号立即拉高,但是我们看数据手册可以发现

在spi_clk停止输出的时候,CS信号至少要间隔4ns才拉高,虽然说实际上的时钟信号并不是理想的马上拉高,而是有一段过渡时间,但是这个过渡时间并不好把控,所以稳妥起见还是应该至少打一拍,因为时钟频率是100MHz,那么延迟未0.01us,即10ns,是满足时序要求的;

另外还有问题,看下图:

红圈标注的位置,从图中可以看出,我第一次发送写使能命令后进行轮询,会发现状态寄存器的第6位WEL并没有拉高,而是第二次发送写使能命令的时候才拉高。

根据数据手册上的要求,发送完写使能命令后,WEL位是应该拉高为高电平的

最后一个问题如下图所示:

该时序图是我我发送完全擦除指令随即发送轮询寄存器指令(读状态寄存器指令),会发现蓝线部分表示WEL位,红线部分表示WIP位,此时WIP位应该是高电平,轮询寄存器应该继续轮询才对,直到WIP为0表示擦除操作已完成,但是原代码中却是直接拉高,这就不合理。

代码修改---spi_drive.v

c 复制代码
//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           spi_drive
// Last modified Date:  2020/12/01 10:39:20
// Last Version:        V1.0
// Descriptions:        FLASH读写实验
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2020/12/01 10:39:20
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module spi_drive(

	input             clk_100m      ,
	input             sys_rst_n     ,
	
	//user interface
	input             spi_start     ,//spi开启使能。
	input [7:0 ]      spi_cmd       ,//FLAH操作指令
	input [23:0]      spi_addr      ,//FLASH地址
	input [7:0 ]      spi_data      ,//FLASH写入的数据
	input [3:0 ]      cmd_cnt       ,//指令计数器
	
	output            idel_flag_p   ,//空闲状态标志的上升沿 
	output reg        w_data_req    ,//FLASH写数据请求 
	output reg        error_flag     ,//读出的数据错误标志
	
	//spi interface
	output reg        spi_cs        ,//SPI从机的片选信号,低电平有效。
	output reg        spi_clk       ,//主从机之间的数据同步时钟。
	output reg        spi_mosi      ,//数据引脚,主机输出,从机输入。
	input             spi_miso       //数据引脚,主机输入,从机输出。

);

//define parameter
//状态机
parameter IDLE          = 4'd0;		//空闲状态
parameter WR_EN         = 4'd1;		//写使能状态
parameter S_ERA         = 4'd2;		//扇区擦除状态
parameter B_ERA         = 4'd3;		//全局擦除
parameter READ          = 4'd4;		//读状态
parameter WRITE         = 4'd5;		//写状态
parameter R_STA_REG     = 4'd6;		//读状态寄存器状态
//指令集
parameter WEL_CMD       = 8'h06;	//写使能指令
parameter SE_CMD        = 8'hd8;	//扇区擦除指令
parameter BE_CMD        = 8'hc7;	//全擦除指令
parameter READ_CMD      = 8'h03;	//读指令
parameter WRITE_CMD     = 8'h02;	//写指令
parameter R_STA_REG_CMD = 8'h05;	//读状态寄存器指令

//wire define
wire      idel_flag;

//reg define
reg		      		idel_flag_d0   ;		
reg		      		idel_flag_d1   ;	
reg		      		spi_clk_d0     ;
reg		[3:0] 		current_state  ;		
reg		[3:0] 		next_state     ;		
reg		[7:0 ]		data_reg	   ;		//数据寄存
reg		[7:0 ]		cmd_reg        ;		//指令寄存
reg		[23:0]		addr_reg       ;		//地址寄存器
reg		[31:0]		bit_cnt        ;		//bit计数器
reg		      		clk_cnt        ;		//时钟计数器
reg		      		delay_cnt      ;		//延迟计数器
reg		[15:0]		delay_state_cnt ;		//状态延迟计数器
reg		[7:0 ]		rd_data_reg    ;		//读数据寄存器	
reg		      		stdone         ;		//状态完成标志
reg		[7:0 ]		data_check     ;		//数据校验

reg     [2047:0]    r_w_data       ;
reg                 r_w_data_req   ;
reg     [2047:0]    r_r_data       ;//FLASH读出的数据

reg                 r_wip_flag          ;
reg     [7 :0  ]    r_rd_status_reg;
reg                 r_wel          ;
//*****************************************************
//**                    main code
//*****************************************************

assign idel_flag = (current_state == IDLE) ? 1:0;		//空闲状态标志
assign idel_flag_p = idel_flag_d0 && (~idel_flag_d1);	//空闲状态标志的上升沿

//idel_flga打拍取沿
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)begin
		idel_flag_d0 <= 1'b1;
		idel_flag_d1 <= 1'b1;
	end
	else begin
		idel_flag_d0 <= idel_flag;
		idel_flag_d1 <= idel_flag_d0;
	end
end

//写数据请求信号
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		w_data_req <= 1'b0;
	else if(current_state == WRITE && (bit_cnt+2)%8 == 0 && bit_cnt >= 30 && clk_cnt == 0)
		w_data_req <= 1'b1;
	else
		w_data_req <= 1'b0;
end

always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
        r_w_data_req <= 'd0;
    else
        r_w_data_req <= w_data_req;
end

always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
        r_w_data <= 'd0;
    else if(r_w_data_req)
        r_w_data <= {r_w_data[2039:0],spi_data};
end

//读出的数据移位寄存
always @(posedge clk_100m or negedge sys_rst_n )begin	
	if(!sys_rst_n)
		rd_data_reg <= 8'd0;
	else if(current_state == READ && bit_cnt >= 32 && bit_cnt <= 2080 && clk_cnt == 0)									
		rd_data_reg <= {rd_data_reg[6:0],spi_miso};
	else
		rd_data_reg <= rd_data_reg;
end

// //检查读出的数据是否正确
// always @(posedge clk_100m or negedge sys_rst_n )begin
// 	if(!sys_rst_n)
// 		data_check <= 8'd0;
// 	else if(current_state == READ && bit_cnt%8 == 0 && bit_cnt >= 40 && clk_cnt == 1)
// 		data_check <= data_check + 1'd1;
// 	else
// 		data_check <= data_check;
// end

//读出的数据
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		r_r_data <= 2048'd0;
	else if(current_state == READ && bit_cnt%8 == 0 && bit_cnt >38 && clk_cnt==1)
		r_r_data <= {r_r_data[2039:0],rd_data_reg};
	else
		r_r_data <= r_r_data;
end

//读出的数据错误标志
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		error_flag<=1'd0;
	else if(current_state == READ && cmd_cnt == 6 && idel_flag_p)begin
		if(r_r_data!=r_w_data)
			error_flag <= 1'd1;
		else
			error_flag <= error_flag;
		end
	else
		error_flag <= error_flag;
end
	
//数据寄存器	
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		data_reg <= 8'd0;
	else if((bit_cnt + 1'd1)%8 == 0 && bit_cnt > 30 && clk_cnt == 1)
		data_reg <= spi_data;
	else if(current_state == WRITE && clk_cnt == 1 && bit_cnt >= 32)
		data_reg <= {data_reg[6:0],data_reg[7]};
	else
		data_reg <= data_reg;
end

//指令寄存器
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		cmd_reg <= 8'd0;
	else if(spi_cs == 0 && delay_cnt == 0)
		cmd_reg <= spi_cmd;
	else if((clk_cnt == 1) && (current_state == WR_EN || current_state == S_ERA
		|| current_state == B_ERA || current_state == READ || current_state == WRITE 
		|| current_state == R_STA_REG) && (bit_cnt < 8))
		cmd_reg <= {cmd_reg[6:0],1'b1};
	else
		cmd_reg <= cmd_reg;
end

//地址寄存器
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		addr_reg <= 8'd0;
	else if(spi_cs == 0 && delay_cnt == 0)
		addr_reg <= spi_addr;
	else if(clk_cnt==1 && (current_state == READ || current_state == WRITE) && bit_cnt >= 8 && bit_cnt < 32)
		addr_reg <= {addr_reg[22:0],addr_reg[23]};
	else
		addr_reg <= addr_reg;
end

//时钟计数器
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		clk_cnt <= 1'd0;
	else if(delay_cnt==1)
		clk_cnt <= clk_cnt+1'd1;
	else 
		clk_cnt <= 1'd0;
end	

//延迟标志
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		delay_cnt <= 1'd0;
	else if(spi_cs == 0)begin
	    if(delay_cnt < 1)
			delay_cnt <= delay_cnt + 1'd1;
		else
			delay_cnt <= delay_cnt;
	end
	else
		delay_cnt <= 1'd0;
end
		
		
//状态延迟计数器
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		delay_state_cnt <= 1'd0;
    else if(spi_start)
        delay_state_cnt <= 1'd0;
	else if(spi_cs)begin
	    if(delay_state_cnt < 20)
			delay_state_cnt <= delay_state_cnt + 1'd1;
		else
			delay_state_cnt <= delay_state_cnt;
	end
	else
		delay_state_cnt <= 1'd0;
end

//bit计数器
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		bit_cnt <= 16'd0;
	else if(delay_cnt == 1)begin
		if(clk_cnt == 1'b1)
			bit_cnt <= bit_cnt+1'd1;
		else
			bit_cnt <= bit_cnt;
	end
	else
		bit_cnt <= 16'd0;
end

// RDSR状态寄存器寄存
always @(posedge clk_100m or negedge sys_rst_n )begin	
	if(!sys_rst_n)
		r_rd_status_reg <= 8'd0;
	else if(current_state == R_STA_REG && bit_cnt >= 8 && clk_cnt == 1)
		r_rd_status_reg <= {r_rd_status_reg[6:0],spi_miso};
	else
		r_rd_status_reg <= r_rd_status_reg;
end
		
//三段式状态机
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n)
		current_state <= IDLE;
	else
		current_state <= next_state;
end

always @(*)begin
	case(current_state)
	   IDLE: begin
	          if(spi_start && spi_cmd == WEL_CMD)
				next_state = WR_EN;
			  else if(spi_start && spi_cmd == BE_CMD)
				next_state = B_ERA;
			  else if(spi_start && spi_cmd == SE_CMD)
				next_state = S_ERA;
			  else if(spi_start && spi_cmd == READ_CMD)
				next_state = READ;
			  else if(spi_start && spi_cmd == WRITE_CMD)
				next_state = WRITE;
			  else if(spi_start && spi_cmd == R_STA_REG_CMD)
				next_state = R_STA_REG;
			  else
	            next_state = IDLE;
			end
	
		WR_EN: begin
			  if(stdone && bit_cnt >= 8)
				   next_state = IDLE;
			  else
		           next_state = WR_EN;
			  end
			 
		S_ERA: begin
				if(stdone)
					next_state = IDLE;
				else
					next_state = S_ERA;
				end
		B_ERA: begin		
				if(stdone)
					next_state = IDLE;
				else
					next_state = B_ERA;
				end
		READ: begin 		
				if(stdone && bit_cnt >= 8)
					next_state = IDLE;
				else
					next_state = READ;
				end
		WRITE: begin		
				 if(stdone && bit_cnt >= 8)
					next_state = IDLE;
				else
					next_state = WRITE;
				end
		R_STA_REG: begin		
				 if(stdone)
					next_state = IDLE;
				else
					next_state = R_STA_REG;
				end
		
	default: next_state = IDLE;			
	endcase				
end
									
always @(posedge clk_100m or negedge sys_rst_n )begin
	if(!sys_rst_n) begin
		spi_cs <= 1'b1;
		spi_clk <= 1'b0;
		spi_clk_d0 <= 1'b0;
		spi_mosi <= 1'b0;	
		stdone <= 1'b0;		
	end
	else begin
		case(current_state)
			IDLE: begin
				stdone <= 1'b0;
				spi_cs <= 1'b1;
				spi_clk <= 1'b0;
				spi_mosi <= 1'b0;	
                r_wip_flag <= 1'b0;	
                spi_clk_d0 <= 'd0;
			end
			
			WR_EN: begin
			     stdone <= 1'b0;
				 	if(delay_state_cnt == 10)  
						spi_cs <= 1'b0;
					else if(delay_cnt == 1 && bit_cnt < 8) begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					else if(bit_cnt == 8 && clk_cnt == 0)begin
					    stdone <= 1'b1;
						spi_clk <= 1'b0;						
						spi_mosi <= 1'b0;						
					end
					else if(bit_cnt == 8 && clk_cnt == 1)begin
						spi_cs <= 1'b1;						
				 end
				 end
			B_ERA: begin
					stdone <= 1'b0;
			         if(delay_state_cnt == 10)                
						spi_cs <= 1'b0;
					 else if(delay_cnt == 1 && bit_cnt < 8) begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					 else if(bit_cnt == 8 && clk_cnt == 0)begin
					    stdone <= 1'b1;				    
						spi_clk <= 1'b0;
						spi_mosi <= 1'b0;	
					 end
					  else if(bit_cnt == 8 && clk_cnt == 1)begin
						spi_cs <= 1'b1;						
				 end
				 end
			S_ERA: begin
			       stdone <= 1'b0;				 
					if(delay_state_cnt == 10)                
						spi_cs <= 1'b0;
					 else if(delay_cnt == 1 && bit_cnt < 8) begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					 else if(bit_cnt >= 8&& bit_cnt < 32 && spi_cs == 0)begin
					    spi_cs <= 1'b0;
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= addr_reg[23];
					 end
					 else if(bit_cnt == 32 && clk_cnt == 0) begin
						spi_cs <= 1'b1;
						spi_clk <= 1'b0;
						spi_mosi <= 1'b0;
						stdone <= 1'b1;
					 end
				 end
            READ: begin
			      stdone <= 1'b0;
				  if(delay_state_cnt == 10)                
						spi_cs <= 1'b0;
					else if(delay_cnt == 1 && bit_cnt < 8) begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					 else if(bit_cnt >= 8 && bit_cnt < 32 && spi_cs == 0)begin					    
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= addr_reg[23];
					 end
					 else if(bit_cnt >= 32 && bit_cnt < 2080)begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= 1'b0;						
					 end
					 else if(bit_cnt == 2080 && clk_cnt == 0) begin						
						spi_clk <= 1'b0;
						spi_mosi <= 1'b0;
						stdone <= 1'b1;						
					 end
					  else if(bit_cnt == 2080 && clk_cnt == 1) begin
						spi_cs<=1'b1;
					 end
				 end
            WRITE: begin
			     stdone<=1'b0;
				  if(delay_state_cnt == 10)                
						spi_cs <= 1'b0;
					 else if(delay_cnt == 1 && bit_cnt < 8) begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					 else if(bit_cnt >= 8 && bit_cnt < 32 && spi_cs == 0)begin					   
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= addr_reg[23];
					 end
					 else if(bit_cnt >= 32 && bit_cnt < 2080)begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= data_reg[7];
					 end
					 else if(bit_cnt == 2080 && clk_cnt == 0) begin
						spi_clk <= 1'b0;
						spi_mosi <= 1'b0;
						stdone <= 1'b1;
					 end
					  else if(bit_cnt == 2080 && clk_cnt == 1) begin
						spi_cs <= 1'b1;
					 end
                end
			R_STA_REG:begin				              
					stdone <= 1'b0;
                    if(delay_state_cnt == 10)                
						spi_cs <= 1'b0;
					else if(delay_cnt == 1 && bit_cnt < 8)begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					else if(bit_cnt == 8)begin					   				    
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= 1'b0;						
					end           
					else if(~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 0)begin
                        r_wip_flag <= 1'b1;
                        spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
                    end
                    else if(r_wip_flag && ~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 1)begin
                        spi_clk <= 1'b0;
						spi_cs <= 1'b1;
						stdone <= 1'b1;
                    end
					else if(~spi_cs && delay_cnt == 1)begin
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
				end	   			         	 
			  end 
             default: begin
			            stdone <= 1'b0;
                        spi_cs <= 1'b1;
				        spi_clk <= 1'b0;
						spi_clk_d0 <= 1'b0;
				        spi_mosi <= 1'b0;				        
			end
         endcase
	end
end

ila_spi u_ila_spi (
	.clk(clk_100m), // input wire clk


	.probe0(spi_start), // input wire [0:0]  probe0  
	.probe1(spi_cmd  ), // input wire [7:0]  probe1 
	.probe2(spi_addr ), // input wire [23:0]  probe2 
	.probe3(spi_data ), // input wire [7:0]  probe3 
	.probe4(cmd_cnt  ), // input wire [3:0]  probe4 
	.probe5(idel_flag_p), // input wire [0:0]  probe5 
	.probe6(w_data_req ), // input wire [0:0]  probe6 
	.probe7(error_flag ), // input wire [0:0]  probe7 
	.probe8(spi_cs  ), // input wire [0:0]  probe8 
	.probe9(spi_clk ), // input wire [0:0]  probe9 
	.probe10(spi_mosi), // input wire [0:0]  probe10 
	.probe11(spi_miso), // input wire [0:0]  probe11
    .probe12(idel_flag), // input wire [0:0]  probe12 
	.probe13(idel_flag_d0), // input wire [0:0]  probe13 
	.probe14(idel_flag_d1), // input wire [0:0]  probe14 
	.probe15(spi_clk_d0  ), // input wire [0:0]  probe15 
	.probe16(current_state  ), // input wire [3:0]  probe16 
	.probe17(next_state     ), // input wire [3:0]  probe17 
	.probe18(data_reg	   ), // input wire [7:0]  probe18 
	.probe19(cmd_reg        ), // input wire [7:0]  probe19 
	.probe20(addr_reg       ), // input wire [23:0]  probe20 
	.probe21(bit_cnt        ), // input wire [31:0]  probe21 
	.probe22(clk_cnt        ), // input wire [0:0]  probe22 
	.probe23(delay_cnt      ), // input wire [0:0]  probe23 
	.probe24(delay_state_cnt), // input wire [15:0]  probe24 
	.probe25(rd_data_reg    ), // input wire [7:0]  probe25 
	.probe26(stdone         ), // input wire [0:0]  probe26 
	.probe27(data_check     ), // input wire [7:0]  probe27 
	.probe28(r_w_data_req), // input wire [0:0]  probe28
    .probe29(r_wip_flag)
);

endmodule

修改后的代码核心在于判断轮询寄存器那里,以及spi_clk_d0每次在idle状态的时候都要清零,清零这个步骤是在为了确保每次新的指令来时,时钟状态都能从0开始(由SPI的驱动模式决定);

c 复制代码
R_STA_REG:begin				              
					stdone <= 1'b0;
                    if(delay_state_cnt == 10)                
						spi_cs <= 1'b0;
					else if(delay_cnt == 1 && bit_cnt < 8)begin						
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= cmd_reg[7];
						end
					else if(bit_cnt == 8)begin					   				    
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
						spi_mosi <= 1'b0;						
					end           
					else if(~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 0)begin
                        r_wip_flag <= 1'b1;
                        spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
                    end
                    else if(r_wip_flag && ~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 1)begin
                        spi_clk <= 1'b0;
						spi_cs <= 1'b1;
						stdone <= 1'b1;
                    end
					else if(~spi_cs && delay_cnt == 1)begin
						spi_clk_d0 <= ~spi_clk_d0;
						spi_clk <= spi_clk_d0;
				end	   			         	 
			  end 

主要修改的就是这里,思路是:

我会首先判断WIP位是否为0,如果为0,则把r_wip_flag标志位拉高,等到下一次轮询状态寄存器的时候就可以跳出当前轮询寄存器的状态。

修改后的时序如下:

可以看到擦除命令执行完之后,还需要等待一段时间后才会完成擦除,擦除后的时序为:

即回到初始状态。

遗留问题

其实从上面波形中可以看到,仍然是第二次发送写指令的时候,WEL位才会拉高,目前猜测是flash本身的问题,之后的思路可以改成直到WEL位拉高后才执行之后的擦除或者写命令,否则就会一直发送写使能指令,直到WEL拉高。

目前可以暂时改成发送两次写使能

相关推荐
fei_sun10 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto10 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安15 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈15 小时前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun16 小时前
【Verilog】第二章作业
fpga开发·verilog
碎碎思17 小时前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望19 小时前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇20 小时前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核
CWNULT20 小时前
AMD(Xilinx) FPGA配置Flash大小选择
fpga开发
碎碎思1 天前
很能体现FPGA硬件思维的一道面试题
fpga开发