PAJ7620U2手势识别——配置0x00寄存器(3)


前言

  在前面的教程中,小编带领各位读者学习了如何通过I2C协议去唤醒PAJ7620U2,如何激活BANK0。本章教程,小编会继续一步一步带领各位读者,继续学习如何配置0x00寄存器,具体操作请仔细阅读本章教程。

一、为啥要配置0x00寄存器?

  在回答这个问题之前,我们先看一下正点原子给的该模块的文档:

在这里插入图片描述
  这里参考的文档,在上一章有为各位读者进行简单讲解,这里小编再详细讲解一下。在我们激活BANK0以后,我们是向里面写入了0x00数据,读者需要注意的是,这里写入的0x00不是寄存器地址,而是数值。如果激活BANK1,写入的数值就是0x01了。因此,我们还需要再次写入0x00数据,这里就表示写入的是0x00寄存器,将0x00寄存器配置好,便于我们后续读取操作。

二、配置步骤

1.单个读操作步骤图

  参考官方数据手册,我们需要用到单个读指令:

在这里插入图片描述
  当然,本指令我们需要拆分成两部分来看,我们先看第一部分,第一部分是配置0x00寄存器,首先发送从设备地址,从设备地址为从设备ID+W(WRITE)操作,发送完成后返回一个ACK响应,ACK响应正确后,发送0X00数据,这里的0x00代表寄存器地址是0x00,发送完成后返回一个ACK响应,ACK响应正确,跳转到结束状态,配置0x00寄存器结束。

2.模块状态转移图绘制

在这里插入图片描述

  结合状态转移图,我们发现,这个状态转移和激活BANK0的状态转移图类似,因此在这里我们就再赘述,读者若有遗忘请参考如何激活BANK0,即上一章教程。

3.模块波形图绘制

  参考状态转移图,绘制出的波形图如下所示:

在这里插入图片描述
  这里呢,我们也只绘制部分波形图即可,即空闲状态延迟1000us后跳转到开始状态,检测到开始信号有效后,跳转到发送从设备地址状态,从设备地址发送成功,跳转到接收从机发送的响应状态。后续从机发送的响应有效,跳转到发送0x00数据,即发送0x00寄存器地址状态,发送完成后再跳转到接收从机的响应状态,最后结束。因为最后的发送数据和接收响应这两个状态,与前面状态变化一致,因此参考上述波形图即可在原来的代码的基础上修改、编写代码。

4.上板验证

  上板抓取信号波形,我们设置skip_en_3上升沿为触发条件:

在这里插入图片描述
  抓取到的信号波形如下所示:

在这里插入图片描述
  从抓取到的信号波形图可以看出,我们工程中设定的IDLE状态到STOP状态都有跳转,都有持续一段时间的高电平且持续时间与我们工程中所设置的一致。在结束状态,结束信号拉高,模式自增1,表示配置0x00寄存器这个模式结束,跳转到下一个配置模式。因此上板验证成功。

5.参考代码

module  i2c_ctrl
#(
	parameter	SLAVE_ID	=	7'b111_0011		,
				SENSOR_ADDR	=	8'hEF			,
				SYS_CLK_FREQ=	26'd50_000_000	,
				SCL_FREQ	=	23'd250_000
)                                                                                                              
(
	input	wire			sys_clk		,
	input	wire			sys_rst_n	,
	
	output	wire			scl			,
	
	inout	wire			sda		
);

localparam	CNT_CLK_MAX		=	(SYS_CLK_FREQ/SCL_FREQ) >> 2'd3  ;
localparam	CNT_T1_MAX		=	'd1000  ,
			CNT_T2_MAX		=	'd1000	;
parameter	IDLE			=	'd0		,
			START			=	'd1		,
			SLAVE_ADDR		=	'd2		,
			ACK_1			=	'd3		,
			DEVICE_ADDR		=	'd4		,
			ACK_2			=	'd5		,
			DATA			=	'd6		,
			ACK_3			=	'd7		,
			WAIT			=	'd8		,
			STOP			=	'd9		;	
			
reg		[4:0]	n_state		;
reg		[4:0]	c_state		;
reg		[4:0]	cnt_clk		;
reg				i2c_clk		;
reg				skip_en_1	;
reg				skip_en_2	;
reg				skip_en_3	;
reg		[9:0]	cnt_wait	;
reg				i2c_scl		;
reg				i2c_sda		;
reg				i2c_end		;
reg		[1:0]	cnt_i2c_clk	;
reg		[2:0]	cnt_bit		;
reg				ack			;
reg		[9:0]	cnt_delay	;
reg		[2:0]	mode		;
reg		[7:0]	slave_addr	;
reg		[7:0]	device_addr	;
reg		[7:0]	wr_addr		;
wire			sda_en		;
wire			sda_in		;

