前言
在前一章教程中,小编带领各位读者通过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结束,跳转到另一个模式。因此我们编写的代码验证通过。文章来源:https://www.toymoban.com/news/detail-476764.html
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),敬请期待。文章来源地址https://www.toymoban.com/news/detail-476764.html
到了这里,关于PAJ7620U2手势识别——激活BANK0(2)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!