Read DMA data disorderly from FIFO

I am reading IMU data from LSM6DS3 in XIAO nRF52840. I have got the data from easyDMA via FIFO mode. when it read the 1st loop, the data is correct(24 bytes contains accel3, gyro3 and 0*6, acctually I prefect if only the first 12 bytes be moved into the array list). but the 2nd, 3rd, 4th… loop, some data will be discarded. Attached my code and the printed message:

// ============================================================================
// XIAO nRF52840 Sense - LSM6DS3 FIFO via EasyDMA (Auto-detect TWIM, Polling)
// Rev 1.2 - 2025-11-12
// ----------------------------------------------------------------------------
// - Board: Seeed XIAO nRF52840 Sense (Seeed nRF52 Boards 1.1.11, non-mbed)
// - IMU:   LSM6DS3TR-C on internal I2C bus (NOT on external SDA/SCL header)
// - Idea:  Let Seeed's LSM6DS3 lib configure the I2C bus, then re-use the
//          same TWIM instance for raw EasyDMA FIFO reads without touching PSEL.
// ============================================================================

#include <Arduino.h>
#include <Adafruit_TinyUSB.h>
#include "nrf.h"
#include <LSM6DS3.h>
#include <Wire.h>

// ------------------------- Config / Defines ---------------------------------
#define IMU_ADDR            0x6A
// #define FIFO_DATA_OUT_L     0x3E
#define FIFO_READ_SIZE      96

#ifdef PIN_LSM6DS3TR_C_POWER
  #define IMU_POWER_PIN PIN_LSM6DS3TR_C_POWER
#endif
#define INT1_PIN PIN_LSM6DS3TR_C_INT1  // Interrupt pin
const char FW_REV[] = "Rev 1.2 - 2025-11-12";

// ------------------------- Globals ------------------------------------------
NRF_TWIM_Type *imu_twim = nullptr;   // will point to whichever TWIM talks to IMU

bool     dma_done      = false;
bool     dma_error     = false;
uint32_t dma_error_src = 0;

uint8_t dma_buffer[FIFO_READ_SIZE];
// uint8_t dma_buffer_rec[FIFO_READ_SIZE];

bool     buff_ready      = false;
// 解析 LSM6DS3 FIFO: [Gx,Gy,Gz,Ax,Ay,Az] 小端,每轴 int16
// 量程:Gyro ±2000 dps,Accel ±16 g
// 输入:raw = FIFO 字节缓冲区;len = 字节长度(建议为 12 的整数倍)
// 输出:打印每个样本的原始计数和物理量

struct ImuSample {
  int16_t gx, gy, gz;
  int16_t ax, ay, az;
  float   gx_dps, gy_dps, gz_dps;
  float   ax_g,  ay_g,  az_g;
};

static inline int16_t le_to_i16(const uint8_t* p) {
  return (int16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8));
}

// LSM6DS3 object using the standard IMU address
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        = 0;

  myIMU.settings.commMode           = 1;    // I2C

  myIMU.settings.fifoThreshold      = 96;
  myIMU.settings.fifoSampleRate     = 400;
  myIMU.settings.fifoModeWord       = 6;    // continuous mode

  myIMU.settings.timestampEnabled       = 0;    // continuous mode
  myIMU.settings.timestampFifoEnabled   = 0;    // continuous mode
  
      uint8_t result;

    result = 0x44;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL3_C, result);
    result = 0x00;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_FIFO_CTRL4, result);
    result = 0x60;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL5_C, result);
    result = 0x40;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, result);
    
}



// ==================== Detect which TWIM the IMU uses ========================
bool twim_has_valid_pins(NRF_TWIM_Type *twim) {
  // On nRF52, "disconnected" PSEL is usually 0xFFFFFFFF.
  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) {
    // If both look valid (unlikely), prefer TWIM1 (historically used for IMU)
    imu_twim = NRF_TWIM1;
    Serial.println("Both TWIM0 and TWIM1 have pins; defaulting to TWIM1.");
  } else {
    imu_twim = nullptr;
    Serial.println("ERROR: Could not find an active TWIM for IMU.");
  }
}