assign	scl		=	i2c_scl		;
assign	sda_in	=	sda			;
assign	sda_en	=	((c_state == ACK_1)||(c_state == ACK_2)||(c_state == ACK_3)) ? 1'b0 : 1'b1  ;
assign	sda		=	(sda_en == 1'b1) ? i2c_sda : 1'bz  ;

always@(*)
	case(mode)
		3'd0	:	begin
						slave_addr	<=  {SLAVE_ID,1'b0}  ;	//激活
						device_addr	<=  8'd0  ;
						wr_addr		<=  8'd0  ;					
					end
		3'd1	:	begin
						slave_addr	<=  {SLAVE_ID,1'b0}  ;	//写入0xEF 00
						device_addr	<=  SENSOR_ADDR  ;
						wr_addr		<=  8'd0  ;					
					end		
		3'd2	:	begin
				 		slave_addr	<=  {SLAVE_ID,1'b0}  ;	//写入00寄存器	
				 		device_addr	<=  8'b0000_0000  ;	
					end	
		default	:	begin
						slave_addr	<=  slave_addr   ;			
						device_addr	<=	device_addr  ;	
						wr_addr		<=	wr_addr		 ; 
					end
    endcase

///生成i2c设备驱动时钟/
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)
		c_state  <=  IDLE  ;
	else
		c_state  <=  n_state  ;
		
//状态机第二段
always@(*)
	case(c_state)
		IDLE		:	if((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_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_1 == 1'b1)
							n_state  <=  WAIT  ;
						else  if((skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  <=  ACK_1  ;
						else
							n_state  <=  SLAVE_ADDR  ;
		ACK_1		:	if((skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  <=  DEVICE_ADDR  ;
						else
							n_state  <=  ACK_1  ;
		WAIT		:	if(skip_en_1 == 1'b1)
							n_state  <=  STOP  ;
						else
							n_state  <=  WAIT  ;
		DEVICE_ADDR	:	if((skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  <=  ACK_2  ;
						else
							n_state  <=  DEVICE_ADDR  ;
		ACK_2		:	if(skip_en_2 == 1'b1)
							n_state  <=  DATA  ;
						else  if(skip_en_3 == 1'b1)
							n_state  <=  STOP  ;
						else
							n_state  <=  ACK_2  ;
		DATA		:	if(skip_en_2 == 1'b1)
							n_state  <=  ACK_3  ;
						else
							n_state  <=  DATA  ;
		ACK_3		:	if(skip_en_2 == 1'b1)
							n_state  <=  STOP  ;
						else
							n_state  <=  ACK_3  ;
		STOP		:	if((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
			cnt_wait  	<=  10'd0  	;
			skip_en_1	<=  1'b0    ;
			skip_en_2   <=  1'b0	;
			skip_en_3   <=  1'b0	;
			cnt_i2c_clk	<=  2'd0	;
			cnt_bit		<=  3'd0	;
			i2c_end		<=  1'b0	;
			mode		<=  3'd0	;
			cnt_delay	<=  10'd0	;
		end
	else
		case(c_state)
			IDLE		:begin
							if(cnt_wait == CNT_T1_MAX - 1'b1)
								cnt_wait  <=  10'd0  ;
							else
								cnt_wait  <=  cnt_wait + 1'b1  ;
							if((cnt_wait == CNT_T1_MAX - 2'd2)&&(mode == 3'd0))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_wait == CNT_T1_MAX - 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_wait == CNT_T1_MAX - 2'd2)&&(mode == 3'd2))
								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)&&(mode == 3'd0))
								skip_en_1  <=  1'b1  ;
						    else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
						    else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd2))
								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 == 3'd7))
								cnt_bit  <=  3'd0  ;
							else  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)&&(mode == 3'd0))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd2))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
						 end
			ACK_1		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd2))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
						 end
		    DEVICE_ADDR	:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd3)&&(cnt_bit == 3'd7))
								cnt_bit  <=  3'd0  ;
							else  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)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd2))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
						 end
			ACK_2		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd2))
								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 == 3'd7))
								cnt_bit  <=  3'd0  ;
							else  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)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;								
						 end
			ACK_3		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;							
						 end
			WAIT		:begin
							cnt_delay  <=  cnt_delay + 1'b1  ;
							if(cnt_delay == CNT_T2_MAX - 2'd2)
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
						 end
		    STOP		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if(cnt_i2c_clk == 2'd2)
								i2c_end  <=  1'b1  ;
							else
								i2c_end  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd0))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd2))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;
							if(i2c_end == 1'b1)
								mode  <=  mode + 1'b1  ;
							else
								mode  <=  mode  ;
						 end
			default		:begin
							cnt_wait 	<=  10'd0	;
							skip_en_1	<=	1'b0	;
							skip_en_2	<=  1'b0	;
							cnt_i2c_clk	<=  2'd0	;
							cnt_bit		<=  3'd0	;
							i2c_end		<=  1'b0	;
							mode		<=  mode	;
							cnt_delay	<=  10'd0	;
						 end
		endcase
		
always@(*)	
	case(c_state)
		ACK_1,ACK_2,ACK_3	:	ack  <=  ~sda_in  ;
		default	:	ack  <=  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,ACK_1,DEVICE_ADDR,ACK_2,DATA,ACK_3:
						if((cnt_i2c_clk == 2'd1)||(cnt_i2c_clk == 2'd2))
							i2c_scl  <=  1'b1  ;
						else
							i2c_scl  <=  1'b0  ;
		WAIT		:	if((cnt_delay == 10'd0)||(cnt_delay == CNT_T2_MAX - 1'b1))
							i2c_scl  <=  1'b0  ;
						else
							i2c_scl  <=  1'b1  ;
		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)
							i2c_sda  <=  1'b1  ;
						else
							i2c_sda  <=  1'b0  ;
		SLAVE_ADDR	:	i2c_sda  <=  slave_addr[7-cnt_bit]  ;
		ACK_1,ACK_2,ACK_3:	
						i2c_sda  <=  1'b0  ;
		DEVICE_ADDR	:	i2c_sda  <=  device_addr[7-cnt_bit]  ;
		DATA		:	i2c_sda	 <=  wr_addr[7-cnt_bit]  ;
		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

总结

  本章教程带领各位读者学习了如何配置0x00寄存器,如果各位读者在之前已经配置好了BANK0,相信这一章教程在大家眼里是非常简单的。当然如果各位读者未配置成功也不用焦躁,请大家参考本文提供的状态转移图和波形图一步一步地对照自己的波形查找错误,加以修改。下一章要讲解的是:PAJ7620U2手势识别——读取0x00寄存器数据(4),敬请期待。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值