Hi there,
Ok, So a lot to unpack here. You mixed methods, for the Easy DMA for one. The peripheral never actually gets a valid read, so EasyDMA never writes anything into it. If you use Arduino LSMDS3.h it uses WIRE under the Hood , Wire uses I2C different, than TWIM . Twim is a manual method. pick one or the other.
So I compiled it using the Seeed Nrf52840 Sense BSP at 1.1.11, I had to comment out the Timestamp business, because it is not there or wrong. I get the same serial output… verifies your process.
SO there’s That 
Also the DMA read is mixing polling with a callback interrupt, and a manual StartRX and even a Manual STOP the shorts get over written multiple times (buffer count ?) TOO much activity no way you can debug all that.
Start with a Polling only first version. then enable interrupts after you get some buffer data.
On nRF52 TWIM, ERRORSRC bits are:
0x01 – OVERRUN
0x02 – ANACK (address not acknowledged)

0x04 – DNACK (data not acknowledged)
Get rid of the ANACK and it will work.
Wire use twim0 already, so you reconfigure it and it breaks after the LMS6DS3 sets it… fix that.
So ERRORSRC = 2 means ANACK: the slave did not acknowledge the address phase.
If the address phase fails, the RX part never happens → EasyDMA never moves any bytes → your dma_buffer stays all zeros, exactly like you’re seeing.
So the real issue is before the buffer: the I²C transaction itself is failing.
On the XIAO nRF52840 Sense the LSM6DS3 is not on the external SDA/SCL header. It’s on an internal I²C bus wired to TWIM1 with private pins.
When you configured NRF_TWIM0 (or overwrote PSEL on TWIM1), you were talking to an empty bus, which is why you always saw ERRORSRC = 2 (ANACK) and a zeroed DMA buffer.
The trick is:
- Let the Seeed
LSM6DS3 library run myIMU.begin() so it configures the right TWIM and pins.
- After that, detect which TWIM instance has valid PSEL (not
0xFFFFFFFF) and reuse that peripheral for your EasyDMA transfers without changing its PSEL or ADDRESS.
- Just set
TXD.PTR/MAXCNT, RXD.PTR/MAXCNT, SHORTS = LASTTX_STARTRX | LASTRX_STOP, then TASKS_STARTTX = 1 and poll for EVENTS_STOPPED / EVENTS_ERROR.
Once you do that, DMA works and the FIFO bytes come out correctly.
This works 
// ============================================================================
// XIAO nRF52840 Sense - LSM6DS3 FIFO via EasyDMA (Auto-detect TWIM, Polling)
// Rev 1.3 - 2025-11-12
// PJGlasso & AI adv model NSD
// ----------------------------------------------------------------------------
// - Board: Seeed XIAO nRF52840 Sense (Seeed nRF52 Boards BSP 1.1.11)
// - IMU: LSM6DS3TR-C on internal I2C bus (not external SDA/SCL header)
// - Idea: Let the LSM6DS3 library configure the I2C bus, then reuse the
// same TWIM instance for raw EasyDMA FIFO reads.
// ============================================================================
#include <Arduino.h>
#include <Adafruit_TinyUSB.h>
#include "nrf.h"
#include <LSM6DS3.h>
#define IMU_ADDR 0x6A
#define FIFO_DATA_OUT_L 0x3E
#define FIFO_READ_SIZE 32
#ifdef PIN_LSM6DS3TR_C_POWER
#define IMU_POWER_PIN PIN_LSM6DS3TR_C_POWER
#endif
const char FW_REV[] = "Rev 1.3 - 2025-11-12";
NRF_TWIM_Type *imu_twim = nullptr;
bool dma_done = false;
bool dma_error = false;
uint32_t dma_error_src = 0;
uint8_t dma_buffer[FIFO_READ_SIZE];
LSM6DS3 myIMU(I2C_MODE, IMU_ADDR);
// ---------------- IMU FIFO config (no timestamp fields) ----------------
void init_IMU_fifo() {
myIMU.settings.gyroEnabled = 1;
myIMU.settings.gyroRange = 2000;
myIMU.settings.gyroSampleRate = 833;
myIMU.settings.gyroBandWidth = 200;
myIMU.settings.gyroFifoEnabled = 1;
myIMU.settings.gyroFifoDecimation = 1;
myIMU.settings.accelEnabled = 1;
myIMU.settings.accelRange = 16;
myIMU.settings.accelSampleRate = 833;
myIMU.settings.accelBandWidth = 200;
myIMU.settings.accelFifoEnabled = 1;
myIMU.settings.accelFifoDecimation= 1;
myIMU.settings.tempEnabled = 1;
myIMU.settings.commMode = 1; // I2C
myIMU.settings.fifoThreshold = 100;
myIMU.settings.fifoSampleRate = 50;
myIMU.settings.fifoModeWord = 6; // continuous mode
}
// ---------------- Detect which TWIM the IMU is on ----------------------
static bool twim_has_valid_pins(NRF_TWIM_Type *twim) {
return (twim->PSEL.SCL != 0xFFFFFFFFu) && (twim->PSEL.SDA != 0xFFFFFFFFu);
}
void detect_imu_twim() {
bool t0 = twim_has_valid_pins(NRF_TWIM0);
bool t1 = twim_has_valid_pins(NRF_TWIM1);
Serial.println("Detecting IMU TWIM instance...");
Serial.print(" TWIM0 PSEL.SCL: 0x"); Serial.println(NRF_TWIM0->PSEL.SCL, HEX);
Serial.print(" TWIM0 PSEL.SDA: 0x"); Serial.println(NRF_TWIM0->PSEL.SDA, HEX);
Serial.print(" TWIM1 PSEL.SCL: 0x"); Serial.println(NRF_TWIM1->PSEL.SCL, HEX);
Serial.print(" TWIM1 PSEL.SDA: 0x"); Serial.println(NRF_TWIM1->PSEL.SDA, HEX);
if (t0 && !t1) {
imu_twim = NRF_TWIM0;
Serial.println("Selected IMU TWIM: TWIM0");
} else if (!t0 && t1) {
imu_twim = NRF_TWIM1;
Serial.println("Selected IMU TWIM: TWIM1");
} else if (t0 && t1) {
imu_twim = NRF_TWIM1; // if both, prefer TWIM1
Serial.println("Both TWIM0 and TWIM1 valid, defaulting to TWIM1.");
} else {
imu_twim = nullptr;
Serial.println("ERROR: Could not find an active TWIM for IMU.");
}
}
// ---------------- Prepare EasyDMA on that TWIM -------------------------
void init_twim_for_dma() {
if (!imu_twim) return;
// Start HFCLK (shared for all TWIMs)
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
// Do NOT touch PSEL or ADDRESS here, reuse what the library set
imu_twim->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;
imu_twim->EVENTS_STOPPED = 0;
imu_twim->EVENTS_LASTTX = 0;
imu_twim->EVENTS_LASTRX = 0;
imu_twim->EVENTS_TXSTARTED = 0;
imu_twim->EVENTS_RXSTARTED = 0;
imu_twim->EVENTS_ERROR = 0;
imu_twim->ERRORSRC = 0;
imu_twim->SHORTS = 0;
Serial.println("TWIM + EasyDMA prepared (reusing IMU bus config).");
}
// ---------------- Polling DMA FIFO read --------------------------------
void dma_read_fifo_polling(uint8_t *buf, uint16_t len) {
static uint8_t reg_addr = FIFO_DATA_OUT_L;
if (!imu_twim) {
Serial.println("dma_read_fifo_polling(): imu_twim is NULL.");
return;
}
dma_done = false;
dma_error = false;
dma_error_src = 0;
imu_twim->EVENTS_STOPPED = 0;
imu_twim->EVENTS_LASTTX = 0;
imu_twim->EVENTS_LASTRX = 0;
imu_twim->EVENTS_TXSTARTED = 0;
imu_twim->EVENTS_RXSTARTED = 0;
imu_twim->EVENTS_ERROR = 0;
imu_twim->ERRORSRC = 0;
imu_twim->TXD.PTR = (uint32_t)®_addr;
imu_twim->TXD.MAXCNT = 1;
imu_twim->RXD.PTR = (uint32_t)buf;
imu_twim->RXD.MAXCNT = len;
imu_twim->SHORTS =
TWIM_SHORTS_LASTTX_STARTRX_Msk |
TWIM_SHORTS_LASTRX_STOP_Msk;
imu_twim->TASKS_STARTTX = 1;
uint32_t guard = 0;
while (!imu_twim->EVENTS_STOPPED && !imu_twim->EVENTS_ERROR) {
if (guard++ > 2000000) {
Serial.println("Timeout waiting for TWIM STOP/ERROR.");
break;
}
}
if (imu_twim->EVENTS_ERROR) {
dma_error = true;
dma_error_src = imu_twim->ERRORSRC;
imu_twim->EVENTS_ERROR = 0;
imu_twim->ERRORSRC = 0;
} else if (imu_twim->EVENTS_STOPPED) {
dma_done = true;
}
imu_twim->EVENTS_STOPPED = 0;
imu_twim->EVENTS_LASTTX = 0;
imu_twim->EVENTS_LASTRX = 0;
}
// ---------------- Helpers ----------------------------------------------
void print_fifo_bytes(const uint8_t *buf, size_t len) {
Serial.print("FIFO bytes: ");
for (size_t i = 0; i < len; ++i) {
Serial.printf("%02X ", buf[i]);
}
Serial.println();
}
// ---------------- setup() ----------------------------------------------
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); }
Serial.println();
Serial.println("=================================================");
Serial.println(" XIAO nRF52840 Sense - LSM6DS3 FIFO DMA Demo (Auto TWIM)");
Serial.println(" Using EasyDMA on the same TWIM as the IMU library");
Serial.print (" Firmware: "); Serial.println(FW_REV);
Serial.println(" MCU: nRF52840 @ 64 MHz");
Serial.println(" Board: Seeed XIAO nRF52840 Sense");
Serial.println("=================================================");
#ifdef IMU_POWER_PIN
pinMode(IMU_POWER_PIN, OUTPUT);
digitalWrite(IMU_POWER_PIN, HIGH);
Serial.println("IMU power pin enabled (PIN_LSM6DS3TR_C_POWER).");
#endif
Serial.println("Initializing LSM6DS3 via library...");
if (myIMU.begin() != 0) {
Serial.println("ERROR: Failed to initialize LSM6DS3!");
while (true) { delay(500); }
}
Serial.println("LSM6DS3 initialized OK.");
init_IMU_fifo();
Serial.print("Configuring FIFO..."); myIMU.fifoBegin(); Serial.println("Done!");
Serial.print("Clearing FIFO..." ); myIMU.fifoClear(); Serial.println("Done!");
detect_imu_twim();
init_twim_for_dma();
Serial.println("Setup complete. Starting main loop...");
}
// ---------------- loop() ------------------------------------------------
void loop() {
dma_read_fifo_polling(dma_buffer, FIFO_READ_SIZE);
Serial.print("dma_done: "); Serial.println(dma_done);
Serial.print("dma_error: "); Serial.println(dma_error);
if (dma_error) {
Serial.print("dma_error_src: 0x"); Serial.println(dma_error_src, HEX);
}
print_fifo_bytes(dma_buffer, FIFO_READ_SIZE);
Serial.println();
delay(200);
}
Output is this
=================================================
XIAO nRF52840 Sense - LSM6DS3 FIFO DMA Demo (Auto TWIM)
Using EasyDMA on the same TWIM as the IMU library
Firmware: Rev 1.3 - 2025-11-12
MCU: nRF52840 @ 64 MHz
Board: Seeed XIAO nRF52840 Sense
=================================================
IMU power pin enabled (PIN_LSM6DS3TR_C_POWER).
Initializing LSM6DS3 via library...
LSM6DS3 initialized OK.
Configuring FIFO...Done!
Clearing FIFO...Done!
Detecting IMU TWIM instance...
TWIM0 PSEL.SCL: 0xFFFFFFFF
TWIM0 PSEL.SDA: 0xFFFFFFFF
TWIM1 PSEL.SCL: 0x1B
TWIM1 PSEL.SDA: 0x7
Selected IMU TWIM: TWIM1
TWIM + EasyDMA prepared (reusing IMU bus config).
Setup complete. Starting main loop...
dma_done: 1
dma_error: 0
FIFO bytes: 47 05 8F FF 5C FB 2B 00 54 00 FA 07 FA 07 FA 07 FA 07 FA 07 FA 07 FA 07 FA 07 FA 07 FA 07 FA 07
dma_done: 1
dma_error: 0
FIFO bytes: EF 00 76 F9 5F FE 4E 00 5C 00 3D 08 15 00 E3 FF F5 FF 48 00 5E 00 45 08 14 00 E5 FF F3 FF 45 00
dma_done: 1
dma_error: 0
FIFO bytes: 59 00 3D 08 05 00 E5 FF F5 FF 4B 00 5C 00 40 08 00 00 E8 FF F7 FF 4C 00 5F 00 46 08 03 00 E5 FF
HTH
GL
PJ 
Add the Interrupt part now we know how the TWIM is setup.