// ==================== Init EasyDMA on the detected TWIM =====================
void init_twim_for_dma() {
  if (!imu_twim) {
    Serial.println("init_twim_for_dma(): imu_twim is NULL, abort.");
    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 – keep whatever the library set up.
  // Just make sure the peripheral is enabled.
  imu_twim->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;

  // Clear events / errors
  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 on imu_twim =====================
void dma_read_fifo_polling(uint8_t *buf, uint16_t len) {
  static uint8_t reg_addr = LSM6DS3_ACC_GYRO_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;

  // Clear events / ERRORSRC
  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;

  // Configure TX (register address)
  imu_twim->TXD.PTR    = (uint32_t)&reg_addr;
  imu_twim->TXD.MAXCNT = 1;

  // Configure RX (FIFO buffer)
  imu_twim->RXD.PTR    = (uint32_t)buf;
  imu_twim->RXD.MAXCNT = len;

  // One combined transaction: write reg, repeated START, read len, STOP
  imu_twim->SHORTS =
      TWIM_SHORTS_LASTTX_STARTRX_Msk
      | TWIM_SHORTS_LASTRX_STOP_Msk;

  // Serial.print("Starting DMA read, len = ");
  // Serial.println(len);

  imu_twim->TASKS_STARTTX = 1;

  // Poll until STOP or ERROR
  uint32_t guard = 0;
  while (!imu_twim->EVENTS_STOPPED && !imu_twim->EVENTS_ERROR) {
    if (guard++ > 5000000) { // crude timeout
      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: Print FIFO bytes ============================
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();
}

static inline int16_t i16_le(uint8_t lo, uint8_t hi) {
  return (int16_t)((uint16_t)hi << 8 | lo);
}

void parse_fifo_frame(uint8_t *buf, size_t len) {
  if (!buf) return;
  const float ACC_mg_LSB = 0.488f;   // ±16g
  const float GYR_dps_LSB = 0.07f;   // ±2000 dps

  for (size_t i = 0; i + 12 <= len; i += 12) {
    int16_t gyroX = i16_le(buf[i+0], buf[i+1]);
    int16_t gyroY = i16_le(buf[i+2], buf[i+3]);
    int16_t gyroZ = i16_le(buf[i+4], buf[i+5]);

    int16_t accX  = i16_le(buf[i+6], buf[i+7]);
    int16_t accY  = i16_le(buf[i+8], buf[i+9]);
    int16_t accZ  = i16_le(buf[i+10], buf[i+11]);

    float accX_g = accX * (ACC_mg_LSB / 1000.0f);
    float accY_g = accY * (ACC_mg_LSB / 1000.0f);
    float accZ_g = accZ * (ACC_mg_LSB / 1000.0f);

    float gyroX_dps = gyroX * GYR_dps_LSB;
    float gyroY_dps = gyroY * GYR_dps_LSB;
    float gyroZ_dps = gyroZ * GYR_dps_LSB;

    Serial.printf("Acc[g]: %.3f %.3f %.3f  |  Gyro[dps]: %.2f %.2f %.2f\n",
                  accX_g, accY_g, accZ_g, gyroX_dps, gyroY_dps, gyroZ_dps);
  }
}

// ==================== 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!");

  // After the library has configured the bus, detect which TWIM is used.
  detect_imu_twim();
  init_twim_for_dma();

  Serial.println("Setup complete. Starting main loop...");
}

// ==================== loop() ===============================================
void loop() {
//   if (imu_twim->EVENTS_TXSTARTED || imu_twim->EVENTS_RXSTARTED) {
//     Serial.println("[WARNING] Detected unexpected TWIM activity outside DMA!");
// }
    uint8_t result;
    if(buff_ready){
      
    }
    dma_read_fifo_polling(dma_buffer, FIFO_READ_SIZE);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL1);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL1: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL2);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL2: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL3);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL3: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL4);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL4: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL5);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL5: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL1_XL);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL1_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL2_G);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL2_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL3_C);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL3_C: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL4_C);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL4_C: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL5_C);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL5_C: 0x");Serial.println(result,HEX);    
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL6_G);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL6_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL7_G);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL7_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL8_XL);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL8_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL9_XL);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL9_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL10_C);
    Serial.print("LSM6DS3_ACC_GYRO_CTRL10_C: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUT_TEMP_L);
    Serial.print("LSM6DS3_ACC_GYRO_OUT_TEMP_L: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUT_TEMP_H);
    Serial.print("LSM6DS3_ACC_GYRO_OUT_TEMP_H: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTX_L_G);
    Serial.print("LSM6DS3_ACC_GYRO_OUTX_L_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTX_H_G);
    Serial.print("LSM6DS3_ACC_GYRO_OUTX_H_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTY_L_G);
    Serial.print("LSM6DS3_ACC_GYRO_OUTY_L_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTY_H_G);
    Serial.print("LSM6DS3_ACC_GYRO_OUTY_H_G: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTZ_L_G);
    Serial.print("LSM6DS3_ACC_GYRO_OUTZ_H_G: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTX_L_XL);
    Serial.print("LSM6DS3_ACC_GYRO_OUTX_L_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTX_H_XL);
    Serial.print("LSM6DS3_ACC_GYRO_OUTX_H_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTY_L_XL);
    Serial.print("LSM6DS3_ACC_GYRO_OUTY_L_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTY_H_XL);
    Serial.print("LSM6DS3_ACC_GYRO_OUTY_H_XL: 0x");Serial.println(result,HEX);
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_OUTZ_L_XL);
    Serial.print("LSM6DS3_ACC_GYRO_OUTZ_H_XL: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS1);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS1 : 0x");Serial.println(result,DEC);
    
    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS2);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS2: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS3);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS3: 0x");Serial.println(result,HEX);

    myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS4);
    Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS4: 0x");Serial.println(result,HEX);



  // 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();
  parse_fifo_frame(dma_buffer, FIFO_READ_SIZE);

  Serial.println();
  delay(1000);
}

the printed message:

=================================================
 XIAO nRF52840 Sense - LSM6DS3 FIFO DMA Demo (Auto TWIM)
 Using EasyDMA on the same TWIM as the IMU library
 Firmware: Rev 1.2 - 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...
LSM6DS3_ACC_GYRO_FIFO_CTRL1: 0x60
LSM6DS3_ACC_GYRO_FIFO_CTRL2: 0x0
LSM6DS3_ACC_GYRO_FIFO_CTRL3: 0x9
LSM6DS3_ACC_GYRO_FIFO_CTRL4: 0x9
LSM6DS3_ACC_GYRO_FIFO_CTRL5: 0x36
LSM6DS3_ACC_GYRO_CTRL1_XL: 0x66
LSM6DS3_ACC_GYRO_CTRL2_G: 0x6C
LSM6DS3_ACC_GYRO_CTRL3_C: 0x44
LSM6DS3_ACC_GYRO_CTRL4_C: 0x80
LSM6DS3_ACC_GYRO_CTRL5_C: 0x60
LSM6DS3_ACC_GYRO_CTRL6_G: 0x0
LSM6DS3_ACC_GYRO_CTRL7_G: 0x0
LSM6DS3_ACC_GYRO_CTRL8_XL: 0x0
LSM6DS3_ACC_GYRO_CTRL9_XL: 0xE0
LSM6DS3_ACC_GYRO_CTRL10_C: 0x0
LSM6DS3_ACC_GYRO_OUT_TEMP_L: 0x8
LSM6DS3_ACC_GYRO_OUT_TEMP_H: 0xFC
LSM6DS3_ACC_GYRO_OUTX_L_G: 0x1
LSM6DS3_ACC_GYRO_OUTX_H_G: 0x3
LSM6DS3_ACC_GYRO_OUTY_L_G: 0x74
LSM6DS3_ACC_GYRO_OUTY_H_G: 0xF7
LSM6DS3_ACC_GYRO_OUTZ_H_G: 0xD6
LSM6DS3_ACC_GYRO_OUTX_L_XL: 0xCA
LSM6DS3_ACC_GYRO_OUTX_H_XL: 0xFF
LSM6DS3_ACC_GYRO_OUTY_L_XL: 0xCB
LSM6DS3_ACC_GYRO_OUTY_H_XL: 0xFF
LSM6DS3_ACC_GYRO_OUTZ_H_XL: 0x58
LSM6DS3_ACC_GYRO_FIFO_STATUS1 : 0x84
LSM6DS3_ACC_GYRO_FIFO_STATUS2: 0x0
LSM6DS3_ACC_GYRO_FIFO_STATUS3: 0x0
LSM6DS3_ACC_GYRO_FIFO_STATUS4: 0x0
FIFO bytes: 19 04 DB FD 26 FB D1 FF CB FF 0D 08 00 00 00 00 00 00 00 00 00 00 00 00 58 00 A1 FF DE FD D4 FF CB FF 51 08 00 00 00 00 00 00 00 00 00 00 00 00 C0 00 62 FE 6E FE D2 FF C8 FF 55 08 00 00 00 00 00 00 00 00 00 00 00 00 7F 00 37 FD B5 FE D1 FF C8 FF 60 08 00 00 00 00 00 00 00 00 00 00 00 00 
Acc[g]: -0.023 -0.026 1.006  |  Gyro[dps]: 73.43 -38.43 -86.94
Acc[g]: 0.000 0.000 0.000  |  Gyro[dps]: 0.00 0.00 0.00
Acc[g]: -0.021 -0.026 1.039  |  Gyro[dps]: 6.16 -6.65 -38.22
Acc[g]: 0.000 0.000 0.000  |  Gyro[dps]: 0.00 0.00 0.00
Acc[g]: -0.022 -0.027 1.041  |  Gyro[dps]: 13.44 -28.98 -28.14
Acc[g]: 0.000 0.000 0.000  |  Gyro[dps]: 0.00 0.00 0.00
Acc[g]: -0.023 -0.027 1.046  |  Gyro[dps]: 8.89 -49.91 -23.17
Acc[g]: 0.000 0.000 0.000  |  Gyro[dps]: 0.00 0.00 0.00

LSM6DS3_ACC_GYRO_FIFO_CTRL1: 0x60
LSM6DS3_ACC_GYRO_FIFO_CTRL2: 0x0
LSM6DS3_ACC_GYRO_FIFO_CTRL3: 0x9
LSM6DS3_ACC_GYRO_FIFO_CTRL4: 0x9
LSM6DS3_ACC_GYRO_FIFO_CTRL5: 0x36
LSM6DS3_ACC_GYRO_CTRL1_XL: 0x66
LSM6DS3_ACC_GYRO_CTRL2_G: 0x6C
LSM6DS3_ACC_GYRO_CTRL3_C: 0x44
LSM6DS3_ACC_GYRO_CTRL4_C: 0x80
LSM6DS3_ACC_GYRO_CTRL5_C: 0x60
LSM6DS3_ACC_GYRO_CTRL6_G: 0x0
LSM6DS3_ACC_GYRO_CTRL7_G: 0x0
LSM6DS3_ACC_GYRO_CTRL8_XL: 0x0
LSM6DS3_ACC_GYRO_CTRL9_XL: 0xE0
LSM6DS3_ACC_GYRO_CTRL10_C: 0x0
LSM6DS3_ACC_GYRO_OUT_TEMP_L: 0x3B
LSM6DS3_ACC_GYRO_OUT_TEMP_H: 0xFC
LSM6DS3_ACC_GYRO_OUTX_L_G: 0x12
LSM6DS3_ACC_GYRO_OUTX_H_G: 0x0
LSM6DS3_ACC_GYRO_OUTY_L_G: 0xCB
LSM6DS3_ACC_GYRO_OUTY_H_G: 0xFF
LSM6DS3_ACC_GYRO_OUTZ_H_G: 0xF0
LSM6DS3_ACC_GYRO_OUTX_L_XL: 0xD6
LSM6DS3_ACC_GYRO_OUTX_H_XL: 0xFF
LSM6DS3_ACC_GYRO_OUTY_L_XL: 0xC9
LSM6DS3_ACC_GYRO_OUTY_H_XL: 0xFF
LSM6DS3_ACC_GYRO_OUTZ_H_XL: 0x6C
LSM6DS3_ACC_GYRO_FIFO_STATUS1 : 0x0
LSM6DS3_ACC_GYRO_FIFO_STATUS2: 0xE0
LSM6DS3_ACC_GYRO_FIFO_STATUS3: 0x4
LSM6DS3_ACC_GYRO_FIFO_STATUS4: 0x0
FIFO bytes: C8 FF 68 08 00 00 C9 FF 6A 08 00 00 00 00 00 00 00 00 00 00 00 00 14 00 CC FF F1 FF CC FF CB FF 69 08 00 00 00 00 00 00 00 00 00 00 00 00 12 00 CB FF F1 FF D1 FF CA FF 6A 08 00 00 00 00 00 00 00 00 00 00 00 00 13 00 CC FF F2 FF D3 FF C9 FF 67 08 00 00 00 00 00 00 00 00 00 00 00 00 12 00 
Acc[g]: -0.027 1.051 0.000  |  Gyro[dps]: -3.92 150.64 0.00
Acc[g]: 0.000 0.000 0.010  |  Gyro[dps]: 0.00 0.00 0.00
Acc[g]: -0.026 1.051 0.000  |  Gyro[dps]: -3.64 -1.05 -3.64
Acc[g]: 0.000 0.000 0.009  |  Gyro[dps]: 0.00 0.00 0.00
Acc[g]: -0.026 1.051 0.000  |  Gyro[dps]: -3.71 -1.05 -3.29
Acc[g]: 0.000 0.000 0.009  |  Gyro[dps]: 0.00 0.00 0.00
Acc[g]: -0.027 1.050 0.000  |  Gyro[dps]: -3.64 -0.98 -3.15
Acc[g]: 0.000 0.000 0.009  |  Gyro[dps]: 0.00 0.00 0.00

I’d suspect that the MCU is spending too much time on printing serial data to service the Imu effectively. Try printk ,the logging system or RTT.

I want to use interrupt when FIFO or DMA is ready to copy data to buffer, but it only stopped after several loop. Fortunately, the data seems work correctly in these loop. But what happen in the interrupt, how to correct it?

// ============================================================================
// XIAO nRF52840 Sense - LSM6DS3 FIFO via EasyDMA (Auto-detect TWIM, Polling)
// Rev 1.2 - 2025-11-12
// ----------------------------------------------------------------------------
// - Board: Seeed XIAO nRF52840 Sense (Seeed nRF52 Boards 1.1.11, non-mbed)
// - IMU:   LSM6DS3TR-C on internal I2C bus (NOT on external SDA/SCL header)
// - Idea:  Let Seeed's LSM6DS3 lib configure the I2C bus, then re-use the
//          same TWIM instance for raw EasyDMA FIFO reads without touching PSEL.
// ============================================================================

#include <Arduino.h>
#include <Adafruit_TinyUSB.h>
#include "nrf.h"
#include <LSM6DS3.h>
#include <Wire.h>

// ------------------------- Config / Defines ---------------------------------
#define IMU_ADDR            0x6A
// #define FIFO_DATA_OUT_L     0x3E
#define FIFO_READ_SIZE      48

#ifdef PIN_LSM6DS3TR_C_POWER
  #define IMU_POWER_PIN PIN_LSM6DS3TR_C_POWER
#endif
#define INT1_PIN PIN_LSM6DS3TR_C_INT1  // Interrupt pin
const char FW_REV[] = "Rev 1.2 - 2025-11-12";

// ------------------------- Globals ------------------------------------------
NRF_TWIM_Type *imu_twim = nullptr;   // will point to whichever TWIM talks to IMU

bool     dma_done      = false;
bool     dma_error     = false;
uint32_t dma_error_src = 0;

uint8_t dma_buffer[FIFO_READ_SIZE];
// uint8_t dma_buffer_rec[FIFO_READ_SIZE];
volatile bool buff_ready = false;
// bool     buff_ready      = false;
// 解析 LSM6DS3 FIFO: [Gx,Gy,Gz,Ax,Ay,Az] 小端,每轴 int16
// 量程:Gyro ±2000 dps,Accel ±16 g
// 输入:raw = FIFO 字节缓冲区;len = 字节长度(建议为 12 的整数倍)
// 输出:打印每个样本的原始计数和物理量

struct ImuSample {
  int16_t gx, gy, gz;
  int16_t ax, ay, az;
  float   gx_dps, gy_dps, gz_dps;
  float   ax_g,  ay_g,  az_g;
};

static inline int16_t le_to_i16(const uint8_t* p) {
  return (int16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8));
}

// LSM6DS3 object using the standard IMU address
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      = FIFO_READ_SIZE;
  myIMU.settings.fifoSampleRate     = 400;
  myIMU.settings.fifoModeWord       = 6;    // continuous mode

  myIMU.settings.timestampEnabled       = 1;    // continuous mode
  myIMU.settings.timestampFifoEnabled   = 0;    // continuous mode
  
      uint8_t result;

    result = 0x44;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL3_C, result);
    result = 0x00;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_FIFO_CTRL4, result);
    result = 0x60;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL5_C, result);
    result = 0x40;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, result);
    
}



