使用verilog写了一个P3T1750DP温度传感器的驱动代码,但是测量出来的温度只有上电后第一次采集的是准的,后面采集回来的都是不准了。工程代码如下:
top.v
module top(
input pl_ref_clk_100m_p ,
input pl_ref_clk_100m_n ,
output ex_i2c_scl ,
inout ex_i2c_sda
);
wire p3t1750dp_en;
wire clk_100m;
wire rst_n;
wire p3t1750dp_done;
wire [15:0] temp_out;
wire [7:0] p3t1750dp_addr,p3t1750dp_pointer;
vio_0 vio_0 (
.clk(clk_100m), // input wire clk
.probe_out0(p3t1750dp_en), // output wire [0 : 0] probe_out0
.probe_out1(p3t1750dp_addr), // output wire [7 : 0] probe_out1
.probe_out2(p3t1750dp_pointer), // output wire [7 : 0] probe_out2
.probe_out3(rst_n) // output wire [0 : 0] probe_out2
);
p3t1750dp p3t1750dp(
.clk_100m (clk_100m ),
.rst_n (rst_n ),
.p3t1750dp_en (p3t1750dp_en ),
.p3t1750dp_addr (p3t1750dp_addr ),
.p3t1750dp_pointer(p3t1750dp_pointer),
.scl (ex_i2c_scl ),
.sda (ex_i2c_sda ),
.p3t1750dp_done (p3t1750dp_done ),
.temp_out (temp_out )
);
IBUFDS clk_100m_ibufds(
.O (clk_100m ),
.I (pl_ref_clk_100m_p ),
.IB (pl_ref_clk_100m_n )
);
endmodule
p3t1750dp.v模块参照官方的时序Figure 19. Read register including pointer byte (2-byte data)写的。
module p3t1750dp(
input clk_100m ,
input rst_n ,
input p3t1750dp_en ,
input [7:0] p3t1750dp_addr ,
input [7:0] p3t1750dp_pointer,
(* MARK_DEBUG="true" *)output scl ,
inout sda ,
(* MARK_DEBUG="true" *)output p3t1750dp_done ,
(* MARK_DEBUG="true" *)output reg [15:0] temp_out
);
localparam SCL_NUM = 64;
(* MARK_DEBUG="true" *)reg [$clog2(SCL_NUM) -1:0] cnt_scl ; // 100MHz/64=1.5625MHz
reg p3t1750dp_en_d ;
(* MARK_DEBUG="true" *)wire scl_high ;
(* MARK_DEBUG="true" *)wire neg_scl ;
(* MARK_DEBUG="true" *)wire scl_low ;
(* MARK_DEBUG="true" *)wire scl_done ;
assign scl_high = (cnt_scl == ((SCL_NUM >>2) -1));
assign neg_scl = (cnt_scl == ((SCL_NUM >>1) -1));
assign scl_low = (cnt_scl == (SCL_NUM -(SCL_NUM >>2) -1));
assign scl = (!cnt_scl[$clog2(SCL_NUM) -1]);
assign scl_done = (&cnt_scl);
always @(posedge clk_100m or negedge rst_n) begin
if(!rst_n)begin
p3t1750dp_en_d <= 1'b0;
cnt_scl <= 'd0;
end
else begin
p3t1750dp_en_d <= p3t1750dp_en;
cnt_scl <= p3t1750dp_en_d ? (cnt_scl + 'd1) : 'd0;
end
end
(* MARK_DEBUG="true" *)reg [5:0] bit_cnt ;
(* MARK_DEBUG="true" *)reg [15:0] read_data ;
reg sda_o ;
reg sda_en_d,master_ack_d,slave_ack_d ;
wire sda_i ;
wire sda_en ;
wire start ; //1 20
wire addr_w ; //2-9
wire pointer ; //11-18
wire slave_ack ; //10 19 29
wire addr_r ; //21-28
wire read_byte1 ; //30-37
wire master_ack ; //38 47
wire read_byte2 ; //39-46
wire stop ; //48
wire idle ; //49
wire [7:0] address_w,address_r;
assign sda_i = sda;
assign sda_en = (start | addr_w | pointer | addr_r | master_ack | stop | idle);
assign sda = sda_en_d ? sda_o : 1'bz;
assign address_w= {p3t1750dp_addr[6:0],1'b0}; // write
assign address_r= {p3t1750dp_addr[6:0],1'b1}; // read
assign p3t1750dp_pointer = 8'h00;
assign p3t1750dp_done = (stop & scl_high);
assign start = ((bit_cnt == 'd0)|(bit_cnt == 'd19)); //1 20
assign addr_w = ((bit_cnt >= 'd1)&(bit_cnt <= 'd8)); //2-9
assign pointer = ((bit_cnt >= 'd10)&(bit_cnt <= 'd17)); //11-18
assign slave_ack = ((bit_cnt == 'd9)|(bit_cnt == 'd18)|(bit_cnt == 'd28)); //10 19 29
assign addr_r = ((bit_cnt >= 'd20)&(bit_cnt <= 'd27)); //21-28
assign read_byte1 = ((bit_cnt >= 'd29)&(bit_cnt <= 'd36)); //30-37
assign master_ack = ((bit_cnt == 'd37)|(bit_cnt == 'd46)); //38 47
assign read_byte2 = ((bit_cnt >= 'd38)&(bit_cnt <= 'd45)); //39-46
assign stop = (bit_cnt == 'd47); //48
assign idle = (bit_cnt == 'd48); //49
always @(posedge clk_100m or negedge rst_n) begin
if(!rst_n)
bit_cnt <= 'd0;
else if(neg_scl)
if(idle)
bit_cnt <= 'd0;
else
bit_cnt <= (bit_cnt + 'd1);
else
bit_cnt <= bit_cnt;
end
always @(posedge clk_100m or negedge rst_n) begin
if(!rst_n)begin
master_ack_d <= 1'b0;
slave_ack_d <= 1'b0;
sda_en_d <= 1'b0;
temp_out <= 'd0;
end
else begin
master_ack_d <= master_ack;
slave_ack_d <= slave_ack;
sda_en_d <= sda_en;
temp_out <= p3t1750dp_done ? read_data : temp_out;
end
end
always@(posedge clk_100m or negedge rst_n)begin
if(!rst_n)
sda_o <= 1'd1;
else if(start)// 1 20
sda_o <= scl_high ? 1'b0 : sda_o;
else if(addr_w)// 2-9
sda_o <= scl_low ? address_w[8 - bit_cnt] : sda_o;
else if(slave_ack)
sda_o <= 1'b1;
else if(pointer)// 11-18
sda_o <= scl_low ? p3t1750dp_pointer[17 - bit_cnt] : sda_o;
else if(addr_r)// 21-28
sda_o <= scl_low ? address_r[27 - bit_cnt] : sda_o;
else if(master_ack)
if(scl_low)// 38 47
sda_o <= (bit_cnt == 'd37) ? 1'b0 : 1'b1;
else
sda_o <= ((bit_cnt == 'd46)& neg_scl) ? 1'b0 : sda_o;
else if(stop)// 48
sda_o <= scl_high ? 1'b1 : sda_o;
else if(idle)// 49
sda_o <= 1'b1;
else
sda_o <= sda_o;
end
always@(posedge clk_100m or negedge rst_n)begin
if(!rst_n)
read_data <= 'd0;
else
read_data <= ((read_byte1 | read_byte2)& scl_high) ? {read_data[14:0],sda_i} : read_data;
end
endmodule
测试时ila设置抓取p3t1750dp_done 的上升沿。
vio依次配置p3t1750dp_addr(硬件上设置器件地址为0x00),p3t1750dp_pointer(指向温度传感器寄存测量结果的寄存器),拉高rst_n信号,最后打开p3t1750dp_en(iic开始和器件通讯)。
第一次触发抓到的结果,温度数据为高12bit,7520右移4位后为470,器件测量精度为0.0625,所以第一次测量结果为:470*0.0625=29.375℃。
第二次触发的测量结果:结果直接变负数了
|