Post Go back to editing

Maximizing vibration data sampling rate from ADXL357 for condition monitoring application

Category: Hardware
Product Number: ADXL357

Hi there !!

I am building a vibration monitoring application using ADXL357 with esp32 microcontroller. As per the information provided in cbm setup guide by ADI the number of datapoints collected in a second should be 5khz for 2.4 khz bandwidth. 

I have set the ODR_LPF at 2000 Hz and 500 Hz and HPF_CORNER at 6.2084 × 10−4 × ODR. and esp32 baud rate at 115200 through I2C. 

Problem:

I am getting 350 - 410 samples of vibration data in a second when I run a count to calculate the no of samples/sec. 

Question 

How can I get 5000 data samples/ sec ? 

Is my way of measuring the sampling data rate using a counter correct?

Kindly provide me some guidance in the right direction. 

Thanks.

  • Hello Parminder

    Why do you need 5000sps?

    Could you please share the ADXL357 register configurations.

    I assume you are reading the ADXL357 data over I2C? If so, the ODR is limited to 800Hz as you pointed out.

    You can poll DRDY to get an exact number of samples per second.  DRDY is an output indicator signaling a sample is ready. 

  • Hi Chris 

    I am building CBM application by considering ADI's condition based monitoring program setup guide which is based on voyager 3 platform. There it is mentioned that "The ADXL356 bandwidth is 2.4kHz, so sampling frequency should displayed , for optimally be 5kHz or higher. Sampling at lower frequencies is possible by changing the settings but please be aware of the danger of aliasing 510 . By default, the sampling frequency is chosen as Hz. This sampling frequency was chosen for demonstration purposes, as it shows roughly one second of time data." - page no-27

    So that's the reason for 5ksps.

    here I am attaching the .cpp file for consideration. Kindly let me know if something correct should be done. 

    Thankyou 

    #include "Seeed_adxl357b.h"
    
    
    
    
    
    /** begin(),i2c init & set defaule I2C address.
        @param set i2c_address
    **/
    int32_t Adxl357b::begin(uint8_t dev_addr) {
        uint8_t ID = 0;
        Wire.begin();
        _dev_addr = dev_addr;
        if (readDeviceID(ID) || (ID != 0xed)) {
            return -1;
        }
        adxlReset();
        delay(200);
        return 0;
    }
    
    
    int32_t Adxl357b::setAdxlRange(Adxl_Range range) 
    {
        uint8_t orig = 0;
        i2cReadByte(SET_RANGE_REG_ADDR, orig);
        //Serial.print("read reg = ");
        //Serial.println(range, BIN);
        //Serial.println(orig, BIN);
        orig |= range;
        //Serial.println(orig, BIN);
        return i2cWriteByte(SET_RANGE_REG_ADDR, orig);
         
    }
    
    
    int32_t Adxl357b::getActiveCnt(void) {
        uint8_t cnt = 0;
        if (i2cReadByte(GET_ACTIVE_COUNT_REG_ADDR, cnt)) {
            return -1;
        }
        return cnt;
    }
    
    int32_t Adxl357b::adxlReset(void) {
        return i2cWriteByte(RESET_REG_ADDR, 0x52);
    }
    
    
    int32_t Adxl357b::setActThreshold(float acc_g, float factory) {
        int16_t thres = 0;
        thres = (int16_t)(acc_g / factory);
        thres >>= 3;
        // thres = 13300;
        // thres >>= 3;
        Serial.println(thres, HEX);
    
        return i2cWriteU16(SET_THRESHOLD_REG_ADDR, (uint16_t)thres);
    }
    
    /** set action enable.
        @param enable_x enable x axis action.When the x axis result above threshold,trigger event.
        @param enable_y enable y axis action.When the y axis result above threshold,trigger event.
        @param enable_z enable z axis action.When the z axis result above threshold,trigger event.
     **/
    int32_t Adxl357b::setActEnable(bool enable_x, bool enable_y, bool enable_z) {
        uint8_t val = 0;
        val = val | (enable_z << 2) | (enable_y << 1) | enable_x;
        return i2cWriteByte(ACTION_ENABLE_REG_ADDR, val);
    }
    
    int32_t Adxl357b::setIntPinMap(uint8_t val) {
        return i2cWriteByte(SET_INT_PIN_MAP_REG_ADDR, val);
    }
    
    /** Config ADXL357 mode.
        bit2 - DRDY_OFF ,
        bit1 - TEMP-OFF ,
        bit0 - running mode,0 for measurement mode,1 for standby mode.
     **/
    int32_t Adxl357b::setPowerCtr(uint8_t val) {
        return i2cWriteByte(POWER_CTR_REG_ADDR, val);
    }
    
    
    int32_t Adxl357b::readTemperature(float& T) {
        int32_t ret = 0;
        int16_t temperature = 0;
        uint16_t val = 0;
        if (i2cReadU16(TEMPERATURE_REG_ADDR, val)) {
            return -1;
        }
    
        temperature = val;
        T = 25 + (temperature - 1852) / (-9.05);
        return 0;
    }
    
    int32_t Adxl357b::setFilter(void) {
        /*011 - 15.545*10^-3*ODR, 0011 - 500HZ&125HZ*/
        return i2cWriteByte(FILTER_REG_ADDR, 0x00);
    }
    
    
    int32_t Adxl357b::getFifoEntry(uint8_t& entry) {
        return i2cReadByte(FIFO_ENTRY_REG_ADDR, entry);
    }
    
    
    int32_t Adxl357b::readXYZAxisResultDataFromFIFO(int32_t& x, int32_t& y, int32_t& z) {
        uint8_t data[9] = {0};
        x = y = z = 0;
    
        if (i2cReadBytes(FIFO_DATA_REG_ADDR, data, 9)) {
            return -1;
        }
        x = ((uint32_t)data[0] << 12) | ((uint32_t)data[1] << 4) | ((uint32_t)data[2] >> 4);
        y = ((uint32_t)data[3] << 12) | ((uint32_t)data[4] << 4) | ((uint32_t)data[5] >> 4);
        z = ((uint32_t)data[6] << 12) | ((uint32_t)data[7] << 4) | ((uint32_t)data[8] >> 4);
    
        if (x & 0x80000) {
            x = (x & 0x7ffff) - 0x80000;
        }
        if (y & 0x80000) {
            y = (y & 0x7ffff) - 0x80000;
        }
        if (z & 0x80000) {
            z = (z & 0x7ffff) - 0x80000;
        }
    
        // Serial.println("....");
        // Serial.println(x);
        // Serial.println(y);
        // Serial.println(z);
        // Serial.println("....");
        return 0;
    }
    
    
    
    int32_t Adxl357b::readXYZAxisResultData(int32_t& x, int32_t& y, int32_t& z) {
        uint8_t data[9] = {0};
        x = y = z = 0;
    
        if (i2cReadBytes(FIFO_DATA_REG_ADDR, data, 9)) {
            return -1;
        }
        x = ((uint32_t)data[0] << 12) | ((uint32_t)data[1] << 4) | ((uint32_t)data[2] >> 4);
        y = ((uint32_t)data[3] << 12) | ((uint32_t)data[4] << 4) | ((uint32_t)data[5] >> 4);
        z = ((uint32_t)data[6] << 12) | ((uint32_t)data[7] << 4) | ((uint32_t)data[8] >> 4);
        // Serial.println("....");
        // for(int i=0;i<9;i++)
       //  {
       // 	Serial.print(data[i],HEX);
       //  	Serial.print(".");
       //  }
        if (x & 0x80000) {
            x = (x & 0x7ffff) - 0x80000;
        }
        if (y & 0x80000) {
            y = (y & 0x7ffff) - 0x80000;
        }
        if (z & 0x80000) {
            z = (z & 0x7ffff) - 0x80000;
        }
    
        // Serial.println("....");
         //Serial.println(x);
        // Serial.println(y);
        // Serial.println(z);
        // Serial.println("....");
        return 0;
    }
    
    
    
    int32_t Adxl357b::readDeviceID(uint8_t& ID) {
        return i2cReadByte(DEV_ID_REG_ADDR, ID);
    }
    
    int32_t Adxl357b::readDeviceVersion(uint8_t& ver) {
        return i2cReadByte(DEV_VERSION_ID_REG_ADDR, ver);
    }
    
    
    
    int32_t Adxl357b::getAdxl357Status(uint8_t& byte) {
        return i2cReadByte(STATUS_REG_ADDR, byte);
    }
    
    bool Adxl357b::checkDataReady(void) {
        uint8_t stat = 0;
        getAdxl357Status(stat);
        // Serial.println(",,,");
        // Serial.println(stat,HEX);
        // Serial.println(",,,");
        return stat & 0x01;
    }
    
    /*********************************************************************************************************************/
    /*********************************************************************************************************************/
    
    int32_t Adxl357b::i2cWriteBytes(uint8_t reg, uint8_t* data, uint32_t write_len) {
        Wire.beginTransmission(_dev_addr);
        Wire.write(reg);
        for (int i = 0; i < write_len; i++) {
            Wire.write(data[i]);
        }
        return Wire.endTransmission();
    }
    
    
    int32_t Adxl357b::i2cWriteByte(uint8_t reg, uint8_t data) {
        Wire.beginTransmission(_dev_addr);
        Wire.write(reg);
        Wire.write(data);
        return Wire.endTransmission();
    }
    
    
    int32_t Adxl357b::i2cWriteU16(uint8_t reg, uint16_t data) {
        uint8_t temp[2] = {0};
        temp [0] = (uint8_t)(data >> 8);
        temp [1] = (uint8_t)data;
        return i2cWriteBytes(reg, temp, 2);
    }
    
    
    int32_t Adxl357b::i2cWriteU32(uint8_t reg, uint32_t data) {
        uint8_t temp[4] = {0};
        temp [0] = (uint8_t)(data >> 24);
        temp [1] = (uint8_t)(data >> 16);
        temp [2] = (uint8_t)(data >> 8);
        temp [3] = (uint8_t)(data);
        return i2cWriteBytes(reg, temp, 4);
    }
    
    
    
    int32_t Adxl357b::i2cReadByte(uint8_t reg, uint8_t& byte) {
        uint32_t time_out_count = 0;
        Wire.beginTransmission(_dev_addr);
        Wire.write(reg);
        Wire.endTransmission(false);
        Wire.requestFrom(_dev_addr, (uint8_t)1);
        while (1 != Wire.available()) {
            time_out_count++;
            if (time_out_count > 10) {
                return -1;
            }
            delay(1);
        }
        byte = Wire.read();
        return 0;
    }
    
    
    int32_t Adxl357b::i2cReadU16(uint8_t reg, uint16_t& value) {
        uint32_t time_out_count = 0;
        value = 0;
        Wire.beginTransmission(_dev_addr);
        Wire.write(reg);
        Wire.endTransmission(false);
        Wire.requestFrom(_dev_addr, (uint8_t)2);
        while (2 != Wire.available()) {
            time_out_count++;
            if (time_out_count > 10) {
                return -1;
            }
            delay(1);
        }
        value |= Wire.read();
        value <<= 8;
        value |= Wire.read();
        return 0;
    }
    
    
    int32_t Adxl357b::i2cReadU32(uint8_t reg, uint32_t& value) {
        uint32_t time_out_count = 0;
        value = 0;
        Wire.beginTransmission(_dev_addr);
        Wire.write(reg);
        Wire.endTransmission(false);
        Wire.requestFrom(_dev_addr, (uint8_t)4);
        while (4 != Wire.available()) {
            time_out_count++;
            if (time_out_count > 10) {
                return -1;
            }
            delay(1);
        }
        value |= Wire.read();
        value <<= 24;
    
        value |= Wire.read();
        value <<= 16;
    
        value |= Wire.read();
        value <<= 8;
    
        value |= Wire.read();
        return 0;
    }
    
    
    
    int32_t Adxl357b::i2cReadBytes(uint8_t reg, uint8_t* data, uint32_t read_len) {
        uint32_t time_out_count = 0;
        Wire.beginTransmission(_dev_addr);
        Wire.write(reg);
        Wire.endTransmission(false);
    
        Wire.requestFrom(_dev_addr, read_len);
        while (read_len != Wire.available()) {
            time_out_count++;
            if (time_out_count > 10) {
                return -1;
            }
            delay(1);
        }
        for (int i = 0; i < read_len; i++) {
            data[i] = Wire.read();
        }
        return 0;
    
    }
    
    /*********************************************************************************************************************/
    /*********************************************************************************************************************/

  • and here is the .h file 

    #ifndef __SEEED_ADXL357B_H
    #define __SEEED_ADXL357B_H
    
    
    #include <Wire.h>
    #include <Arduino.h>
    
    #define DEFAULT_DEV_I2C_ADDRESS   0x1d
    
    
    
    #define DEV_MEMS_REG_ADDR         0x01
    #define DEV_ID_REG_ADDR           0x02
    #define DEV_VERSION_ID_REG_ADDR   0x03
    #define STATUS_REG_ADDR           0x04
    #define FIFO_ENTRY_REG_ADDR       0x05 //0x06
    
    #define ACTION_ENABLE_REG_ADDR    0x24
    #define SET_THRESHOLD_REG_ADDR    0x25
    #define GET_ACTIVE_COUNT_REG_ADDR 0x27 //0x26
    #define SET_INT_PIN_MAP_REG_ADDR  0x2a
    
    #define X_DATA_REG_ADDR           0x08
    #define FIFO_DATA_REG_ADDR        0x11
    
    #define POWER_CTR_REG_ADDR        0x2d
    
    #define TEMPERATURE_REG_ADDR      0x06
    #define FILTER_REG_ADDR           0x28
    
    #define SET_RANGE_REG_ADDR        0x2c
    #define RESET_REG_ADDR            0x2f
    
    typedef enum {
        X_DIR,
        Y_DIR,
        Z_DIR,
    } AxisPos;
    
    
    typedef enum {
        TEN_G = 1,
        TWENTY_G = 2,
        FOURTY_G = 3,
    } Adxl_Range;
    
    class Adxl357b {
      public:
        Adxl357b() {};
        ~Adxl357b() {};
        /** begin(),i2c init & set defaule I2C address.
            @param set i2c_address
         **/
        int32_t begin(uint8_t dev_addr = DEFAULT_DEV_I2C_ADDRESS);
    
        /** set action enable.
            @param enable_x enable x axis action.When the x axis result above threshold,trigger event.
            @param enable_y enable y axis action.When the y axis result above threshold,trigger event.
            @param enable_z enable z axis action.When the z axis result above threshold,trigger event.
         **/
        int32_t setActEnable(bool enable_x, bool enable_y, bool enable_z);
    
    
        int32_t readDeviceID(uint8_t& ID);
        int32_t readDeviceVersion(uint8_t& ver);
        /** Read x/y/z axis data from register.
    
         **/
        int32_t readXYZAxisResultData(int32_t& x, int32_t& y, int32_t& z);
        /** Config ADXL357 mode.
            bit2 - DRDY_OFF ,
            bit1 - TEMP-OFF ,
            bit0 - running mode,0 for measurement mode,1 for standby mode.
         **/
        int32_t setPowerCtr(uint8_t val);
    
        int32_t readTemperature(float& T);
    
        /** Get status register data.
            bit4 - NVM-BUSY
            bit3 - Activity
            bit2 - FIFO_OVR
            bit1 - FIFO_FULL
            bit0 - DATA_RDY
         **/
        int32_t getAdxl357Status(uint8_t& byte);
        /** Check whether the  status register's first bit is 1.
         **/
        bool checkDataReady(void);
    
        int32_t adxlReset(void);
    
        int32_t setFilter(void);
        /** Set ADXL357's full scale range.
            ±10g,±20g,±40g
         **/
        int32_t setAdxlRange(Adxl_Range range);
        /** Read x/y/z axis data from FIFO.
    
         **/
        int32_t readXYZAxisResultDataFromFIFO(int32_t& x, int32_t& y, int32_t& z);
    
        int32_t getFifoEntry(uint8_t& entry);
    
        /** Set threshold,when measured result over than threshold,trigger event,if corresponding INT function has enabled,trigger interruct event.
            @param acc_g The threshold value,unit is g.
            @param factory Acceleration value corresponding to one acceleration result value,the result value is read from register.
    
         **/
        int32_t setActThreshold(float acc_g, float factory);
        /** Set config INT pin.
    
         **/
        int32_t setIntPinMap(uint8_t val);
        /** Event count.event count incresed when axis result value over than threshold.
    
         **/
        int32_t getActiveCnt(void);
      private:
        uint32_t _x_data;
        uint32_t _y_data;
        uint32_t _z_data;
        uint8_t  _dev_addr;
    
    
        int32_t i2cWriteByte(uint8_t reg, uint8_t data);
        int32_t i2cWriteU16(uint8_t reg, uint16_t data);
        int32_t i2cWriteU32(uint8_t reg, uint32_t data);
        int32_t i2cWriteBytes(uint8_t reg, uint8_t* data, uint32_t write_len);
    
        int32_t i2cReadBytes(uint8_t reg, uint8_t* data, uint32_t read_len);
        int32_t i2cReadU16(uint8_t reg, uint16_t& value);
        int32_t i2cReadByte(uint8_t reg, uint8_t& byte);
        int32_t i2cReadU32(uint8_t reg, uint32_t& value);
    
    };
    
    
    
    #endif

  • Thanks for sharing. If you could post a plot that would be very helpful.

    When you plot the acceleration data does it look as expected?

  • Sure Chris 

    Here is the link of plot image. https://drive.google.com/file/d/1pNxf0WLpMmzOAn-U6Cbw8twWYFoZ2Bk9/view?usp=sharing

    When I plot the data the ADXL357's response is accurate and great but the only doubt I have is when I run a counter to calculate the number of samples microcontroller is getting then I get 430 samples/sec at baud rate of 1000000. 
    I also wanted to convert the acceleration values in G to velocity as mentioned in https://www.analog.com/en/analog-dialogue/articles/mems-vibration-monitoring-acceleration-to-velocity.html 
    Here I need frequency value to calculate the velocity, So I am confused that shall I consider 430hz ? where it should be 5khz according to the theory.  

    Thanks for your quick response Chris!!

  • Hi  , 

    you can convert from acceleration to velocity by integrating acceleration output over time. 

    The clock variation for the ADXL357 is +/-10%, so 430 samples per second is within expected. If you need a more accurate sampling rate, you can use the external clock and/or external synchronization feature of the ADXL357. 

    Regards, 

    Pablo.