/ Adafruit_LIS331.cpp
Adafruit_LIS331.cpp
  1  /*!
  2   * @file Adafruit_LIS331.cpp
  3   */
  4  
  5  #include "Arduino.h"
  6  
  7  #include <Adafruit_LIS331.h>
  8  #include <Wire.h>
  9  
 10  /*!
 11   *  @brief  Instantiates a new LIS331 class in I2C
 12   *  @param  TheWire
 13   *          optional wire object
 14   */
 15  Adafruit_LIS331::Adafruit_LIS331(TwoWire *TheWire) {}
 16  
 17  /*!
 18   *   @brief  Instantiates a new LIS331 class using hardware SPI
 19   *   @param  cspin
 20   *           number of CSPIN (Chip Select)
 21   *   @param  *theSPI
 22   *           optional parameter contains spi object
 23   */
 24  Adafruit_LIS331::Adafruit_LIS331(int8_t cspin, SPIClass *theSPI) {}
 25  
 26  /*!
 27   *   @brief  Instantiates a new LIS331 class using software SPI
 28   *   @param  cspin
 29   *           number of CSPIN (Chip Select)
 30   *   @param  mosipin
 31   *           number of pin used for MOSI (Master Out Slave In))
 32   *   @param  misopin
 33   *           number of pin used for MISO (Master In Slave Out)
 34   *   @param  sckpin
 35   *           number of pin used for CLK (clock pin)
 36   */
 37  Adafruit_LIS331::Adafruit_LIS331(int8_t cspin, int8_t mosipin, int8_t misopin,
 38                                   int8_t sckpin) {}
 39  
 40  /*!
 41   *  @brief  Get Device ID from LIS331_REG_WHOAMI
 42   *  @return WHO AM I value
 43   */
 44  uint8_t Adafruit_LIS331::getDeviceID(void) {
 45    Adafruit_BusIO_Register _chip_id = Adafruit_BusIO_Register(
 46        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_WHOAMI, 1);
 47  
 48    return _chip_id.read();
 49  }
 50  
 51  /*!
 52   *  @brief  Reads x y z values at once
 53   */
 54  void Adafruit_LIS331::read(void) {
 55  
 56    uint8_t register_address = LIS331_REG_OUT_X_L;
 57    if (i2c_dev) {
 58      register_address |= 0x80; // set [7] for auto-increment
 59    } else {
 60      register_address |= 0x40; // set [6] for auto-increment
 61      register_address |= 0x80; // set [7] for read
 62    }
 63  
 64    Adafruit_BusIO_Register xl_data = Adafruit_BusIO_Register(
 65        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, register_address, 6);
 66  
 67    uint8_t buffer[6];
 68    xl_data.read(buffer, 6);
 69  
 70    x = buffer[0];
 71    x |= ((uint16_t)buffer[1]) << 8;
 72    y = buffer[2];
 73    y |= ((uint16_t)buffer[3]) << 8;
 74    z = buffer[4];
 75    z |= ((uint16_t)buffer[5]) << 8;
 76  
 77    _scaleValues();
 78  }
 79  
 80  /**
 81   * @brief Setup  the INT1 or INT2 pin to trigger when new data is ready
 82   *
 83   * @param irqnum The interrupt number/pin to configure
 84   * @param activelow The polarity of the pin. true: active low false: active high
 85   * @param opendrain The pinmode for the given interrupt pin. true: open drain.
 86   * Connects to GND when activated false: push-pull: connects to VCC when
 87   * activated
 88   * @return true
 89   * @return false
 90   */
 91  bool Adafruit_LIS331::configIntDataReady(uint8_t irqnum, bool activelow,
 92                                           bool opendrain) {
 93    Adafruit_BusIO_Register ctrl3_reg = Adafruit_BusIO_Register(
 94        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL3, 1);
 95  
 96    Adafruit_BusIO_RegisterBits opendrain_and_polarity_bits =
 97        Adafruit_BusIO_RegisterBits(&ctrl3_reg, 2, 6);
 98    Adafruit_BusIO_RegisterBits int1_bits =
 99        Adafruit_BusIO_RegisterBits(&ctrl3_reg, 2, 0);
100    Adafruit_BusIO_RegisterBits int2_bits =
101        Adafruit_BusIO_RegisterBits(&ctrl3_reg, 2, 3);
102    opendrain_and_polarity_bits.write((activelow << 1) | (opendrain));
103  
104    if (irqnum == 1) {
105      int1_bits.write(0b10);
106      int2_bits.write(0);
107    } else {
108      int2_bits.write(0b10);
109      int1_bits.write(0);
110    }
111  }
112  
113  /**************************************************************************/
114  /*!
115      @brief Enables the high pass filter and/or slope filter
116      @param filter_enabled Whether to enable the slope filter (see datasheet)
117      @param cutoff The frequency below which signals will be filtered out
118      @param use_reference Selects if the reference value set by `setReference`
119     should be used
120  
121      See section **4** of the LIS331DLH application note for more information
122  
123      https://www.st.com/content/ccc/resource/technical/document/application_note/b5/8e/58/69/cb/87/45/55/CD00215823.pdf/files/CD00215823.pdf/jcr:content/translations/en.CD00215823.pdf
124  */
125  void Adafruit_LIS331::enableHighPassFilter(bool filter_enabled,
126                                             lis331_hpf_cutoff_t cutoff,
127                                             bool use_reference) {
128    Adafruit_BusIO_Register ctrl2_reg = Adafruit_BusIO_Register(
129        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL2);
130  
131    Adafruit_BusIO_RegisterBits HPF_mode =
132        Adafruit_BusIO_RegisterBits(&ctrl2_reg, 1, 5);
133  
134    Adafruit_BusIO_RegisterBits HPF_internal_filter_en =
135        Adafruit_BusIO_RegisterBits(&ctrl2_reg, 1, 4);
136  
137    Adafruit_BusIO_RegisterBits HPF_cuttoff =
138        Adafruit_BusIO_RegisterBits(&ctrl2_reg, 2, 0);
139  
140    if (filter_enabled) {
141      HPF_mode.write(use_reference);
142      HPF_cuttoff.write(cutoff);
143    }
144    HPF_internal_filter_en.write(filter_enabled);
145  }
146  
147  /**
148   * @brief Set the reference value to offset measurements when using the
149   High-pass filter.
150   *
151   * @param reference The offset amount. The conversion of `reference` to milli-g
152   depends on the selected range:
153   *
154   *  * Full scale Reference mode LSB value (mg)
155      6g/100g                     ~16mg
156      12g/200g                    ~31mg
157      24g/400g                    ~63mg
158   */
159  void Adafruit_LIS331::setHPFReference(int8_t reference) {
160    Adafruit_BusIO_Register reference_reg = Adafruit_BusIO_Register(
161        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_REFERENCE);
162    reference_reg.write(reference);
163  }
164  /**
165   * @brief Gets the current high-pass filter reference/offset
166   * @return int8_t The current reference value.
167   * See `enableHighPassFilter` and `setHPFReference` for more information.
168   */
169  int8_t Adafruit_LIS331::getHPFReference(void) {
170    Adafruit_BusIO_Register reference_reg = Adafruit_BusIO_Register(
171        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_REFERENCE);
172    return reference_reg.read();
173  }
174  
175  /**
176   * @brief Zero the measurement offsets while the high-pass filter is enabled
177   when not using a reference.
178   *
179   * See `enableHighPassFilter` and `setHPFReference` for more information.
180   */
181  void Adafruit_LIS331::HPFReset(void) {
182    Adafruit_BusIO_Register reference_reset_reg = Adafruit_BusIO_Register(
183        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_HP_FILTER_RESET);
184    reference_reset_reg.read();
185  }
186  
187  /**
188   * @brief Scale the acceleration measuremets from their raw value to milli-g
189   * depending on the current measurement range
190   *
191   */
192  void Adafruit_LIS331::_scaleValues(void) {}
193  
194  /**
195   * @brief Set the measurement range for the sensor
196   *
197   * @param range The measurement range to set
198   */
199  void Adafruit_LIS331::writeRange(uint8_t range) {
200  
201    Adafruit_BusIO_Register _ctrl4 = Adafruit_BusIO_Register(
202        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL4, 1);
203  
204    Adafruit_BusIO_RegisterBits range_bits =
205        Adafruit_BusIO_RegisterBits(&_ctrl4, 2, 4);
206    range_bits.write(range);
207    delay(15); // delay to let new setting settle
208  }
209  
210  /**
211   * @brief Get the measurement range
212   *
213   * @return uint8_t The measurement range
214   */
215  uint8_t Adafruit_LIS331::readRange(void) {
216    Adafruit_BusIO_Register _ctrl4 = Adafruit_BusIO_Register(
217        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL4, 1);
218  
219    Adafruit_BusIO_RegisterBits range_bits =
220        Adafruit_BusIO_RegisterBits(&_ctrl4, 2, 4);
221  
222    return (uint8_t)range_bits.read();
223  }
224  
225  /******** Power mode, data rate, and Low-pass filter methods ***********/
226  /*!
227   *  @brief  Sets the data rate for the LIS331 (affects power consumption)
228   *  @param  data_rate The new data rate to set.
229   */
230  void Adafruit_LIS331::setDataRate(lis331_data_rate_t data_rate) {
231    int8_t dr_value = 0;
232    int8_t pm_value = 0;
233  
234    lis331_mode_t new_mode = getMode(data_rate);
235    Adafruit_BusIO_Register _ctrl1 = Adafruit_BusIO_Register(
236        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL1, 1);
237    Adafruit_BusIO_RegisterBits pm_bits =
238        Adafruit_BusIO_RegisterBits(&_ctrl1, 3, 5);
239  
240    switch (new_mode) {
241    case LIS331_MODE_SHUTDOWN:
242      break;
243  
244    case LIS331_MODE_LOW_POWER: // ODR bits are in CTRL1[7:5] (PM)
245      pm_value = ((data_rate & 0x1C)) >> 2;
246      break;
247  
248    case LIS331_MODE_NORMAL: // ODR bits are in CTRL1[4:3] (DR)
249      pm_value = ((data_rate & 0x1C)) >> 2;
250      dr_value = (data_rate & 0x7);
251  
252      // only Normal mode uses DR to set ODR, so we can set it here
253      Adafruit_BusIO_RegisterBits dr_bits =
254          Adafruit_BusIO_RegisterBits(&_ctrl1, 2, 3);
255      dr_bits.write(dr_value);
256      break;
257    }
258  
259    pm_bits.write(pm_value);
260  }
261  
262  /*!
263   *   @brief  Gets the data rate for the LIS331 (affects power consumption)
264   *   @return Returns Data Rate value
265   */
266  lis331_data_rate_t Adafruit_LIS331::getDataRate(void) {
267    Adafruit_BusIO_Register _ctrl1 = Adafruit_BusIO_Register(
268        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL1, 1);
269    Adafruit_BusIO_RegisterBits pm_dr_bits =
270        Adafruit_BusIO_RegisterBits(&_ctrl1, 5, 3);
271    return (lis331_data_rate_t)pm_dr_bits.read();
272  }
273  
274  /**
275   * @brief  Return the current power mode from the current data rate
276   * @return lis331_mode_t The currently set power mode
277   */
278  lis331_mode_t Adafruit_LIS331::getMode(void) {
279    lis331_data_rate_t current_rate = getDataRate();
280    return getMode(current_rate);
281  }
282  
283  /**
284   * @brief Return the current power mode from a given data rate value
285   *
286   * @param data_rate The `lis331_data_rate_t` to return the `lis331_mode_t` for
287   * @return lis331_mode_t
288   */
289  lis331_mode_t Adafruit_LIS331::getMode(lis331_data_rate_t data_rate) {
290    uint8_t pm_value = (data_rate & 0x1C) >> 2;
291    if (pm_value >= LIS331_MODE_LOW_POWER) {
292      return LIS331_MODE_LOW_POWER;
293    }
294    return (lis331_mode_t)pm_value;
295  }
296  /**
297   * @brief Set the Low Pass Filter cutoff frequency. Useful for removing high
298   * frequency noise while sensing orientation using the acceleration from
299   * gravity.
300   *
301   * **Will not work** when sensor is **in Normal mode** because the LPF cutoff
302   * bits are used to set the ODR while in Normal mode.
303   *
304   * @param cutoff The frequency above which signals will be ignored.
305   * @returns true: success false: cuttoff frequency was not set because the
306   */
307  bool Adafruit_LIS331::setLPFCutoff(lis331_lpf_cutoff_t cutoff) {
308  
309    lis331_mode_t current_mode = getMode();
310    if (current_mode == LIS331_MODE_NORMAL) {
311      return false;
312    }
313    Adafruit_BusIO_Register _ctrl1 = Adafruit_BusIO_Register(
314        i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LIS331_REG_CTRL1, 1);
315    Adafruit_BusIO_RegisterBits data_rate_bits =
316        Adafruit_BusIO_RegisterBits(&_ctrl1, 2, 3); // including LPen bit
317  
318    data_rate_bits.write(cutoff);
319    return true;
320  }
321  
322  /************************************************************************/
323  /*!
324   *  @brief  Gets the most recent sensor event
325   *  @param  *event
326   *          sensor event that we want to read
327   *  @return true if successful
328   */
329  bool Adafruit_LIS331::getEvent(sensors_event_t *event) {
330    /* Clear the event */
331    memset(event, 0, sizeof(sensors_event_t));
332  
333    event->version = sizeof(sensors_event_t);
334    event->sensor_id = _sensorID;
335    event->type = SENSOR_TYPE_ACCELEROMETER;
336    event->timestamp = 0;
337  
338    read();
339  
340    event->acceleration.x = x_g * SENSORS_GRAVITY_STANDARD;
341    event->acceleration.y = y_g * SENSORS_GRAVITY_STANDARD;
342    event->acceleration.z = z_g * SENSORS_GRAVITY_STANDARD;
343  
344    return true;
345  }
346  
347  /*!
348   *   @brief  Gets the sensor_t data
349   *   @param  *sensor
350   *           sensor that we want to write data into
351   */
352  void Adafruit_LIS331::getSensor(sensor_t *sensor) {
353    /* Clear the sensor_t object */
354    memset(sensor, 0, sizeof(sensor_t));
355  
356    /* Insert the sensor name in the fixed length char array */
357    strncpy(sensor->name, "LIS331", sizeof(sensor->name) - 1);
358    sensor->name[sizeof(sensor->name) - 1] = 0;
359    sensor->version = 1;
360    sensor->sensor_id = _sensorID;
361    sensor->type = SENSOR_TYPE_ACCELEROMETER;
362    sensor->min_delay = 0;
363    sensor->max_value = 0;
364    sensor->min_value = 0;
365    sensor->resolution = 0;
366  }