// ==================== Detect which TWIM the IMU uses ========================
bool twim_has_valid_pins(NRF_TWIM_Type *twim) {
  // On nRF52, "disconnected" PSEL is usually 0xFFFFFFFF.
  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) {
    // If both look valid (unlikely), prefer TWIM1 (historically used for IMU)
    imu_twim = NRF_TWIM1;
    Serial.println("Both TWIM0 and TWIM1 have pins; defaulting to TWIM1.");
  } else {
    imu_twim = nullptr;
    Serial.println("ERROR: Could not find an active TWIM for IMU.");
  }
}

// ==================== Init EasyDMA on the detected TWIM =====================
void init_twim_for_dma() {
  if (!imu_twim) {
    Serial.println("init_twim_for_dma(): imu_twim is NULL, abort.");
    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 – keep whatever the library set up.
  // Just make sure the peripheral is enabled.
  imu_twim->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;

  // Clear events / errors
  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 on imu_twim =====================
void dma_read_fifo_polling(uint8_t *buf) {
  static uint8_t reg_addr = LSM6DS3_ACC_GYRO_FIFO_DATA_OUT_L;

  if (!imu_twim) {
    Serial.println("dma_read_fifo_polling(): imu_twim is NULL.");
    return;
  }

  dma_done      = false;
  dma_error     = false;
  buff_ready    = false;
  dma_error_src = 0;

  // Clear events / ERRORSRC
  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;

  // Configure TX (register address)
  imu_twim->TXD.PTR    = (uint32_t)&reg_addr;
  imu_twim->TXD.MAXCNT = 1;

  // Configure RX (FIFO buffer)
  imu_twim->RXD.PTR    = (uint32_t)buf;
  imu_twim->RXD.MAXCNT = FIFO_READ_SIZE;

  // One combined transaction: write reg, repeated START, read len, STOP
  imu_twim->SHORTS =
      TWIM_SHORTS_LASTTX_STARTRX_Msk
      | TWIM_SHORTS_LASTRX_STOP_Msk;

  // Serial.print("Starting DMA read, len = ");
  // Serial.println(len);

  imu_twim->TASKS_STARTTX = 1;

  // Poll until STOP or ERROR
  uint32_t guard = 0;
  while (!imu_twim->EVENTS_STOPPED && !imu_twim->EVENTS_ERROR) {
    if (guard++ > 1000000) { // crude timeout
      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;
    // interrupts();
  }

  imu_twim->EVENTS_STOPPED  = 0;
  imu_twim->EVENTS_LASTTX   = 0;
  imu_twim->EVENTS_LASTRX   = 0;

}

// ==================== Helpers: Print FIFO bytes ============================
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();
}

static inline int16_t i16_le(uint8_t lo, uint8_t hi) {
  return (int16_t)((uint16_t)hi << 8 | lo);
}

void parse_fifo_frame(uint8_t *buf, size_t len) {
  if (!buf) return;
  const float ACC_mg_LSB = 0.488f;   // ±16g
  const float GYR_dps_LSB = 0.07f;   // ±2000 dps

  for (size_t i = 0; i + 12 <= len; i += 12) {
    int16_t gyroX = i16_le(buf[i+0], buf[i+1]);
    int16_t gyroY = i16_le(buf[i+2], buf[i+3]);
    int16_t gyroZ = i16_le(buf[i+4], buf[i+5]);

    int16_t accX  = i16_le(buf[i+6], buf[i+7]);
    int16_t accY  = i16_le(buf[i+8], buf[i+9]);
    int16_t accZ  = i16_le(buf[i+10], buf[i+11]);

    float accX_g = accX * (ACC_mg_LSB / 1000.0f);
    float accY_g = accY * (ACC_mg_LSB / 1000.0f);
    float accZ_g = accZ * (ACC_mg_LSB / 1000.0f);

    float gyroX_dps = gyroX * (ACC_mg_LSB / 1000.0f);
    float gyroY_dps = gyroY * (ACC_mg_LSB / 1000.0f);
    float gyroZ_dps = gyroZ * (ACC_mg_LSB / 1000.0f);

    // float gyroX_dps = gyroX * GYR_dps_LSB;
    // float gyroY_dps = gyroY * GYR_dps_LSB;
    // float gyroZ_dps = gyroZ * GYR_dps_LSB;

    Serial.printf("Gyro[dps]: %.2f %.2f %.2f  |  Acc[g]: %.3f %.3f %.3f\n",
                  gyroX_dps, gyroY_dps, gyroZ_dps,accX_g, accY_g, accZ_g);
  }
}

// -------------------- Interrupts ------------------------- //

volatile uint16_t detectCount = 0;

void int1ISR() {
    buff_ready = true;
    dma_done =false;
    // noInterrupts();
    Serial.println("Interrupt Triggered!");
}

// ==================== setup() ==============================================
void setup() {
  Serial.begin(115200);
  while (!Serial) { delay(10); }
  pinMode(INT1_PIN, INPUT_PULLDOWN);
  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!");

  // After the library has configured the bus, detect which TWIM is used.
  detect_imu_twim();
  init_twim_for_dma();

    // Enable Latching of 6D Orientation Interrupt
  uint8_t int1_ctrl = 0x38;  // Set LIR bit to latch interrupt
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, int1_ctrl);

  attachInterrupt(digitalPinToInterrupt(INT1_PIN), int1ISR, RISING);
  Serial.println("Setup complete. Starting main loop...");
}

// ==================== loop() ===============================================
void loop() {
//   if (imu_twim->EVENTS_TXSTARTED || imu_twim->EVENTS_RXSTARTED) {
//     Serial.println("[WARNING] Detected unexpected TWIM activity outside DMA!");
// }
    uint8_t result;
    if(buff_ready) dma_read_fifo_polling(dma_buffer);
    if(!dma_done) return;
    
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL1);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL1: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL2);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL2: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL3);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL3: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL4);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL4: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_CTRL5);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_CTRL5: 0x");Serial.println(result,HEX);

    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL1_XL);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL1_XL: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL2_G);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL2_G: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL3_C);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL3_C: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL4_C);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL4_C: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL5_C);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL5_C: 0x");Serial.println(result,HEX);    
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL6_G);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL6_G: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL7_G);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL7_G: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL8_XL);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL8_XL: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL9_XL);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL9_XL: 0x");Serial.println(result,HEX);
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_CTRL10_C);
    // Serial.print("LSM6DS3_ACC_GYRO_CTRL10_C: 0x");Serial.println(result,HEX);

    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS1);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS1 : 0x");Serial.println(result,DEC);
    
    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS2);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS2: 0x");Serial.println(result,HEX);

    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS3);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS3: 0x");Serial.println(result,HEX);

    // myIMU.readRegister(&result, LSM6DS3_ACC_GYRO_FIFO_STATUS4);
    // Serial.print("LSM6DS3_ACC_GYRO_FIFO_STATUS4: 0x");Serial.println(result,HEX);



  // 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();
  // parse_fifo_frame(dma_buffer, FIFO_READ_SIZE);
  dma_done =false;
  Serial.println();
  // delay(1000);
}

