PAJ7620U2手势识别——读取0x00寄存器数据(4)


前言

  在之前的教程中,小编带领各位读者完成了手势识别模块PAJ7620U2的基本设置,本章教程通过读取0x00寄存器内的值,判断该值是否为0x20,如果是,则代表唤醒成功,如果不是,则代表唤醒失败,需要重新回到唤醒操作。具体的操作步骤请各位读者继续往下浏览。

一、为何要读取0x00寄存器内的值?

  相信有仔细阅读前面几节教程的读者,这个问题肯定是难不倒你们的。我们唤醒操作是否成功的标志就是,读取0x00寄存器内的值,看是否是0x20,如果不是则重新唤醒。但是经过小编的测试,如果前面每个模块的Singal Tap波形抓取无误,唤醒操作一般一次就可成功,因此按照小编的思路编写代码,是可以比较顺利实现功能的。

二、读取步骤

1.单个读操作步骤图

  根据官方数据手册:
在这里插入图片描述
  在上一章教程中,我们看的是前面写入从机地址和写入0x00数据这一部分,现在我们来看后一部分。这一部分的从机地址最后一位会发生变化,变为7位从机ID+1位读操作,从机地址发送完成后,主机放弃对SDA信号线的控制。这时,从机控制SDA信号线,向主机发送ACK响应数据,收到响应后,主机这时还是要将控制权交给从机,从机发送8bit的数据,主机读取这8bit的数据,从高到低依次拼接,看最后拼接成的数据是否为0x20,如果是的话,主机则获取对SDA信号线的控制,并返回一个高电平的NACK信号,发送给从机,最后结束。
  如果接收到的数据不是0x20,则代表唤醒失败,代码中的mode信号一定要清零,同时直接由DATA状态跳转到IDLE状态。

2.模块状态转移图绘制

在这里插入图片描述
  结合状态转移图,我们不难发现,多了一个新的状态:NACK,同时,DATA这个状态,在之前的模块中,是可以在这个状态,主机向从机发送数据,我们把这个过程叫做写入。也可以在DATA状态,从机向主机发送数据,我们把主机接收数据这个过程叫做读取。NACK可以理解为,主机收到从机发送的数据后,要给予从机一个回应,像我们向从机发送数据一样,从机也是需要给与主机一个ACK回应。但是ACK和NACK不同的是,从机返回的响应数据是低电平有效,主机返回的响应数据是高电平有效。

3.模块波形图绘制

在这里插入图片描述
  这里我们只绘制部分波形即可,前面初始状态和发送从设备地址状态因为在前面章节已经有绘制,在这里我们就不再赘述,如读者有遗忘,请移步前面几章的教程,查看波形图找回记忆。
  我们在这个波形图中,多引入了两个信号,一个是error_en错误信号,配合skip_en信号检测读取出来的数据是否是正确的,如果数据是0x20,则skip_en拉高,否则error_en拉高。另一个信号是rec_data信号,除了DATA状态,我们不关心其它时刻它的值为多少,因为不管值为多少,每次读取出来的1bit数据都会一个一个地把原有的数据顶替下去。根据以上的波形图,我们对原有的代码进行更改,然后上板抓取信号波形验证。

4.上板验证

  上板抓取信号波形,设置skip_en_4上升沿触发:
在这里插入图片描述
  抓取到的信号如下所示:
在这里插入图片描述
  如图所示,信号波形从IDLE状态到STOP状态,每个状态都有持续一段时间的高电平,且保持的时间与我们工程中设置的一样,在DATA状态为高电平时,采集到的数据为0x20,代表我们唤醒操作成功。

4.参考代码

module  i2c_ctrl
(
	input	wire			sys_clk		,
	input	wire			sys_rst_n	,
	
	output	wire			scl			,
	
	inout	wire			sda
);

localparam	CNT_CLK_MAX		=	5'd25	;
localparam	CNT_WAIT_MAX	=	10'd1000;
localparam	CNT_DELAY_MAX	=	10'd1000;
localparam	SENSOR_ADDR		=	8'hEF	;
localparam	SLAVE_ID		=	7'h73	;
localparam	RD_ADDR			=	8'h43	;
localparam	IDLE			=	'd0		,
			START			=	'd1		,
			SLAVE_ADDR		=	'd2		,
			ACK_1			=	'd3		,
			DEVICE_ADDR		=	'd4		,
			ACK_2			=	'd5		,
			DATA			=	'd6		,
			ACK_3			=	'd7		,
			STOP			=	'd8		,
			WAIT			=	'd9		,
			NACK			=	'd10	;
			
reg		[4:0]	cnt_clk		;	//分频计数器
reg				i2c_clk		;	//i2c分频后的驱动时钟
reg		[9:0]	cnt_wait	;	//开始状态等待1000us计数器
reg				skip_en_1	;	//唤醒状态跳转信号
reg				skip_en_2	;
reg				skip_en_3	;
reg				skip_en_4	;
reg				error_en	;
reg		[3:0]	n_state		;	//次态
reg		[3:0]	c_state		;	//现态	
reg		[1:0]	cnt_i2c_clk	;	//对i2c_clk分频时钟个数计数			
reg		[2:0]	cnt_bit		;	//对传输的8bit数据进行计数	
reg				i2c_scl		;	//就是SCL		
reg				i2c_sda		;	//SDA赋值给i2c_sda
reg		[9:0]	cnt_delay	;	//发送完指令后等待1000us计数器		
reg		[3:0]	mode		;	//模式选择		
reg				i2c_end		;	//i2c结束信号
reg		[7:0]	rec_data	;	//接收的数据,用来判断是否为0x20	
reg				ack			;
reg 	[7:0]	slave_addr	;
reg 	[7:0]	device_addr	;
reg 	[7:0]	wr_addr		;
wire			sda_in		;
wire			sda_en		;

