littleshrimp 发表于 2021-2-28 18:09

LSM6DSO(X)传感器驱动关键代码解析:read_data_polling例程(二)

<div class='showpostmsg'> 本帖最后由 littleshrimp 于 2021-2-28 18:21 编辑

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif"><span style="font-size:12.0pt"><span style="font-family:宋体">通过前面帖子对ST传感器的Standard C驱动和read_data_polling有了一个大概了解,接下来我将继续对read_data_polling例程做更深入的介绍。</span></span></span></span></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif"><span lang="EN-US" style="font-size:12.0pt"><span style="font-family:宋体"><a href="https://bbs.eeworld.com.cn/thread-1157700-1-1.html" style="color:blue; text-decoration:underline">https://bbs.eeworld.com.cn/thread-1157700-1-1.html</a></span></span></span></span></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif"><span lang="EN-US" style="font-size:12.0pt"><span style="font-family:宋体">lsm6dso_read_data_polling</span></span><span style="font-size:12.0pt"><span style="font-family:宋体">函数里在对传感器复位并判断复位成功后会对传感器进行配置,首先执行了lsm6dso_i3c_disable_set函数,这个函数是用来配置和禁止I3C功能,至于什么是I3C可以自行搜索&ldquo;MIPI I3C&rdquo;。例程里禁用了I3C功能,查看lsm6dso_i3c_disable_set函数看到里边还是有些复杂的,我们先来看看函数参数中val ,它对应的枚举类型lsm6dso_i3c_disable_t,LSM6DSO_I3C_DISABLE是关闭I3C,剩下的是ENABLE和对应的时间,LSM6DSO_I3C_DISABLE的数值是0x80,其它分别为0,1,2,3。回到lsm6dso_i3c_disable_set函数,函数里首先执行lsm6dso_read_reg读取CTRL9_XL寄存器,然后对ctrl9_xl.i3c_disabl进行设置,((uint8_t)val &amp; 0x80U) &gt;&gt; 7作用是当val第7位为1时(LSM6DSO_I3C_DISABLE)为1,否则为0。这里也可以使用其它方法,比如val == LSM6DSO_I3C_DISABLE ? 1 : 0,或者((uint8_t)val &amp; 0x80U) == 0x80U等等。查看数据手册看到CTRL9_XL的I3C_disable位就是用来使能或禁止I3C接口的,为1时禁止。</span></span></span></span></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">在配置好CTRL9_XL 的i3c_disable 后又通过lsm6dso_read_reg函数读取了I3C_BUS_AVB寄存器,然后将val 的0-1位赋给i3c_bus_avb_sel,查看数据手册的I3C_BUS_AVB它对应了50us、2ms、1ms和5ms,这个参数和I3C有关我也不是很了解,这里就不解释了。</span></span></span></span></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">再回到lsm6dso_read_data_polling函数,执行完lsm6dso_i3c_disable_set关闭I3C功能后又执行了lsm6dso_block_data_update_set,这个函数很多传感器都会使用。查看lsm6dso_block_data_update_set内部, 看到他是用来设置CTRL3_C的bdu位,同样是先读取再设置。BDU全称Block Data Update,因为传感器分辨率为16位,每一组数据由高字节MSB和低字节LSB组成,比如正巧MCU在刚读完第一个数据的MSB或者LSB后,传感器的这两个寄存器数据就马上更新了,然后MCU再读取到的另外一个字节(MSB或者LSB)实际上已经是第二个数据了,这样再用这两个字节拼成的&nbsp; 16位数据相当于包含了第一数据和第二个数据。为防止这种情况发生,可以将BDU设置为1,这样传感器会判断一组寄存器的MSB和LSB是否已经被全部读取,只有在被全部读取后才会更新这两个寄存器。</span></span></span></span></p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">说完BDU剩下的代码就比较容易理解了,lsm6dso_xl_data_rate_set是用来设置加速度的ODR,lsm6dso_gy_data_rate_set是用来设置陀螺仪的ODR,lsm6dso_xl_full_scale_set是设置加速度的full scale,</span></span>lsm6dso_gy_full_scale_set<span style="font-size:12.0pt"><span style="font-family:宋体">是用来设置陀螺仪的full scale。驱动头文件lsm6dso_reg.h里已经做好了定义,只要把相应的定义作为参数传递给对应的函数就能实现对应的配置。</span></span></span></span></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">设置好传感器的数据输出速率和满量程,最后又对传感器的滤波器进行配置。lsm6dso_xl_hp_path_on_out_set函数的输入参数是LSM6DSO_LP_ODR_DIV_100,从字面上理解是设置加速度低通滤波(Low Pass)频率为ODR/100,因为之前将ODR设置成了12.5Hz,所以波滤器允许低于0.125Hz的信号通过。lsm6dso_xl_hp_path_on_out_set分别设置了CTRL8_XL的hp_slope_xl_en、hp_ref_mode_xl和hpcf_xl,查看数据手册的CTRL8_XL,和AN5192应用笔记,HP_SLOPE_ XL_EN是高通滤波器使能,为1时为高通波滤,0时为低通滤波。hp_ref_mode_xl是高通波滤器参考模式,使能此模式同时还要将HP_SLOPE_ XL_EN置1(高通模式),并且 HPCF_XL数值不能为0(也就是说不支持ODR / 4 (slope filter))。使能参考模式后传感器会保存当前的加速度值,并且之后再读取的数据都是当时的值差去当前值。举个例子更容易理解,假设参考模式使能时加速度的值为X=0,Y=0,Z=1000mg,这个值会被一直保存,然后如果传感器保持不动,再获得到的数据理论上还是X=0,Y=0,Z=1000mg,此时读取到的数据为X=0,Y=0,Z=0,是2组数据相减的结果。hpcf_xl对应CTRL8_XL的BIT7-BIT5,占用3个位,对应的截止频率为ODR/4到ODR/800。</span></span></span></span></p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">接着执行了lsm6dso_xl_filter_lp2_set函数,将能数是PROPERTY_ENABLE,通过观察lsm6dso_xl_filter_lp2_set函数发现它用来设置CTRL1_XL寄存器的lpf2_xl_en位。通过下图中的表格可以看到lpf2_xl_en只对低通滤波器有效,为0时相当于把LPF2给屏蔽掉了。</span></span></span></span></p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">至此整个例程的传感器配置工具就已经完成了,剩下的代码都在while块里重复执行,这部分也比较容易理解,lsm6dso_xl_flag_data_ready_get函数用来读取STATUS_REG寄存器的xlda位,STATUS_REG的2、1、0位分别对应温度数据有效、角速度数据有效和加速度数据有效。xlda表示加速度数据有效,为1时表示加速度数据转换完成。接着使用memset把data_raw_acceleration的数据清零,然后通过lsm6dso_acceleration_raw_get函数读取加速度的x,y,z轴数据到data_raw_acceleration。</span></span></span></span></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif"><span lang="EN-US" style="font-size:12.0pt"><span style="font-family:宋体">&nbsp;&nbsp;&nbsp; lsm6dso_acceleration_raw_get</span></span><span style="font-size:12.0pt"><span style="font-family:宋体">函数从OUTX_L_A寄存器开始一次读取6个字节数据,对应分别对应X,Y,Z的LSB和MSB,然后分别将2个字节合并成一个16位数据。再接下来是通过lsm6dso_from_fs2_to_mg函数将读取出的16位加速度原数据转换成对应的以mg为单位的加速度数值。注意这里的代码并没有对加速度的量程做判断,而是使用了一种固定的写法,lsm6dso_from_fs2_to_mg即只有在量程为2g时才有效,如果量程是4g就需要用到lsm6dso_from_fs4_to_mg函数,这里如果想灵活一些网友可以自己使用宏定义,或者在配置量程时保存量程信息再做判断,方便日后修改代码。lsm6dso_from_fs2_to_mg是用当前读取到的16位加速度原数据乘以0.061f,这个0.061怎么来的可以在数据手册中找到,就是下边的最后一个图片。最后通过sprintf将浮点类型的加速度数据转换成字符串形式并通过tx_com将数据发送到上位机进行分析。</span></span></span></span></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify">&nbsp;</p>