the printed message

Selected IMU TWIM: TWIM1
TWIM + EasyDMA prepared (reusing IMU bus config).
Setup complete. Starting main loop...
Interrupt Triggered!
Interrupt Triggered!
Interrupt Triggered!
FIFO bytes: 87 03 00 FE 4D FB ED FD E8 FF C6 07 00 00 00 00 00 00 00 00 00 00 00 00 5F 00 D0 FF D4 FD DF FD E7 FF 0E 08 00 00 00 00 00 00 00 00 00 00 00 00 
Interrupt Triggered!
Interrupt Triggered!
FIFO bytes: A8 00 82 FE 50 FE E1 FD E8 FF 07 08 00 00 00 00 00 00 00 00 00 00 00 00 82 00 3A FD A2 FE E4 FD ED FF 03 08 00 00 00 00 00 00 00 00 00 00 00 00 
FIFO bytes: E2 02 2D F7 A2 FB E2 FD ED FF FE 07 00 00 00 00 00 00 00 00 00 00 00 00 1D 03 13 F7 46 FA E0 FD EC FF F8 07 00 00 00 00 00 00 00 00 00 00 00 00 

Hi there,

So, Of course the First time looks perfect!! Because :grin: it Always is…You’ve got EasyDMA + FIFO working now, which is great — the IMU and DMA are behaving correctly.

