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

news2024/9/21 4:36:36

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

  • 问题概述
  • 代码修改—spi_drive.v
  • 遗留问题

问题概述

因为项目需求,需要利用spi对flash进行擦除和写入操作,所使用的开发板是正电原子的达芬奇开发板,我事先往Flash里面存了两个bit,分别对应LED0和LED1的点亮,但是我使用了正点原子的spi_dirve进行全擦除操作之后发现了很奇怪的现象:
1、没擦完,因为明显的看到LED1的灯亮了,说明擦除操作或许有效,但是可能只是破坏了第一个bit,第二个bit没有做修改;
2、时序不对,通过ila抓波形可以发现,全擦除之后的轮询寄存器,竟然只查了一次就自动跳出轮询的状态了,但是全擦除怎么说也不至于这么快吧。
我的flash_contol部分的指令操作顺序如下:

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

//****************************************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的驱动模式决定);

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拉高。
目前可以暂时改成发送两次写使能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1934855.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

笔记 7 :linux 011 注释,函 bread () , get_hash_table () , find_buffer ()

&#xff08;57&#xff09;接着介绍另一个读盘块的函数 bread&#xff08;&#xff09;&#xff1a; &#xff08;58&#xff09;因为 函数 get_blk&#xff08;&#xff09;大量调用了其它函数&#xff0c;一版面列举不完&#xff0c;故对其调用的函数先行注释&#xff1a;ge…

分布式搜索引擎ES-Elasticsearch进阶

1.head与postman基于索引的操作 引入概念&#xff1a; 集群健康&#xff1a; green 所有的主分片和副本分片都正常运行。你的集群是100%可用 yellow 所有的主分片都正常运行&#xff0c;但不是所有的副本分片都正常运行。 red 有主分片没能正常运行。 查询es集群健康状态&…

PyQt5中pyqtgraph鼠标获取坐标

PyQt5中pyqtgraph鼠标获取坐标 1、效果 2、流程 安装库: pip install numpy==1.19.5 pip install PyQt5==5.15.9 pip install pyqtgraph==0.11.11、创建一个ui 2、在ui中添加一个Vertical Layout控件,命名为my_view 3、把ui转成py 4、绑定鼠标移动事件 5、x,y值向下取整 6…

Linux下vim编辑器的使用方法

Vim编辑器 vim kk 使用vim来创建或编辑 kk文件 一般模式下的操作 x 为向后删除一个字符 nx 连续向后删除n个字符 dd 删除光标所在行 ndd 删除光标所在的向下n行 yy 复制光标所在的那一行 nyy 复制光标所在的向下n列 p 将已复制的数据在光标下一行粘贴上 P 则为贴在光标的上一…

vscode 中python 支持自动跳转

随笔记录 目录 1. 背景介绍 2. 解决方案 1. 背景介绍 vscode 远程ssh 打开python 脚本无法自动跳转 2. 解决方案 安装python 插件即可。 至此&#xff0c;已完成vscode 上py 文件支持自动跳转功能

如何获得Cesium的TileSet并设置本地服务器的Url

一.总体思路 首先使用管理者获得TileSet&#xff0c;通过JSON文件读写&#xff0c;调用对应的Cesium内部提供的函数。 UE5中Json文件的读取与解析 - 知乎 (zhihu.com) 不太了解JSON的可以学习这个。 二.具体实现 1.创建Actor,并且 如何获得Cesium的TileSet,设置本地Url 一…

鸿蒙Navigation路由能力汇总

基本使用步骤&#xff1a; 1、新增配置文件router_map&#xff1a; 2、在moudle.json5中添加刚才新增的router_map配置&#xff1a; 3、使用方法&#xff1a; 属性汇总&#xff1a; https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-compone…

Docker安装mysql详细教程, mysqld: Can‘t read dir of ‘/etc/mysql/conf.d/‘(已解决)

文章目录 一、下载MySQL的docker镜像二、启动MySQL容器2.1 命令2.2 报错mysqld: Cant read dir of /etc/mysql/conf.d/ (Errcode: 2 - No such file or directory) 三、进入mysql容器四、修改mysql默认配置4.1 查看mysql挂载的文件夹4.2 mysql配置 五、补充 如果还没在虚拟机/服…

41 QOS技术(服务质量)

1 QOS 产生背景 对于网络业务&#xff0c;影响服务质量的因素包括传输的带宽、传送的时延、数据的丢包率等。网络资源总是有限的&#xff0c;只要存在抢夺网络资源的情况&#xff0c;就会出现服务质量的要求网络总带宽固定的情况下&#xff0c;如果某类业务占用的带宽越多&am…

