在前面的教程中,小编带领各位读者学习了如何通过I2C协议去唤醒PAJ7620U2,如何激活BANK0。本章教程,小编会继续一步一步带领各位读者,继续学习如何配置0x00寄存器,具体操作请仔细阅读本章教程。
在回答这个问题之前,我们先看一下正点原子给的该模块的文档:
这里参考的文档,在上一章有为各位读者进行简单讲解,这里小编再详细讲解一下。在我们激活BANK0以后,我们是向里面写入了0x00数据,读者需要注意的是,这里写入的0x00不是寄存器地址,而是数值。如果激活BANK1,写入的数值就是0x01了。因此,我们还需要再次写入0x00数据,这里就表示写入的是0x00寄存器,将0x00寄存器配置好,便于我们后续读取操作。
参考官方数据手册,我们需要用到单个读指令:
当然,本指令我们需要拆分成两部分来看,我们先看第一部分,第一部分是配置0x00寄存器,首先发送从设备地址,从设备地址为从设备ID+W(WRITE)操作,发送完成后返回一个ACK响应,ACK响应正确后,发送0X00数据,这里的0x00代表寄存器地址是0x00,发送完成后返回一个ACK响应,ACK响应正确,跳转到结束状态,配置0x00寄存器结束。
结合状态转移图,我们发现,这个状态转移和激活BANK0的状态转移图类似,因此在这里我们就再赘述,读者若有遗忘请参考如何激活BANK0,即上一章教程。
参考状态转移图,绘制出的波形图如下所示:
这里呢,我们也只绘制部分波形图即可,即空闲状态延迟1000us后跳转到开始状态,检测到开始信号有效后,跳转到发送从设备地址状态,从设备地址发送成功,跳转到接收从机发送的响应状态。后续从机发送的响应有效,跳转到发送0x00数据,即发送0x00寄存器地址状态,发送完成后再跳转到接收从机的响应状态,最后结束。因为最后的发送数据和接收响应这两个状态,与前面状态变化一致,因此参考上述波形图即可在原来的代码的基础上修改、编写代码。
上板抓取信号波形,我们设置skip_en_3上升沿为触发条件:
从抓取到的信号波形图可以看出,我们工程中设定的IDLE状态到STOP状态都有跳转,都有持续一段时间的高电平且持续时间与我们工程中所设置的一致。在结束状态,结束信号拉高,模式自增1,表示配置0x00寄存器这个模式结束,跳转到下一个配置模式。因此上板验证成功。
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),敬请期待。