The reason you’re “losing data” after the first read is that your FIFO fill rate and your readout rate don’t match.

Right now:
– FIFO puts data in at up to 400 Hz (12 bytes per sample: gyro+accel).
– You only read 96 bytes (8 samples) once per loop, and your loop has a 1 second delay plus a huge number of I²C + Serial debug prints.
– The FIFO overflows and overwrites older samples before you read them, so later reads look like data is missing.

To fix it:

  1. Reduce your IMU/FIFO rate to something you can actually handle (e.g. 100 Hz).

  2. Remove most of the readRegister + Serial.println spam inside loop() – do configuration dumps once in setup().

  3. Read the FIFO more often (no delay(1000) if you want high-rate data).

  4. Optionally, use the FIFO status registers to compute how many bytes are currently in the FIFO and read exactly that.

  5. Once that’s stable, you can move to a FIFO threshold interrupt on INT1 plus EasyDMA in the ISR so the CPU just wakes when enough samples are ready.

The DMA isn’t dropping data — the IMU FIFO is simply overwriting old samples because the MCU isn’t emptying it fast enough.

after that, start using the FIFO watermark interrupt to trigger the DMA instead of a polled 1 Hz loop :+1:

@Toastee0 also , points out a big one… : debug spam

Inside loop() you do dozens of:

