简介:面向嵌入式传感器开发者的ST官方AN5763中文应用笔记,聚焦LSM6DSV16X六轴惯性模块的硬件接口、寄存器配置与应用设计,适合正在做可穿戴、IoT及手持设备运动检测方案的工程师查阅。压缩包仅含1个PDF文件,大小约6.77MB,内容围绕3轴加速度计与3轴陀螺仪的I²C/SPI/MIPI I3C接口、±2~±16g与±125~±4000dps量程、低功耗唤醒、中断与传感器集线器等展开。文档还讲解嵌入式机器学习内核、有限状态机、Qvar电荷变化检测和4.5KB FIFO批处理等特性,并给出引脚说明与典型应用提示,便于读者快速理解器件能力、核对设计参数并排查配置问题。已有488人学习下载,可作为选型评估与驱动开发阶段的参考材料。
1. 从“只读得出加速度”到“传感器自己会判断”:这份 140 页笔记补的是什么
很多做腕上设备、手柄和手持云台的团队,第一次拿到这颗六轴器件时的进度条都卡在同一个位置:能读到 WHO_AM_I 的固定回值,也能把三轴原始值打成波形,然后就不知道该动哪个寄存器了。数据手册给的是位定义,AN5763 这份 140 页的中文应用笔记给的是“把位连成链路”的过程——I²C、SPI 四线与 MIPI I3C 三种接法怎么取舍,加速度 ±2/±4/±8/±16 g 与角速率 ±125 到 ±4000 dps 的满量程怎么和 ODR 配对,4.5 KB 的 FIFO 水位该按多少个样本算,最多 8 个有限状态机和嵌入式机器学习内核的配置字是怎么一页一页灌进去的,以及 Qvar 电荷变化检测通道的两个电极引脚该怎么布。它适合正在做可穿戴、手柄、云台防抖和人体接近检测的工程师,也适合刚接手这颗器件、想把识别和判决策略尽量压在传感器内部完成、好让主控多睡一会儿的同学。
2. 接口与引脚:14 个脚怎么接,三种总线的取舍点在哪
2.1 I²C、SPI 四线与 MIPI I3C 的取舍,先看吞吐再看布线
三种串行接口在这颗器件上不是“有就行”的并列项,选错了会在后面调试 FIFO 的时候反复卡住。I²C 只占两根线,最大的好处是省引脚、能挂多个器件,代价是速率受限,读一次三轴数据要走地址加寄存器地址再加读的完整时序,当 ODR 上到 833 Hz 以上、又要同时读加速度和陀螺时,总线占用会明显吃掉主控的调度余量。SPI 四线是全双工,配合 0x12 寄存器(CTRL3)里的 IF_INC 位做地址自增,可以一次把 OUTX_L_G 到 OUTZ_H_A 共 12 个字节连续读出来,这是高 ODR 场景下的常规做法。
MIPI I3C 是这两年的新选项,物理上还是两根线,但带宽和带内中断能力比 I²C 强得多,适合主控本身就支持 I3C 的平台。判断依据很直接:主控有没有 I3C 控制器、板子上是不是已经有一堆 I²C 从设备在抢总线、以及产品对采样率的要求。如果主控只支持 I²C,硬上 I3C 没有意义;如果产品要做云台或相机防抖,陀螺的 ODR 往往要开到 1 kHz 以上,这时优先考虑 SPI 或 I3C。
提示:模式选择落在 12 号脚 CS 上。CS 为高(SPI 空闲模式)时 I²C 通信使能,CS 为低时进入 SPI 通信模式、I²C 被禁用。很多人 I²C 扫不到地址,就是这根线没处理好。
2.2 14 个脚的三套身份:UI 主接口、辅助总线与 OIS/EIS 通路
这颗器件用 LGA-14L 封装,14 个脚里有好几个在不同工作模式下功能完全不同,这点在文档第 1 章的引脚表里写得很细,但翻的时候容易只看第一列。
| 引脚 | 模式 1(UI 主接口) | 模式 2(传感器集线器) | 模式 3(OIS / 辅助 SPI) |
|---|---|---|---|
| 1 SDO/SA0 | SPI 四线 SDO / I²C 地址最低位 | 同左 | 同左 |
| 2 SDx/AH1/Qvar1 | 复用脚,Qvar 使能时接电极 1 | I²C 主机数据 MSDA | 辅助 SPI 数据输入 SDI |
| 3 SCx/AH2/Qvar2 | 复用脚,Qvar 使能时接电极 2 | I²C 主机时钟 MSCL | 辅助 SPI 时钟 SPC_Aux |
| 4 INT1 | 可编程中断 1 | 同左 | 同左 |
| 9 INT2/DEN | 中断 2 / 数据使能 | 中断 2 / I²C 主线外部同步 MDRDY | 中断 2 / DEN |
| 10 OCS_Aux | 接 Vdd_IO 或悬空 | 同左 | 辅助 SPI 使能 |
| 11 SDO_Aux | 接 Vdd_IO 或悬空 | 同左 | 三线时悬空,四线时为 SDO_Aux |
| 12 CS | 模式选择 | 同左 | 同左 |
模式 3 的使能条件写在 UI_CTRL1_OIS(0x70)里,把 OIS_XL_EN 或 OIS_G_EN 置 1 就切过去了。模式 2 走的是传感器集线器,主接口之外再拉一条辅助 I²C,把磁力计、气压计这类从设备挂上去,数据由器件自己采集并塞进 FIFO,主控醒来一次性取走,省掉轮询的开销。
模式 1 下 2、3 脚如果既不开模拟集线器也不开 Qvar,规范要求接到 Vdd_IO 或 GND,不能悬空。这个细节在做低功耗认证的时候影响很大,悬空脚会带来额外的漏电和噪声耦合。
引脚内部上拉也值得看一眼。1 号脚(SDO)和 2、3、11 号脚的上拉由 PIN_CTRL(0x02)和 IF_CFG(0x03)里的位控制,内部上拉阻值在 30 kΩ 到 50 kΩ 之间随 Vdd_IO 变化。如果板子上已经放了外部上拉,记得把内部上拉关掉,两个并联会把上升沿拖慢或者多耗电。
2.3 复位与初始化顺序:先清 FUNC_CFG_ACCESS 再动别的
顺序错了会出现“配置写进去了但数据不动”的情况。合理的上电流程是:Vdd 和 Vdd_IO 稳定,等到器件内部上电复位完成,先读一次 WHO_AM_I(0x0F)确认通信正常,再走软复位,然后再配置。
软复位靠 CTRL3(0x12)的 SW_RESET 位。这里有个容易忽略的点:复位之后,之前写到嵌入式功能页的东西不会自动保留,配置得重做。而 FUNC_CFG_ACCESS(0x01)这个寄存器如果在上一次调试时被置成了 1(进入嵌入式功能页),复位后虽然会清零,但如果你中途手动改过,它没清掉,之后读 OUTX_L_A(0x28)读到的就不是加速度数据,而是同一地址在嵌入式功能页里的含义——这是最典型的一类“数据全是 0 或者全是固定值”的翻车现场。
BDU(Block Data Update)位在 CTRL3 的 bit6,必须置 1。这颗器件的输出是 16 位,分高低两个字节放在相邻地址,如果读低字节和读高字节之间刚好赶上新一次采样更新,拼出来的值就是两次采样混在一起的,看起来像偶尔跳一下的毛刺。BDU 置 1 之后,输出寄存器在两次读之间被锁住,等两个字节都读完才更新。
IF_INC 在 CTRL3 的 bit2,控制地址是否自增。做连续读的时候必须打开,否则你从 0x28 开始读,读到的永远是同一个地址。
2.4 最小初始化代码与逐行说明
下面这段是上板第一件事,跑通它再谈后面的功能。
import smbus2 import time I2C_BUS = 1 ADDR = 0x6A # 由 1 号脚 SA0 决定:接地为 0x6A,接 Vdd_IO 为 0x6B,以实测为准 bus = smbus2.SMBus(I2C_BUS) def rd(reg): return bus.read_byte_data(ADDR, reg) def wr(reg, val): bus.write_byte_data(ADDR, reg, val) def soft_reset(): wr(0x12, 0x01) # CTRL3.SW_RESET = 1,触发软复位 time.sleep(0.05) # 留出内部寄存器重新加载的时间 for _ in range(20): # 轮询等待复位位自动清零,不要死等 if (rd(0x12) & 0x01) == 0: return time.sleep(0.005) raise RuntimeError("SW_RESET 未完成,检查供电与 CS 电平") def base_init(): wr(0x01, 0x00) # 回到主页,EMB_FUNC_REG_ACCESS / SHUB_REG_ACCESS 都清 0 wr(0x12, 0x44) # BDU=1(bit6)、IF_INC=1(bit2),其余保持默认 wr(0x10, 0x04) # 加速度:高性能模式 + ODR 档位(编码按 0x10 位定义填) wr(0x11, 0x04) # 陀螺:高性能模式 + ODR 档位 # 满量程:加速度落在 CTRL8(0x17) 的 FS_XL 位段,陀螺落在 CTRL6(0x15) 的 FS_G 位段 wr(0x17, (rd(0x17) & 0xFC) | 0x00) # 示例取最小档,实际按量程需求改 wr(0x15, (rd(0x15) & 0xF0) | 0x00) soft_reset() base_init() print("WHO_AM_I =", hex(rd(0x0F)))逻辑上分三层。soft_reset负责把器件拉回已知状态,轮询而不是死等,是因为复位时间和供电斜率、温度都有关系,固定延时在某些板子上会短一点。base_init第一句写 0x01 是整套流程里最容易被跳过的一步,它的作用是确保后面所有地址都按主页解释。第三条和第四条命令给加速度和陀螺设 ODR 与功耗模式,OP_MODE 位段决定的是内部模拟前端的档位,不是简单的开关,高性能模式下组合电流标称 0.65 mA,低功耗档位会显著低于这个值但噪声底会抬上去。
参数上主要改两个地方:ADDR跟着 SA0 走,0x04这个 ODR 编码跟着实际需要的采样率走。加速度和陀螺可以设成不同的 ODR,这在只做倾角检测、不做高频运动识别的场景里很实用——陀螺直接关掉能省一大截电。
3. 数据通路:ODR、满量程与 4.5 KB FIFO 的批处理水位怎么算
3.1 ODR、满量程与噪声底的三角关系
这三者是互相牵制的。ODR 决定单位时间出多少样本,满量程决定每个样本用多少位去表达多大的物理量,噪声底则由器件本身的模拟前端和数字滤波决定。把满量程开到 ±16 g,能测到更大的冲击,但同样的 16 位量化精度摊到 32 g 的跨度上,每一级对应的加速度值就变大,静态倾角测量的分辨率会下降。反过来,只测 ±2 g,抬手一个动作就可能削顶。
常见做法是按应用场景选:腕上设备做手势和计步,加速度一般在 ±4 g 或 ±8 g,陀螺在 ±1000 dps 或 ±2000 dps;做跌落检测要留够余量,加速度往 ±16 g 走;做云台或相机防抖,陀螺的角速率范围往往要开到 ±2000 dps 以上,因为快速转动的瞬时角速度很容易超过 ±1000 dps。
ODR 的选择更直接地和功耗、总线带宽绑在一起。文档给的寄存器里,CTRL1(0x10)低 4 位是 ODR_XL,CTRL2(0x11)低 4 位是 ODR_G,高 3 位是各自的 OP_MODE。同一颗器件里加速度和陀螺的 ODR 可以不同,做纯倾角检测时把陀螺 ODR 关掉,功耗下降很明显。
滤波器这块,CTRL6(0x15)里有 LPF1_G_BW 和 LPF1_G_EN,CTRL8(0x17)里有 HP_LPF2_XL_BW,CTRL9(0x18)还有 LPF2_XL_EN 和 HP_SLOPE_XL_EN。低速场景下把低通打开能压掉高频振动,但相位延迟会变大,做实时姿态解算的时候这个延迟要算进去。
3.2 4.5 KB FIFO 的水位:按帧算而不是按字节算
4.5 KB 听着挺大,但要看清楚一帧占多少。FIFO 数据出口是 FIFO_DATA_OUT_TAG(0x78)加 X/Y/Z 各高低字节(0x79 到 0x7E),一帧 7 个字节,其中 tag 里带的是传感器来源标识和计数。4.5 KB 除以 7,大约六百五十多帧。如果加速度和陀螺的批处理速率都设成同一个 ODR,那每个 ODR 周期会产出两帧,实际能缓存的时长要再折半。
水位相关的字段有两个,用途不一样。FIFO_CTRL1(0x07)里的 WTM 是 8 位,对应水印中断,FIFO 里的帧数到这个值就触发 INT 上的 FIFO_TH 标志。COUNTER_BDR_REG1(0x0B)的低 2 位和 COUNTER_BDR_REG2(0x0C)拼起来是 10 位的 CNT_BDR_TH,对应按样本数触发的批处理中断,精度更高,能设到 1023。做低功耗方案时一般用后者,因为它能让你精确地按“攒够 N 个样本再叫醒主控”来设计。
批处理的速率在 FIFO_CTRL3(0x09)里,高 4 位 BDR_GY、低 4 位 BDR_XL,都是从对应 ODR 分频下来的。FIFO_CTRL4(0x0A)的低 3 位 FIFO_MODE 决定模式:旁路、FIFO、连续、连续转 FIFO 等。连续模式适合主控周期性来取,转 FIFO 模式适合“出事之前的数据也要留着”的场景,比如跌落检测需要看跌落前几百毫秒的波形。
FIFO_CTRL2(0x08)里几个位容易被忽略:STOP_ON_WTM 置 1 之后,水位到了就停止写入,防止覆盖旧数据,对做事件回溯的场景是必须的;ODR_CHG_EN 允许 ODR 变化时 FIFO 不中断,动态调采样率的时候用得上;UNCOMPR_RATE 两位控制非压缩数据的抽取比例。
3.3 时间戳、温度与 MLC 特征的批处理对齐
时间戳是 32 位,分四个字节放在 0x40 到 0x43,读的时候要连续读,中间被打断就会拼错。它和 FIFO 里的数据帧不是一一对应的,FIFO_CTRL4 里的 DEC_TS_BATCH 两位控制时间戳的抽取率,实际工程里要么按固定比例对齐,要么在解析每帧时用帧计数反推时间。
温度在 0x20 和 0x21,16 位。它主要用于补偿,不是精密测温。文档里 OUT_TEMP 的更新频率和 ODR 相关,做长时间漂移分析时可以顺手把温度一起批处理进 FIFO,FIFO_CTRL4 里的 ODR_T_BATCH 就是干这个的。
MLC 导出的滤波器和特征也能进 FIFO,开关在嵌入式功能页的 EMB_FUNC_FIFO_EN_A(0x44)和 EMB_FUNC_FIFO_EN_B(0x45)里。这一点对做端侧识别的项目很关键:传感器自己算完特征,把特征塞进 FIFO,主控不需要读原始波形,醒来只拿结果,功耗差一个数量级。
3.4 一个 FIFO 排空循环
FIFO_TAG = 0x78 FIFO_STATUS1 = 0x1B FIFO_STATUS2 = 0x1C def fifo_pending(): # DIFF_FIFO 低 8 位在 0x1B,第 9 位在 0x1C 的 bit0 return rd(FIFO_STATUS1) | ((rd(FIFO_STATUS2) & 0x01) << 8) def drain_fifo(max_frames=256): frames = [] n = fifo_pending() if n == 0: return frames n = min(n, max_frames) # 限制单次读取量,避免长时间占用总线 for _ in range(n): tag = rd(FIFO_TAG) x = rd(0x79) | (rd(0x7A) << 8) y = rd(0x7B) | (rd(0x7C) << 8) z = rd(0x7D) | (rd(0x7E) << 8) # 16 位有符号数还原 for v in (x, y, z): if v & 0x8000: v -= 0x10000 frames.append({ "sensor": (tag >> 3) & 0x1F, # TAG_SENSOR 位段标识数据来源 "cnt": tag & 0x03, # TAG_CNT 用于识别同批次的连续帧 "x": x, "y": y, "z": z, }) return frames这里的关键是 tag 的拆解。TAG_SENSOR 决定这一帧是加速度、陀螺、还是外部从设备或 MLC 特征,解析的时候必须按 tag 分发到不同的换算系数上——加速度和陀螺的灵敏度不一样,混着算出来的数值完全没有物理意义。TAG_CNT 用来识别同一次采样的多轴数据是否连续,出现跳变说明中间丢帧了。
max_frames这个参数是保护性的。FIFO 满了以后不读会持续覆盖,但一次读几百帧会长时间占用 I²C 总线,如果主控还有别的实时任务,最好分片读。读之前先查 DIFF_FIFO,比盲目按固定数量读要稳。
注意 16 位有符号数的还原。Python 里没有天然的 int16 溢出,必须手动做补码转换,否则负的加速度值会变成一个六万多的正数,画出来的波形会在零点处上下翻飞。
4. 嵌入式机器学习内核、FSM 与 Qvar:把判断逻辑放进传感器里
4.1 八个 FSM 的状态结构:输入条件、阈值与下一状态
有限状态机是这颗器件里最“可编程”的部分,最多能同时跑 8 个,每个状态机由一串状态组成。每个状态定义三件事:进入条件(某个轴的加速度或角速度超过阈值、或者持续时间满足)、输出动作(复位、置位、清零、或者跳到下一个状态)、以及下一状态编号。
这套结构适合描述“先这样再那样”的时序型事件。比如连续两次摇晃,第一个状态捕获第一次超过阈值的动作,进入等待窗口,第二个状态在窗口内再捕获一次,两个都满足才输出。文档里提到的查看、绝对手腕倾斜、摇晃、拿起这些手势,都是这个套路。
结果从两处读。FSM_OUTS1 到 FSM_OUTS8 在嵌入式功能页的 0x4C 到 0x53,每个字节的 8 位对应不同方向的组合,用来表达“抬起来的方向”这类信息。状态位在 FSM_STATUS(0x13)和主页面的 FSM_STATUS_MAINPAGE(0x4A)里,前者是嵌入式页,后者是主页映射,读的时候别搞混。
FSM_LONG_COUNTER(0x48 和 0x49)是个 16 位计数器,配合 FSM_ENABLE(0x46)里的长计数使能位,可以做持续几十秒甚至几分钟的慢过程判定,比如“保持某个姿势超过两分钟”。
中断出口在 EMB_FUNC_INT1(0x0A)和 FSM_INT1(0x0B),以及对应的 INT2 版本(0x0E、0x0F)。想让某个状态机的输出触发 INT1,就要在 0x0B 里把对应的 FSMx 位置 1。
4.2 嵌入式机器学习内核:决策树、特征窗口与 MLC_BEFORE_FSM_EN
机器学习内核跑的是决策树,不是神经网络。配置进去的是一组树结构,每棵树对若干特征做阈值判断,最后投票出类别。文档里给的典型例子是跑步、行走、驾车这类活动识别,类别数最多 4 个,结果位在 MLC_STATUS(0x15)和 MLC_STATUS_MAINPAGE(0x4B)的 IS_MLC1 到 IS_MLC4。
这里有个设计上的细节值得单独说:EMB_FUNC_EN_A(0x04)的 bit7 是 MLC_BEFORE_FSM_EN。把这个位置 1,MLC 就会在 FSM 之前运行,FSM 的输入条件可以直接用 MLC 的分类结果。反过来,默认顺序是 FSM 先跑,MLC 拿 FSM 的输出当特征之一。这个顺序决定了你的逻辑是“先做时序判断再做分类”还是“先分类再按时序过滤”,两种思路对应完全不同的产品需求。
MLC 的运算频率在 MLC_ODR(0x60)里设。频率越高响应越快,功耗也越高。特征窗口的长度和这个频率是绑定的,配置工具里算出来的窗口长度是采样点数,实际时间要除以 ODR。
配置字的生成一般靠配套工具,工具输出的是一份二进制配置流,最终要转成“页地址 + 页数据”的写序列。这颗器件没有直接的“加载固件”命令,全靠页写机制搬进去。
4.3 配置字怎么灌进去:页写机制与代码
嵌入式功能寄存器和主寄存器是两套地址空间,靠 FUNC_CFG_ACCESS(0x01)的 bit7 切换。切换过去之后,0x08(PAGE_ADDRESS)和 0x09(PAGE_VALUE)就成了数据通道,0x02(PAGE_SEL)选页,0x17(PAGE_RW)的 bit6 是写使能、bit5 是读使能。
PAGE_SIZE = 256 def emb_write(program: bytes): """把工具生成的配置流按页写进嵌入式功能 <p> <a href="https://download.csdn.net/download/u014319604/88278031" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>