KX134 Sampling Frequency greater than 1000Hz

I cannot achieve a faster sampling rate than 1000Hz. I have changed the ODR register but I am still stuck at 1000Hz (~1024microsecond intervals).

Has anyone accomplished sampling rates greater than 1000Hz using the KX134?

If so, can you share your setup and sketch?

Is there a setting on the board I need to consider? Wire.SetClock does not increase sampling rate.

I am using an Adafruit Metro board (Arduino Uno clone) with a QWIIC cable connection between board and sensor.

The sketch is not pretty but works. It has changed from its original purpose as I have been troubleshooting and have not omitted unnecessary variables/structures.

#include <Wire.h>
#include "SparkFun_Qwiic_KX13X.h"
#define ArraySize 100
#define rate 0b00001101 //0b00001101 6400Hz, 0b00001100 3200Hz, 0b00001011 1600Hz,
QwiicKX134 kxAccel;
outputData myData;

uint8_t address = 0x1F;
uint8_t Reg01 = KX13X_XOUT_L; //KX13X_XOUT_L
uint8_t Reg02 = 0x09;
uint8_t slaveByte1;
//uint16_t buf;
uint8_t slaveByte2;
int16_t value = 0U;
uint16_t value2 = 0;

float ScaledValue = 0.0f;
float a = 0.0f;

short i = 0;
short j = 0;
int16_t DataX[ArraySize];
//short DataY[ArraySize];
//short DataZ[ArraySize];
uint8_t DataY[ArraySize];
uint8_t DataZ[ArraySize];
uint8_t Bytes1;
uint8_t Bytes2;
uint8_t Buffer[2];
/*
  uint8_t Bytes3;
  uint8_t Bytes4;
  uint8_t Bytes5;
  uint8_t Bytes6;
*/

unsigned long times [ArraySize];
unsigned long timeDiff [ArraySize];
unsigned long currentTime = 0UL;
unsigned long startTime = 0UL;
unsigned long FinishTime = 0UL;

unsigned long Interval = 1000UL;

const unsigned long Delay = 20000UL;
const unsigned long Delay02 = 1UL;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    ;
  }

  // put your setup code here, to run once:
  Wire.begin();
  Wire.setClock(400000);
  if ( !kxAccel.begin() ) {
    Serial.println("Could not communicate with the the KX13X. Freezing.");
    while (1);
  }
  else
    //Serial.println("Ready.");
    if ( !kxAccel.initialize(DEFAULT_SETTINGS)) { // Loading default settings.
      // Serial.println("Could not initialize the chip.");
      while (1);
    }
  kxAccel.setRange(KX134_RANGE64G); // For a larger range uncomment
  kxAccel.setOutputDataRate(rate);
  delay(5000);
  Serial.println("0,0,0");
  delay(5000);
  kxAccel.readMultipleRegisters(0x1B, Buffer, 2);

  Serial.print("CNTL1\t");
  Serial.println(Buffer[0], BIN);
}

void loop() {
  // put your main code here, to run repeatedly:
  i = 0;
  while (i < ArraySize)
  {
    times[i] = micros();
    currentTime = millis();
    startTime = currentTime + Delay02;
    FinishTime = currentTime + 1000UL;

    kxAccel.readMultipleRegisters(Reg01, Buffer, 2);

    
    DataX[i] = (int16_t)(Buffer[1] << 8 | Buffer[0]);
    DataY[i] = Buffer[0];
    DataZ[i] = Buffer[1];
    if (i > 0)
    {
      j = i - 1;
      timeDiff[i] = times[i] - times[j];
    }
    i++;

    currentTime = millis();
    //FinishTime = currentTime + Delay02;
    while (currentTime < startTime)
    {
      currentTime = millis();
    }
  }
  i = 1;
  //Serial.println("B");
  currentTime = millis();
  FinishTime = currentTime - 1UL;
  while (i < ArraySize)
  {
    //Serial.println("C");
    currentTime = millis();
    if (currentTime >= FinishTime)
    {
      //Serial.print("D");
      ScaledValue = ((float)(DataX[i])) / 512.0f;
      Serial.print(timeDiff[i]);
      //Serial.print("\t");
      Serial.print(",");
      Serial.print(ScaledValue, DEC);
      Serial.print("\t");

      Serial.print(DataX[i], BIN);
      //Serial.print("\t");
      Serial.print(",");
      Serial.print(DataY[i], BIN);
      //Serial.print("\t");

      Serial.print(",");
      Serial.print(DataZ[i], BIN);
      //Serial.print("\t");

      Serial.println("");
      i++;
      FinishTime = currentTime + 500UL;
    }
    else {
      //Serial.println("E");
      //i++;
    }
  }
  //Serial.println("F");
  i = 0;
  currentTime = millis();
  FinishTime = currentTime + 10000UL;
  //startTime = currentTime + Interval;

  while (currentTime < FinishTime)
  {
    currentTime = millis();
  }
  while (currentTime < FinishTime)
  {
    currentTime = millis();
    if (currentTime > startTime)
    {
      Serial.println(i);
      startTime = currentTime + Interval;
      i++;
    }
  }
  i = 0;
}