myIMU.readRegister(&result, ...);
Serial.println(...);

Every readRegister is another I²C transaction on the same bus right after a long DMA read. Every Serial.println at 115200 baud is slow.

This absolutely kills throughput and timing.

Put bluntly:
You’re hammering Serial and I²C so hard that it’s impossible to keep up with a 400 Hz FIFO, especially with a 1-second delay thrown in.

Decide what output rate YOU actually need.

Match FIFO read rate to sample rate.

Stop dumping every register on every loop.

  • Do a one-time register dump in setup() for debug.

  • In loop(), only:

    • Read FIFO

    • Parse samples

    • Print just a few numbers (or even better, only every N-th sample).

Yes, interrupts are the next logical step – but fix the fundamentals first. :face_with_peeking_eye:

HTH

GL :slight_smile: PJ :v:

Hi there,

SO , :grin: the the interrupt version is almost there, but right now it’s doing a couple of “never do this in an ISR” things that will absolutely cause it to lock up after a few loops.

No# 1 rule of Interrupts and ISR’s (interrupt service routine)

KISS , keep it super short…

I have heard other interpretations, but I digress… :v:

The big killer: Serial in the ISR

Current ISR:

void int1ISR() {
    buff_ready = true;
    dma_done =false;
    // noInterrupts();
    Serial.println("Interrupt Triggered!");
}

  • Serial.println() inside an ISR on nRF52 (with TinyUSB behind Serial) is a great way to deadlock or crash.

  • USB/TinyUSB/RTOS internals are not IRQ-safe; after a few interrupts, it will jam.

  • You are also touching dma_done from the ISR, but dma_done is not volatile and doesn’t need to be touched in the ISR at all. (stop that) :point_left:

