ADT7420测温
0. 未理解的点
使用下面注释的代码会出现错误
//cnt_bit
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 3'd0;
else if(state == IDLE || state == START || state == ACK_1 || state == ACK_2 ||
state == RE_START || state == ACK_3 || state == MASTER_ACK ||
state == NO_ACK)
cnt_bit <= 3'd0;
else if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
cnt_bit <= 3'd0;
else if((cnt_i2c_clk == 2'd3) && (state != IDLE))
cnt_bit <= cnt_bit + 1'b1;
/* else if(state == STOP && cnt_i2c_clk == 2'd3 && cnt_bit == 3'd3)
cnt_bit <= 3'd0;
else if((state == SEND_D_ADDR || state == SEND_R_ADDR ||
state == RSEND_D_ADDR || state == RD_DATA_MSB || state == RD_DATA_LSB
|| state == STOP) && cnt_i2c_clk == 2'd3)
cnt_bit <= cnt_bit + 1'b1; */
体现在使用 ila 核抓取数据时
写设备地址和寄存器地址都出现了重复写的问题,导致后面状态无法转移
正常状态抓取
1. ADT7420简介
1.1 特性
ADT7420是基于 I2C 协议的16-bit数字温度传感器,精度为0.25摄氏度
其中,scl 的最高时钟频率可达 400kHz;
上电后默认工作在13-bit模式下;第一次快速转换在6ms后完成,精度为5摄氏度,此后240ms完成一次转换
1.2 引脚配置与原理图
原理图中 A1A0 = 11;
文档中有表述:
The five MSBs of this address for the ADT7420 are hardwired internally to 10010. Pin A1 and Pin A0 set the two LSBs.
即 7bit 设备地址为 10010_11
1.3 寄存器
全部的寄存器地址
在读取温度的过程中,主要关注温度高低位寄存器,即 0x00 和 0x01
正常读取的模式下,还需要指针寄存器 (pointer register) 的地址,但是读取完高位 (0x00) 的数据后,指针会自动指向下一个地址,即 0x01
温度寄存器
默认13-bit的情况下,主要关注 reg[15:3]
1.4 读写等操作时序
1.4.1 写单字节数据
1.4.2 写双字节数据
1.4.3 读配置寄存器数据
1.4.4 读温度寄存器数据
1.5 温度计算
符号判断 bits[15] = 0,正数;bits[15] = 1,负数;
数值计算 bits[14:3] * 0.0625
2. 系统框图
3. 状态转移图
定义的状态
4. 时序图
4.1 生成i2c_clk信号
4.2 i2c_sda 与 i2c_scl 等信号
5. 设计文件
5.1 i2c_adt7420.v
module i2c_adt7420
(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire i2c_sda ,
output wire i2c_scl ,
output wire [7:0] sel ,
output wire [7:0] seg
);
wire [26:0] rd_data;
i2c_adt7420_ctrl
#(
.DEVICE_ADDR ( 7'b1001_011 ),
.SYS_CLK_FREQ ( 'd100_000_000),
.SCL_FREQ ( 'd250_000 )
)
i2c_adt7420_ctrl_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.i2c_sda (i2c_sda ),
.i2c_scl (i2c_scl ),
.rd_data (rd_data )
);
seg_dynamic
#(
.CNT_MAX(17'd99_999)
)
seg_dynamic_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data (rd_data ),
.sel (sel ),
.seg (seg )
);
endmodule
5.2 i2c_adt7420_ctrl.v
module i2c_adt7420_ctrl
#(
parameter DEVICE_ADDR = 7'b1001_011 ,
parameter SYS_CLK_FREQ = 'd100_000_000,
parameter SCL_FREQ = 'd200_000
)
(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire i2c_sda ,
output reg i2c_scl ,
output reg [26:0] rd_data
);
parameter CNT_CLK_MAX = (SYS_CLK_FREQ / SCL_FREQ) >> 3;
parameter CNT_DELAY_MAX = 20'd125_000;
parameter IDLE = 4'd0,
START = 4'd1,
SEND_D_ADDR = 4'd2,
ACK_1 = 4'd3,
SEND_R_ADDR = 4'd4,
ACK_2 = 4'd5,
RE_START = 4'd6,
RSEND_D_ADDR = 4'd7,
ACK_3 = 4'd8,
RD_DATA_MSB = 4'd9,
MASTER_ACK = 4'd10,
RD_DATA_LSB = 4'd11,
NO_ACK = 4'd12,
STOP = 4'd13;
reg [19:0] cnt_delay ;
reg i2c_scl_reg ;
reg [7:0] cnt_clk ;
reg i2c_clk ;
reg [3:0] state ;
reg [1:0] cnt_i2c_clk ;
reg cnt_i2c_clk_en ;
reg [3:0] cnt_bit ;
wire sda_in ;
reg sda_out ;
wire sda_en ;
reg [15:0] rd_data_reg ;
reg ack ;
//cnt_clk
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 8'd0;
else if(cnt_clk == CNT_CLK_MAX - 1)
cnt_clk <= 8'd0;
else
cnt_clk <= cnt_clk + 1'b1;
//i2c_clk
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
i2c_clk <= 1'b1;
else if(cnt_clk == CNT_CLK_MAX - 1)
i2c_clk <= ~i2c_clk;
//cnt_delay 延时500ms,等待温度转换完成(初始6ms,正常240ms)
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_delay <= 20'd0;
else if(cnt_delay == CNT_DELAY_MAX - 1)
cnt_delay <= 20'd0;
else if(cnt_i2c_clk == 2'd3 && state == IDLE)
cnt_delay <= cnt_delay + 1'b1;
//state
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE ://0
if(cnt_delay == CNT_DELAY_MAX - 1)
state <= START;
else
state <= state;
START ://1
if(cnt_i2c_clk == 2'd3)
state <= SEND_D_ADDR;
else
state <= state;
SEND_D_ADDR ://2
if(cnt_i2c_clk == 2'd3 && cnt_bit == 3'd7)
state <= ACK_1;
else
state <= state;
ACK_1 ://3
if(cnt_i2c_clk == 2'd3 && ack == 1'b0)
state <= SEND_R_ADDR;
else
state <= state;
SEND_R_ADDR ://4
if(cnt_i2c_clk == 2'd3 && cnt_bit == 3'd7)
state <= ACK_2;
else
state <= state;
ACK_2 ://5
if(cnt_i2c_clk == 2'd3 && ack == 1'b0)
state <= RE_START;
else
state <= state;
RE_START :
if(cnt_i2c_clk == 2'd3)
state <= RSEND_D_ADDR;
else
state <= state;
RSEND_D_ADDR :
if(cnt_i2c_clk == 2'd3 && cnt_bit == 3'd7)
state <= ACK_3;
else
state <= state;
ACK_3 :
if(cnt_i2c_clk == 2'd3 && ack == 1'b0)
state <= RD_DATA_MSB;
else
state <= state;
RD_DATA_MSB :
if(cnt_i2c_clk == 2'd3 && cnt_bit == 3'd7)
state <= MASTER_ACK;
else
state <= state;
MASTER_ACK :
if(cnt_i2c_clk == 2'd3)
state <= RD_DATA_LSB;
else
state <= state;
RD_DATA_LSB :
if(cnt_i2c_clk == 2'd3 && cnt_bit == 3'd7)
state <= NO_ACK;
else
state <= state;
NO_ACK :
if(cnt_i2c_clk == 2'd3)
state <= STOP;
else
state <= state;
STOP ://13
if(cnt_i2c_clk == 2'd3 && cnt_bit == 3'd3)
begin
state <= IDLE;
//cnt_bit <= 3'd0;
end
else
state <= state;
default : state <= IDLE;
endcase
//cnt_i2c_clk
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_i2c_clk <= 2'd0;
//else if(cnt_i2c_clk_en == 1'b1)
else if(state == STOP && cnt_i2c_clk == 2'd3 && cnt_bit == 3'd3)
cnt_i2c_clk <= 2'd0;
else
cnt_i2c_clk <= cnt_i2c_clk + 1'b1;
//cnt_i2c_clk_en
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_i2c_clk_en <= 1'b0;
else if(state == STOP && cnt_i2c_clk == 2'd3 && cnt_bit == 3'd3)
cnt_i2c_clk_en <= 1'b0;
else if(state == IDLE && cnt_i2c_clk == 2'd3)
cnt_i2c_clk_en <= 1'b1;
//cnt_bit
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 3'd0;
else if(state == IDLE || state == START || state == ACK_1 || state == ACK_2 ||
state == RE_START || state == ACK_3 || state == MASTER_ACK ||
state == NO_ACK)
cnt_bit <= 3'd0;
else if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
cnt_bit <= 3'd0;
else if((cnt_i2c_clk == 2'd3) && (state != IDLE))
cnt_bit <= cnt_bit + 1'b1;
/* else if(state == STOP && cnt_i2c_clk == 2'd3 && cnt_bit == 3'd3)
cnt_bit <= 3'd0;
else if((state == SEND_D_ADDR || state == SEND_R_ADDR ||
state == RSEND_D_ADDR || state == RD_DATA_MSB || state == RD_DATA_LSB
|| state == STOP) && cnt_i2c_clk == 2'd3)
cnt_bit <= cnt_bit + 1'b1; */
//i2c_sda
assign i2c_sda = (sda_en == 1'b1) ? sda_out : 1'bz;
//sda_in
assign sda_in = i2c_sda;
//sda_out
always@(*)
case(state)
IDLE :
sda_out <= 1'b1;
START :
if(cnt_i2c_clk == 2'd0)
sda_out <= 1'b1;
else
sda_out <= 1'b0;
SEND_D_ADDR :
if(cnt_bit == 3'd7)
sda_out <= 1'b0;
else
sda_out <= DEVICE_ADDR[6 - cnt_bit];
ACK_1 :
sda_out <= 1'b0;
SEND_R_ADDR :
sda_out <= 1'b0;
ACK_2 :
sda_out <= 1'b1;
RE_START :
if(cnt_i2c_clk <= 2'd1)
sda_out <= 1'b1;
else
sda_out <= 1'b0;
RSEND_D_ADDR :
if(cnt_bit == 3'd7)
sda_out <= 1'b1;
else
sda_out <= DEVICE_ADDR[6 - cnt_bit];
ACK_3 :
sda_out <= 1'b1;
RD_DATA_MSB :
sda_out <= 1'b1;
MASTER_ACK :
sda_out <= 1'b0;
RD_DATA_LSB :
sda_out <= 1'b1;
NO_ACK :
sda_out <= 1'b1;
STOP :
if(cnt_bit == 3'd0 && cnt_i2c_clk < 2'd3)
sda_out <= 1'b0;
else
sda_out <= 1'b1;
default : sda_out <= 1'b1;
endcase
//sda_en
assign sda_en = (state == ACK_1 || state == ACK_2 || state == ACK_3 ||
state == RD_DATA_MSB || state == RD_DATA_LSB) ? 1'b0 : 1'b1;
//rd_data_reg[15:0]
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_data_reg <= 16'd0;
else case(state)
RD_DATA_MSB :
if(cnt_i2c_clk == 2'b1)
rd_data_reg[15 - cnt_bit] <= sda_in;
else
rd_data_reg <= rd_data_reg;
RD_DATA_LSB :
if(cnt_i2c_clk == 2'b1)
rd_data_reg[7 - cnt_bit] <= sda_in;
else
rd_data_reg <= rd_data_reg;
endcase
//rd_data
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_data <= 27'd0;
else if(state == RD_DATA_LSB && cnt_bit == 3'd7 && cnt_i2c_clk == 2'd3)
rd_data <= rd_data_reg[14:3] * 625;
//i2c_scl
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
i2c_scl <= 1'b1;
else if((cnt_i2c_clk == 2'd2 || cnt_i2c_clk == 2'd3) && (state != STOP)
&& (state != IDLE))
i2c_scl <= 1'b0;
else
i2c_scl <= 1'b1;
//ack
always@(*)
case(state)
ACK_1,ACK_2,ACK_3 :
if(cnt_i2c_clk == 2'b0)
ack <= sda_in;
else
ack <= ack;
default : ack <= 1'b1;
endcase
endmodule
5.3 seg_dynamic.v
module seg_dynamic
#(
parameter CNT_MAX = 17'd99_999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [26:0] data ,
output reg [7:0] sel ,
output reg [7:0] seg
);
wire [3:0] in ;
wire [3:0] ten ;
wire [3:0] hun ;
wire [3:0] tho ;
wire [3:0] ten_tho ;
wire [3:0] hun_tho ;
wire [3:0] mil ;
wire [3:0] must ;
reg [3:0] seg_data ;
reg [2:0] cnt_sel ;
reg [16:0] cnt_1ms ;
reg flag_1ms ;
//cnt_1ms:1ms循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1ms <= 17'd0;
else if(cnt_1ms == CNT_MAX)
cnt_1ms <= 17'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1ms <= 1'b0;
else if(cnt_1ms == CNT_MAX - 1'b1)
flag_1ms <= 1'b1;
else
flag_1ms <= 1'b0;
//cnt_sel:从0到7循环数,用于选择当前显示的数码管
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sel <= 3'd0;
else if((cnt_sel == 3'd7) && (flag_1ms == 1'b1))
cnt_sel <= 3'd0;
else if(flag_1ms == 1'b1)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= cnt_sel;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg_data <= 8'b0000_0011;
else
begin
case(cnt_sel)
3'd0: seg_data <= in ;
3'd1: seg_data <= ten ;
3'd2: seg_data <= hun ;
3'd3: seg_data <= tho ;
3'd4: seg_data <= ten_tho;
3'd5: seg_data <= hun_tho;
3'd6: seg_data <= mil ;
3'd7: seg_data <= must ;
endcase
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 8'b0111_1111;
else if(flag_1ms == 1'b1)
begin
case(cnt_sel)
3'd0: sel <= 8'b0111_1110;
3'd1: sel <= 8'b1111_1101;
3'd2: sel <= 8'b1111_1011;
3'd3: sel <= 8'b1111_0111;
3'd4: sel <= 8'b1110_1111;
3'd5: sel <= 8'b1101_1111;
3'd6: sel <= 8'b1011_1111;
3'd7: sel <= 8'b0111_1111;
endcase
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= 8'b0000_0011;
else if(flag_1ms == 1'b1)
begin
case(seg_data)
4'd0: seg <= 8'b0000_0011;
4'd1: seg <= 8'b1001_1111;
4'd2: seg <= 8'b0010_0101;
4'd3: seg <= 8'b0000_1101;
4'd4: seg <= 8'b1001_1001;
4'd5: seg <= 8'b0100_1001;
4'd6: seg <= 8'b0100_0001;
4'd7: seg <= 8'b0001_1111;
4'd8: seg <= 8'b0000_0001;
4'd9: seg <= 8'b0000_1001;
endcase
end
else
seg <= seg;
bcd_8421 bcd_8421_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data (data ),
.in (in ), //个
.ten (ten ), //十
.hun (hun ), //百
.tho (tho ), //千
.ten_tho (ten_tho ), //万
.hun_tho (hun_tho ), //十万
.mil (mil ), //百万
.must (must ) //千万
);
endmodule
5.4 bcd_8421.v
module bcd_8421
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [26:0] data ,
output reg [3:0] in , //个
output reg [3:0] ten , //十
output reg [3:0] hun , //百
output reg [3:0] tho , //千
output reg [3:0] ten_tho , //万
output reg [3:0] hun_tho , //十万
output reg [3:0] mil , //百万
output reg [3:0] must //千万
);
reg [4:0] cnt_shift ;
reg [58:0] data_shift ;
reg shift_flag ;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd28) && (shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_shift <= 59'd0;
else if(cnt_shift == 5'd0)
data_shift <= {32'b0,data};
else if((cnt_shift <= 5'd27) && (shift_flag == 1'b0))
begin
data_shift[30:27] <= (data_shift[30:27] > 4) ? (data_shift[30:27] + 2'd3) : (data_shift[30:27]);
data_shift[34:31] <= (data_shift[34:31] > 4) ? (data_shift[34:31] + 2'd3) : (data_shift[34:31]);
data_shift[38:35] <= (data_shift[38:35] > 4) ? (data_shift[38:35] + 2'd3) : (data_shift[38:35]);
data_shift[42:39] <= (data_shift[42:39] > 4) ? (data_shift[42:39] + 2'd3) : (data_shift[42:39]);
data_shift[46:43] <= (data_shift[46:43] > 4) ? (data_shift[46:43] + 2'd3) : (data_shift[46:43]);
data_shift[50:47] <= (data_shift[50:47] > 4) ? (data_shift[50:47] + 2'd3) : (data_shift[50:47]);
data_shift[54:51] <= (data_shift[54:51] > 4) ? (data_shift[54:51] + 2'd3) : (data_shift[54:51]);
data_shift[58:55] <= (data_shift[58:55] > 4) ? (data_shift[58:55] + 2'd3) : (data_shift[58:55]);
end
else if((cnt_shift <= 5'd27) && (shift_flag == 1'b1))
data_shift <= data_shift << 1;
else
data_shift <= data_shift;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
in <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
ten_tho <= 4'b0;
hun_tho <= 4'b0;
mil <= 4'b0;
must <= 4'b0;
end
else if(cnt_shift == 5'd28)
begin
in <= data_shift[30:27];
ten <= data_shift[34:31];
hun <= data_shift[38:35];
tho <= data_shift[42:39];
ten_tho <= data_shift[46:43];
hun_tho <= data_shift[50:47];
mil <= data_shift[54:51];
must <= data_shift[58:55];
end
endmodule
6. NEXYS4_DDR迪芝伦XC7A100TCSG324-1型的原理图与管脚绑定
此处的管脚只使用到 scl 与 sda
set_property IOSTANDARD LVCMOS33 [get_ports i2c_scl]
set_property IOSTANDARD LVCMOS33 [get_ports i2c_sda]
set_property PACKAGE_PIN C14 [get_ports i2c_scl]
set_property PACKAGE_PIN C15 [get_ports i2c_sda]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[0]}]
set_property PACKAGE_PIN E3 [get_ports sys_clk]
set_property PACKAGE_PIN J15 [get_ports sys_rst_n]
set_property PACKAGE_PIN J17 [get_ports {sel[0]}]
set_property PACKAGE_PIN J18 [get_ports {sel[1]}]
set_property PACKAGE_PIN T9 [get_ports {sel[2]}]
set_property PACKAGE_PIN J14 [get_ports {sel[3]}]
set_property PACKAGE_PIN P14 [get_ports {sel[4]}]
set_property PACKAGE_PIN T14 [get_ports {sel[5]}]
set_property PACKAGE_PIN K2 [get_ports {sel[6]}]
set_property PACKAGE_PIN U13 [get_ports {sel[7]}]
set_property PACKAGE_PIN H15 [get_ports {seg[0]}]
set_property PACKAGE_PIN L18 [get_ports {seg[1]}]
set_property PACKAGE_PIN T11 [get_ports {seg[2]}]
set_property PACKAGE_PIN P15 [get_ports {seg[3]}]
set_property PACKAGE_PIN K13 [get_ports {seg[4]}]
set_property PACKAGE_PIN K16 [get_ports {seg[5]}]
set_property PACKAGE_PIN R10 [get_ports {seg[6]}]
set_property PACKAGE_PIN T10 [get_ports {seg[7]}]