• ZC-CLS381RGB颜色识别——配置寄存器组(上)



    前言

      在现代工业生产中,颜色识别技术已经成为了一个非常重要的技术。颜色识别可以用于产品质量检测、物料分类、机器视觉等领域。本文将介绍如何使用FPGA结合ZC-CLS381RGB进行颜色识别。
      本教程通过对采集到的图像信息中,R、G、B三个颜色分量的占比,来判断识别到的颜色信息。本教程只实现对红色、绿色、蓝色的识别,如果各位读者要想实现对其它色彩信息的识别,可根据三个色彩分量的占比来判断。

    一、ZC-CLS381RGB简介

      ZC-CLS381RGB是一款基于RGB三基色原理的颜色识别传感器。它可以通过对物体反射光的RGB三基色分量进行测量,来判断物体的颜色。该传感器具有高精度、快速响应、稳定性好等特点,广泛应用于自动化生产线、机器人、智能家居等领域。

    二、配置寄存器组

      ZC-CLS381RGB是一款RGB LED驱动器芯片,需要通过配置寄存器来让该模块正常工作。下面就对颜色识别需要配置的寄存器进行介绍。

    1.主控寄存器

      MAIN_CTRL Register是主控寄存器,下图是主控寄存器的配置介绍:

    在这里插入图片描述
      bit7~bit5,bit3,bit0:保留位(Reserved),使用时将这几位置0即可。
      bit4:软件复位位(SW Reset),当该位被置1时,芯片会进行软件复位,即将所有寄存器的值恢复为默认值。在使用ZC-CLS381RGB时,如果出现异常情况,例如芯片无法正常工作或者输出异常,可以通过将SW Reset位置1来进行软件复位,以恢复芯片的正常工作状态。同时,在初始化芯片时,也可以通过将SW Reset位置1来确保芯片的寄存器值处于默认状态,以避免出现不可预期的问题。但是如果软件复位位一直为高电平,模块就无法正常采集颜色,一直处于复位状态,如果要关闭该位则还需要发送一次指令。因此在本设计初始化时,将该位置为0,不启用软件复位。
      bit2:颜色传感器模式位(CS Mode),该位置为1时,表示所有的光传感器通道都被激活,包括RGB(三原色)、IR(红外光)和COMP(环境光)。这意味着该传感器可以同时测量红、绿、蓝三种颜色的光线强度、红外线的强度以及环境光的强度,并将这些数据传输到寄存器中进行处理。初始化配置时,需将该位置为1。
      bit1:环境光传感器/颜色传感器使能位(ALS/CS Enable),当该位置1时,表示使能环境光传感器和颜色传感器。在本设计中,需要使用到这两个传感器,因此在初始化时需要将该位置为1。

    2.检测速率寄存器

      ALS_CS_MEAS_RATE Register是环境光传感器和颜色传感器检测速率寄存器,下图是对该寄存器的配置介绍:

    在这里插入图片描述
      bit7、bit3:保留位(Reserved),使用时这两位需要置0。
      bit6,bit5,bit4:环境光传感器和颜色传感器速率位(ALS/CS Resolution),初始化时设置{bit6,bit5,bit4}=100,利用最快的时间对采集到的数据进行转换。
      bit2,bit1,bit0:环境光传感器和颜色传感器测量速率位(ALS/CS Measurement Rate),初始化设置{bit2,bit1,bit0}=000,利用最快的采集速率采集数据。

    2.增益寄存器

      ALS_CS_MEAS_RATE Register是环境光传感器和颜色传感器增益寄存器,下图是对该寄存器的配置介绍:

    在这里插入图片描述
      bit7~bit3:保留位(Reserved),使用时这两位需要置0。
      bit2~bit0:环境光传感器和颜色传感器增益率位(Reserved),初始化时设置{bit2,bit1,bit0}=100,将增益率调到最大,以此增强信号的强度,使得信号更容易被检测到。

    2.颜色数据寄存器

      因为本教程采集的是红色、绿色、蓝色数据,芯片手册提供的寄存器组如下图所示:

    在这里插入图片描述
      0x0D、0x0E、0x0F分别表示绿色信息的低8位、中8位、高8位数据;0x10、0x11、0x12分别表示红色信息的低8位、中8位、高8位数据;0x13、0x14、0x15分别表示蓝色信息的低8位、中8位、高8位数据。在使用中,直接读取这些寄存器内的数据,然后拼接起来,即可得到红、绿、蓝色数据,再根据三个数据的占比,从而对采集到的物体颜色进行判断。

    三、状态转移图和信号波形图绘制

      在正式开始使用器件时,需要等待一段时间让器件稳定下来,如图所示:

    在这里插入图片描述
      待机唤醒时间最大为10ms,表示在测量的时候,两次获取数据的时间间隔最大为10ms。由于在数据手册内,未说明上电后直到模块稳定需要等待的时间,在这里我们人为设置上电等待的时间为20ms,给模块一个缓冲的时间,然后再对它进行配置。配置寄存器组信号波形图如下图所示:

    在这里插入图片描述
      其中,i2c_start作为i2c控制模块的开始信号,检测到该开始信号后,就开始配置寄存器,向各个寄存器内写入数据。综上绘制的i2c控制模块配置寄存器组的状态转移图如下图所示:

    在这里插入图片描述
      为了设计方便,对于50MHZ的系统时钟,将其分频为1MHZ的i2c驱动时钟用来驱动后续模块,同时令一个SCL时钟周期为4us,高电平持续时间为2us,低电平持续时间也为2us。这样设计的好处是,满足SCL高电平持续时间大于0.6us,SCL低电平持续时间大于1.3us。如下图所示:

    在这里插入图片描述
      综上,绘制的分频信号波形图如下图所示:

    在这里插入图片描述
      结合状态转移图,绘制的配置寄存器信号波形图如下图所示:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
      需要注意的是,配置寄存器组跳转条件为skip_en_0,这里配置的寄存器是向寄存器里面写入数据,总共需要配置三个,三个寄存器配置完成后,才能读出颜色数据。因此,step从0自增到1,必须要在cfg_num为3并且检测到结束信号的情况下进行。

    总结

      本章配置完成颜色识别所需的寄存器,下一章完成ws2812 8x8点阵的驱动配置。

    参考代码

    1.配置模块

    module  cls381_cfg_ctrl
    (
    	input	wire			i2c_clk		,	//与i2c_ctrl公用的驱动时钟
    	input	wire			sys_rst_n	,
    	input	wire			cfg_start	,	//cfg_ctrl模块开始信号,i2c_ctrl模块每配置完成一次产生
    	
    	output	wire	[15:0]	cfg_data	,	//打包的寄存器地址和数据
    	output	reg		[3:0]	cfg_num		,	//配置的寄存器个数
    	output	reg				i2c_start		//i2c_ctrl模块开始信号
    );
    
    localparam	CNT_WAIT_MAX  =  15'd20_000  ;	//上电等待20ms
    
    reg		[14:0]	cnt_wait		;		//等待20ms计数器
    reg				i2c_start_reg	;		//i2c_start未打拍的信号,打拍后才与数据和个数保持同步
    wire	[15:0]	cfg_data_reg[11:0]	;	//待发送数据的寄存
    
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		cnt_wait  <=  15'd0  ;
    	else  if(cnt_wait >= CNT_WAIT_MAX - 1'b1)
    		cnt_wait  <=  CNT_WAIT_MAX  ;
    	else
    		cnt_wait  <=  cnt_wait + 1'b1  ;
    
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		i2c_start_reg  <=  1'b0  ;
    	else  if(cnt_wait == CNT_WAIT_MAX - 2'd2)
    		i2c_start_reg  <=  1'b1  ;
    	else
    		i2c_start_reg  <=  1'b0  ;
    		
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		cfg_num  <=  4'd0  ;
    	else  if((cfg_num == 4'd12)&&(cfg_start == 1'b1))
    		cfg_num  <=  4'd4  ;
    	else  if((cfg_start == 1'b1)||(i2c_start_reg == 1'b1))
    		cfg_num  <=  cfg_num + 1'b1  ;
    	else
    		cfg_num  <=  cfg_num  ;
    	
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)	
    		i2c_start  <=  1'b0  ;
    	else  if((cfg_start == 1'b1)||(i2c_start_reg == 1'b1))	
    		i2c_start  <=  1'b1  ;
    	else
    		i2c_start  <=  1'b0  ;
    
    assign  cfg_data = (cfg_num == 4'd0) ? 16'd0 : cfg_data_reg[cfg_num - 1]  ;
    assign  cfg_data_reg[00]  =  {8'h00,8'b0000_0110}  ;
    assign  cfg_data_reg[01]  =  {8'h04,8'b0100_0000}  ;
    assign  cfg_data_reg[02]  =  {8'h05,8'b0000_0100}  ;
    assign  cfg_data_reg[03]  =  {8'h0F,8'h0}  ;
    assign  cfg_data_reg[04]  =  {8'h0E,8'h0}  ;
    assign  cfg_data_reg[05]  =  {8'h0D,8'h0}  ;
    assign  cfg_data_reg[06]  =  {8'h12,8'h0}  ;
    assign  cfg_data_reg[07]  =  {8'h11,8'h0}  ;
    assign  cfg_data_reg[08]  =  {8'h10,8'h0}  ;
    assign  cfg_data_reg[09]  =  {8'h15,8'h0}  ;
    assign  cfg_data_reg[10]  =  {8'h14,8'h0}  ;
    assign  cfg_data_reg[11]  =  {8'h13,8'h0}  ;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    2.i2c控制模块

    module  i2c_ctrl
    (
    	input	wire			sys_clk		,
    	input	wire			sys_rst_n	,
    	input	wire			i2c_start	,
    	input	wire	[3:0]	cfg_num		,
    	input	wire	[15:0]	cfg_data	,
    	
    	output	wire			scl			,
    	output	reg				i2c_clk		,
    	output	reg				cfg_start	,
    	output	reg		[23:0]	data_r		,
    	output	reg		[23:0]	data_g		,
    	output	reg		[23:0]	data_b		,
    	
    	inout	wire			sda
    );
    
    localparam	IDLE		=	4'd0	,
    			START		=	4'd1	,
    			SLAVE_ADDR	=	4'd2	,
    			ACK_1		=	4'd3	,
    			REG_ADDR	=	4'd4	,
    			ACK_2		=	4'd5	,
    			DATA		=	4'd6	,
    			ACK_3		=	4'd7	,
    			STOP		=	4'd8	,
    			NACK		=	4'd9	,
    			WAIT		=	4'd10	;
    localparam	CNT_CLK_MAX		=	5'd25		;	//系统时钟计数器最大值
    localparam	SLAVE_ID		=	7'h53		;	//从设备的I2C ID号
    
    reg		[4:0]	cnt_clk		;	//系统时钟计数器,计数25次产生1MHZ i2c驱动时钟
    reg				skip_en_0	;	//配置寄存器状态跳转信号
    reg				skip_en_1	;	//读取绿色分量状态跳转信号
    reg				skip_en_2	;	//读取红色分量状态跳转信号
    reg				skip_en_3	;	//读取蓝色分量状态跳转信号
    reg		[3:0]	n_state		;	//次态
    reg		[3:0]	c_state		;	//现态
    reg		[1:0]	cnt_i2c_clk	;	//i2c_clk时钟计数器,每计数4次就是一个SCL周期
    reg		[2:0]	cnt_bit		;	//计数发送的比特数
    reg				i2c_scl		;	//这就是scl信号,加i2c_是为了与i2c_sda同步
    reg				i2c_sda		;	//由主机产生,在主机控制SDA通信总线时赋值给SDA
    reg				ack_en		;	//响应使能信号,为1时代表接收的ACK响应有效
    reg				i2c_end		;	//结束信号,在STOP最后一个时钟周期拉高,表示一次通信结束
    reg		[2:0]	step		;	//操作步骤信号,与跳转信号相关联
    								//在向寄存器里面写入数据或者读出数据时,状态跳转情况是不一样的
    reg				flag_g		;	//读取绿色数据指示不同的状态跳转
    reg		[1:0]	cnt_g		;	//绿色寄存器个数计数
    (*noprune*)reg		[23:0]	rec_data_g	;	//读取到的绿色分量
    reg				flag_r		;	//读取红色数据指示不同的状态跳转
    reg		[1:0]	cnt_r		;	//红色寄存器个数计数
    (*noprune*)reg		[23:0]	rec_data_r	;	//读取到的红色分量
    reg				flag_b		;	//读取蓝色数据指示不同的状态跳转
    reg		[1:0]	cnt_b		;	//蓝色寄存器个数计数
    (*noprune*)reg		[23:0]	rec_data_b	;	//读取到的蓝色分量
    reg		[7:0]	slave_addr	;
    reg		[7:0]	reg_addr	;
    reg		[7:0]	wr_data		;
    wire			sda_in		;	//sda赋值给sda_in,主机在接收从机数据时采集sda_in的数据,间接采集了SDA数据
    wire			sda_en		;	//主机控制SDA使能信号,为1代表主机控制SDA,为0代表控制权为从机
    
    assign  scl  =  i2c_scl  ;
    //三态门
    assign  sda_in  =  sda  ;
    assign  sda_en  =  ((c_state == ACK_1)||(c_state == ACK_2)||(c_state == ACK_3)||((step != 3'd0)&&(c_state == DATA))) ? 1'b0 : 1'b1  ;
    assign  sda     =  (sda_en == 1'b1) ? i2c_sda : 1'bz  ;
    
    always@(*)
    	case(step)
    		3'd0	:begin	
    					slave_addr  =  {SLAVE_ID,1'b0}  ;
    					reg_addr	=  cfg_data[15:8]  ;	//主控寄存器地址
    					wr_data		=  cfg_data[7:0]  ;
    				 end
    		3'd1	:begin
    					slave_addr  =  {SLAVE_ID,flag_g}  ;
    					reg_addr	=  cfg_data[15:8]  ;
    					wr_data		=  8'h0  ;	//未写入数据
    				 end
    		3'd2	:begin
    					slave_addr  =  {SLAVE_ID,flag_r}  ;
    					reg_addr	=  cfg_data[15:8]  ;
    					wr_data		=  8'h0  ;	//未写入数据
    				 end
    		3'd3	:begin
    					slave_addr  =  {SLAVE_ID,flag_b}  ;
    					reg_addr	=  cfg_data[15:8]  ;
    					wr_data		=  8'h0  ;	//未写入数据
    				 end				 
    		default	:begin	
    					slave_addr  =  slave_addr  ;
    					reg_addr	=  reg_addr  ;
    					wr_data		=  wr_data  ;
    				 end
    	endcase		
    
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		cnt_clk  <=  5'd0  ;
    	else  if(cnt_clk == CNT_CLK_MAX - 1'b1)
    		cnt_clk  <=  5'd0  ;
    	else
    		cnt_clk  <=  cnt_clk + 1'b1  ;
    
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		i2c_clk  <=  1'b0  ;
    	else  if(cnt_clk == CNT_CLK_MAX - 1'b1)
    		i2c_clk  <=  ~i2c_clk  ;
    	else
    		i2c_clk  <=  i2c_clk  ;
    		
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		cfg_start  <=  1'b0  ;
    	else
    		cfg_start  <=  i2c_end  ;
    		
    //状态机第一段
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		c_state  <=  IDLE  ;
    	else
    		c_state  <=  n_state  ;
    		
    //状态机第二段
    always@(*)
    	case(c_state)
    		IDLE		:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  START  ;
    						else
    							n_state  =  IDLE  ;
    		START		:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  SLAVE_ADDR  ;
    						else
    							n_state  =  START  ;
    		SLAVE_ADDR	:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  ACK_1  ;
    						else
    							n_state  =  SLAVE_ADDR  ;
    		ACK_1		:	if((skip_en_0 == 1'b1)||((skip_en_1 == 1'b1)&&(flag_g == 1'b0))||((skip_en_2 == 1'b1)&&(flag_r == 1'b0))||((skip_en_3 == 1'b1)&&(flag_b == 1'b0)))
    							n_state  =  REG_ADDR  ;
    						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  DATA  ;
    						else
    							n_state  =  ACK_1  ;
    		REG_ADDR	:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  ACK_2  ;
    						else
    							n_state  =  REG_ADDR  ;
    		ACK_2		:	if(skip_en_0 == 1'b1)
    							n_state  =  DATA  ;
    						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  WAIT  ;
    						else
    							n_state  =  ACK_2  ;
    		WAIT		:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  START  ;
    						else
    							n_state  =  WAIT  ;
    		DATA		:	if(skip_en_0 == 1'b1)
    							n_state  =  ACK_3  ;
    						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  NACK  ;
    						else
    							n_state  =  DATA  ;
    		ACK_3		:	if(skip_en_0 == 1'b1)
    							n_state  =  STOP  ;
    						else
    							n_state  =  ACK_3  ;
    		NACK		:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  STOP  ;
    						else
    							n_state  =  NACK  ;
    		STOP		:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
    							n_state  =  IDLE  ;
    						else
    							n_state  =  STOP  ;
    		default		:	n_state  =  IDLE  ;
    	endcase
    	
    //状态机第三段
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		begin
    			skip_en_0	<=  1'b0   	;
    			skip_en_1	<=  1'b0	;
    			skip_en_2 	<=  1'b0	;
    			skip_en_3	<=  1'b0	;
    			cnt_i2c_clk	<=  2'd0	;
    			cnt_bit		<=  3'd0	;
    			flag_g		<=  1'b0	;
    			cnt_g		<=  2'd0	;
    			flag_r		<=  1'b0	;
    			cnt_r		<=  2'd0	;	
    			flag_b		<=  1'b0	;
    			cnt_b		<=  2'd0	;			
    			i2c_end		<=  1'b0    ;
    			step		<=  3'd0	;
    		end
    	else
    		case(c_state)
    			IDLE		:begin
    							if((i2c_start == 1'b1)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((i2c_start == 1'b1)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;
    							if((i2c_start == 1'b1)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((i2c_start == 1'b1)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;								
    						 end
    			START		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;								
    						 end
    			SLAVE_ADDR	:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if(cnt_i2c_clk == 2'd3)
    								cnt_bit  <=  cnt_bit + 1'b1  ;
    							else
    								cnt_bit  <=  cnt_bit  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;									
    						 end
    			ACK_1		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;									
    						 end
    			REG_ADDR	:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if(cnt_i2c_clk == 2'd3)
    								cnt_bit  <=  cnt_bit + 1'b1  ;
    							else
    								cnt_bit  <=  cnt_bit  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;									
    						 end
    			ACK_2		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;									
    						 end	
    			WAIT		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;	
    							flag_g  <=  1'b1  ;
    							flag_r  <=  1'b1  ;
    							flag_b  <=  1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;									
    						 end
    			DATA		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if(cnt_i2c_clk == 2'd3)
    								cnt_bit  <=  cnt_bit + 1'b1  ;
    							else
    								cnt_bit  <=  cnt_bit  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;									
    						 end
    			NACK		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;		
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;								
    						 end	
    			ACK_3		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    						 end	
    			STOP		:begin
    							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd0))
    								skip_en_0  <=  1'b1  ;
    							else
    								skip_en_0  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd1))
    								skip_en_1  <=  1'b1  ;
    							else
    								skip_en_1  <=  1'b0  ;	
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd2))
    								skip_en_2  <=  1'b1  ;
    							else
    								skip_en_2  <=  1'b0  ;
    							if((cnt_i2c_clk == 2'd2)&&(step == 3'd3))
    								skip_en_3  <=  1'b1  ;
    							else
    								skip_en_3  <=  1'b0  ;								
    							if(cnt_i2c_clk == 2'd2)	
    								i2c_end  <=  1'b1  ;
    							else
    								i2c_end  <=  1'b0  ;
    							if((cnt_b == 2'd2)&&(cnt_i2c_clk == 2'd3))
    								step  <=  3'd1  ;
    							else  if((cfg_num == 3'd3)&&(cnt_i2c_clk == 2'd3))
    								step  <=  step + 1'b1  ;
    							else  if((cnt_r == 2'd2)&&(cnt_i2c_clk == 2'd3))
    								step  <=  step + 1'b1  ;
    							else  if((cnt_g == 2'd2)&&(cnt_i2c_clk == 2'd3))
    								step  <=  step + 1'b1  ;							
    							else
    								step  <=  step  ;
    							if((i2c_end == 1'b1)&&(cnt_g == 2'd2))
    								cnt_g  <=  2'd0  ;
    							else  if((i2c_end == 1'b1)&&(cfg_num >= 4'd4)&&(cfg_num <= 4'd6))
    								cnt_g  <=  cnt_g + 1'b1  ;
    							else
    								cnt_g  <=  cnt_g  ;
    							if((i2c_end == 1'b1)&&(cnt_r == 2'd2))
    								cnt_r  <=  2'd0  ;
    							else  if((i2c_end == 1'b1)&&(cfg_num >= 4'd7)&&(cfg_num <= 4'd9))
    								cnt_r  <=  cnt_r + 1'b1  ;
    							else
    								cnt_r  <=  cnt_r  ;	
    							if((i2c_end == 1'b1)&&(cnt_b == 2'd2))
    								cnt_b  <=  2'd0  ;
    							else  if((i2c_end == 1'b1)&&(cfg_num >= 4'd10)&&(cfg_num <= 4'd12))
    								cnt_b  <=  cnt_b + 1'b1  ;
    							else
    								cnt_b  <=  cnt_b  ;									
    							if(i2c_end == 1'b1)
    								begin
    									flag_g  <=  1'b0  ;
    									flag_r  <=  1'b0  ;
    									flag_b  <=  1'b0  ;
    								end
    							else
    								begin
    									flag_g  <=  flag_g  ;
    									flag_r  <=  flag_r  ;
    									flag_b  <=  flag_b  ;
    								end
    						 end
    			default		:begin
    							skip_en_0	<=  1'b0   	;
    							skip_en_1   <=  1'b0    ;
    							cnt_i2c_clk	<=  2'd0	;
    							cnt_bit		<=  3'd0	;
    							flag_g		<=  1'b0	;
    							cnt_g		<=  2'd0	;
    							i2c_end		<=  1'b0    ;
    							step		<=  3'd0	;
    						 end
    		endcase
    		
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		rec_data_g  <=  24'd0  ;
    	else
    		case(c_state)
    			DATA	:	if((step == 3'd1)&&(cnt_i2c_clk == 2'd1))
    							rec_data_g  <=  {rec_data_g[22:0],sda_in}  ;
    						else
    							rec_data_g  <=  rec_data_g  ;
    			default	:	rec_data_g  <=  rec_data_g  ;	//必须写这一句
    		endcase
    		
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		rec_data_r  <=  24'd0  ;
    	else
    		case(c_state)
    			DATA	:	if((step == 3'd2)&&(cnt_i2c_clk == 2'd1))
    							rec_data_r  <=  {rec_data_r[22:0],sda_in}  ;
    						else
    							rec_data_r  <=  rec_data_r  ;
    			default	:	rec_data_r  <=  rec_data_r  ;	//必须写这一句
    		endcase	
    
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		rec_data_b  <=  24'd0  ;
    	else
    		case(c_state)
    			DATA	:	if((step == 3'd3)&&(cnt_i2c_clk == 2'd1))
    							rec_data_b  <=  {rec_data_b[22:0],sda_in}  ;
    						else
    							rec_data_b  <=  rec_data_b  ;
    			default	:	rec_data_b  <=  rec_data_b  ;	//必须写这一句
    		endcase	
    
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		begin
    			data_r	<=  24'd0  ;
    			data_g	<=  24'd0  ;
    			data_b	<=  24'd0  ;
    		end
    	else  if((step == 3'd3)&&(c_state == STOP)&&(cnt_b == 2'd2))
    		begin
    			data_r  <=  rec_data_r  ;
    			data_g	<=  rec_data_g  ;
    			data_b  <=  rec_data_b  ;
    		end
    	else
    		begin
    			data_r  <=  data_r  ;
    			data_g	<=  data_g  ;
    			data_b  <=  data_b  ;
    		end
    		
    always@(*)
    	case(c_state)
    		ACK_1,ACK_2,ACK_3
    					:	ack_en  =  ~sda_in  ;
    		NACK		:	ack_en  =  i2c_sda  ;
    		default		:	ack_en  =  1'b0  ;
    	endcase
    	
    always@(*)
    	case(c_state)
    		IDLE		:	i2c_scl  =  1'b1  ;
    		START		:	if(cnt_i2c_clk == 2'd3)
    							i2c_scl  =  1'b0  ;
    						else
    							i2c_scl  =  1'b1  ;
    		SLAVE_ADDR,REG_ADDR,DATA,ACK_1,ACK_2,ACK_3,NACK
    					:	if((cnt_i2c_clk == 2'd0)||(cnt_i2c_clk == 2'd3))
    							i2c_scl  =  1'b0  ;
    						else
    							i2c_scl  =  1'b1  ;
    		WAIT		:	i2c_scl  =  1'b0  ;
    		STOP		:	if(cnt_i2c_clk == 2'd0)
    							i2c_scl  =  1'b0  ;
    						else
    							i2c_scl  =  1'b1  ;	
    		default		:	i2c_scl  =  1'b1  ;
    	endcase
    	
    always@(*)
    	case(c_state)
    		IDLE		:	i2c_sda  =  1'b1  ;
    		START		:	if((cnt_i2c_clk == 2'd0)||(cnt_i2c_clk == 2'd1))
    							i2c_sda  =  1'b1  ;
    						else
    							i2c_sda  =  1'b0  ;
    		SLAVE_ADDR	:	i2c_sda  =  slave_addr[7 - cnt_bit]  ;
    		REG_ADDR	:	i2c_sda  =  reg_addr[7 - cnt_bit]  ;
    		DATA		:	i2c_sda  =  wr_data[7 - cnt_bit]  ;
    		ACK_1,ACK_2,ACK_3,NACK,WAIT	
    					:	i2c_sda  =  1'b1  ;
    		STOP		:	if((cnt_i2c_clk == 2'd0)||(cnt_i2c_clk == 2'd1))
    							i2c_sda  =  1'b0  ;
    						else
    							i2c_sda  =  1'b1  ;
    		default		:	i2c_sda  =  1'b1  ;
    	endcase
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566

    3.顶层模块

    module  cls381_top
    (
    	input	wire			sys_clk		,
    	input	wire			sys_rst_n	,
    	
    	output	wire			scl			,
    	output	reg				r_valid		,
    	output	reg				g_valid		,
    	output	reg				b_valid		,
    	
    	inout	wire			sda
    );
    
    wire			i2c_start	;
    wire	[3:0]	cfg_num		;
    wire	[15:0]	cfg_data	;
    wire			i2c_clk		;
    wire			cfg_start	;
    wire	[23:0]	data_r		;
    wire	[23:0]	data_g		;
    wire	[23:0]	data_b		;
    
    always@(posedge i2c_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		begin
    			r_valid  <=  1'b0  ;
    			g_valid  <=  1'b0  ;
    			b_valid  <=  1'b0  ;
    		end
    	else  if(data_r > data_g + data_b)
    		begin
    			r_valid  <=  1'b1  ;
    			g_valid  <=  1'b0  ;
    			b_valid  <=  1'b0  ;
    		end
    	else  if(data_g > data_r + data_b)
    		begin
    			r_valid  <=  1'b0  ;
    			g_valid  <=  1'b1  ;
    			b_valid  <=  1'b0  ;
    		end
    	else  if(data_b > data_r + data_g)
    		begin
    			r_valid  <=  1'b0  ;
    			g_valid  <=  1'b0  ;
    			b_valid  <=  1'b1  ;
    		end
    	else
    		begin
    			r_valid  <=  1'b0  ;
    			g_valid  <=  1'b0  ;
    			b_valid  <=  1'b0  ;		
    		end
    
    i2c_ctrl  i2c_ctrl_inst
    (
    	.sys_clk	(sys_clk	),
    	.sys_rst_n	(sys_rst_n	),
    	.i2c_start	(i2c_start	),
    	.cfg_num	(cfg_num	),
    	.cfg_data	(cfg_data	),
    	.scl		(scl		),
    	.i2c_clk	(i2c_clk	),
    	.cfg_start	(cfg_start	),
    	.data_r		(data_r		),
    	.data_g		(data_g		),
    	.data_b		(data_b		),
    	.sda        (sda        )
    );
    
    cls381_cfg_ctrl  cls381_cfg_ctrl_inst
    (
    	.i2c_clk	(i2c_clk	),
    	.sys_rst_n	(sys_rst_n	),
    	.cfg_start	(cfg_start	),
    	.cfg_data	(cfg_data	),
    	.cfg_num	(cfg_num	),
    	.i2c_start	(i2c_start	)
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    Android ASM插桩探索及实战
    0034力扣67题---二进制求和
    Python 3.10里面的Match-Case语法详解
    v3 + ts 商城项目的支付模块
    Python标准库分享之文件管理 (部分os包,shutil包)
    STM32:TTL串口调试
    GIS前端—Popup标注视图
    RFSoC应用笔记 - RF数据转换器 -07- RFSoC关键配置之RF-DAC内部解析(一)
    MongoDB索引操作和执行计划Explain()详解
    接口测试入门必会知识总结(学习笔记)
  • 原文地址:https://blog.csdn.net/weixin_43828944/article/details/131093272