拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ISM330DLC三线SPI模式实战:从接线到STM32驱动

最近在调一个基于ISM330DLC的六轴姿态监测方案板子空间吃紧GPIO数量被压缩到极限。I2C要两根线4线SPI要四根线算来算去手上的接口都不够用。后来把心一横直接走3 wire SPI mode把ISM330DLC的SPI接口砍到三根线硬件一下子松绑了。但这玩意从硬件接线到驱动适配坑位比我想象中多得多光是把数据从传感器里正确读出来就折腾了一整个下午。ISM330DLC是ST推出的一款低功耗六轴惯性传感器集成了3轴MEMS加速度计和3轴MEMS陀螺仪内置完整的信号调理链路和数字接口逻辑在可穿戴设备、TWS耳机、工业状态监测、AGV惯性导航、电动工具姿态感知等场景里都能看到它的身影。这颗芯片在数字接口上提供了I2C、4线SPI和3线SPI三种模式很多人默认只用了I2C或标准4线SPI实际上3线SPI模式在IO资源紧张时是很好用的备选方案但网上专门讲清楚3线模式的资料并不多。这篇文章主要面向两类读者一类是正在把ISM330DLC从4线SPI改到3线SPI的嵌入式开发另一类是刚接触六轴传感器、想搞明白3线SPI和普通SPI到底差在哪里的人。我会把这几天踩过的雷全部摊开讲引脚定义、寄存器SIM位配置、时序细节、STM32实测代码、逻辑分析仪波形验证以及排查通讯失败的几个高概率原因。1. 为什么单把一个3线SPI模式拿出来说1.1 IO资源紧张时的接口选型思路先聊聊为什么要折腾3线SPI。无论是做可穿戴设备还是小型化模组MCU的GPIO都是稀缺资源。以常见的STM32G0系列为例很多封装只有20脚或28脚一个UART、一个I2C、两个SPI接口、几路ADC、几个按键和LEDGPIO基本就满了。如果你的系统里恰好同时用了SPI Flash、SD卡、TFT屏那么SPI总线的压力会更大。这个时候每省一根数据线对系统设计和布线都是实实在在的帮助。标准的4线SPI需要SCLK、MOSI、MISO、CS四根信号线加上电源、地、中断输出一个传感器至少要吃掉6到7个引脚。I2C虽然只要两根线但I2C的速率上限通常在1MHz左右而且要处理地址仲裁、时钟拉伸等问题在传感器数据吞吐要求较高或者需要多个从设备的场景里并不总是最优解。3线SPI正好卡在两者中间它保留了SPI的帧结构、全双工能力和高时钟频率又比4线SPI少一根数据线把MOSI和MISO合并成一根双向数据线这时候传感器只需要SCLK、CS、DATA三根线配合中断引脚一个六轴传感器总共只占5个GPIO。从系统架构的角度来看3线SPI还有一个隐形的优势如果MCU原生的硬件SPI外设支持半双工单线模式那么3线SPI的数据收发可以完全交给硬件不需要占用CPU轮询DMA也能配合使用。这意味着你既能获得I2C级别的引脚经济性又能获得接近标准SPI的传输带宽对于需要持续高频读取加速度计和陀螺仪数据的姿态解算场景非常友好。1.2 ISM330DLC的数字接口全景ISM330DLC的数字接口引脚设计是典型的“一针多功能”策略。物理上它把SCL和SPC合并成一个引脚把SDO和SA0合并成一个引脚把SDI和SDA的概念也做了复用。这颗芯片支持从机模式接口协议选择取决于CS引脚的电平状态CS拉高时走I2CCS拉低时走SPI。这也是ST传感器的一贯设计好处是同一颗芯片可以灵活适配不同主控方案坏处是引脚功能表看起来容易把人绕晕。切换到SPI模式之后还能再细分出4线SPI和3线SPI两种工作方式。4线SPI用SDI做MOSISDO做MISO3线SPI把SDI和SDO合并到一个物理引脚上方向由主机在帧的不同阶段控制。这个“合并”实际上是通过寄存器里的一个位来切换的不是单纯把两根线短接在一起这一点太关键了如果只是把SDI和SDO短接却不去配置寄存器结果是读操作时MISO信号被MOSI驱动端强行拉低或拉高传感器根本无法正常回复数据。1.3 3线SPI和4线SPI的本质区别用一句话概括3线SPI和4线SPI的帧结构一样区别在物理信号线的数量和数据线上方向控制的责任方不同。先看帧结构。ISM330DLC的SPI访问流程是先由主机发送一个命令字节这个字节的高7位是寄存器地址最低位是读写标志。读操作时最低位为1写操作时最低位为0。命令字节发送完之后写操作接着由主机继续发送数据字节读操作则由传感器把数据放到数据线上主机在时钟边沿采样。4线SPI模式下命令字节和数据字节的接收是并行展开的主机通过MOSI发送命令传感器的响应通过MISO回来两条线的方向是固定的主机不需要在帧中间切换引脚方向。3线SPI模式下命令字节必须由主机通过这条双向数据线发出去然后主机必须立刻把这条线的方向从输出切换到输入接下来的每个时钟周期传感器会把数据一位一位推到同一条线上主机再把它采样进来。方向切换不能有丝毫犹豫如果切换早了或者晚了读到的数据就会错位导致整个数据帧报废。这个“方向切换”就是3线SPI比4线SPI多出来的核心复杂度。2. 硬件接线方案先把这个搞对了再谈代码2.1 ISM330DLC引脚定义与3线接线表ISM330DLC常见封装是LGA-14体积非常小。在进行3线SPI接线之前先记住引脚功能引脚编号引脚名称4线SPI功能3线SPI功能I2C功能1SCL/SPCSPI时钟输入(SCLK)SPI时钟输入(SPC)I2C时钟(SCL)2CS片选输入片选输入I2C地址选择(电平决定)3SDI/SDO数据输入(MOSI)双向数据线(SDx)I2C数据(SDA)4SDO/SA0数据输出(MISO)地址选择输入(SA0)I2C地址位(SA0)3线SPI模式下引脚4不再参与数据收发它的功能退化成I2C地址选择位。如果系统只用SPI这个引脚可以接一个下拉电阻到地把SA0固定为0如果后续还可能切换到I2C调试就接一个上拉电阻到VDD把SA0固定为1这样I2C地址和SPI模式互不冲突。两种接法我都试过实测只要在CS为高时SA0电平稳定SPI通讯都不受影响。接线时注意把主控端的GPIO类型配置对时钟线和CS接普通推挽输出双向数据线要配置成开漏输出并外接上拉电阻或者配置成推挽输出但内部使能上拉。推荐直接使用MCU内部的上下拉或者外接一颗4.7kΩ到10kΩ的上拉电阻这样在主机方向切换的空窗期数据线不会进入高阻浮动状态避免误触发传感器侧的电平判断。2.2 为什么SDO引脚在3线模式下变成了地址引脚这部分很容易让人困惑。在4线SPI模式下SDO是数据输出脚传感器通过它把读出的数据送回主机但在3线SPI模式下数据输出功能和数据输入功能合并到引脚3上了引脚4上的SDO功能就完全没用了。ST的数据手册里明确写着在3线模式或I2C模式下SDO/SA0这个引脚要作为SA0地址输入来使用。这意味着什么意味着如果你在做PCB设计时把引脚4焊死接地芯片在I2C模式下的地址就被固定了在3线SPI模式下则不会影响SPI通讯因为SPI不依赖I2C地址。但如果你的系统同时保留了I2C和SPI两种接口打算用跳线切换那么引脚4的电平必须在每次上电时保持稳定否则I2C地址可能随机漂移。我在实际项目中遇到过一个问题把SDO/SA0悬空SPI通讯正常但偶尔上电后I2C扫描不到设备后来发现是悬空引脚电平不稳定导致的。虽然你用的是3线SPI但还是建议引脚4别悬空直接接一个100kΩ下拉或者上拉电阻把电平固定下来省心不少。2.3 硬件接线实拍与注意事项拿STM32G474为例我把SPI1的SCK、CS和MOSI引脚分别映射到PA5、PA6、PA7MOSI引脚在3线模式下要复用为双向数据线。接线图大概是这样的ISM330DLC SCL/SPC → STM32 PA5 (SPI1_SCK)ISM330DLC CS → STM32 PA6 (SPI1_NSS软件控制)ISM330DLC SDI/SDO → STM32 PA7 (SPI1_MOSI半双工模式下作为数据线)ISM330DLC SDO/SA0 → 100kΩ下拉电阻到地VDD_I/O → 1.8V或3.3V接主控IO电源域VDD → 主电源1.71V~3.6VGND → 地有几个细节值得提醒。第一ISM330DLC的VDD_I/O和VDD可以独立供电如果主控IO电平是1.8V传感器模拟电源用3.3V记得把VDD_I/O接到1.8V否则引脚电平可能不符合IO电平规范。第二上电时序上VDD要先于VDD_I/O或者同时上电这个在数据手册里有时序图建议严格按照手册来。第三MEMS传感器对电源纹波敏感VDD引脚旁边要放一颗100nF的陶瓷电容尽量靠近引脚放置有条件再加一颗10μF的钽电容稳压这个对减少加速度计数据的噪声有直接帮助。3. 寄存器配置让传感器真正进入3线SPI模式3.1 CTRL3_C寄存器SIM位解析关键寄存器是CTRL3_C地址0x12。这个寄存器是ISM330DLC接口配置的枢纽很多关键功能都集中在这里。里面的SIM位bit3专门控制SPI工作线数寄存器位名称功能含义默认值bit7BOOT重新启动内部存储器0bit6BDU块数据更新0bit5H_LACT中断输出高/低有效0bit4PP_OD推挽/开漏输出0bit3SIMSPI接口模式04线13线0bit2IF_INC寄存器地址自动递增1bit1SW_RESET软件复位0bit0保留保留0把SIM位写1传感器就切换到3线SPI模式。注意这个位在默认状态下是0也就是上电后芯片默认工作在4线SPI模式。如果你硬件上只接了三根线又没有改这个寄存器就想直接读数据大概率读不回来。因为芯片还在期待MISO输出数据而MISO引脚也就是上面表格里的SDO/SA0已经被用作地址选择了数据通道没有物理意义。3.2 软件复位与初始化序列推荐在写SIM位之前进行一次软件复位让芯片回到一个确定的起始状态。复位方法有两种上电自动复位或者把CTRL3_C的SW_RESET位置1然后等待复位完成。软件复位的等待时间一般建议30ms以上实际测试中给足50ms比较稳妥。完整的初始化序列如下void ism330dlc_init_3wire(void) { // 1. 上电后延时等电源稳定 HAL_Delay(20); // 2. 软件复位 ism330dlc_write_reg(0x12, 0x01); // SW_RESET 1 HAL_Delay(50); // 3. 进入3线模式 使能块数据更新 地址自动递增 // 0x4C BDU(bit61) SIM(bit31) IF_INC(bit21) ism330dlc_write_reg(0x12, 0x4C); // 4. 配置加速度计量程±2gODR 416Hz // 具体ODR位参考数据手册Table 3 ism330dlc_write_reg(0x10, 0x60); // 5. 配置陀螺仪量程±250dpsODR 416Hz // 具体ODR位参考数据手册Table 13 ism330dlc_write_reg(0x11, 0x60); }SMAP具体写入0x4C的含义要拆开算一下0x4C二进制是0100 1100bit61对应BDUbit31对应SIMbit21对应IF_INC。BDU建议开启它的作用是保证数据寄存器在读取过程中不会因为新数据到来而被半覆盖避免我们看到的高字节和低字节分别来自两次不同的采样造成数据撕裂IF_INC建议开启这样连续读取6个轴的数据时只需要给一次起始地址后面自动递增不用每个字节都发一次地址。3.3 写寄存器时命令字节的格式初始化代码里的write_reg函数内部必须符合ISM330DLC的SPI帧格式。命令字节由7位寄存器地址加上1位读写标志组成寄存器地址左移1位读写标志位放在最低位。因此写寄存器0x12的地址时命令字节是0x12 1 0x24再加上数据字节0x4C一帧总共两个字节void ism330dlc_write_reg(uint8_t reg, uint8_t data) { uint8_t cmd (reg 1) 0xFE; // 最低位置0表示写操作 // 发送cmd再发送data }读寄存器时命令字节最低位置1例如读0x0FWHO_AM_I要发送0x1F。这个细节我在第一次接手ST传感器时踩过坑很多人直接把寄存器地址0x0F当成SPI命令发出去结果读回来全是0xFF。ST的SPI地址格式和有些厂商不一样它要求地址占据高7位读/写标志放在最低位这点务必在代码注释里写清楚防止以后维护的人再踩。4. 读取数据的底层时序与实测4.1 读操作的方向切换时间窗3线SPI模式下的读操作是最考验时序的部分。先把读操作的完整时序流程拆开主机把CS拉低。主机的数据线处于输出状态发送命令字节地址 读标志。命令字节的最后一位发送完成后主机必须在极短的时间内把数据线切换成输入状态。传感器感知到命令字节的读标志后会在下一个时钟周期开始把数据一位一位地放到数据线上。主机继续产生8个时钟脉冲或更多视读取长度而定在每一个时钟的采样边沿读取数据线上的电平拼成完整字节。读完之后主机把CS拉高一次读事务结束。关键点在第3步到第4步之间的切换窗口。如果切换太晚传感器已经在数据线上输出了第一个数据位而主机还在驱动数据线双方就会互相打架造成读到的第一个字节发生位错误。如果切换太早也就是在命令字节还没有完全发出的时候切到输入状态那命令字节的最后几位会发送不完整。所以这个切换窗口非常狭窄实际经验是必须在命令字节最后一位边沿之后、下一个时钟边沿之前完成大概只有几十纳秒的窗口。对于MCU如果使用硬件SPI外设的3线模式这个切换是硬件自动完成的——前提是配置正确。如果是使用GPIO模拟SPI就需要在代码里对方向切换的插入位置非常敏感。我在用软件模拟的时候会在发送完命令字节之后立刻执行GPIO方向切换寄存器写入中途不插入任何多余语句然后才开始产生读时钟。这里需要提醒一下GPIO方向切换通常是对ODR、IDR或者方向寄存器的写操作要尽量选择支持快速切换的引脚有些MCU的GPIO切换引脚方向需要好几个系统时钟周期这时候就要降低SPI时钟频率给方向切换留出余量。4.2 读WHO_AM_I的验证流程任何SPI外设初始化后的第一件事都应该是读WHO_AM_I寄存器验证通信链路是否打通。ISM330DLC的WHO_AM_I寄存器地址是0x0F读出来应该固定是0x6A。3线SPI模式下读WHO_AM_I的逻辑分析仪波形清楚地显示了三个关键区段CS拉低命令字节0x1F出现在数据线上然后数据线方向反转并出现8个时钟数据线返回0x6A。只要时序配合正确这个波形看起来非常干净。如果示波器上看到命令字节之后数据线持续输出低电平或者高电平基本可以肯定是方向切换没有生效或者传感器没有进入3线模式。我把一次读WHO_AM_I的伪代码贴在下面这段代码在STM32的多种系列上都验证过uint8_t ism330dlc_read_reg(uint8_t reg) { uint8_t cmd (reg 1) | 0x01; // 读命令 uint8_t data 0; // 拉低CS HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET); // 模式切换确保数据线为输出模式并发送命令 SPI3_LINE_DIR_OUTPUT(); spi3_write_byte(cmd); // 关键方向切换 SPI3_LINE_DIR_INPUT(); // 产生8个时钟读回数据 data spi3_read_byte(); // 拉高CS HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET); return data; }第一次跑通这个函数后我用逻辑分析仪确认了读回的0x6A那一刻才算真正松口气。后面接陀螺仪和加速度计数据只要这个链路是通的剩下的就是寄存器配置正确性问题。4.3 连续多字节读取时的地址自增逻辑ISM330DLC的六个轴数据分布在连续的寄存器区间陀螺仪X轴低字节为0x22按OUTX_L_G、OUTX_H_G、OUTY_L_G、OUTY_H_G、OUTZ_L_G、OUTZ_H_G的顺序排列加速度计则从0x28开始。如果IF_INC位已经置1那么读取时可以只发送一次起始地址然后连续产生几十个时钟脉冲传感器会自动把后续寄存器地址的内容依次放到数据线上。但这里有一个细节需要注意3线SPI模式下多字节读取的方向切换发生在命令字节之后之后的每个字节读取期间主机的数据线都需要保持输入状态同时持续产生时钟。这意味着数据线的方向切换只发生两次——发送命令前的输出状态和命令后的输入状态——而不是每个字节都切来切去。这也是3线模式在多字节读取时效率比想象中高很多的原因。我推荐在读六轴数据时一次读完14个字节把温度0x20/0x21、陀螺仪0x22-0x27、加速度计0x28-0x2D全部装回来然后在内存里做解析而不是挨个寄存器分次读。这样做既减少了CS的翻转次数也减少了命令字节的重复发送对效率和实时性都有帮助。void ism330dlc_read_all(float* accel_g, float* gyro_dps) { uint8_t buf[14]; uint8_t reg 0x20; // OUT_TEMP_L 起始地址 uint8_t cmd (reg 1) | 0x01; HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET); SPI3_LINE_DIR_OUTPUT(); spi3_write_byte(cmd); SPI3_LINE_DIR_INPUT(); for (int i 0; i 14; i) { buf[i] spi3_read_byte(); } HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET); // 解析小端模式int16_t int16_t gx (int16_t)((buf[2] 8) | buf[1]); // ... 按需解析 }4.4 CPOL和CPHA到底该选哪个ISM330DLC数据手册里明确写了SPI支持模式0CPOL0CPHA0和模式3CPOL1CPHA1。实际工程中绝大多数人都用模式0和大多数SPI从机设备的兼容性最好。在代码里配置STM32的时候把时钟极性设为低电平空闲时钟相位设为第一个边沿采样也就是CPOL0、CPHA0。如果配置成模式1或模式2CPOL与CPHA不匹配通常现象是能读回数据但数据是错位的或者第一个字节总是丢一个位。因为SPI模式选择直接决定了数据线和时钟沿的相位关系ISD330DLC的输入锁存边沿如果和主机输出数据的变化边沿重叠就会出现采样到错误电平的问题。我在调试过程中曾用逻辑分析仪对比过模式0和模式3的波形模式3也能读出正确数据但模式0的波形更标准所以最终固定使用模式0。5. STM32上用硬件SPI跑3线模式的实操过程5.1 硬件SPI半双工模式怎么配STM32的SPI外设原生支持半双工单线模式在CubeMX里对应的方向配置是“1 LineHalf-Duplex”。这个模式正好能对接ISM330DLC的3线SPI。但有几个关键配置项必须特别注意第一复用引脚必须要用MOSI不能用MISO。半双工模式下数据线借用MOSI引脚MISO引脚会被释放出来做普通GPIO。在CubeMX里配置引脚功能时如果误把MISO复用了数据线就不会通。第二需要注意SPI的BIDIMODE和BIDIOE两个位的状态。BIDIMODE置1启用单线半双工BIDIOE决定当前数据线方向1为输出0为输入。硬件在发送数据时自动把方向设为输出但在进接收阶段时通常需要软件干预。第三时钟速度不要拉到最高。ISM330DLC数据手册标称最大SPI时钟10MHz但3线模式下由于方向切换的存在建议实际使用中不要把SCLK推到极限。我测试过5MHz以下非常稳定10MHz在短距离接线5cm时也能跑通但一旦数据线走线超过10cm或者经过接插件信号质量下降明显容易偶尔读到错误数据。工程上建议先从较低频率1MHz开始调通验证通过后再慢慢往上提。5.2 STM32代码中方向切换的具体写法在STM32上BIDIOE位的切换依赖于寄存器操作。下面是STM32G4系列上的一个示例片段// 发送命令字节函数 static void spi3_send_cmd(uint8_t cmd) { // 确保数据线为输出方向 SET_BIT(SPI1-CR1, SPI_CR1_BIDIOE); while (!(SPI1-SR SPI_SR_TXE)); *((volatile uint8_t*)SPI1-DR) cmd; while (SPI1-SR SPI_SR_BSY); // 等待发送完成 } // 读数据字节函数 static uint8_t spi3_read_byte(void) { uint8_t data; CLEAR_BIT(SPI1-CR1, SPI_CR1_BIDIOE); // 切换为输入 // 写一个伪字节产生时钟 *((volatile uint8_t*)SPI1-DR) 0xFF; while (!(SPI1-SR SPI_SR_RXNE)); data *((volatile uint8_t*)SPI1-DR); return data; }发命令字节后如果紧接着要读数据需要先确认命令字节已经完全移出等待BSY清零然后再切换方向。否则可能在命令字节还没完全发出去时就把数据线切到输入方向导致命令字节不完整。这一点在时序上非常讲究很多人刚开始写的时候在发送命令和切换方向之间不加等待结果读出来永远是错的数据。读取完成后如果需要在下一次操作时发送命令记得恢复BIDIOE为输出。我封装了一个三合一函数把片选、命令发送、方向切换和数据读取都包在里面这样调用侧不用关系底层细节代码也更不容易出错。5.3 HAL库API和寄存器操作的取舍STM32的HAL库对SPI半双工模式有封装HAL_SPI_Transmit和HAL_SPI_Receive可以分别处理发送和接收阶段。但在实际调试3线SPI时我发现直接操作寄存器往往更可控因为HAL库在方向切换的处理上有时过于“智能”会引入不必要的延迟导致时序窗口不稳定。HAL库的问题在于它默认认为SPI是全双工或者半双工的在调用HAL_SPI_Transmit之后SPI硬件方向位会自动变为输出调用HAL_SPI_Receive时方向位理论上应该切回输入但部分HAL实现在切换前会等待TXE标志这已经引入了额外延时。如果你对实时性要求不高用HAL库能跑通但如果传感器读取频率很高或者系统里还有别的中断干扰HAL库的状态机我建议像我一样直接在驱动层写寄存器操作绕开HAL库的中间层。这样代码可读性稍差一点但可控性强了不止一档。另外一个常见的优化空间是用DMA。ISM330DLC的3线SPI模式下如果主机在接收阶段使用DMA外设自动产生时钟并搬运数据很大程度能减轻CPU负担。要注意的是DMA接收前同样要把BIDIOE位切到输入方向DMA传输完成后恢复为输出。在STM32G4上配置DMA时传输方向是针对SPI_RX的这个方向和BIDIOE是两回事需要分开处理。6. 调试实录典型问题与排查思路6.1 读WHO_AM_I返回0xFF或0x00这是最常见的故障现象出现这个问题的原因通常有三个。第一个是硬件接线问题3线SPI模式下如果数据线接错了引脚或者把SDO引脚当作数据线来用读回来肯定是0xFF。务必检查SDI/SDO引脚是否接到了主机侧的MOSI/数据引脚上SDO/SA0引脚是否用作地址选择而非数据线。第二个是寄存器配置问题芯片上电后默认处于4线SPI模式如果你的代码还没有把CTRL3_C的SIM位写成1芯片就不会在SDI引脚上输出数据命令字节发过去数据根本不会回来。解决办法是在初始化时确保CTRL3_C写入0x4C。第三个是时钟极性/相位配置错误CPOL/CPHA一旦选错数据采样点落在错误的边沿上读出来的数据每个bit都有机会错位最终结果就是0xFF或者0x00这种极端值。把CPOL设为0、CPHA设为0再试一次大多数情况下能解决。6.2 数据时好时坏、偶尔跳变这种现象在排除供电问题之后大概率是数据线方向切换时序抖动所致。在硬件SPI模式下如果使用了偏高的SPI时钟方向切换窗口会变窄再加上系统里中断的干扰个别数据帧就会读错。措施有三个降低SPI时钟、把片选控制改成硬件CS以缩短端到端延时、在数据线方向切换前后加适当延时。如果是GPIO模拟的方式还有一个常见原因是读取数据的采样语句放在了时钟边沿的错误一侧。要保证在时钟的采样边沿到来时数据线已经稳定同时方向切换要早于第一个采样边沿至少半个周期。推荐把方向切换放在命令字节发送完成后、产生第一个读时钟之前中间用一条空的NOP指令做保险。6.3 与SPI Flash或TFT屏共用总线时的坑很多系统里ISM330DLC会和其他SPI设备挂在同一条总线上。4线SPI模式时ISM330DLC的SDO输出只有在CS拉低、且确实在读操作时才会激活其他时间MISO线处于高阻状态外部通常需要加上拉电阻来保证浮空时保持稳定。3线SPI模式时数据线是双向的如果同一时刻有两个从设备试图驱动这条线就会发生总线冲突导致所有设备都收到错误数据。共用总线的安全做法是每个片选都由MCU单独控制ISM330DLC的CS绝对不能和Flash的CS并到一起在ISM330DLC的读操作完成、CS拉高之前确保数据线的方向已经切回输出或者保持高阻总线上的上拉电阻值不能太小建议4.7kΩ到10kΩ太小会加重驱动负担太大会导致边沿变缓、信号质量下降。6.4 3线SPI模式下的散热和布局注意事项这个可能听起来有点奇怪但在我实际测试中发现ISM330DLC这种MEMS传感器对高频数字信号串扰很敏感。SPI时钟线如果和数据线平行走线过长时钟跳变可能通过寄生电容耦合到数据线上造成读取数据跳变。建议在PCB上让SPC时钟线尽量远离数据线如果空间允许中间隔一条地平面或者走一根地线屏蔽。另外传感器芯片下方尽量不要走大电流的数字信号线避免地弹噪声影响MEMS敏感单元。7. 最后再分享一个小技巧调试3线SPI模式的过程中最让我受益的还是那句老话先把链路验证通了再做应用层的功能。所谓链路验证就是老老实实读WHO_AM_I确认读到0x6A然后再去折腾加速度计和陀螺仪的配置。不少朋友一上来就急着读取实时数据结果发现数据全零或者乱跳最后排查了半天才发现连最基本的寄存器通信都没建立起来。如果手头有逻辑分析仪或者示波器务必把SPC、CS、数据线三根线都抓出来看一遍波形。3线SPI的时序比4线SPI更需要肉眼确认尤其是命令字节和读数据之间的方向切换点。我这次调试时就是靠逻辑分析仪抓到了一处方向切换晚了半拍的波形才定位到问题。把基础时序跑对之后剩下的事情无非就是按照数据手册把量程和采样率配好然后安心做姿态解算就行了。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门