Fix: ISR must be tiny and fast. No I²C, no Serial, no heavy work.

Use it only to set a flag:

volatile bool fifo_irq = false;

void int1ISR() {
  fifo_irq = true;
}

That’s it. Nothing else.

Use ONE flag, not two… One flag from ISR: “FIFO threshold hit” (fifo_irq).

It’s unnecessary and redundant

Main loop:

  • If fifo_irq set → clear it (with interrupts briefly off) and run one DMA transaction.

  • When DMA completes and is OK → parse + print.

Something like:

volatile bool fifo_irq = false;
bool dma_done = false;
bool dma_error = false;
uint32_t dma_error_src = 0;

void int1ISR() {
  fifo_irq = true;
}

void loop() {
  if (fifo_irq) {
    noInterrupts();
    fifo_irq = false;      // consume the interrupt
    interrupts();

    dma_read_fifo_polling(dma_buffer);   // blocking DMA read

    if (dma_done && !dma_error) {
      print_fifo_bytes(dma_buffer, FIFO_READ_SIZE);
      // parse_fifo_frame(dma_buffer, FIFO_READ_SIZE);
    } else if (dma_error) {
      Serial.print("dma_error_src: 0x");
      Serial.println(dma_error_src, HEX);
    }

    dma_done = false;  // ready for next one
  }

  // Do other non-time-critical stuff here if you want
}

