树莓派通过SPI与ADXL355通信时寄存器地址不匹配问题排查
排查ADXL355与树莓派SPI通信寄存器地址不符的问题
我之前帮好几个开发者踩过ADXL355 SPI通信的坑,你遇到的“寄存器地址与手册不符”问题,基本都是以下几个细节没处理到位:
1. SPI读写的地址位格式错误(最常见的坑)
ADXL355的SPI协议和I2C完全不同,寄存器地址的最高位是读写控制位:
- 写操作时,最高位设为
0 - 读操作时,最高位设为
1
很多人直接用手册里的寄存器地址(比如0x00对应DEVID_AD)发送,但SPI读操作需要把原地址和0x80做或运算——比如读0x00寄存器,实际要发送的地址是0x00 | 0x80 = 0x80。如果直接发0x00,本质是在写这个寄存器,返回的自然是无关数据,和预期的寄存器值完全对不上。
举个正确的读寄存器函数示例:
uint8_t adxl355_read_reg(uint8_t reg_addr) { uint8_t tx[2] = {reg_addr | 0x80, 0x00}; // 第一个字节是带读位的地址,第二个是dummy字节 uint8_t rx[2]; // 执行SPI传输 bcm2835_spi_transfernb(tx, rx, 2); return rx[1]; // 第二个字节才是寄存器的返回值 }
2. SPI模式不匹配
ADXL355默认支持SPI模式0(CPOL=0, CPHA=0)和模式3(CPOL=1, CPHA=1),出厂默认是模式0。如果你的代码没明确设置SPI模式,或者设置成了模式1/2,时序不匹配会导致数据乱码,看起来就像寄存器地址不对。
初始化SPI时一定要加上模式设置:
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
3. CS片选时序问题
不管你用硬件CS还是软件控制CS,都要确保片选信号的时序符合要求:
- 读写前拉低CS,操作完成后必须拉高CS
- 如果用软件CS,要先把对应的GPIO配置为输出模式
示例代码里的软件CS配置:
#define CS_PIN RPI_GPIO_P1_24 // 对应GPIO8(SPI0 CS0) // 初始化CS引脚 bcm2835_gpio_fsel(CS_PIN, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_write(CS_PIN, HIGH); // 默认拉高 // 读写时的CS操作 bcm2835_gpio_write(CS_PIN, LOW); // 执行SPI传输 bcm2835_gpio_write(CS_PIN, HIGH);
4. SPI时钟频率过高
ADXL355的SPI最大时钟频率是5MHz,如果树莓派设置的SPI时钟超过这个值,会导致通信错误。bcm2835库的默认时钟可能高于这个上限,所以要手动设置分频器:
// 树莓派3(核心时钟1.2GHz)用256分频,得到≈4.68MHz,低于5MHz上限 bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_256); // 树莓派4(核心时钟1.5GHz)可以用512分频,得到≈2.93MHz,更稳定 // bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_512);
完整的修正示例代码
#include <bcm2835.h> #include <stdio.h> #define CS_PIN RPI_GPIO_P1_24 // 软件控制CS引脚(GPIO8) uint8_t adxl355_read_reg(uint8_t reg) { uint8_t tx_buf[2] = {reg | 0x80, 0x00}; uint8_t rx_buf[2]; bcm2835_gpio_write(CS_PIN, LOW); bcm2835_spi_transfernb(tx_buf, rx_buf, 2); bcm2835_gpio_write(CS_PIN, HIGH); return rx_buf[1]; } int main() { if (!bcm2835_init()) { printf("bcm2835初始化失败!\n"); return 1; } // SPI初始化 bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // ADXL355是MSB优先 bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // 匹配芯片默认模式 bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_256); // 控制时钟在5MHz以内 bcm2835_spi_chipSelect(BCM2835_SPI_CS_NONE); // 使用软件CS // 配置CS引脚 bcm2835_gpio_fsel(CS_PIN, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_write(CS_PIN, HIGH); // 读取关键寄存器 uint8_t devid_ad = adxl355_read_reg(0x00); uint8_t devid_mst = adxl355_read_reg(0x01); uint8_t partid = adxl355_read_reg(0x02); uint8_t revid = adxl355_read_reg(0x03); printf("DEVID_AD: 0x%02X(预期0xAD)\n", devid_ad); printf("DEVID_MST: 0x%02X(预期0x1D)\n", devid_mst); printf("PARTID: 0x%02X(预期0xED)\n", partid); printf("REVID: 0x%02X\n", revid); bcm2835_spi_end(); bcm2835_close(); return 0; }
先从地址位的读写控制开始排查,这是最容易忽略的点,基本能解决你遇到的问题。
内容的提问来源于stack exchange,提问作者Derek Nash
相关产品推荐
相关产品推荐