<p style="text-align:justify"></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri,sans-serif">&nbsp;&nbsp;&nbsp; <span style="font-size:12.0pt"><span style="font-family:宋体">剩下的陀螺仪和温度的数据的有效判断、读取、转换和发送都和加速度类型,这里就不重复介绍了。到此为止整个read_data_polling例程就已经全部介绍完了,有问题的网友欢迎发回帖交流。</span></span></span></span></p>

<p>&nbsp;</p>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </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>

Jacktang 发表于 2021-3-1 21:07

<p>谢谢分享,以后学习这些很有借鉴意义</p>

hubusbwxz69 发表于 2023-9-16 14:31

学习了

luobote 发表于 2023-11-13 14:22

<p>各位专家,我现在用的LSM6DSO做低功耗应用,检测运动/静止,倾斜检测,6D方向检测,数据输出率为26hz,和单片机之间用SPI总线通信的,但是现在发现整机电流很大(单片机进入STOP模式后,整机电流还有570uA,我电路中的其他模块都摘除了,电流还是这么大),我在网上也产过相关方面的资料,说这个芯片是IIC&nbsp;和SPI共用接口的问题,我也进行多种方式进行尝试,但仍然无法解决,不知道大家有没有好的方式!</p>

GaleJ 发表于 2023-12-11 01:33

luobote 发表于 2023-11-13 14:22
各位专家,我现在用的LSM6DSO做低功耗应用,检测运动/静止,倾斜检测,6D方向检测,数据输出率为26hz,和单 ...

<p>请问你解决这个问题了吗</p>
页: [1]
查看完整版本: LSM6DSO(X)传感器驱动关键代码解析:read_data_polling例程(二)