And inside dma_read_fifo_polling() you do not touch buff_ready or fifo_irq at all, just:

  • clear TWIM events

  • set TXD/RXD pointers

  • start TX

  • spin until STOP or ERROR

  • set dma_done / dma_error flags accordingly

You’re already almost doing that; just stop mixing it with ISR state. Don’t modify dma_done from the ISR, Big NO-NO. :face_with_monocle:

You’ve got:

result = 0x40;
myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, result);
...
uint8_t int1_ctrl = 0x38;  // Set LIR bit to latch interrupt  (comment is suspicious)
myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, int1_ctrl);

Points:

  • You’re writing INT1_CTRL twice; only the last write wins (0x38).

  • The comment “Set LIR bit to latch interrupt” is wrong — LIR is in a different register (TAP or INT config), not INT1_CTRL.

  • For FIFO threshold interrupt, the key bit is INT1_FTH in INT1_CTRL. That’s fine if 0x38 has that bit set, but the comment is misleading.

Check out the PARK IMU demo thread. I use this in that code, the interrupts sets a flag , and the read of the register resets the INT. Don’t make it harder than it has to be. :crossed_fingers:

For clarity, I’d suggest:

// Enable FIFO threshold interrupt on INT1
uint8_t int1_ctrl = 0;
int1_ctrl |= 0x08; // INT1_FTH (check datasheet bit position)
myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, int1_ctrl);

And remove the earlier 0x40 write unless you actually need that function.

Keep going, you WILL get it working perfectly.

HTH

GL :slight_smile: PJ :v: