Efinity写Flash实验疑问(附代码)

 有个疑问,代码哪里写错了,为什么在0到2状态以及0到4状态时,cs会被拉低一小段

 注(平台是国产的efinity,该代码需要在interface的GPIO中添加flash的四根线以及系统时钟clk,还需添加一个锁相环输出clk54m+rst)

该代码可以正确执行写数据功能,状态从写使能到读寄存器到写使能到写数据到读寄存器,注意状态转换之中会插入一个空闲状态IDLE

`timescale 1ms / 10ns
module flash_wr(
       input       clk,     ///54M
	   output reg  spi_clk ,///27M
	   output reg  spi_cs  ,
	   output reg  spi_mosi,
       input       spi_miso,
       input       clk_54m  , 
	   input       rst_n          
);      

//状态机
parameter IDLE         =4'd0;//空闲状态
parameter WEL          =4'd1;//写使能状态///cmd_cnt=3 spicmd=1
parameter C_ERA        =4'd2;//全局擦除
parameter READ         =4'd3;//读数据状态///cmd_cnt=6
parameter WRITE        =4'd4;//写状态
parameter S_ERA        =4'd6;//全局擦除
parameter R_STA_REG    =4'd5;//读寄存器//


//指令集
parameter WEL_CMD      =8'h06;
parameter C_ERA_CMD    =8'hc7;
parameter S_ERA_CMD    =8'h20;//块擦除
parameter READ_CMD     =8'h03;
parameter WRITE_CMD    =8'h02;
parameter R_STA_REG_CMD=8'h05;//读状态寄存器
//`include "parameter.v"


wire[23:0] spi_addr               ;
//reg define
reg [3:0]  current_state          ;
reg [3:0]  next_state             ;
reg [7:0 ] data_buffer            ;
reg [7:0 ] cmd_buffer             ;
reg [23:0] addr_buffer            ;
reg [31:0] bit_cnt                ;
reg        dely_cnt               ;
reg        clk_cnt                ;
reg [31:0] dely_state_cnt         ;
reg        stdone                 ;
reg [7:0]  r_data                 ;
reg [7:0]  spi_data               ;
reg [7:0]  spi_cmd                ;
reg [3:0]  change                 ;
reg        spi_clk0               ;
reg [3:0]  q                      ;
reg [3:0]  x                      ;
reg        stdone_buff            ;
reg        alldone                ;
reg        rst_n_buffer           ;
///reg        rst_n                  ;


assign     spi_addr = 24'b00010   ;

    
initial begin
           spi_data        = 8'b10011100 ;
           current_state   = 1'b0        ;
           data_buffer     = 8'b0        ;
           bit_cnt         = 32'b0       ;///FFF*0.037*2=0.3ms  FFFFFFFF*0.037*2=317.8s 他结束后会返回值吗
           spi_cs          = 1'b1        ;
           addr_buffer     = 8'd0        ;
           dely_cnt        = 8'b0        ;
           clk_cnt         = 8'b0        ;
           dely_state_cnt  = 32'b0       ;
           cmd_buffer      = 8'b0        ;
           spi_mosi        = 8'b0        ;
           spi_clk         = 8'b0        ;
           spi_clk0        = 8'b0        ;
           stdone          = 1'b0        ;
           change          = 8'b0        ;
///           rst_n           = 1'b1        ;
           q               = 1'b0        ;//debugger状态机具体步骤检测标志位
           x               = 1'b0        ;//debugger状态机检测标志位
           alldone         = 1'b0        ;//写数据执行完寻reg也结束后标志位
end


//always @(posedge clk_54m or negedge rst_n) begin
//	if (!rst_n) 
//		spi_data <= 8'b10011100   ;
//	else 
//		spi_data <= spi_data+1'b1 ;
//end


//定义一个计数器产生延时以匹配spi mode0模式
always @(posedge clk_54m or negedge rst_n )begin
	if(!rst_n)
		dely_cnt<=1'd0;
	else if(spi_cs==0)begin///是不是可以用stdone_buff
	    if(dely_cnt<1)
			dely_cnt<=dely_cnt+1'd1;
		else
			dely_cnt<=dely_cnt;
	end
	else
		dely_cnt<=1'd0;