There’s a hardware limit for i2c; try swapping to SPI https://learn.sparkfun.com/tutorials/tr … e-overview and see how that goes :smiley:

Hey TS-Russell,

Can you elaborate by what you mean by “hardware limit”.

The spec sheet says the sensor is good for I2C communication at 3.4MHz (page 6).

The Arduino can have a Wire.SetClock at least to 400kHz.

Are you referencing a hardware limit of the I2C connection in that I need an active terminator (like LTC4311)?

https://learn.adafruit.com/adafruit-ltc … terminator

I have the sensor wired for SPI… fastest is still 1000Hz.

Does anyone have a knowledge set on configuration settings I should be checking?

#include <Wire.h>
#include <SPI.h>
#include <P1AM.h>
#include "SparkFun_Qwiic_KX13X.h"
#define ArraySize 2000
#define rate 0b00001100 //0b00001101 6400Hz, 0b00001100 3200Hz, 0b00001011 1600Hz,
#define Mcode 0b00001000

QwiicKX134 kxAccel;
outputData myData;

//#define TWI_FREQ 1000000L
#define TWI_FREQ 1000000L

/* TWBR       12
    F_CPU     16000000
    TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
  twi bit rate formula from atmega128 manual pg 204
  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
  note: TWBR should be 10 or higher for master mode
  It is 72 for a 16mhz Wiring board with 100kHz TWI
*/

uint8_t address = 0x1F;
uint8_t Reg01 = KX13X_XOUT_L; //KX13X_XOUT_L
uint8_t Reg02 = 0x09;

//uint8_t SSpin = 0;
//uint32_t PortSPEED = 10000000;

/*
  uint8_t slaveByte1;
  //uint16_t buf;
  uint8_t slaveByte2;
*/
int16_t value = 0U;
uint16_t value2 = 0;

uint8_t b1;
uint8_t b2;

float ScaledValue = 0.0f;
float ScaledValue2 = 0.0f;
float a = 0.0f;

short i = 0;
short j = 0;
short k = 0;
int16_t DataX[ArraySize];
//short DataY[ArraySize];
//short DataZ[ArraySize];
uint8_t DataY[ArraySize];
int8_t DataZ[ArraySize];
uint8_t Bytes1;
uint8_t Bytes2;
uint8_t Buffer01[2];
uint8_t Buffer02[10];
/*
  uint8_t Bytes3;
  uint8_t Bytes4;
  uint8_t Bytes5;
  uint8_t Bytes6;
*/

unsigned long times [ArraySize];
unsigned long timeDiff [ArraySize];
unsigned long currentTime = 0UL;
unsigned long startTime = 0UL;
unsigned long FinishTime = 0UL;

unsigned long Interval = 1000UL;

const unsigned long Delay = 20000UL;
const unsigned long Delay02 = 1UL;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    ;
  }

  // put your setup code here, to run once:
  SPI.begin();

  //TWBR = 20;
  /*
    if ( !kxAccel.beginSPICore(4,10000000) )
    {
    Serial.println("Could not communicate with the the KX13X. Freezing.");
    while (1);
    }
  */
  //kxAccel.beginSPI();
  kxAccel.beginSPI(4, 48000000);
  //else
  //Serial.println("Ready.");
  if ( !kxAccel.initialize(DEFAULT_SETTINGS))
  { // Loading default settings.
    Serial.println("Could not initialize the chip.");
    while (1);
  }
  kxAccel.setRange(KX134_RANGE64G); // For a larger range uncomment
  kxAccel.setOutputDataRate(rate);
  delay(5000);
  // Serial.println("0,0,0");
  delay(5000);
  kxAccel.readMultipleRegisters(0x1B, Buffer01, 1);

  Serial.print("CNTL1\t");
  Serial.println(Buffer01[0], BIN);//// 11011000

  //Serial.print("TWBR\t"); Serial.println(TWBR);
  Serial.print("F_CPU\t"); Serial.println(F_CPU);
  Serial.print("TWI_FREQ\t"); Serial.println(TWI_FREQ);


  //TWBR = 40;

  // Serial.print("TWBR\t"); Serial.println(TWBR);
}

