ZC-CLS381RGB颜色识别+8x8点阵指示——配置颜色识别寄存器组(上)


前言

  在现代工业生产中,颜色识别技术已经成为了一个非常重要的技术。颜色识别可以用于产品质量检测、物料分类、机器视觉等领域。本文将介绍如何使用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

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

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
  • 24
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值