1nnocet- 发表于 2024-12-28 16:50

温度传感器只有第一次采集的是准的是怎么回事?

<p>&nbsp; &nbsp; 使用verilog写了一个P3T1750DP温度传感器的驱动代码,但是测量出来的温度只有上电后第一次采集的是准的,后面采集回来的都是不准了。工程代码如下:</p>

<p>top.v</p>

<pre>
<code>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          temp_out;
    wire           p3t1750dp_addr,p3t1750dp_pointer;

vio_0 vio_0 (
.clk(clk_100m),                // input wire clk
.probe_out0(p3t1750dp_en),// output wire probe_out0
.probe_out1(p3t1750dp_addr),// output wire probe_out1
.probe_out2(p3t1750dp_pointer),// output wire probe_out2
.probe_out3(rst_n)// output wire 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</code></pre>

<p>p3t1750dp.v模块参照官方的时序<span style="color:#1abc9c;">Figure 19. Read register including pointer byte (2-byte data)</span>写的。</p>

<p> &nbsp;</p>

<pre>
<code>module p3t1750dp(
    input               clk_100m      ,
    input               rst_n         ,
   
    input               p3t1750dp_en    ,
    input      p3t1750dp_addr,
    input      p3t1750dp_pointer,
    (* MARK_DEBUG="true" *)output            scl             ,
    inout               sda             ,
    (* MARK_DEBUG="true" *)output            p3t1750dp_done,
    (* MARK_DEBUG="true" *)output reg    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 &gt;&gt;2) -1));
    assign neg_scl= (cnt_scl == ((SCL_NUM &gt;&gt;1) -1));
    assign scl_low= (cnt_scl == (SCL_NUM -(SCL_NUM &gt;&gt;2) -1));
    assign scl      = (!cnt_scl[$clog2(SCL_NUM) -1]);
    assign scl_done = (&amp;cnt_scl);

    always @(posedge clk_100m or negedge rst_n) begin
      if(!rst_n)begin
            p3t1750dp_en_d &lt;= 1'b0;
            cnt_scl &lt;= 'd0;
      end
      else begin
            p3t1750dp_en_d &lt;= p3t1750dp_en;
            cnt_scl &lt;= p3t1750dp_en_d ? (cnt_scl + 'd1) : 'd0;
      end
    end

    (* MARK_DEBUG="true" *)reg                  bit_cnt         ;
    (* MARK_DEBUG="true" *)reg               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                   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,1'b0};   // write
    assign address_r= {p3t1750dp_addr,1'b1};   // read
    assign p3t1750dp_pointer = 8'h00;
    assign p3t1750dp_done = (stop &amp; scl_high);

    assign start      = ((bit_cnt == 'd0)|(bit_cnt == 'd19));//1 20   
    assign addr_w   = ((bit_cnt &gt;= 'd1)&amp;(bit_cnt &lt;= 'd8));//2-9
    assign pointer    = ((bit_cnt &gt;= 'd10)&amp;(bit_cnt &lt;= 'd17)); //11-18
    assign slave_ack= ((bit_cnt == 'd9)|(bit_cnt == 'd18)|(bit_cnt == 'd28));//10 19 29
    assign addr_r   = ((bit_cnt &gt;= 'd20)&amp;(bit_cnt &lt;= 'd27));//21-28
    assign read_byte1 = ((bit_cnt &gt;= 'd29)&amp;(bit_cnt &lt;= 'd36));//30-37
    assign master_ack = ((bit_cnt == 'd37)|(bit_cnt == 'd46));//38 47
    assign read_byte2 = ((bit_cnt &gt;= 'd38)&amp;(bit_cnt &lt;= '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 &lt;= 'd0;
      else if(neg_scl)
            if(idle)
                bit_cnt &lt;= 'd0;
            else
                bit_cnt &lt;= (bit_cnt + 'd1);
      else
            bit_cnt &lt;= bit_cnt;
    end
    always @(posedge clk_100m or negedge rst_n) begin
      if(!rst_n)begin
            master_ack_d &lt;= 1'b0;
            slave_ack_d &lt;= 1'b0;
            sda_en_d &lt;= 1'b0;
            temp_out &lt;= 'd0;
      end
      else begin
            master_ack_d &lt;= master_ack;
            slave_ack_d &lt;= slave_ack;
            sda_en_d &lt;= sda_en;
            temp_out &lt;= p3t1750dp_done ? read_data : temp_out;
      end
    end
    always@(posedge clk_100m or negedge rst_n)begin
      if(!rst_n)
            sda_o &lt;= 1'd1;
      else if(start)// 1 20
            sda_o &lt;= scl_high ? 1'b0 : sda_o;
      else if(addr_w)// 2-9
            sda_o &lt;= scl_low ? address_w : sda_o;
      else if(slave_ack)
            sda_o &lt;= 1'b1;
      else if(pointer)// 11-18
            sda_o &lt;= scl_low ? p3t1750dp_pointer : sda_o;
      else if(addr_r)// 21-28
            sda_o &lt;= scl_low ? address_r : sda_o;
      else if(master_ack)
            if(scl_low)// 38 47
                sda_o &lt;= (bit_cnt == 'd37) ? 1'b0 : 1'b1;
            else
                sda_o &lt;= ((bit_cnt == 'd46)&amp; neg_scl) ? 1'b0 : sda_o;
      else if(stop)// 48
            sda_o &lt;= scl_high ? 1'b1 : sda_o;
      else if(idle)// 49
            sda_o &lt;= 1'b1;
      else
            sda_o &lt;= sda_o;
    end
    always@(posedge clk_100m or negedge rst_n)begin
      if(!rst_n)
            read_data &lt;= 'd0;
      else
            read_data &lt;= ((read_byte1 | read_byte2)&amp; scl_high) ? {read_data,sda_i} : read_data;
    end
endmodule</code></pre>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; 测试时ila设置抓取<span style="color:#1abc9c;">p3t1750dp_done </span>的上升沿。</p>

<p>&nbsp; &nbsp; &nbsp; vio依次配置p3t1750dp_addr(硬件上设置器件地址为0x00),p3t1750dp_pointer(指向温度传感器寄存测量结果的寄存器),拉高rst_n信号,最后打开p3t1750dp_en(iic开始和器件通讯)。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 第一次触发抓到的结果,温度数据为高12bit,7520右移4位后为470,器件测量精度为0.0625,所以第一次测量结果为:470*0.0625=29.375℃。</p>

<p>&nbsp; &nbsp; &nbsp; 第二次触发的测量结果:结果直接变负数了</p>

<p> &nbsp;</p>

1nnocent 发表于 2025-1-6 16:29

<div class='shownolgin' data-isdigest='no'><p></p>


<p>我看你配置的vio里面期间的地址addr怎么配置的0x00啊?数据手册里的给地址不可能有0x00的情况,检查下地址是不是搞错了</p>
</div><script>showreplylogin();</script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

tagetage 发表于 2024-12-28 20:14

<p>temperature conversion time One-shot mode&nbsp; &nbsp; -----有2个地方需要注意,一个是温度的转换时间,一个是工作模式,单一模式或连续模式 。。</p>

1nnocet- 发表于 2024-12-28 21:30

tagetage 发表于 2024-12-28 20:14
temperature conversion time One-shot mode&nbsp; &nbsp; -----有2个地方需要注意,一个是温度的转换时间 ...

<p>数据手册好像没写上电默认是单一模式还是连续模式,我直接当成上电默认连续模式了</p>

tagetage 发表于 2024-12-28 22:28

1nnocet- 发表于 2024-12-28 21:30
数据手册好像没写上电默认是单一模式还是连续模式,我直接当成上电默认连续模式了

<p>那你到底解决问题没有了啊?????</p>

秦天qintian0303 发表于 2024-12-29 12:31

1nnocet- 发表于 2024-12-28 21:30
数据手册好像没写上电默认是单一模式还是连续模式,我直接当成上电默认连续模式了

<p>这个得看数据手册了,有得都不需要设置,有的传感器需要配置才可以</p>

wangerxian 发表于 2024-12-30 13:15

<p>可以把单一模式和连续模式都测试一下。既然能读出来第一个,说明IIC通信是没有问题的。</p>

1nnocet- 发表于 2025-1-6 19:51

<div class='shownolgin' data-isdigest='no'>1nnocent 发表于 2025-1-6 16:29
我看你配置的vio里面期间的地址addr怎么配置的0x00啊?数据手册里的给地址不可能有0x00的情况,检查下 ...

<p>改了下地址,还真是地址的原因,把温度寄存器的pointer当成地址配置了</p>
</div><script>showreplylogin();</script>

1nnocet- 发表于 2025-1-6 19:53

<div class='shownolgin' data-isdigest='no'>tagetage 发表于 2024-12-28 22:28
那你到底解决问题没有了啊?????

<p>不是你说的这个问题,是地址搞错了</p>
</div><script>showreplylogin();</script>
页: [1]
查看完整版本: 温度传感器只有第一次采集的是准的是怎么回事?