assign	scl		=	i2c_scl		;
assign	sda_in	=	sda			;	//从设备发送到主机的数据
assign	sda_en	=	((c_state == ACK_1)||(c_state == ACK_2)||(c_state == ACK_3)||(c_state == DATA&&mode == 3'd3)) ? 1'b0 : 1'b1  ;	//主机控制sda有效
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	
		3'd3	:	begin
						slave_addr	<=  {SLAVE_ID,1'b1}  ;	//读取00寄存器的值
					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  ;
	
//产生i2c驱动时钟	
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)||(skip_en_4 == 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)||(skip_en_4 == 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)||(skip_en_4 == 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  if(skip_en_4 == 1'b1)
							n_state  =  DATA  ; 
						else
							n_state  =  ACK_1  ;
		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  if(skip_en_4 == 1'b1)
							n_state  =  NACK  ;
						else  if(error_en == 1'b1)
							n_state  =  IDLE  ;
						else
							n_state  =  DATA  ;
		ACK_3		:	if(skip_en_2 == 1'b1)
							n_state  =  STOP  ;
						else
							n_state  =  ACK_3  ;
		WAIT		:	if(skip_en_1 == 1'b1)
							n_state  =  STOP  ;
						else
							n_state  =  WAIT  ;
		NACK		:	if(skip_en_4 == 1'b1)
							n_state  =  STOP  ;
						else
							n_state  =  NACK  ;
	    STOP		:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1)||(skip_en_4 == 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	;
			skip_en_4	<=  1'b0	;
			error_en	<=  1'b0	;
			cnt_i2c_clk	<=  2'd0	;
			cnt_bit		<=  3'd0	;
			cnt_delay	<=  10'd0	;
			mode		<=  3'd0	;
			i2c_end		<=  1'b0	;
		end
	else
		case(c_state)
			IDLE		:begin
							cnt_wait  <=  cnt_wait + 1'b1  ;
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd0))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;	
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd2))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;		
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd3))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  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  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd3))
								skip_en_4  <=  1'b1  ;
						    else
								skip_en_4  <=  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)&&(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  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd3))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  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  ;	
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd3))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  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  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd3)&&(rec_data == 8'h20))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd3)&&(rec_data != 8'h20))
								begin
									error_en  <=  1'b1  ;
									mode	  <=  3'd0  ;
								end
							else
								begin
									error_en  <=  1'b0  ;
									mode	  <=  mode  ;
								end	
						 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
							if((cnt_delay == CNT_DELAY_MAX - 2'd2)&&(mode == 3'd0))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							cnt_delay  <=  cnt_delay + 1'b1  ;
						 end
			NACK		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((ack == 1'b1)&&(cnt_i2c_clk == 2'd2)&&(mode == 3'd3))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;							
						 end
			STOP		: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  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd3))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;	
							if(cnt_i2c_clk == 2'd2)
								i2c_end  <=  1'b1  ;
							else
								i2c_end  <=  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	;
							skip_en_3	<=  1'b0	;
							skip_en_4   <=  1'b0	;
							error_en	<=  1'b0	;
							cnt_i2c_clk	<=  2'd0	;
							cnt_bit		<=  3'd0	;
							cnt_delay	<=  10'd0	;
							mode		<=  mode	;
							i2c_end		<=  1'b0	;
						 end
		endcase
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rec_data  <=  8'd0  ;
	else
		case(c_state)
			DATA	:	if((mode == 3'd3)&&(cnt_i2c_clk == 2'd1))
							rec_data  <=  {rec_data[6:0],sda_in}  ;
						else
							rec_data  <=  rec_data  ;
			default	:	rec_data  <=  rec_data  ;
		endcase

always@(*)
	case(c_state)
		ACK_1,ACK_2,ACK_3	:	ack  <=  ~sda_in  ;
		NACK				:	ack  <=  i2c_sda  ;
		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,NACK:
						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_DELAY_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  ;
		WAIT,NACK	:	i2c_sda  <=  1'b1  ;
		DEVICE_ADDR	:	i2c_sda  <=  device_addr[7-cnt_bit]  ;
		DATA		:	if((mode == 3'd3)||(mode == 3'd6))
							i2c_sda  <=  sda_in  ;
						else
							i2c_sda  <=  wr_addr[7-cnt_bit]  ;
		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寄存器内的数据,根据抓取的波形图来看,读取出来的数据是0x20,因此证明我们的唤醒操作是成功的。本章教程到此结束,下一章教程是:PAJ7620U2手势识别——配置寄存器组(5)。如果各位读者朋友对本教程有疑问,可以将问题留言,小编看到后会及时为大家解答,谢谢大家支持。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值