end

//定义一个状态来区分数据采样完/传输完 上升沿在采样,下降沿在输出,如果不定义这个直接采用spiclk的反向逻辑行吗?
//不行,spiclk需要bitcnt来开启,这里如果bitcnt再由spiclk会出现锁存情况
always @(posedge clk_54m or negedge rst_n )begin
	if(!rst_n)
		clk_cnt<=1'd0;
	else if(dely_cnt==1)
		clk_cnt<=clk_cnt+1'd1;
	else 
		clk_cnt<=1'd0;
end

//定义一个计数器统计开始后的传输位数///有办法舍去clk_cnt吗
always @(posedge clk_54m or negedge rst_n )begin ///若dely==1
	if(!rst_n)begin
		bit_cnt<=8'b0; 
     end   
	else if(dely_cnt==1)begin
			if(clk_cnt==1'b1)begin
				bit_cnt<=bit_cnt+1'd1;
                 end
			else begin
				bit_cnt<=bit_cnt;
                 end
	end
	else begin
		bit_cnt<=8'b0;
         end
end

//定义一个计数器(满足状态切换间的时间延迟)
always @(posedge clk_54m or negedge rst_n )begin
	if(!rst_n)
		dely_state_cnt<=1'd0;
	else if(spi_cs)begin
	    if(dely_state_cnt<400000000)
			dely_state_cnt<=dely_state_cnt+1'd1;
		else
			dely_state_cnt<=dely_state_cnt;
	end
	else
		dely_state_cnt<=1'd0;
end

//指令的移位变化
always @(posedge clk_54m or negedge rst_n) begin
	if (!rst_n) 
		cmd_buffer <= 8'b0;
	else if (stdone==0&&dely_cnt==0)//cs改用stdone,这里spi_cmd应会晚一个54M的clk赋值,cmd_buf落后两个///注意此处的时序问题
	       cmd_buffer <= spi_cmd;
	else if (clk_cnt==1&&bit_cnt<8) begin///如果不管IDLE状态会怎么样//这里clk_cnt应该也可以换成spiclk的反逻辑
              cmd_buffer <= {cmd_buffer[6:0],cmd_buffer[7]};		
	end
	else   cmd_buffer <= cmd_buffer;
end

//地址位的移位变化
always @(posedge clk_54m or negedge rst_n )begin
	if(!rst_n) 
		addr_buffer<=8'd0;
	else if(spi_cs==0&&dely_cnt==0)
		addr_buffer<=spi_addr;
	else if(clk_cnt==1&&current_state==WRITE&&bit_cnt>=8&&bit_cnt<32)
		addr_buffer<={addr_buffer[22:0],addr_buffer[23]};
	else
		addr_buffer<=addr_buffer;
end

//写数据移位寄存
always @(posedge clk_54m or negedge rst_n )begin
	if(!rst_n)begin
		data_buffer<=8'd0;
//		spi_data   <=8'b10011100;
	end
	else if((bit_cnt+1)%8==0&&bit_cnt>30&&clk_cnt==1)///因为是31结束,32开始给,所以要+1除8,bitcnt之所以不是大于32,是因为写数据请求发送后要占用一个时钟周期,而我们中间设定的缓冲区也要占用一个时钟
		data_buffer<=spi_data;
	else if(clk_cnt==1&&current_state==WRITE&&bit_cnt>=32)
		data_buffer<={data_buffer[6:0],data_buffer[7]};
	else
		data_buffer<=data_buffer;
end


 //----------------------------------------------------------------------
 //--   状态机第1段
 //----------------------------------------------------------------------
 always @(posedge clk_54m or negedge rst_n)begin
     if(!rst_n)
         current_state <= IDLE;
     else
         current_state <= next_state;
 end

 
 //----------------------------------------------------------------------
 //--   状态机第2段//写nextstate根据change的变化
 //----------------------------------------------------------------------
 always @(*)begin
     case(current_state)
         IDLE: begin1011之后是WEL,然后WEL返回0000,0000之后是CERA,然后CERA返回0001,0001之后是REG,然后REG返回0010,0010之后是WEL,然后WEL返回0011,
                    0011之后是WRITE,然后WRITE返回0100,0100之后是REG,然后REG返回1011进行循环。
             if(change==4'b1011||change==4'b0010)
                 next_state = WEL  ;
             else  if(change==4'b0000)
                 next_state = C_ERA;
             else  if(change==4'b0001||change==4'b0100)
                 next_state = R_STA_REG;
             else  if(change==4'b0011)begin
                 next_state = WRITE;
 //                x=7;
                 end
             else begin
                 next_state = IDLE;注意状态转化
 //                x=5;
             end    
         end
         WEL: begin
             if(change==4'b1011||change==4'b0010)begin//1011
                 next_state = WEL;
   //              x=1;  
             end    
             else begin
                 next_state = IDLE;
  //               x=2;
             end    
         end
         C_ERA: begin
             if(change==4'b0000)begin
                 next_state = C_ERA;
 //                x=3;
                 end   
             else begin 
                 next_state = IDLE;
 //                x=4;  
                 end  
         end
         R_STA_REG: begin
             if(change==4'b0001||change==4'b0100)begin      
                 next_state = R_STA_REG; 
             end      
             else begin
                 next_state = IDLE;
             end     
         end
         WRITE: begin
             if(change==4'b0011)      
                 next_state = WRITE;     
             else
                 next_state = IDLE;

         end
         default:begin
                 next_state = IDLE;
 //                x=15;
         end        
     endcase
 end
 
 //----------------------------------------------------------------------
 //--   状态机第3段 写change的变化以及具体执行功能
 //----------------------------------------------------------------------
 always @(posedge clk_54m or negedge rst_n)begin
     if(!rst_n)begin
          change   <= 4'b1011 ;
          spi_clk  <= 1'b0    ;
          spi_clk0 <= 1'b0    ;
          spi_cs   <= 1'b1    ;
          spi_mosi <= 1'b0    ;
          alldone  <= 1'b0    ;    
     end
     ///可设计当bitcnt>某值时,给rst一个复位信号

     else begin
		case(current_state)
			IDLE:  begin
			    spi_cs   <=1'b1   ;
				spi_clk  <=1'b0   ;
				spi_clk0 <=1'b0   ;
				spi_mosi <=1'b0   ;
				alldone  <=1'b0   ;
				change   <= change;
			    stdone   <= stdone;
			    q        <=1'b0   ;
			       end    			
			
			WEL:   begin
			       spi_cmd<=WEL_CMD;
			       stdone<=1'b0;                
				   spi_cs<=1'b0;
                   if (dely_cnt==1&&bit_cnt<8) begin
                     spi_clk0<=~spi_clk0;
				     spi_clk<=spi_clk0;
				     spi_mosi<=cmd_buffer[7];
//				   q<=2;
				   end
				   else if(bit_cnt==8&&clk_cnt==0)begin
					    stdone<=1'b1;
					    spi_clk<=1'b0;						
					    spi_mosi<=1'b0;
//					    q<=3;
				    end	
				    else if(bit_cnt==8&&clk_cnt==1)begin
						spi_cs<=1'b1;
						stdone<=1'b1;
//						q<=4;
					end				    	
				    else if(dely_cnt==1&&stdone&&change==4'b1011)begin
        	              change <= 4'b0000;//进入空闲,空闲后是擦除(0000),
				    end      
				    else if(dely_cnt==1&&stdone&&change==4'b0010)begin 
				              change <= 4'b0011;//进入空闲,空闲后写数据(0011)
				    end           
///				    else begin  change <= change;
///				                stdone <= stdone;
///				    end          
                  end

            C_ERA:  begin
                    spi_cmd<=C_ERA_CMD; 
                    stdone<=1'b0;
                    spi_clk  <=1'b0   ;
				    spi_clk0 <=1'b0   ;
                        if(dely_state_cnt==10)begin                
				        spi_cs<=1'b0;
//				        q<=1;
                        end
                        else if (dely_cnt==1&&bit_cnt<8) begin
                            spi_clk0<=~spi_clk0;
				            spi_clk<=spi_clk0;
				            spi_mosi<=cmd_buffer[7];
//				            q<=2;	
                        end
                        else if(bit_cnt==8&&clk_cnt==0)begin
					           // stdone<=1'b1;				    
						        spi_clk<=1'b0;
						        spi_mosi<=1'b0;	
//						        q<=3;
					    end
					    else if (bit_cnt==8&&clk_cnt==1)begin
						        spi_cs<=1'b1;
						        stdone<=1'b1;
//						        q<=4;
						end        
                        else if(stdone&&change==4'b0000)begin//之前是空闲,空闲前是写使能(0000)
				                change<=4'b0001;//进入空闲,空闲后寻reg(0001)
				                x<=3;
				        end        
                    end

            R_STA_REG: begin
                            spi_cmd<=R_STA_REG_CMD;
                            stdone<=1'b0;
                            spi_clk  <=1'b0   ;
				            spi_clk0 <=1'b0   ;
///                           q<=6;
                            if(dely_state_cnt==10)begin                
					           spi_cs<=1'b0;
///					           q<=3;
                            end
					else if(dely_cnt==1&&bit_cnt<8) begin						
						spi_clk0<=~spi_clk0;
						spi_clk<=spi_clk0;
						spi_mosi<=cmd_buffer[7];
///						q<=7;
				    end
                    else if(bit_cnt==8)begin		//发送完instruction			   				    
						spi_clk0<=~spi_clk0;
						spi_clk<=spi_clk0;
						spi_mosi<=1'b0;	
///						q<=8;					
					end                      				 
					else if(~spi_miso&&bit_cnt%8==0&&clk_cnt==0)begin//这里应该是-1之后%8但是因为只有一次,所以直接给%9
					    spi_clk<=1'b0;
						spi_cs<=1'b1;
						stdone<=1'b1;
				    end				    
                    else if(~spi_cs&&dely_cnt)begin  //else if(~spi_cs&&==1)begin
						spi_clk0<=~spi_clk0;
						spi_clk<=spi_clk0;
				    end

				       else if(stdone&&change==4'b0001)begin//之前是空闲,空闲前是片擦除
				              change<=4'b0010;
///				              q<=11;
                       end
				       else if(stdone&&change==4'b0100)begin//之前是空闲,空闲前是写数据
				              change<=4'b1110;//进入长期空闲//这里如果需要循环的化可以接如初始状态1011
				              alldone<=1;
				              q<=13;
                       end                               
///				       else begin   change <= change;
///				                    stdone <= stdone;
///				                    q<=15;
///                       end
				 end

                           

            WRITE: begin
                            spi_cmd<=WRITE_CMD;
                            stdone<=1'b0;
                            q<=1;
                            spi_clk  <=1'b0   ;
				            spi_clk0 <=1'b0   ;
				       if(dely_state_cnt==10)begin                
						spi_cs<=1'b0;
//						q<=7;
                        end
					else if(dely_cnt==1&&bit_cnt<8) begin						
						spi_clk0<=~spi_clk0;
						spi_clk<=spi_clk0;
						spi_mosi<=cmd_buffer[7];
					end
					else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin					   
						spi_clk0<=~spi_clk0;
						spi_clk<=spi_clk0;
						spi_mosi<=addr_buffer[23];
					end
					else if(bit_cnt>=32&&bit_cnt<2080)begin						
						spi_clk0<=~spi_clk0;
						spi_clk<=spi_clk0;
						spi_mosi<=data_buffer[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;
						stdone<=1'b1;
//						q<=5;
					end
					else if(stdone&&change==4'b0011)begin//之前是空闲,空闲前是写使能  ///第十步
				              change<=4'b0100;//进入空闲,空闲后是询reg  
				              x<=1; 
				    end              
///				    else begin      change <= change;
///				                    stdone <= stdone; 
///                    end
                end    
			default:begin
			            stdone<=1'b0;
                        spi_cs<=1'b1;
				        spi_clk<=1'b0;
						spi_clk0<=1'b0;
				        spi_mosi<=1'b0;
				        change <= 15;
				        q<=0;
			end
		endcase
	 end	
 end
endmodule 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值