PAJ7620U2手势识别——激活BANK0(2)

PAJ7620U2手势识别——激活BANK0(2)本文详细介绍了为何需要激活 BANK0 以及如何通过 I2C 协议的单个写操作步骤 模块状态转移图和波形图来实现激活


前言

  在前一章教程中,小编带领各位读者通过I2C协议配置了手势识别模块当中,较简单的唤醒操作。在本章教程中,小编会继续带领各位读者继续配置PAJ7620U2手势识别模块,本章主要是讲解如何激活BANK0,详细操作请各位读者继续浏览下去。

一、为啥要激活BANK0?

  相信很多读者都会有这样的疑问,我们参考一下正点原子提供的文档教程:

在这里插入图片描述
  同时参考一下官方的文档:

在这里插入图片描述
  我们发现,在手势识别内部是有很多寄存器的,但是官方和正点原子教程只列出了一部分寄存器,而这些寄存器呢,是分布在两个BANK区域。如果操作者要想访问某个寄存器,则需要先要激活该寄存器对应的BANK区域,激活之后才能访问。小编在前一章教程中列出了使用这个模块的部分操作步骤,现在我们接着看官方教程:

在这里插入图片描述

  这里说明了,唤醒操作结束后,需要访问0x00寄存器,读取其内部数据,看读取出来的数据是否为0x20.如果是0x20的话,则代表唤醒操作成功,如果不为0x20,则代表唤醒失败,继续重新唤醒。但是0x00寄存器,归属于BANK0区域,上电后BANK0区域是未被激活的,因此首先要激活BANK0区域,激活后才可以访问内部的0x00寄存器,从而根据返回值来判断是否激活成功。

二、激活步骤

1.单个写操作步骤图

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

在这里插入图片描述

2.模块状态转移图绘制

在这里插入图片描述
  结合模块状态转移图我们可以大致了解整个过程:初始状态延迟1000us后,跳转到开始状态,检测到开始信号后,跳转到发送从设备地址状态,从设备地址8’b1110_0110发送成功,返回一个响应值。检测到响应值有效,跳转到发送BANK0地址,BANK0地址8’b1110_1111发送完成之后,又接收到一个响应值。检测到响应值有效,跳转到发送寄存器地址状态,寄存器地址0x00数据发送完成,接收到响应信号,响应信号有效,跳转到停止状态。

3.模块波形图绘制

  首先,是模块的空闲状态和起始状态:
在这里插入图片描述
  空闲状态延迟1000us后,跳转到开始状态,在SCL信号为高电平,SDA信号发生下降沿变化时,跳转到发送从设备地址状态。从设备地址状态如下:

在这里插入图片描述
  从设备地址8’b1110_0110发送完成,主机即FPGA放弃对SDA总线的控制,从机PAJ7620U2控制SDA总线,接收到主机发送的数据以后向主机发送一个ACK响应信号,如果响应信号取反为高电平,则代表从机返回的是有效的响应数据,反之无效,主机发送的数据从机没有接收到。ACK响应状态如下:

在这里插入图片描述
  响应数据有效,跳转到发送BANK0地址状态,因为后续发送BANK0地址并响应和发送寄存器0x00地址并响应,与上述发送从机地址并响应的波形图一致,因此后续的波形图我们不再绘制。只需要参考上述波形图即可在唤醒操作基础上修改代码,比起唤醒操作,激活BANK0操作只是多了几个状态,信号基本没有发生多少变化。

4.上板验证

  上板抓取信号波形,设置skip_en_2上升沿为出发条件,设置如下:

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

在这里插入图片描述
  我们发现,从IDLE状态到STOP状态,每个状态高电平持续情况都是按照我们所设置的进行变化,且在STOP状态下,结束信号拉高,模式自增1,表示配置BANK0结束,跳转到另一个模式。因此我们编写的代码验证通过。

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 [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 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)) n_state <= START ; else n_state <= IDLE ; START : if((skip_en_1 == 1'b1)||(skip_en_2 == 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) n_state <= ACK_1 ; else n_state <= SLAVE_ADDR ; ACK_1 : if(skip_en_2 == 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) n_state <= ACK_2 ; else n_state <= DEVICE_ADDR ; ACK_2 : if(skip_en_2 == 1'b1) n_state <= DATA ; 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)) 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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(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 

总结

  以上就是激活BANK0操作流程,各位读者可以作一个参考,绘制出波形图,写出代码后抓取波形,观察波形变化是否与本教程一致,若有误差再利用Singal Tap抓取波形修改。下一篇文章将为各位读者讲解:PAJ7620U2手势识别——配置0x00寄存器(3),敬请期待。

今天的文章 PAJ7620U2手势识别——激活BANK0(2)分享到此就结束了,感谢您的阅读。
编程小号
上一篇 2024-12-13 22:17
下一篇 2024-12-13 22:11

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/85057.html