STM32C5与IIS2ICLX双轴加速度计SPI通信实战:从寄存器配置到高分辨率数据读取
发布时间:2026/9/28 1:38:08来源:尧图网络
最近在折腾一块 STM32C5 开发板正好手边有一颗 IIS2ICLX。这颗芯片是意法半导体主攻工业倾斜测量和低频振动监测的双轴加速度计内部 16 位 ADC在 ±0.5g 量程下的典型灵敏度能做到 0.0154 mg/LSB 这个级别。光看参数就知道它不是拿来玩简单计步的而是奔着高分辨率测量去的。IIS2ICLX 的物理接口同时支持 I2C 和 SPI我这次选择用 SPI原因后面会展开如果要拉高输出数据率、配合 FIFO 批量搬数据SPI 的时钟驱动和连续读能力比 I2C 干净得多。这篇是 IIS2ICLX 系列博客的第一篇目标定得很小把 STM32C5 的 SPI 外设和 IIS2ICLX 之间的链路打通正确读出 X/Y 两轴加速度原始值再换算成 mg 或 g 在串口上打出来。整个过程不涉及 FFT、不涉及姿态解算甚至不用 FIFO 和 DMA先确认最底层的寄存器访问是对的。我见过太多人在高分辨率流式传输这件事上折腾一整天最后发现其实连 WHO_AM_I 都读不回来。如果你是第一次在 STM32 上接数字加速度计这一篇足够让你少走几条弯路。1. 为什么是STM32C5加IIS2ICLX以及这个组合的关键特点1.1 STM32C5的定位Cortex-M33的新一代主流选择先聊主控。STM32C5 是 ST 新推出的一代 MCU 系列内核换成了 Arm Cortex-M33相比 C0 系列的 M0 内核性能、中断响应和安全特性都有了明显提升。放在几年前M33 内核基本属于中高端定位现在被压到更主流的价位段这就让“一颗低成本的 MCU 去接高精度 MEMS 传感器”这件事变得很划算。我手上这颗芯片最大的感触是外设没有堆得很夸张但该有的都给了——SPI、I2C、UART、定时器、DMA 一应俱全做传感器数据采集绰绰有余。需要提醒的是STM32C5 这颗料相对比较新在 STM32CubeMX 里如果要选到对应型号记得先升级 CubeMX 和 STM32Cube 固件包到较新版本。我一开始用旧版本打开芯片列表里压根找不到 C5 开头型号换了个新版本才正常。这个坑很基础但确实容易卡人。1.2 IIS2ICLX不是普通三轴加速度计双轴、高分辨、低噪声很多做消费电子出身的人看到加速度计第一反应是三轴 XYZ。IIS2ICLX 不是这个路数它是双轴加速计只输出 X 和 Y也就是水平面内两个正交方向。可能有人会疑惑现在手机里的加速度计不都三轴吗没错但 IIS2ICLX 的设计目标是工业倾斜测量、平台水平校准、结构健康监测这类场景。工业上很多需求只需要知道设备相对重力方向的两个角度省掉一路 Z 轴把面积和功耗留给精度这才是这颗芯片的核心定位。它的分辨率是真的高。在 ±0.5g 量程下16 位输出对应的灵敏度约为 0.0154 mg/LSB这是什么概念一个 LSB 对应的重力加速度变化量只有 0.0000154 g。也就是说传感器能分辨出非常微小的倾斜角度变化。配合低噪声设计它做倾角测量的分辨率能到 0.001° 级别这在传统的 8 位、10 位加速度计上根本不敢想。1.3 SPI接口选择的工程逻辑为什么高分辨率场景默认走SPIIIS2ICLX 同时支持 I2C 和 SPI但我在项目里会优先选 SPI理由其实不复杂。I2C 是半双工、帧格式里有地址确认和起始停止位每次读数据都要做总线仲裁速率和效率天然被协议限制。SPI 是全双工主机给时钟想读多少字节就连着读多少字节尤其适合后面要做 FIFO 批量导出、连续高频采样的场景。这颗芯片声称的高分辨率能力往往要配合较高的数据率使用比如几百赫兹的低频振动采样。这种情况下SPI 的优势就非常明显时钟由主机完全掌控数据流可以做到严格连续不会像 I2C 那样在主机和从机之间反复协商。不过这里要提前说清楚一个容易误解的点高分辨率不等于必须用 SPII2C 在低速率下也能读出 16 位数据。选 SPI 更多是为了“数据连续性和高吞吐”这个思考方式在第四章会专门展开。2. CubeMX工程与接线先把SPI物理层跑通2.1 硬件接线四线就够了IIS2ICLX 的 SPI 接口是标准四线制SCLK、MOSISDI、MISOSDO、CS。板上供电我直接用 3.3V传感器 VDD 和 VDDIO 并在一起接到同一个 3.3V 电源域。接线表如下传感器引脚功能STM32C5侧备注VDD电源正3.3V靠近引脚放一颗100nF去耦电容GND地GND传感器、MCU共地SCLKSPI时钟SPI_SCK初始速率先压低SDIMOSISPI_MOSI主机发数据给传感器SDOMISOSPI_MISO传感器返回数据给主机CS片选任意GPIO低电平有效软件控制有一个值得注意的细节CS 片选我建议用普通 GPIO 来做软件片选而不是硬件 NSS。原因有两点一是 IIS2ICLX 是单从机软件片选完全够用二是硬件 NSS 在某些 MCU 上会自动输出或者和 SPI 模式绑定一旦没配好会出现片选信号异常排查起来很恼火。软件片选把时序完全握在自己手里调试阶段是最稳的方案。2.2 CubeMX配置里的几个关键选择在 CubeMX 里时钟配置好之后把 SPI1 选为 Full-Duplex Master。参数配置上我最关心的三个点分别是数据帧格式8 位数据宽度Motorola 帧格式这符合绝大多数 MEMS 传感器的 SPI 协议。CPOL/CPHA配置为 Mode 0CPOL0CPHA0。IIS2ICLX 的手册时序图支持这种常规模式SCLK 空闲时低电平数据在上升沿采样。时钟速率先不要追求高速我的初始配置把 SCLK 设成了 1 MHz 左右。SPI 从机对时序的要求通常不高但我们在调试阶段要留足裕量等确认链路稳定后再提高分频比。模式 0 这几个参数看起来简单但实际上很多传感器连接失败都出在这里。CPOL 或 CPHA 配置错一位读回来的数据就是全 0 或者全 1而且不会报错。第一次调试时可以把 SCLK 频率放低再用逻辑分析仪看信号确认每个字节的采样点都对上了再慢慢提速。2.3 NSS软件模式与GPIO初始化CubeMX 里 SPI 的 NSS 要选 Software模式。如果选了硬件 NSSMCU 可能会在传输时自动拉低片选或者需要额外的时序配合在单从机场景下反而麻烦。我用一个普通 GPIO 叫IIS2ICLX_CS_PIN初始化时默认输出高电平需要通信时再拉低一个字节或一帧数据结束后拉高。初始化代码大概是这样的GPIO_InitStruct.Pin IIS2ICLX_CS_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_PULLUP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(IIS2ICLX_CS_GPIO_PORT, GPIO_InitStruct); HAL_GPIO_WritePin(IIS2ICLX_CS_GPIO_PORT, IIS2ICLX_CS_PIN, GPIO_PIN_SET);CS 引脚为什么默认要拉高IIS2ICLX 的片选是低有效只有当 CS 为低时传感器才会响应 SPI 命令所以空闲状态必须保持高电平。这个看似不起眼的行为如果初始化时漏了后面所有读写都会失效。3. 寄存器体系与SPI读写时序从WHO_AM_I开始验证链路3.1 ST MEMS传感器的通用SPI读写格式ST 的 MEMS 传感器在 SPI 通信上有一个很统一的套路第一个字节是地址字节其中最高位表示读写方向bit7 为 1 表示读为 0 表示写剩下的位是寄存器地址。读操作时主机发出地址字节后从请求到读出数据会有一个字节的延迟所以一次读操作往往需要发两个字节第一个是地址第二个是 dummy真正的数据在接收缓冲的第二个字节里。举个例子要读 WHO_AM_I 寄存器地址 0x0F主机发出的第一个字节就是0x0F | 0x80 0x8F然后发一个任意 dummy 字节MISO 上返回的第二个字节就是寄存器内容。这个模式遇到过几次之后就熟门熟路了第一次接触时容易犯的错是把返回值错误地取到第一个接收字节上导致读出来永远是 0。3.2 从WHO_AM_I到加速度数据几个关键寄存器先过一遍IIS2ICLX 的寄存器映射不算复杂第一篇文章里我们只需要关心四个地方WHO_AM_I0x0F设备 ID 寄存器上电后应读回一个固定的非 0 值。这是验证 SPI 链路是否打通的第一道关口。CTRL10x20模式控制寄存器选择连续测量模式、输出数据率 ODR、量程等。CTRL30x22包含地址自动递增 IF_ADD_INC 位。置 1 后连续读多个字节时会自动递增寄存器地址不需要手动逐个指定。OUT_X_L / OUT_X_H / OUT_Y_L / OUT_Y_H0x28~0x2BX 和 Y 轴的 16 位加速度原始值低字节在前。不同版本的数据手册对寄存器位的定义可能有细微差别我第一次用新芯片时总会把 CTRL1 和 CTRL3 的位定义打印出来摆在旁边对照这一步很值得做。因为这些位一旦配错表现出的症状很多样数据不动、数据只有一端变化、量程不对、正负方向相反如果一开始不从寄存器表上校对后面就要靠猜。3.3 地址自增IF_ADD_INC与多字节连续读ST 传感器对多字节读取提供了一个很贴心的机制把 CTRL3 的 IF_ADD_INC 位置 1 后只要在同一个片选周期内连续发送读命令和 dummy 字节传感器内部就会自动把寄存器地址加 1。这意味着我们读四个字节只需要发一次地址后面跟着四个 dummy就能一口气把 X_L、X_H、Y_L、Y_H 全部取回来。这个功能在你做高数据率采集时特别重要。如果没有地址自增每读一个字节就要单独拉低 CS、发一次地址、拉高 CS时序开销会大不少。开了自增之后一次 CS 周期就能完成一帧数据的导出不仅省时间还能保证同一组 X/Y 数据来自同一个采样时刻不会出现 X 是上一帧、Y 是这一帧的错位问题。3.4 验证链路的第一步读WHO_AM_I代码写出来之前先用最简单的方式确认 SPI 链路。我习惯的做法是上电后立刻读 WHO_AM_I把返回值通过串口打出来。如果返回值和数据手册上的设备 ID 一致说明物理接线、SPI 模式、时钟极性全部正确可以继续往下配置寄存器。如果读回来是 0x00大概率是 MISO 没接通、数据采样点不对、或者第一个接收字节被误当成有效数据。如果读回来是 0xFF则多半是 MOSI 或时钟极性出问题。这一步怎么强调都不过分。很多人在 SPI 通信上浪费大半天最后发现只是 dummy 字节顺序没搞清楚或者 CPHA 配错了。先把 WHO_AM_I 弄对后面所有寄存器配置才有可信的基础。4. 高分辨率SPI读取与传统中断/轮询方式的异同选型不只是接口选择4.1 先把概念边界划清楚说到“高分辨率 SPI 读取”和“传统中断/轮询方式”很多人容易把这两个概念放在对立面以为用了 SPI 就是高分辨率用了中断就是传统方案。实际上这两组词不在同一个维度上。SPI 是物理层接口中断和轮询是应用层的数据读取策略。IIS2ICLX 完全可以走“中断触发 SPI 单次读取”也可以走“主循环轮询 SPI 阻塞读取”这些组合里都有 SPI 的身影。我更倾向于把这次要对比的对象定义为两种系统架构流式批量读取架构传感器持续采样数据在 FIFO 里缓存MCU 通过 SPI 批量导出可能配合 DMA 直接把数据搬进内存。这种架构适合高数据率、需要连续样本的应用。事件驱动单次读取架构传感器每完成一次采样就通过 INT 引脚通知 MCUMCU 才去 SPI 读一次或者 MCU 按固定周期轮询状态位。这种架构适合低数据率、低功耗、事件触发类应用。这样划清楚之后比较才有意义我们比的是“流式批量读”和“事件驱动单次读”而不是单纯地比 SPI 和 GPIO。4.2 延迟一致性、CPU占用、数据完整性三个维度从工程学的角度我习惯用三个维度去判断到底选哪种方案延迟一致性、CPU 占用、数据完整性。延迟一致性。中断方式的响应延迟最小理论上数据就绪后 MCU 能立刻感知但代价是延迟的确定性受中断优先级、其他中断抢占、以及 SPI 传输代码本身耗时的影响。举个例子如果 ISR 里用阻塞式 SPI 读两个字节SCLK 从产生到数据接收需要一段时间这段时间内其他中断全被挡着。轮询方式就更不用说了延迟完全取决于主循环什么时候转到这里可能差出好几毫秒。流式批量读取的延迟是周期性的数据以固定的节拍到内存虽然单次事件的“实时响应”不如中断那样立竿见影但整体时间轴非常均匀这对后续做 FFT、做滤波非常友好。CPU 占用。这是流式批量方案最大的优势。如果传感器以 1 kHz 输出频率采样事件驱动模式下意味着每毫秒就要进一次中断MCU 一秒钟被唤醒一千次每次还要跑完整个 SPI 传输。而流式方案里FIFO 可以攒下几百个样本MCU 每隔一小段时间才批量搬一次剩下的时间可以去跑算法、维护通信、睡大觉。对高数据率来说CPU 占用率可能相差一个数量级。数据完整性。高分辨率测量最怕的不是噪声而是丢点。中断模式下MCU 一旦在处理其他任务时错过了 INT 引脚的状态这一帧样本就悄悄丢了。低频倾角测量丢一帧可能无所谓但振动分析里数据流的连续性就是生命线任何丢点都会在频谱上制造假峰。流式批量读取配合 FIFO相当于给数据流加了一个缓冲保护即便 MCU 被别的事情拖住几十毫秒FIFO 里的样本也不会丢缓冲满了还有溢出标志可以查。这三者的对比我总结成一张表对比维度SPI流式批量读取FIFODMA中断驱动单次读取主循环轮询读取延迟周期性、均匀响应快但不均匀延迟最大且不确定CPU占用低批量搬移中每样本进ISR高阻塞等待数据完整性高FIFO兜底中容易丢样本中低取决于循环周期适用数据率数百Hz到数kHz低数据率、事件触发调试、静态标定、低ODR功耗可配合DMA睡眠事件唤醒适合电池不适合低功耗4.3 分辨率不等于采样率SPI也不等于快这里想专门辟一个误区很多人看到 IIS2ICLX 的 16 位分辨率就觉得必须用 SPI 高速连续读取否则浪费了这颗芯片。但“分辨率”和“采样率”是两个完全不同的概念。16 位分辨率描述的是每一个样本的量化精细度它由内部 ADC 的量程和位数决定跟你用 I2C 还是 SPI 读没有关系。哪怕你每秒只读一次只要寄存器配置正确读到的依然是 16 位精度的数据。SPI 的真正价值在于它能够承载“高采样率下的连续数据流”。如果你做的是低频倾角监测ODR 只有 1 Hz 到 12.5 Hz那么用 I2C 或者轮询方式完全够用。只有当 ODR 到几百赫兹甚至上千赫兹、并且需要全部样本做连续分析时SPI 的高吞吐能力才真正变成必要条件。选型第一件事永远是先搞清楚应用到底需要多高的数据率而不是看到“高分辨率”三个字就条件反射地选最贵的方案。4.4 实际项目里我的决策方式在真实的项目里我的判断标准可以浓缩成三条。第一条如果传感器输出数据率低于 100 Hz且 MCU 主要功能是待机、通信、显示那我倾向用中断驱动方式数据就绪才读省电且实现简单。第二条如果 ODR 高于几百 Hz且我需要完整的样本做频谱、滤波、趋势分析那就毫不犹豫走 SPI FIFO DMA 的流式方案这是唯一能保证数据连续性的做法。第三条如果只是调试阶段验证传感器、标定零偏、看看基本输出是否符合预期轮询就够直接定时去读四个字节简单直接。这篇文章的第一版驱动做的就是第三条路线用最保守的阻塞式 SPI 轮询读取先把传感器调通。代码结构上保留了三层分离的接口后续切到中断触发或 DMA 批量搬移时只需要替换最底层的读取函数上层的换算和数据处理逻辑不用动。5. 驱动代码实现从阻塞式读寄存器到加速度换算5.1 驱动分层先想清楚再动手写驱动之前我习惯先分两层。第一层是 SPI 物理层只负责发地址、收数据不关心数据含义这一层直接封装 HAL_SPI_TransmitReceive 系列函数第二层是传感器寄存器层负责组织寄存器地址、配置模式、读取输出数据、做补码换算。分层的好处是将来要换成 DMA 读取只需要重写物理层的函数寄存器层的调用和换算逻辑完全不受影响。5.2 SPI收发函数与寄存器读写函数先定义片选操作和底层收发函数#define IIS2ICLX_CS_LOW() HAL_GPIO_WritePin(IIS2ICLX_CS_GPIO_PORT, IIS2ICLX_CS_PIN, GPIO_PIN_RESET) #define IIS2ICLX_CS_HIGH() HAL_GPIO_WritePin(IIS2ICLX_CS_GPIO_PORT, IIS2ICLX_CS_PIN, GPIO_PIN_SET) uint8_t IIS2ICLX_ReadReg(uint8_t reg) { uint8_t tx[2]; uint8_t rx[2] {0}; tx[0] reg | 0x80; // 读操作最高位置1 tx[1] 0x00; // dummy字节 IIS2ICLX_CS_LOW(); HAL_SPI_TransmitReceive(hspi1, tx, rx, 2, 100); IIS2ICLX_CS_HIGH(); return rx[1]; // 有效数据在第二个接收字节 } void IIS2ICLX_WriteReg(uint8_t reg, uint8_t value) { uint8_t tx[2]; tx[0] reg 0x7F; // 写操作最高位清零 tx[1] value; IIS2ICLX_CS_LOW(); HAL_SPI_Transmit(hspi1, tx, 2, 100); IIS2ICLX_CS_HIGH(); }有不少人一上来就去查 FIFO 配置、查 DMA 通道结果连寄存器读写函数都没写对。读函数返回rx[1]这个细节就是典型问题如果返回了rx[0]那个字节只是地址回显或无效数据会导致后面所有断言全部失败。先把这个函数调对其他都顺了。5.3 初始化配置CTRL3、CTRL1与量程初始化要做的就是把芯片从默认状态切到连续测量模式并打开地址自增。下面代码中的寄存器值是我在调试时使用的示例具体位定义请务必对照你手上的数据手册做二次确认void IIS2ICLX_Init(void) { uint8_t id 0; id IIS2ICLX_ReadReg(0x0F); // WHO_AM_I printf(WHO_AM_I 0x%02X\n, id); // 打开地址自增 IF_ADD_INC IIS2ICLX_WriteReg(0x22, 0x10); // CTRL3示例值按数据手册确认位定义 // 设置连续测量模式、ODR、量程 IIS2ICLX_WriteReg(0x20, 0x80); // CTRL1示例值按数据手册确认位定义 }初始化这一步做两件事读取 WHO_AM_I 确认链路然后配置测量模式。如果你读回来的 ID 是 0 或者 0xFF不要继续往下配寄存器先把 SPI 物理层查干净。我在项目中见过太多人跳过 WHO_AM_I 直接配 CTRL1最后数据出来的形态完全没规律不得不回头检查链路白白浪费大半天。5.4 一次读四个字节X/Y轴原始数据与换算利用地址自增一次片选读完四个输出寄存器。顺序是 X 低字节、X 高字节、Y 低字节、Y 高字节拼成两个 int16_tvoid IIS2ICLX_ReadAccel(int16_t *acc_x, int16_t *acc_y) { uint8_t tx[5]; uint8_t rx[5] {0}; tx[0] 0x28 | 0x80; // OUT_X_L读操作 tx[1] 0x00; // dummy对应 OUT_X_L tx[2] 0x00; // dummy对应 OUT_X_H tx[3] 0x00; // dummy对应 OUT_Y_L tx[4] 0x00; // dummy对应 OUT_Y_H IIS2ICLX_CS_LOW(); HAL_SPI_TransmitReceive(hspi1, tx, rx, 5, 100); IIS2ICLX_CS_HIGH(); *acc_x (int16_t)(rx[1] | (rx[2] 8)); *acc_y (int16_t)(rx[3] | (rx[4] 8)); }拿到原始值后换算公式取决于量程和灵敏度。以 ±0.5g 量程为例IIS2ICLX 的典型灵敏度是 0.0154 mg/LSB换算关系如下#define IIS2ICLX_SENSITIVITY_MG 0.0154f // mg/LSB±0.5g量程 float acc_x_mg (float)acc_x * IIS2ICLX_SENSITIVITY_MG; float acc_y_mg (float)acc_y * IIS2ICLX_SENSITIVITY_MG;如果配置的是 ±1g、±2g、±3g 量程灵敏度要对应减半、或按比例调整。这一点很容易被忽略导致同一个静态角度下数据差了数倍。我一般会在驱动里做一个量程枚举和灵敏度表每次改量程时同步换表避免手动改数字改错。5.5 主循环中的读取与打印主循环就简单了设置一个定时节奏然后读取、换算、通过串口打印int16_t acc_x, acc_y; float x_mg, y_mg; while (1) { IIS2ICLX_ReadAccel(acc_x, acc_y); x_mg (float)acc_x * IIS2ICLX_SENSITIVITY_MG; y_mg (float)acc_y * IIS2ICLX_SENSITIVITY_MG; printf(X: %.3f mg, Y: %.3f mg\r\n, x_mg, y_mg); HAL_Delay(10); }10 毫秒读一次对应约 100 Hz 的数据率。在阻塞模式下这个节奏已经能把 SPI 链路验证得很透彻了。把板子放平、放斜、翻过来观察输出的正负方向和数值变化是否合理这是验证加速度计最直观的手段。6. 实测结果与调试经验静态标定、常见坑、下一步扩展6.1 静态验证水平与竖直放置时数据表现把这块传感器平放在桌面上X 和 Y 轴的输出应该在 0 mg 附近小幅波动波动幅度取决于传感器的噪声水平。再把传感器竖起来让 Y 轴垂直指向地面Y 轴输出会接近 ±1000 mg 左右反过来 X 轴垂直指向地面时X 轴也会有类似表现。通过这种简单的旋转能立刻判断引脚映射、量程配置、正负方向是否正确。这里有个细节值得注意IIS2ICLX 是双轴传感器没有 Z 轴所以当你把传感器竖直放置、让某个轴完全垂直于重力方向时另一个轴会看到接近 1000 mg 的重力分量。如果预期是三轴加速度计那种“Z 轴变 1g、其余两轴接近 0”的行为模式用在这颗芯片上就会觉得“少了一轴”。这是芯片定位决定的不是出了问题。6.2 WHO_AM_I读不到按这条链路去查如果 WHO_AM_I 读出来不对我建议按固定顺序排查线序MISO 和 MOSI 有没有接反。接反后主机发出的地址从机收不到从机返回的数据主机也收不到症状就是读回 0xFF 或 0x00。SPI 模式CPOL/CPHA 是否正确。模式配错时采样点会落在数据变化的瞬间读出的数据毫无规律。片选时序CS 是否在每次通信周期之间拉高。如果 CS 一直低着传感器可能卡在某个状态不再响应新的 SPI 命令。时钟速率很多传感器对 SCLK 的最高频率有上限虽然 IIS2ICLX 不算慢但在长杜邦线、无阻抗匹配的情况下速率太高会导致数据错位先降到 1 MHz 再测。去耦电容供电不稳、电源纹波大也可能导致芯片上电没完成初始化WHO_AM_I 读不到。传感器 VDD 旁边并一颗 100nF大多数情况能解决稳定性问题。排查链路的核心思想是从“链路有没有通”到“链路通得对不对”到“芯片有没有正常工作”一层层剥。不要一上来就怀疑芯片坏了实际上百分之九十的故障都出在接线和 SPI 参数上。6.3 零偏与噪声毛刺短时间波动用均值任何加速度计都不可能完全零偏。IIS2ICLX 的高灵敏度意味着它会忠实地把微小的机械振动、热噪声、电路噪声全部带进数据里。静态放置时数据在小范围内来回跳是很正常的如果每个 LSB 换算后的值一直稳定在 0.0154 mg 的台阶上那才说明传感器已经死掉了。实际做倾角测量时最简单的降噪手段就是滑动均值。我的做法是在驱动层保留原始数据在应用层开一个长度为 16 或 32 的环形缓冲区每来一个新样本就更新平均值。这样既不影响 SPI 读取的实时性又能把高频噪声压下去。对静态倾角应用来说这个方案性价比高到离谱完全不需要先把数据做 FFT 分析再设计滤波器。6.4 从轮询到FIFO与DMA下一阶段的演进方向这篇文章里我们一直用的是阻塞式轮询读取它存在的意义就是把传感器链路先调通。等确认数据格式、量程、正负方向、零偏表现都符合预期后下一步自然要往高分辨率流式方案走配置传感器的 FIFO把多组样本攒在芯片内部然后通过 SPI DMA 批量搬到 MCU 内存。这样做的收益是双重的一方面 CPU 不用频繁进出中断另一方面数据流连续性好给后续的时域分析和频域分析打底。我自己做这类项目时总是认同一句话先把最简单的方式跑通再往复杂方向演进。直接上 DMA 的方案省掉了理解传感器时序的机会一旦出问题芯片、接线、DMA、FIFO 四个变量搅在一起谁也没法快速定位。先轮询跑通等于把变量一个个消掉后面再做优化时思路会清晰很多。就写到这里这颗芯片的 SPI 通路就算打通了。如果只是想先把 IIS2ICLX 跑起来上面的驱动和调试思路已经够用后面要做的 FIFO、DMA、真正的倾角算法都是在这条已经验证过的链路上叠加。我调试传感器时最喜欢的顺序永远是先读 WHO_AM_I再转板子看输出方向最后才碰传输优化这个顺序帮我省下的时间远比看起来多得多。
网站建设高端定制企业官网