void loop() {
  // put your main code here, to run repeatedly:
  i = 0;
  while (i < ArraySize)
  {
    times[i] = micros();
    currentTime = millis();
    startTime = currentTime + Delay02;
    FinishTime = currentTime + 1000UL;

    kxAccel.readMultipleRegisters(Reg01, Buffer01, 2);
    /*
       uint8_t i2cResult;
       _i2cPort->beginTransmission(_deviceAddress);
        _i2cPort->write(reg);
        i2cResult = _i2cPort->endTransmission(false);
        if( i2cResult != 0 )
          return KX13X_I2C_ERROR; //Error: Sensor did not ack

        i2cResult = _i2cPort->requestFrom(_deviceAddress, uint8_t(numBytes), uint8_t(true));
        if( i2cResult == 0 )
          return KX13X_I2C_ERROR;
        for(size_t i = 0; i < numBytes; i++) {
          dataBuffer[i] = _i2cPort->read();
    */
    /*
              Wire.beginTransmission(address);
              Wire.write(Mcode);
              a = Wire.endTransmission(false);
    */
    /*
      Wire.beginTransmission(address);
      Wire.write(Reg01);  //Reg01
      Wire.endTransmission(false);
      Wire.requestFrom(address, 2, true);

      while (currentTime < FinishTime && Wire.available() < 1)
      {
      currentTime = millis();
      }
      if (currentTime > FinishTime)
      {
      Serial.println(F("Timeout"));
      }

      k = 0;

      Serial.print(Wire.available());Serial.print("\t");
      Serial.print(a);Serial.print("\t");
      Serial.print(b);Serial.print("\t");

      while (Wire.available() > 0 && k < ArraySize)
      {
      Buffer01[k] = Wire.read();// read that byte into 'slaveByte2' variable
      k++;
      //Serial.print("F");
      }
      //Serial.println(k);
    */
    //Wire.endTransmission(true);

    DataX[i] = (int16_t)(Buffer01[1] << 8 | Buffer01[0]);
    DataY[i] = Buffer01[0];
    //DataZ[i] = Buffer01[1];
    DataZ[i] = (int8_t)Buffer01[1];

    if (i > 0)
    {
      j = i - 1;
      timeDiff[i] = times[i] - times[j];
    }
    i++;

    currentTime = millis();
    //FinishTime = currentTime + Delay02;
    while (currentTime < startTime)
    {
      currentTime = millis();
    }
  }
  i = 1;
  //Serial.println("B");
  currentTime = millis();
  FinishTime = currentTime - 1UL;
  while (i < ArraySize)
  {
    //Serial.println("C");
    currentTime = millis();
    if (currentTime >= FinishTime)
    {
      //Serial.print("D");
      ScaledValue = ((float)(DataX[i])) / 512.0f;

      ScaledValue2 = ((float)(DataZ[i])) / 2.0f;
      Serial.print(timeDiff[i]);
      Serial.print("\t");
      //Serial.print(",");
      Serial.print(ScaledValue, DEC);
      // Serial.print("\t");
      Serial.print(",");
      Serial.print(ScaledValue2, DEC);

      Serial.print("\r\n");
      /*
        Serial.print("\t");

        Serial.print(DataX[i], DEC);
        //Serial.print("\t");
        Serial.print(",");
        Serial.print(DataY[i], BIN);
        //Serial.print("\t");

        Serial.print(",");
        Serial.print(DataZ[i], DEC);
        //Serial.print("\t");

        Serial.println("");
      */
      i++;
      FinishTime = currentTime + 500UL;
    }
    else {
      //Serial.println("E");
      //i++;
    }
  }
  //Serial.println("F");
  i = 0;
  currentTime = millis();
  FinishTime = currentTime + 10000UL;
  //startTime = currentTime + Interval;

  while (currentTime < FinishTime)
  {
    currentTime = millis();
  }
  while (currentTime < FinishTime)
  {
    currentTime = millis();
    if (currentTime > startTime)
    {
      Serial.println(i);
      startTime = currentTime + Interval;
      i++;
    }
  }
  i = 0;
}

Serial.prints are slow, turn off any you don’t absolutely need and see if that increases your speeds.

At 115200 Baud, it takes 1 millisecond to print just 11 characters, and the print is blocking. As pointed out above, that is a serious limitation to your data collection rate.

If you use an Arduino with a full speed native USB serial connection (e.g. Teensy 3.2) that limitation goes away.

Jremington and YellowDog, please review the script again.

The sketch shows the main loop holds while loops in a linear sequence. The first while loop collects the measurements into an array and then the next loop uses Serial.print to show the entire data collected from the array into the Arduino Serial Monitor.

The first while loop has Serial.print functions that are omitted by the Arduino IDE using the comment operator (/* */).

How do Serial.print function calls in a different while loop affect the function calls from the Sparkfun library in the first loop?

Sorry, did not read the incredibly messy code closely enough.

Haha fair enough… it is messy.

Without reading the code, could you refer back to the original question, jremington?

What configuration and/or parameters could force a faster frequency with the KX134 accelerometer using I2C or SPI?

Maybe you could school me with your knowledge set of these communication protocols for this sensor?