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

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

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

问题概述

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

always @(*)begincase(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 interfaceinput             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 interfaceoutput 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 )beginif(!sys_rst_n)beginidel_flag_d0 <= 1'b1;idel_flag_d1 <= 1'b1;endelse beginidel_flag_d0 <= idel_flag;idel_flag_d1 <= idel_flag_d0;end
end//写数据请求信号
always @(posedge clk_100m or negedge sys_rst_n )beginif(!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;elsew_data_req <= 1'b0;
endalways @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)r_w_data_req <= 'd0;elser_w_data_req <= w_data_req;
endalways @(posedge clk_100m or negedge sys_rst_n )beginif(!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};elserd_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 )beginif(!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};elser_r_data <= r_r_data;
end//读出的数据错误标志
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)error_flag<=1'd0;else if(current_state == READ && cmd_cnt == 6 && idel_flag_p)beginif(r_r_data!=r_w_data)error_flag <= 1'd1;elseerror_flag <= error_flag;endelseerror_flag <= error_flag;
end//数据寄存器	
always @(posedge clk_100m or negedge sys_rst_n )beginif(!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]};elsedata_reg <= data_reg;
end//指令寄存器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!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};elsecmd_reg <= cmd_reg;
end//地址寄存器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!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]};elseaddr_reg <= addr_reg;
end//时钟计数器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!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 )beginif(!sys_rst_n)delay_cnt <= 1'd0;else if(spi_cs == 0)beginif(delay_cnt < 1)delay_cnt <= delay_cnt + 1'd1;elsedelay_cnt <= delay_cnt;endelsedelay_cnt <= 1'd0;
end//状态延迟计数器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)delay_state_cnt <= 1'd0;else if(spi_start)delay_state_cnt <= 1'd0;else if(spi_cs)beginif(delay_state_cnt < 20)delay_state_cnt <= delay_state_cnt + 1'd1;elsedelay_state_cnt <= delay_state_cnt;endelsedelay_state_cnt <= 1'd0;
end//bit计数器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)bit_cnt <= 16'd0;else if(delay_cnt == 1)beginif(clk_cnt == 1'b1)bit_cnt <= bit_cnt+1'd1;elsebit_cnt <= bit_cnt;endelsebit_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};elser_rd_status_reg <= r_rd_status_reg;
end//三段式状态机
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)current_state <= IDLE;elsecurrent_state <= next_state;
endalways @(*)begincase(current_state)IDLE: beginif(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;elsenext_state = IDLE;endWR_EN: beginif(stdone && bit_cnt >= 8)next_state = IDLE;elsenext_state = WR_EN;endS_ERA: beginif(stdone)next_state = IDLE;elsenext_state = S_ERA;endB_ERA: begin		if(stdone)next_state = IDLE;elsenext_state = B_ERA;endREAD: begin 		if(stdone && bit_cnt >= 8)next_state = IDLE;elsenext_state = READ;endWRITE: begin		if(stdone && bit_cnt >= 8)next_state = IDLE;elsenext_state = WRITE;endR_STA_REG: begin		if(stdone)next_state = IDLE;elsenext_state = R_STA_REG;enddefault: next_state = IDLE;			endcase				
endalways @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n) beginspi_cs <= 1'b1;spi_clk <= 1'b0;spi_clk_d0 <= 1'b0;spi_mosi <= 1'b0;	stdone <= 1'b0;		endelse begincase(current_state)IDLE: beginstdone <= 1'b0;spi_cs <= 1'b1;spi_clk <= 1'b0;spi_mosi <= 1'b0;	r_wip_flag <= 1'b0;	spi_clk_d0 <= 'd0;endWR_EN: beginstdone <= 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];endelse if(bit_cnt == 8 && clk_cnt == 0)beginstdone <= 1'b1;spi_clk <= 1'b0;						spi_mosi <= 1'b0;						endelse if(bit_cnt == 8 && clk_cnt == 1)beginspi_cs <= 1'b1;						endendB_ERA: beginstdone <= 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];endelse if(bit_cnt == 8 && clk_cnt == 0)beginstdone <= 1'b1;				    spi_clk <= 1'b0;spi_mosi <= 1'b0;	endelse if(bit_cnt == 8 && clk_cnt == 1)beginspi_cs <= 1'b1;						endendS_ERA: beginstdone <= 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];endelse if(bit_cnt >= 8&& bit_cnt < 32 && spi_cs == 0)beginspi_cs <= 1'b0;spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= addr_reg[23];endelse if(bit_cnt == 32 && clk_cnt == 0) beginspi_cs <= 1'b1;spi_clk <= 1'b0;spi_mosi <= 1'b0;stdone <= 1'b1;endendREAD: beginstdone <= 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];endelse 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];endelse if(bit_cnt >= 32 && bit_cnt < 2080)begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= 1'b0;						endelse if(bit_cnt == 2080 && clk_cnt == 0) begin						spi_clk <= 1'b0;spi_mosi <= 1'b0;stdone <= 1'b1;						endelse if(bit_cnt == 2080 && clk_cnt == 1) beginspi_cs<=1'b1;endendWRITE: beginstdone<=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];endelse 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];endelse if(bit_cnt >= 32 && bit_cnt < 2080)begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= data_reg[7];endelse if(bit_cnt == 2080 && clk_cnt == 0) beginspi_clk <= 1'b0;spi_mosi <= 1'b0;stdone <= 1'b1;endelse if(bit_cnt == 2080 && clk_cnt == 1) beginspi_cs <= 1'b1;endendR_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];endelse 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)beginr_wip_flag <= 1'b1;spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;endelse if(r_wip_flag && ~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 1)beginspi_clk <= 1'b0;spi_cs <= 1'b1;stdone <= 1'b1;endelse if(~spi_cs && delay_cnt == 1)beginspi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;end	   			         	 end default: beginstdone <= 1'b0;spi_cs <= 1'b1;spi_clk <= 1'b0;spi_clk_d0 <= 1'b0;spi_mosi <= 1'b0;				        endendcaseend
endila_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];endelse 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)beginr_wip_flag <= 1'b1;spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;endelse if(r_wip_flag && ~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 1)beginspi_clk <= 1'b0;spi_cs <= 1'b1;stdone <= 1'b1;endelse if(~spi_cs && delay_cnt == 1)beginspi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;end	   			         	 end 

