This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Get X,Y,Z values from LIS3DH using nrf52 development board

Hi!

I am trying to interface LIS3DH module (https://www.adafruit.com/product/2809) with nRF52 DK, SDK 11, via i2c/spi. I tested on Arduino UNO & it gave x,y,z values. So, I decided to write nrf driver for LIS3DH using Adafruit LIS3DH driver(https://github.com/adafruit/Adafruit_LIS3DH/) but I am getting errors like i2c begin & how/what to write to control registers to read data again.

Please suggest me how to write driver or if general LIS3DH driver is available then reply ASAP.

LIS3DH.h

#include <LIS3DH.h>
#include "nrf_drv_twi.h"
#include "nrf_delay.h"

/** Sensor types */
typedef enum
{
  SENSOR_TYPE_ACCELEROMETER         = (1),   /**< Gravity + linear acceleration */
  SENSOR_TYPE_MAGNETIC_FIELD        = (2),
  SENSOR_TYPE_ORIENTATION           = (3),
  SENSOR_TYPE_GYROSCOPE             = (4),
  SENSOR_TYPE_LIGHT                 = (5),
  SENSOR_TYPE_PRESSURE              = (6),
  SENSOR_TYPE_PROXIMITY             = (8),
  SENSOR_TYPE_GRAVITY               = (9),
  SENSOR_TYPE_LINEAR_ACCELERATION   = (10),  /**< Acceleration not including gravity */
  SENSOR_TYPE_ROTATION_VECTOR       = (11),
  SENSOR_TYPE_RELATIVE_HUMIDITY     = (12),
  SENSOR_TYPE_AMBIENT_TEMPERATURE   = (13),
  SENSOR_TYPE_VOLTAGE               = (15),
  SENSOR_TYPE_CURRENT               = (16),
  SENSOR_TYPE_COLOR                 = (17)
} sensors_type_t;

/** struct sensors_vec_s is used to return a vector in a common format. */
typedef struct {
 
        float v[3];
        struct {
            float x;
            float y;
            float z;
    
            float roll;    /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90�<=roll<=90� */
            float pitch;   /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180�<=pitch<=180�) */
            float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359� */
    
					int8_t status;
    uint8_t reserved[3];
} sensors_vec_t;

/** struct sensors_color_s is used to return color data in a common format. */
typedef struct {

        float c[3];
        /* RGB color space */

            float r;       /**< Red component */
            float g;       /**< Green component */
            float b;       /**< Blue component */
  
  
    uint32_t rgba;         /**< 24-bit RGBA value */
} sensors_color_t;

/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
{
    int32_t version;                          /**< must be sizeof(struct sensors_event_t) */
    int32_t sensor_id;                        /**< unique sensor identifier */
    int32_t type;                             /**< sensor type */
    int32_t reserved0;                        /**< reserved */
    int32_t timestamp;                        /**< time is in milliseconds */

        float           data[4];
        float           temperature;          /**< temperature is in degrees centigrade (Celsius) */
        float           distance;             /**< distance in centimeters */
        float           light;                /**< light in SI lux units */
        float           pressure;             /**< pressure in hectopascal (hPa) */
        float           relative_humidity;    /**< relative humidity in percent */
        float           current;              /**< current in milliamps (mA) */
        float           voltage;              /**< voltage in volts (V) */
     
 
} sensors_event_t;

/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
{
    char     name[12];                        /**< sensor name */
    int32_t  version;                         /**< version of the hardware + driver */
    int32_t  sensor_id;                       /**< unique sensor identifier */
    int32_t  type;                            /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
    float    max_value;                       /**< maximum value of this sensor's value in SI units */
    float    min_value;                       /**< minimum value of this sensor's value in SI units */
    float    resolution;                      /**< smallest difference between two values reported by this sensor */
    int32_t  min_delay;                       /**< min delay in microseconds between events. zero = not a constant rate */
} sensor_t;




typedef enum
{
  LIS3DH_RANGE_16_G         = 3,   // +/- 16g
  LIS3DH_RANGE_8_G           = 2,   // +/- 8g
  LIS3DH_RANGE_4_G           = 1,   // +/- 4g
  LIS3DH_RANGE_2_G           = 0    // +/- 2g (default value)
} lis3dh_range_t;

typedef enum
{
  LIS3DH_AXIS_X         = 0x0,
  LIS3DH_AXIS_Y         = 0x1,
  LIS3DH_AXIS_Z         = 0x2,
} lis3dh_axis_t;


  // These must be defined by the subclass
  void enableAutoRange(bool enabled) {};
 

  int16_t readADC(uint8_t a);

  void setRange(lis3dh_range_t range);
  lis3dh_range_t getRange(void);

  void setDataRate(lis3dh_dataRate_t dataRate);
  lis3dh_dataRate_t getDataRate(void);

  bool getEvent(sensors_event_t *event);
  void getSensor(sensor_t *sensor);

  uint8_t getOrientation(void);

  void setClick(uint8_t c, uint8_t clickthresh, uint8_t timelimit = 10, uint8_t timelatency = 20, uint8_t timewindow = 255);
  uint8_t getClick(void);

  int16_t x, y, z;
  float x_g, y_g, z_g;


  uint8_t readRegister8(uint8_t reg);
  void writeRegister8(uint8_t reg, uint8_t value);
  uint8_t spixfer(uint8_t x = 0xFF);


  int32_t _sensorID;
  int8_t  _i2caddr;

  // SPI
  int8_t _cs, _mosi, _miso, _sck;

/**************************************************************************/
/*!
    @brief  Setups the HW (reads coefficients values, etc.)
*/
/**************************************************************************/
bool begin() {



  /* Check connection */
  uint8_t deviceid = readRegister8(LIS3DH_REG_WHOAMI);
  if (deviceid != 0x33)
  {
    /* No LIS3DH detected ... return false */
    //Serial.println(deviceid, HEX);
    return false;
  }

  // enable all axes, normal mode
  writeRegister8(LIS3DH_REG_CTRL1, 0x07);
  // 400Hz rate
  setDataRate(LIS3DH_DATARATE_400_HZ);

  // High res & BDU enabled
  writeRegister8(LIS3DH_REG_CTRL4, 0x88);

  // DRDY on INT1
  writeRegister8(LIS3DH_REG_CTRL3, 0x10);

  // Turn on orientation config
  //writeRegister8(LIS3DH_REG_PL_CFG, 0x40);

  // enable adcs
  writeRegister8(LIS3DH_REG_TEMPCFG, 0x80);

  /*
  for (uint8_t i=0; i<0x30; i++) {
    Serial.print("$");
    Serial.print(i, HEX); Serial.print(" = 0x");
    Serial.println(readRegister8(i), HEX);
  }
  */

  return true;
}


void read(void) {
  // read x y z at once

  if (_cs == -1) {
    // i2c
	nrf_drv_twi_tx(&p_twi_instance,LIS3DH_DEFAULT_ADDRESS,LIS3DH_REG_OUT_X_L,sizeof(LIS3DH_REG_OUT_X_L), true);// PEDO_WRITE(data,6);
	nrf_delay_ms(5);
	do{
	nrf_drv_twi_rx(&p_twi_instance,LIS3DH_DEFAULT_ADDRESS,LIS3DH_REG_OUT_X_L, sizeof(LIS3DH_REG_OUT_X_L), false);
		
	}while(LIS3DH_REG_OUT_X_L[1]!=0x80);
	
    I2Cinterface->requestFrom(_i2caddr, 6);
    x = I2Cinterface->read(); x |= ((uint16_t)I2Cinterface->read()) << 8;
    y = I2Cinterface->read(); y |= ((uint16_t)I2Cinterface->read()) << 8;
    z = I2Cinterface->read(); z |= ((uint16_t)I2Cinterface->read()) << 8;
  } 
  #ifndef __AVR_ATtiny85__
  else {
    if (_sck == -1)
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    digitalWrite(_cs, LOW);
    spixfer(LIS3DH_REG_OUT_X_L | 0x80 | 0x40); // read multiple, bit 7&6 high

    x = spixfer(); x |= ((uint16_t)spixfer()) << 8;
    y = spixfer(); y |= ((uint16_t)spixfer()) << 8;
    z = spixfer(); z |= ((uint16_t)spixfer()) << 8;

    digitalWrite(_cs, HIGH);
    if (_sck == -1)
      SPI.endTransaction();              // release the SPI bus

  }
  #endif
  uint8_t range = getRange();
  uint16_t divider = 1;
  if (range == LIS3DH_RANGE_16_G) divider = 1365; // different sensitivity at 16g
  if (range == LIS3DH_RANGE_8_G) divider = 4096;
  if (range == LIS3DH_RANGE_4_G) divider = 8190;
  if (range == LIS3DH_RANGE_2_G) divider = 16380;

  x_g = (float)x / divider;
  y_g = (float)y / divider;
  z_g = (float)z / divider;

}

/**************************************************************************/
/*!
    @brief  Read the auxilary ADC
*/
/**************************************************************************/

int16_t readADC(uint8_t adc) {
  if ((adc < 1) || (adc > 3)) return 0;
  uint16_t value;

  adc--;

  uint8_t reg = LIS3DH_REG_OUTADC1_L + adc*2;

  if (_cs == -1) {
    // i2c
    I2Cinterface->beginTransmission(_i2caddr);
    I2Cinterface->write(reg | 0x80);   // 0x80 for autoincrement
    I2Cinterface->endTransmission();
    I2Cinterface->requestFrom(_i2caddr, 2);
    value = I2Cinterface->read();  value |= ((uint16_t)I2Cinterface->read()) << 8;
  } 
  #ifndef __AVR_ATtiny85__
  else {
    if (_sck == -1)
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    digitalWrite(_cs, LOW);
    spixfer(reg | 0x80 | 0x40); // read multiple, bit 7&6 high

    value = spixfer(); value |= ((uint16_t)spixfer()) << 8;

    digitalWrite(_cs, HIGH);
    if (_sck == -1)
      SPI.endTransaction();              // release the SPI bus
  }
  #endif

  return value;
}


/**************************************************************************/
/*!
    @brief  Set INT to output for single or double click
*/
/**************************************************************************/

void setClick(uint8_t c, uint8_t clickthresh, uint8_t timelimit, uint8_t timelatency, uint8_t timewindow) {
  if (!c) {
    //disable int
    uint8_t r = readRegister8(LIS3DH_REG_CTRL3);
    r &= ~(0x80); // turn off I1_CLICK
    writeRegister8(LIS3DH_REG_CTRL3, r);
    writeRegister8(LIS3DH_REG_CLICKCFG, 0);
    return;
  }
  // else...

  writeRegister8(LIS3DH_REG_CTRL3, 0x80); // turn on int1 click
  writeRegister8(LIS3DH_REG_CTRL5, 0x08); // latch interrupt on int1

  if (c == 1)
    writeRegister8(LIS3DH_REG_CLICKCFG, 0x15); // turn on all axes & singletap
  if (c == 2)
    writeRegister8(LIS3DH_REG_CLICKCFG, 0x2A); // turn on all axes & doubletap


  writeRegister8(LIS3DH_REG_CLICKTHS, clickthresh); // arbitrary
  writeRegister8(LIS3DH_REG_TIMELIMIT, timelimit); // arbitrary
  writeRegister8(LIS3DH_REG_TIMELATENCY, timelatency); // arbitrary
  writeRegister8(LIS3DH_REG_TIMEWINDOW, timewindow); // arbitrary
}

uint8_t getClick(void) {
  return readRegister8(LIS3DH_REG_CLICKSRC);
}


/**************************************************************************/
/*!
    @brief  Sets the g range for the accelerometer
*/
/**************************************************************************/
void setRange(lis3dh_range_t range)
{
  uint8_t r = readRegister8(LIS3DH_REG_CTRL4);
  r &= ~(0x30);
  r |= range << 4;
  writeRegister8(LIS3DH_REG_CTRL4, r);
}

/**************************************************************************/
/*!
    @brief  Sets the g range for the accelerometer
*/
/**************************************************************************/
lis3dh_range_t getRange(void)
{
  /* Read the data format register to preserve bits */
  return (lis3dh_range_t)((readRegister8(LIS3DH_REG_CTRL4) >> 4) & 0x03);
}

/**************************************************************************/
/*!
    @brief  Sets the data rate for the LIS3DH (controls power consumption)
*/
/**************************************************************************/
void setDataRate(lis3dh_dataRate_t dataRate)
{
  uint8_t ctl1 = readRegister8(LIS3DH_REG_CTRL1);
  ctl1 &= ~(0xF0); // mask off bits
  ctl1 |= (dataRate << 4);
  writeRegister8(LIS3DH_REG_CTRL1, ctl1);
}

/**************************************************************************/
/*!
    @brief  Sets the data rate for the LIS3DH (controls power consumption)
*/
/**************************************************************************/
lis3dh_dataRate_t getDataRate(void)
{
  return (lis3dh_dataRate_t)((readRegister8(LIS3DH_REG_CTRL1) >> 4)& 0x0F);
}

/**************************************************************************/
/*!
    @brief  Gets the most recent sensor event
*/
/**************************************************************************/
bool getEvent(sensors_event_t *event) {
  /* Clear the event */
  memset(event, 0, sizeof(sensors_event_t));

  event->version   = sizeof(sensors_event_t);
  event->sensor_id = _sensorID;
  event->type      = SENSOR_TYPE_ACCELEROMETER;
  event->timestamp = 0;

  read();

  event->acceleration.x = x_g * SENSORS_GRAVITY_STANDARD;
  event->acceleration.y = y_g * SENSORS_GRAVITY_STANDARD;
  event->acceleration.z = z_g * SENSORS_GRAVITY_STANDARD;
}

/**************************************************************************/
/*!
    @brief  Gets the sensor_t data
*/
/**************************************************************************/
void getSensor(sensor_t *sensor) {
  /* Clear the sensor_t object */
  memset(sensor, 0, sizeof(sensor_t));

  /* Insert the sensor name in the fixed length char array */
  strncpy (sensor->name, "LIS3DH", sizeof(sensor->name) - 1);
  sensor->name[sizeof(sensor->name)- 1] = 0;
  sensor->version     = 1;
  sensor->sensor_id   = _sensorID;
  sensor->type        = SENSOR_TYPE_ACCELEROMETER;
  sensor->min_delay   = 0;
  sensor->max_value   = 0;
  sensor->min_value   = 0;
  sensor->resolution  = 0;
}


/**************************************************************************/
/*!
    @brief  Low level SPI
*/
/**************************************************************************/

uint8_t spixfer(uint8_t x) {
  #ifndef __AVR_ATtiny85__
  if (_sck == -1)
    return SPI.transfer(x);

  // software spi
  //Serial.println("Software SPI");
  uint8_t reply = 0;
  for (int i=7; i>=0; i--) {
    reply <<= 1;
    digitalWrite(_sck, LOW);
    digitalWrite(_mosi, x & (1<<i));
    digitalWrite(_sck, HIGH);
    if (digitalRead(_miso))
      reply |= 1;
  }
  return reply;
  #endif
}


/**************************************************************************/
/*!
    @brief  Writes 8-bits to the specified destination register
*/
/**************************************************************************/
void writeRegister8(uint8_t reg, uint8_t value) {
  if (_cs == -1) {
    I2Cinterface->beginTransmission((uint8_t)_i2caddr);
    I2Cinterface->write((uint8_t)reg);
    I2Cinterface->write((uint8_t)value);
    I2Cinterface->endTransmission();
  } 
  #ifndef __AVR_ATtiny85__
  else {
    if (_sck == -1)
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    digitalWrite(_cs, LOW);
    spixfer(reg & ~0x80); // write, bit 7 low
    spixfer(value);
    digitalWrite(_cs, HIGH);
    if (_sck == -1)
      SPI.endTransaction();              // release the SPI bus
  }
  #endif
}

/**************************************************************************/
/*!
    @brief  Reads 8-bits from the specified register
*/
/**************************************************************************/
uint8_t readRegister8(uint8_t reg) {
  uint8_t value;

  if (_cs == -1) {
    I2Cinterface->beginTransmission(_i2caddr);
    I2Cinterface->write((uint8_t)reg);
    I2Cinterface->endTransmission();

    I2Cinterface->requestFrom(_i2caddr, 1);
    value = I2Cinterface->read();
  }  
  #ifndef __AVR_ATtiny85__
  else {
    if (_sck == -1)
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    digitalWrite(_cs, LOW);
    spixfer(reg | 0x80); // read, bit 7 high
    value = spixfer(0);
    digitalWrite(_cs, HIGH);
    if (_sck == -1)
      SPI.endTransaction();              // release the SPI bus
  }
  #endif
  return value;
}

Parents
  • Hello,

    I think you should be able to find a driver for the LIS3DH in a couple of cases here on DevZone. However, we have a driver that is included in a separate SDK. However, this SDK is not open source, but I can give you the driver. See if you can use this one.

    /* Copyright (c) 2016 Nordic Semiconductor. All Rights Reserved.
     *
     * The information contained herein is property of Nordic Semiconductor ASA.
     * Terms and conditions of usage are described in detail in NORDIC
     * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
     *
     * Licensees are granted free, non-transferable use of the information. NO
     * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
     * the file.
     *
     */
    
    #include <string.h>
    #ifndef __ICCARM__
    #include <alloca.h>
    #endif
    
    #include "nordic_common.h"
    #include "nrf.h"
    #include "nrf_assert.h"
    #include "nrf_error.h"
    #include "nrf_delay.h"
    #include "app_debug.h"
    #include "app_error.h"
    #include "app_gpiote.h"
    #include "app_twi.h"
    
    #include "drv_acc_lis3dh.h"
    #include "drv_acc.h"
    
    #include "resources.h"
    #include "twi_common.h"
    #include "sr3_config.h"
    
    #define NRF_LOG_MODULE_NAME drv_acc
    #define NRF_LOG_LEVEL CONFIG_ACC_DRV_LOG_LEVEL
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    #if CONFIG_ACC_ENABLED
    
    // Check pin configuration.
    STATIC_ASSERT(IS_IO_VALID(CONFIG_IO_ACC_IRQ));
    
    #define ACC_TWI_INSTANCE        (g_twi[CONFIG_ACC_TWI_BUS])
    
    static drv_acc_mode_t           m_acc_mode = DRV_ACC_MODE_UNDEFINED;
    static app_gpiote_user_id_t     m_acc_gpiote;
    
    #if CONFIG_ACC_USE_CLICK_DETECTION
    static drv_acc_callback_t       m_acc_callback;
    #endif
    
    /**@brief Reads one or more consecutive registers from the device.
     *
     * @note This function uses unscheduled I2C transactions - must be called only in MAIN CONTEXT.
     *
     * @param[in]  reg      Register address.
     * @param[out] contents Pointer to data buffer.
     * @param[in]  num_regs Number of registers to be read.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_read_regs(uint8_t reg, uint8_t* contents, uint8_t num_regs)
    {
        app_twi_transfer_t transfers[2];
    
        if (num_regs > 1)
        {
            // Setting auto increment
            reg |= BIT_7;
        }
    
        transfers[0].p_data     = &reg;
        transfers[0].length     = 1;
        transfers[0].operation  = APP_TWI_WRITE_OP(LIS3DH_I2C_ADDRESS);
        transfers[0].flags      = APP_TWI_NO_STOP;
    
        transfers[1].p_data     = contents;
        transfers[1].length     = num_regs;
        transfers[1].operation  = APP_TWI_READ_OP(LIS3DH_I2C_ADDRESS);
        transfers[1].flags      = 0;
    
        return app_twi_perform(ACC_TWI_INSTANCE, transfers, ARRAY_SIZE(transfers), twi_idle_func);
    }
    
    /**@brief Writes one or more consecutive registers to the device. This function uses unscheduled I2C transactions - must be called only in MAIN CONTEXT.
     *
     * @param[in] reg      Register address.
     * @param[in] contents Data to write.
     * @param[in] num_regs Length of data/number of registers that should be written.
     *
     * @return NRF_SUCCESS on success, otherwise error code.
     */
    static ret_code_t lis3dh_write_regs(uint8_t reg, uint8_t* contents, uint8_t num_regs)
    {
        app_twi_transfer_t transfers[1];
    
    #ifndef __ICCARM__
        uint8_t *write_buffer = alloca(num_regs + 1);
    #else
        uint8_t write_buffer[6];
    
        ASSERT(sizeof(write_buffer) >= (num_regs + 1));
    #endif
    
        if (num_regs > 1)
        {
            // Setting auto increment
            reg |= BIT_7;
        }
    
        write_buffer[0] = reg;
        memcpy(&write_buffer[1], contents, num_regs);
    
        transfers[0].p_data     = write_buffer;
        transfers[0].length     = num_regs + 1;
        transfers[0].operation  = APP_TWI_WRITE_OP(LIS3DH_I2C_ADDRESS);
        transfers[0].flags      = 0;
    
        return app_twi_perform(ACC_TWI_INSTANCE, transfers, ARRAY_SIZE(transfers), twi_idle_func);
    }
    
    /**@brief Resets the memory contents to its default state.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_reset(void)
    {
        ret_code_t status;
        uint8_t reg_val;
    
        // Resetting takes time - time-out to complete depends on ODR - see AN3308 application note - page 11.
        // Set fast ODR - 1.6 kHz.
        reg_val = 0x80;
        status = lis3dh_write_regs(CTRL_REG1, &reg_val, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Reboot
        reg_val = 0x80;
        status = lis3dh_write_regs(CTRL_REG5, &reg_val, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        nrf_delay_ms(1);
    
        return NRF_SUCCESS;
    }
    
    /**@brief Read and verify ID.
     *
     * @return NRF_SUCCESS if LIS3DH chip was found, otherwise an error code.
     */
    static ret_code_t lis3dh_verify_id(void)
    {
        ret_code_t status;
        uint8_t reg_val;
    
        status = lis3dh_read_regs(WHO_AM_I, &reg_val, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        return (reg_val == I_AM_LIS3DH) ? NRF_SUCCESS : NRF_ERROR_NOT_FOUND;
    }
    
    /**@brief Reads interrupt source registers, which clears interrupt flag.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_int_clear(void)
    {
        ret_code_t status;
        uint8_t reg_val;
    
        status = lis3dh_read_regs(INT1_SRC, &reg_val, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        status = lis3dh_read_regs(CLICK_SRC, &reg_val, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        /*
         * The LIS3DH needs 1/ODR time to clear the interrupt.
         * As we are using 100 Hz ODR, we have to wait 10 ms here to make sure
         * that the interrupt is no longer signaled.
         */
        nrf_delay_ms(10);
    
        return NRF_SUCCESS;
    }
    
    /**@brief Enables selected interrupts.
     *
     * @param[in] int1_cfg  Contents of the INT1_CFG register.
     * @param[in] click_cfg Contents of the CLICK_CFG register.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_int_enable(uint8_t int1_cfg, uint8_t click_cfg)
    {
        ret_code_t status;
    
        status = lis3dh_write_regs(INT1_CFG, &int1_cfg, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
       return lis3dh_write_regs(CLICK_CFG, &click_cfg, 1);
    }
    
    /**@brief Accelerometer Interrupt handler.
     */
    static void m_acc_interupt_handler(uint32_t const *p_event_pins_low_to_high,
                                       uint32_t const *p_event_pins_high_to_low)
    {
    #if CONFIG_ACC_USE_CLICK_DETECTION
        if ((m_acc_mode == DRV_ACC_MODE_CLICK_DETECT) && m_acc_callback)
        {
            NRF_LOG_DEBUG("<Accelerometer Interrupt>");
            m_acc_callback();
        }
    #endif /* CONFIG_ACC_USE_CLICK_DETECTION */
    }
    
    /**@brief Sets the accelerometer in idle mode.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_idle_mode_set(void)
    {
        uint8_t ctrl_regs[] = {0x58, 0x00, 0x00, 0x00, 0x00};
        ret_code_t status;
        uint8_t reg_val;
    
        NRF_LOG_INFO("DRV_ACC_MODE_IDLE");
    
        // Disable all interrupts.
        status = lis3dh_int_enable(0x00, 0x00);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Update configuration.
        status = lis3dh_write_regs(CTRL_REG1, ctrl_regs, sizeof(ctrl_regs));
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Clear interrupts.
        status = lis3dh_int_clear();
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Set Power Down mode.
        reg_val = 0x08;
        return lis3dh_write_regs(CTRL_REG1, &reg_val, 1);
    }
    
    /**@brief Sets the accelerometer in wakeup mode - see AN3308 application note - page 23.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_wakeup_mode_set(void)
    {
        uint8_t ctrl_regs[] = {0x5F, 0x01, 0x40, 0x00, 0x00};
        uint8_t int1_ths[]  = {CONFIG_ACC_WAKEUP_THRESHOLD, 0x00};
        ret_code_t status;
        uint8_t reg_val;
    
        NRF_LOG_INFO("DRV_ACC_MODE_WAKE_UP");
    
        // Disable all interrupts.
        status = lis3dh_int_enable(0x00, 0x00);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Update configuration.
        status = lis3dh_write_regs(CTRL_REG1, ctrl_regs, sizeof(ctrl_regs));
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        status = lis3dh_write_regs(INT1_THS, int1_ths, sizeof(int1_ths));
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // This read resets the LIS3DH internal HP filter.
        status = lis3dh_read_regs(REFERENCE_REG, &reg_val, 1);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Clear interrupts.
        status = lis3dh_int_clear();
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Enable selected interrupts.
        return lis3dh_int_enable(0x2A, 0x00);
    }
    
    #if CONFIG_ACC_USE_CLICK_DETECTION
    /**@brief Sets the accelerometer in click detect mode  - see AN3308 application note - page 35.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_click_detect_mode_set(void)
    {
        uint8_t ctrl_regs[] = {0x57, 0x04, 0x80, 0x00, 0x00};
        uint8_t click_cfg[] = {CONFIG_ACC_CLICK_THRESHOLD,
                               CONFIG_ACC_CLICK_TIMELIMIT,
                               CONFIG_ACC_CLICK_LATENCY};
        ret_code_t status;
    
        NRF_LOG_INFO("DRV_ACC_MODE_CLICK_DETECT");
    
        // Disable all interrupts.
        status = lis3dh_int_enable(0x00, 0x00);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Update configuration.
        status = lis3dh_write_regs(CTRL_REG1, ctrl_regs, sizeof(ctrl_regs));
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        status = lis3dh_write_regs(CLICK_THS, click_cfg, sizeof(click_cfg));
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Clear interrupts.
        status = lis3dh_int_clear();
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        // Enable selected interrupts.
        return lis3dh_int_enable(0x00, CONFIG_ACC_CLICK_AXES);
    }
    #endif /* CONFIG_ACC_USE_CLICK_DETECTION */
    
    /**@brief Sets accelerometer in the given mode.
     *
     * @param[in]   mode    Mode of accelerometer operation.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static ret_code_t lis3dh_mode_set(drv_acc_mode_t mode)
    {
        switch (mode)
        {
            case DRV_ACC_MODE_WAKE_UP:
                return lis3dh_wakeup_mode_set();
    #if CONFIG_ACC_USE_CLICK_DETECTION
            case DRV_ACC_MODE_CLICK_DETECT:
                return lis3dh_click_detect_mode_set();
    #endif
            case DRV_ACC_MODE_IDLE:
                return lis3dh_idle_mode_set();
            default:
                return NRF_ERROR_NOT_SUPPORTED;
        }
    
        /* Not reached */
    }
    
    /**@brief Enables PIO interrupt. */
    static ret_code_t lis3dh_enable_pio_interrupts(void)
    {
        return app_gpiote_user_enable(m_acc_gpiote);
    }
    
    /**@brief Disables PIO interrupt. */
    static ret_code_t lis3dh_disable_pio_interrupts(void)
    {
        return app_gpiote_user_disable(m_acc_gpiote);
    }
    
    /*--- drv_acc.h API ---*/
    
    ret_code_t drv_acc_mode_set(drv_acc_mode_t mode)
    {
        ret_code_t status = NRF_SUCCESS;
    
        if (m_acc_mode != mode)
        {
            status = lis3dh_disable_pio_interrupts();
            if (status != NRF_SUCCESS)
            {
                return status;
            }
    
            status = lis3dh_mode_set(mode);
            if (status != NRF_SUCCESS)
            {
                return status;
            }
    
            switch (mode)
            {
    #if CONFIG_ACC_USE_CLICK_DETECTION
                case DRV_ACC_MODE_CLICK_DETECT:
    #endif
                case DRV_ACC_MODE_WAKE_UP:
                    status = lis3dh_enable_pio_interrupts();
                    if (status != NRF_SUCCESS)
                    {
                        return status;
                    }
                    break;
    
                default:
                    /* Do nothing */
                    break;
            }
    
            m_acc_mode = mode;
        }
    
        return status;
    }
    
    ret_code_t drv_acc_init(drv_acc_callback_t click_handler)
    {
        uint32_t low_to_high_mask = (1 << CONFIG_IO_ACC_IRQ);
        uint32_t high_to_low_mask = (0 << CONFIG_IO_ACC_IRQ);
        ret_code_t status;
    
    #if CONFIG_ACC_USE_CLICK_DETECTION
        m_acc_callback = click_handler;
    #endif
    
        status = app_gpiote_user_register(&m_acc_gpiote,
                                          &low_to_high_mask,
                                          &high_to_low_mask,
                                          m_acc_interupt_handler);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        status = lis3dh_verify_id();
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        status = lis3dh_reset();
        if (status != NRF_SUCCESS)
        {
            return status;
        }
    
        return drv_acc_mode_set(DRV_ACC_MODE_DEFAULT);
    }
    
    #endif /* CONFIG_ACC_ENABLED */
    

    drv_acc_lis3dh.h

     

    Best regards,

    Edvin

  • Please reply with the function to call for X,Y,Z values from main.c ?

  • Hi,

    Thanks a lot for your suggestions. I tried same way using i2c example given here: https://github.com/Martinsbl/nrf5-mpu-examples/blob/master/nrf_drv_mpu_twi.c

    err_code = nrf_drv_twi_tx(&m_twi_instance, LIS3DH_I2C_ADDRESS, &reg, num_regs, false);

    in lis3dh_read_regs() & lis3dh_write_regs()

    but can't understand these:

    transfers[0].p_data = &reg;
    transfers[0].length = 1;
    transfers[0].operation = APP_TWI_WRITE_OP(LIS3DH_I2C_ADDRESS);
    transfers[0].flags = APP_TWI_NO_STOP;

    transfers[1].p_data = contents;
    transfers[1].length = num_regs;
    transfers[1].operation = APP_TWI_READ_OP(LIS3DH_I2C_ADDRESS);
    transfers[1].flags = 0;

    return app_twi_perform(ACC_TWI_INSTANCE, transfers, ARRAY_SIZE(transfers), twi_idle_func);

    What it is returning? Please explain? 

    If I call function like lis3dh_read_regs(OUT_X_L, &reg_val, 1) then it should give X value in reg_val ?

  • It looks like it was written for one of the older SDKs. SDK13 has a function called app_twi_perform, found in app_twi.c and app_twi.h. It returns an uint32_t (ret_code_t)

     

    Best regards,

    Edvin

  • Hi

    Now, I am getting response from LIS3DH module with x,y,z values using nRF52 DK. But, using same driver I am not getting response from target board:

    MDBT42V which has nRF52832

    LIS3DH + MAX30205 IC

    (Given external pull-ups of 4.7k ohm as well as tried with 10k ohm to i2c bus)

    i2c SCL-9, SDA-10 defined same in code & target board

    Please suggest how to debug this issue

  • which one is the "target board"? The MAX30205?

    Do you use the correct TWI/I2C address for the MAX30205?

     

    BR,

    Edvin

  • Target board is MDBT42V module (http://www.raytac.com/product_detail.php?id=73) is based on nrf52832 which has LIS3DH & MAX30205 IC .

    I2C address for both ICs are correct. 

Reply Children
Related