Problems connecting LSM6DS3 to Xiao Ble on SPI

PJ_Glasso
Wed, 01 Apr 2026 17:04:10 +0000

Hi there,

SO, My first guess would be shared SPI bus handling.

A few reasons:

the IMU works over I2C, so the sensor is probably fine

the Adafruit library works in SPI, so the hardware path is at least basically correct

the failures only show up with the other SPI libraries while sharing the bus with the ADS1220

That points more toward chip-select handling, SPI mode/transaction conflicts, or library assumptions than what I first suspected to missing pull-ups.

The LSM6DS3 supports both I2C and SPI, with CS selecting SPI mode, and the SparkFun-style constructor for SPI is the expected pattern.

What I would try first:

1. Set both CS pins as outputs at startup and drive them HIGH before calling either library:

pinMode(IMU_CS, OUTPUT);
pinMode(ADS_CS, OUTPUT);
digitalWrite(IMU_CS, HIGH);
digitalWrite(ADS_CS, HIGH);

Test the IMU alone with the SparkFun/Seeed library, with the ADS1220 code completely removed.

Then test the ADS1220 alone.

When sharing the bus, make sure the other device’s CS is HIGH before every transaction.

Compare the Adafruit library behavior, since that one already works. It may simply be managing SPI transactions or chip select more carefully.

Here’s a cleaned-up test version that does the main things I would want on a shared SPI bus:

sets both CS pins HIGH before any device init

initializes SPI first

forces the other device deselected before talking to one device

adds a little structure so the bus is not left in a bad state

reads the IMU only once per loop pass

This does not fix a broken library internally, but it gives YOU a much better shot at making the shared bus behave.

/*
  XIAO nRF52840 / XIAO BLE
  Shared SPI test: ADS1220 + LSM6DS3TR-C

  Purpose:
  - Force proper chip-select handling on a shared SPI bus
  - Help diagnose why LSM6DS3 SPI init fails with some libraries

  Notes:
  - Both CS pins are driven HIGH before init
  - Only one device is selected at a time
  - IMU is tested with SparkFun/Seeed style LSM6DS3 library constructor
*/

#include <SPI.h>
#include <ADS1220_WE.h>
#include <LSM6DS3.h>

#define SAMPLE_RATE   90

#define IMU_CS        D6
#define ADS_CS        D7
#define ADS_DRDY      D3

bool adcok = false;
bool imuok = false;

LSM6DS3 MyImu(SPI_MODE, IMU_CS);
ADS1220_WE ads(ADS_CS, ADS_DRDY);

// -----------------------------
// Helper functions
// -----------------------------
void deselectAllSPI() {
  digitalWrite(IMU_CS, HIGH);
  digitalWrite(ADS_CS, HIGH);
}

void selectIMU() {
  digitalWrite(ADS_CS, HIGH);
  digitalWrite(IMU_CS, LOW);
}

void deselectIMU() {
  digitalWrite(IMU_CS, HIGH);
}

void selectADS() {
  digitalWrite(IMU_CS, HIGH);
  digitalWrite(ADS_CS, LOW);
}

void deselectADS() {
  digitalWrite(ADS_CS, HIGH);
}

// -----------------------------
// Setup
// -----------------------------
void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println();
  Serial.println("=================================");
  Serial.println("Shared SPI Test: ADS1220 + LSM6DS3");
  Serial.println("=================================");

  // IMPORTANT: set CS lines first
  pinMode(IMU_CS, OUTPUT);
  pinMode(ADS_CS, OUTPUT);

  deselectAllSPI();
  delay(10);

  // Start SPI bus
  SPI.begin();
  delay(10);

  Serial.println("Init Sensors...");

  // -----------------------------
  // Init ADS1220
  // -----------------------------
  deselectAllSPI();
  delay(5);

  ads.setSPIClockSpeed(1000000);

  // Make extra sure IMU is not selected during ADS init
  digitalWrite(IMU_CS, HIGH);
  if (!ads.init()) {
    Serial.println("ADS1220 is not connected!");
    adcok = false;
  } else {
    Serial.println("ADS1220 found");
    adcok = true;

    ads.setGain(ADS1220_GAIN_128);
    ads.setOperatingMode(ADS1220_DUTY_CYCLE_MODE);
    ads.setDataRate(ADS1220_DR_LVL_4);  // 82.5 SPS duty cycle mode
    ads.setConversionMode(ADS1220_CONTINUOUS);
    ads.setCompareChannels(ADS1220_MUX_1_2);
    ads.setVRefSource(ADS1220_VREF_REFP1_REFN1);
    ads.setLowSidePowerSwitch(ADS1220_SWITCH);
  }

  delay(200);

  // -----------------------------
  // Init LSM6DS3
  // -----------------------------
  deselectAllSPI();
  delay(5);

  // Make extra sure ADS is not selected during IMU init
  digitalWrite(ADS_CS, HIGH);

  int imuStatus = MyImu.begin();
  if (imuStatus != 0) {
    Serial.print("IMU not found! begin() returned: ");
    Serial.println(imuStatus);
    imuok = false;
  } else {
    Serial.println("IMU found");
    imuok = true;
  }

  deselectAllSPI();
  delay(100);

  Serial.println("Setup complete.");
  Serial.println();
}

// -----------------------------
// Main loop
// -----------------------------
void loop() {
  int cnt = SAMPLE_RATE;
  int32_t reading = 0;
  float gyroZ = 0.0f;

  while (cnt > 0) {
    // ----- Read ADS1220 -----
    if (adcok) {
      // Make sure IMU is deselected first
      deselectAllSPI();
      delayMicroseconds(5);

      reading = ads.getRawData();

      deselectADS();
    } else {
      delay(15);
    }

    // ----- Read IMU -----
    if (imuok) {
      // Make sure ADS is deselected first
      deselectAllSPI();
      delayMicroseconds(5);

      gyroZ = MyImu.readFloatGyroZ();

      deselectIMU();
    }

    cnt--;
  }

  Serial.print("Bridge Reading: ");
  Serial.println(reading);

  Serial.print("Gyroscope Z = ");
  Serial.println(gyroZ, 4);

  Serial.println("-----------------------------");
  delay(500);
}

First, test IMU only:

comment out all ADS1220 code

see whether MyImu.begin() works reliably

Then test ADS only.

If both work alone but fail together, that is strong proof of a shared-bus conflict, not a dead sensor.

If the IMU still fails with this version, the next things I would look at are:

SPI mode mismatch between the IMU library and ADS library

breakout board wiring for the LSM6DS3 SPI pins

whether the IMU breakout is really set up for 4-wire SPI

whether the library is doing odd things internally during begin()

Try that and report back , please.

HTH
GL PJ