redis server response timeout(3000ms) occurred after 3 retry attempts异常分析

读取redis数据报超时错误&#xff1a; Redis server response timeout (3000 ms) occured after 3 retry attempts2024-07-18 17:07:57.124 ERROR [e8f07b0a671c08311dff589827897232] [http-nio-9528-exec-6] c.z.i.u.m.c.e.BaspUserExceptionHandler.exceptionHandler:83 - R…

【贪心算法】力扣1481.不同整数的最少数目

给你一个整数数组 arr 和一个整数 k 。现需要从数组中恰好移除 k 个元素&#xff0c;请找出移除后数组中不同整数的最少数目。 示例 1&#xff1a; 输入&#xff1a;arr [5,5,4], k 1 输出&#xff1a;1 解释&#xff1a;移除 1 个 4 &#xff0c;数组中只剩下 5 一种整数。…

studio编译报错java.lang.NullPointerException

安卓studio编译报错&#xff0c;这个是一个新建的项目就报错&#xff0c;原因是 implementation androidx.appcompat:appcompat:1.7.0版本太高&#xff0c;修改后版本 implementation androidx.appcompat:appcompat:1.4.0&#xff0c; 编译又报错 18 issues were found wh…

数学基础【俗说矩阵】:矩阵相乘

矩阵乘法 矩阵乘法推导过程 一、两个线性方程复合代入 二、X1和X2合并同类项 三、复合后方程组结果 四、线性方程组矩阵表示 五、线性方程组矩阵映射表示 复合映射表示 六、矩阵乘法导出 矩阵乘法法则 1、规则一推导过程 左取行&#xff0c;右取列&#xff0c;对应相乘后…

maven内网依赖包编译报错问题的一种解决方法

背景 外网开发时可以连接互联网&#xff0c;所以编译没有什么问题&#xff0c;但是将数据库、代码、maven仓库全部拷贝到内网&#xff0c;搭建内网环境之后&#xff0c;编译失败。 此依赖包的依赖层级图 maven镜像库配置使用拷贝到内网的本地库&#xff0c;配置如下&#xff…

数据结构(Java):优先级队列(堆)堆的模拟实现

目录 1、优先级队列 1.1 概念 1.2 PriorityQueue底层结构 2、 堆 2.1 堆的概念 2.2 堆的存储结构 3、优先级队列&#xff08;堆&#xff09;的模拟实现 3.1 堆的创建 3.1.1 向下调整算法建完整堆 3.2 堆的插入 3.2.1 向上调整算法 3.3 堆的删除 3.4 堆排序 1、优先…

c语言题目之打印单身狗

文章目录 一、题目二、思路三、代码实现 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 二、思路 第一步 首先这里先了解两个有关于位操作符异或的知识点 &#xff0c;异或操作符的规则是相同为0&#xff0c;相异为1 。 通过上面我们可以得…

AIGC前沿 | LivePortrait

0. 资源链接 论文超链接: LivePortrait 项目: https://github.com/KwaiVGI/LivePortrait 1. 背景动机 现有AIGC存在的问题 随着智能手机和其他录制设备的普及&#xff0c;人们越来越频繁地捕捉静态肖像来记录珍贵而美好的时刻&#xff0c;但这些静态图像缺乏动态表现力和实…

docker默认存储地址 var/lib/docker 满了,换个存储地址操作流程

1. 查看docker 存储地址 docker info如下 var/lib/docker2、查看内存大小 按需执行 df -h 找超过100M的大文件 find / -type f -size 100M -exec ls -lh {} \; df -Th /var/lib/docker 查找这个文件的容量 df -h 查找所有挂载点 du -hs /home/syy_temp/*1、df -h 2、sud…

数据结构(单链表算法题)

1.删除链表中等于给定值 val 的所有节点。 OJ链接 typedef struct ListNode ListNode;struct ListNode {int val;struct ListNode* next; };struct ListNode* removeElements(struct ListNode* head, int val) {//创建新链表ListNode* newhead, *newtail;newhead newtail N…

视频联网共享平台LntonCVS视频监控汇聚平台视频云解决方案

LntonCVS流媒体平台是一款遵循国家GB28181标准协议的先进视频监控与云服务平台。该平台设计独特&#xff0c;能够同时接入并处理多路设备的视频流&#xff0c;支持包括RTSP、RTMP、FLV、HLS、WebRTC在内的多种视频流格式的分发。其功能丰富多样&#xff0c;涵盖了视频直播监控、…