主要修改的就是这里,思路是:
我会首先判断WIP位是否为0,如果为0,则把r_wip_flag标志位拉高,等到下一次轮询状态寄存器的时候就可以跳出当前轮询寄存器的状态。
修改后的时序如下:
在这里插入图片描述
可以看到擦除命令执行完之后,还需要等待一段时间后才会完成擦除,擦除后的时序为:
在这里插入图片描述

在这里插入图片描述
即回到初始状态。

遗留问题

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

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

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

相关文章

全国产服务器主板:搭载飞腾FT2000+/64处理器的高性能加固服务器

近期很多朋友咨询全国产化的服务器主板。搭载的是飞腾FT-2000/64的全国产化服务器主板。他的主要特点是&#xff1a;①丰富的PCIe、千兆以太网、SATA接口&#xff0c;可用作数据处理、存储、通信服务器&#xff1b;②​​​​​​​板载独立显示芯片&#xff0c;对外HDMI/VGA/L…

DP(6) | 完全背包 | Java | LeetCode 322, 179, 139 做题总结

322. 零钱兑换 我的错误答案 class Solution {public int coinChange(int[] coins, int amount) {int[][]dp new int [coins.length][amount1];for(int j0; j<amount; j) {if(coins[0] j){dp[0][coins[0]] 1;}}for(int i1; i<coins.length; i) {for(int j0; j<am…

vue3前端开发-小兔鲜项目-图片懒加载的自定义标签

vue3前端开发-小兔鲜项目-图片懒加载的自定义标签&#xff01;很多大型网站&#xff0c;因为首页面渲染的内容太多了&#xff0c;然而有些用户&#xff0c;可能在顶部就发现了自己感兴趣的内容&#xff0c;直接就点击跳转去了其他页面&#xff0c;因此&#xff0c;完全没有必要…

神经网络之多层感知机

目录 一、全连接层&#xff1a;二、单层感知机概念&#xff1a;三、多层感知机概念&#xff1a; 一、全连接层&#xff1a; 在神经网络中&#xff0c;全连接层就是每个神经元都与上一层的所有神经元相连接&#xff0c;即每个神经元都接收上一层所有神经元的输入&#xff0c;并…

【面试题】数据结构:堆排序的排序思想?

堆排序的排序思想&#xff1f; 堆排序是一种高效的排序算法&#xff0c;其基本思想是利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树&#xff0c;通常用数组来表示。堆排序的基本步骤如下&#xff1a; 1. 构建初始堆&#xff1a; 将待排序的数组转换成一个最大堆&a…

【JavaEE】volatile + final + wait-notify + join + park-unpark 相关原理

本文基于jdk8 本文所讲的一些原理都是在多线程中经常使用的内容。 参考&#xff1a;黑马程序员深入学习Java并发编程&#xff0c;JUC并发编程全套教程_哔哩哔哩_bilibili 目录 volatile原理 Java内存模型(JMM) 可见性&有序性 双重检查锁应用 final原理 设置final变量…

GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建

原文链接&#xff1a;GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608565&idx3&snd4e9d447efd82e8dd8192f7573886dab&chksmfa826912cdf5e00414e01626b52bab83a96199a6bf69cbbef7f7fe…

学习日志:java线程

文章目录 前言一、线程和进程线程与进程的关系 二、Java 线程和操作系统的线程JDK 1.2 之前JDK 1.2 及以后用户线程和内核线程 三、创建线程四、线程的生命周期和状态五、线程的上下文切换六、Thread#sleep() 方法和Object#wait() 方法 前言 这里总结线程的一些概念。 一、线程…

​探讨元宇宙和VR虚拟现实之间的区别​

在数字时代&#xff0c;人们对虚拟现实的兴趣与日俱增。在虚拟现实技术的推动下&#xff0c;出现了两个概念&#xff1a;元宇宙和VR虚拟现实。虽然这两个概念都与虚拟现实有关&#xff0c;但它们有着不同的特点和用途。在本文中&#xff0c;我们将探讨元宇宙和VR虚拟现实之间的…

香橙派AIpro-携手华为-为AI赋能

文章目录 香橙派AIpro-携手华为-为AI赋能开箱和功能介绍开箱功能介绍 环境搭建镜像烧录进入系统 测试项目YOLOv5部署YOLOv5识别单张图片实时识别视频使用Ascend测试yolov5 产品评价 香橙派AIpro-携手华为-为AI赋能 今天新入手了一款香橙派AIPro&#xff0c;让我们一起跟着文章…

接口防刷!利用redisson快速实现自定义限流注解

问题&#xff1a; 在日常开发中&#xff0c;一些重要的对外接口&#xff0c;需要加上访问频率限制&#xff0c;以免造成资&#xfffd;&#xfffd;损失。 如登录接口&#xff0c;当用户使用手机号验证码登录时&#xff0c;一般我们会生成6位数的随机验证码&#xff0c;并将验…

【iOS】——编译链接和动态链接器

前言 计算机语言分为机器语言&#xff1a;汇编语言&#xff0c;高级语言。 可以将高级语言分为两种&#xff1a;1&#xff0c;编译语言和解释型语言&#xff08;直译式语言&#xff09;。 编译型语言&#xff08;一次性翻译&#xff09; 编译型语言的程序只要经过编译器编译之…

Android 大屏外接显示器锁屏无触摸

一、大海捞针 1、首先查看log,发现异常log log表示主显示器即id 0的显示器有可交互窗口但是没有焦点,副显示器即id 4有焦点但是没有可交互窗口。猜想副显示器把主显示器的焦点抢走了,只需把焦点从副显示器挪回主显示器即可。 通过查看源代码知道上面这段log来自于InputDi…

filebeat,kafka,clickhouse,ClickVisual搭建轻量级日志平台

springboot集成链路追踪 springboot版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.3</version><relativePath/> <!-- lookup parent from…

【CSS in Depth 2 精译_019】3.2 CSS 的盒模型

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

【Qt安装与简易串口控制Arduino开发板小灯教程】

【Qt安装与简易串口控制Arduino开发板小灯教程】 1. 前言2. QT环境搭建3. 验证QT_Creator是否安装成功3.1 设计流程3. 2 上位机界面设计 4. 上位机逻辑代码编写4.1 添加串口库、包含串口相关头文件4.2 添加QSerialPort成员4.3 创建串口对象、搜索所有可用串口4.4 在编写“打开串…

微软成为PostgreSQL主要贡献者

微软对PostgreSQL贡献的很多新功能都来自于客户在使用微软Azure上的PostgreSQL管理实例数据库&#xff0c;所以这些新功能都来自于真实的客户需求 微软贡献的这些新功能都是比较实用的功能 在这里&#xff0c;【真实的客户需求】要突出一下&#xff0c;因为现在很多社区贡献者…

4. docker镜像、Dockerfile

docker镜像、Dockerfile 一、docker镜像1、镜像介绍2、镜像核心技术 二、Dockerfile定制镜像1、Dockerfile使用流程1.1 编写Dockerfile1.2、构建镜像1.3 创建容器测试镜像定制操作 2、Dockerfile常用指令 一、docker镜像 1、镜像介绍 分层的文件系统 优势&#xff1a;节省空间…

基于JAVA+SpringBoot+uniapp的心理小程序(小程序版本)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、SpringCloud、Layui、Echarts图表、Nodejs、爬…

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…