ADXL362 accelerometer library

Dependents:   ADXL362-helloworld EVAL_ADXL362_ARDZ Lab6 Lab6 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ADXL362.cpp Source File

ADXL362.cpp

Go to the documentation of this file.
00001 /**
00002 *   @file     ADXL362.cpp
00003 *   @brief    Source file for ADXL362
00004 *   @author   Analog Devices Inc.
00005 *
00006 * For support please go to:
00007 * Github: https://github.com/analogdevicesinc/mbed-adi
00008 * Support: https://ez.analog.com/community/linux-device-drivers/microcontroller-no-os-drivers
00009 * Product: http://www.analog.com/adxl362
00010 * More: https://wiki.analog.com/resources/tools-software/mbed-drivers-all
00011 
00012 ********************************************************************************
00013 * Copyright 2016(c) Analog Devices, Inc.
00014 *
00015 * All rights reserved.
00016 *
00017 * Redistribution and use in source and binary forms, with or without
00018 * modification, are permitted provided that the following conditions are met:
00019 *  - Redistributions of source code must retain the above copyright
00020 *    notice, this list of conditions and the following disclaimer.
00021 *  - Redistributions in binary form must reproduce the above copyright
00022 *    notice, this list of conditions and the following disclaimer in
00023 *    the documentation and/or other materials provided with the
00024 *    distribution.
00025 *  - Neither the name of Analog Devices, Inc. nor the names of its
00026 *    contributors may be used to endorse or promote products derived
00027 *    from this software without specific prior written permission.
00028 *  - The use of this software may or may not infringe the patent rights
00029 *    of one or more patent holders.  This license does not release you
00030 *    from the requirement that you obtain separate licenses from these
00031 *    patent holders to use this software.
00032 *  - Use of the software either in source or binary form, must be run
00033 *    on or directly connected to an Analog Devices Inc. component.
00034 *
00035 * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
00036 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
00037 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00038 * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
00039 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00040 * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
00041 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00042 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00043 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00044 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045 *
00046 ********************************************************************************/
00047 
00048 #include <stdint.h>
00049 #include "mbed.h"
00050 #include "ADXL362.h"
00051 
00052 /**
00053  * ADXL362 constructor. Sets CS and SPI bus
00054  * @param CS - CS pin of the ADXL362
00055  * @param MOSI - MOSI pin of the ADXL362
00056  * @param MISO - MISO pin of the ADXL362
00057  * @param SCK- SCK pin of the ADXL362
00058  */
00059 ADXL362::ADXL362(PinName CS, PinName MOSI, PinName MISO, PinName SCK) :
00060     adxl362(MOSI, MISO, SCK), cs(CS), _int1(NULL), _int2(NULL), _int1_poll(NC), _int2_poll(
00061         NC)
00062 {
00063     cs = true; // cs is active low
00064     adxl362.format(8, _SPI_MODE);
00065     _temp_stored_in_fifo = false;
00066     _int1_act_low = true;
00067     _int2_act_low = true;
00068 }
00069 
00070 /**
00071  * Sets ADXL362 SPI bus frequency
00072  * @param hz - frequency in hz
00073  */
00074 void ADXL362::frequency(int hz)
00075 {
00076     adxl362.frequency(hz);
00077 }
00078 
00079 /**
00080  * Resets the ADXL362
00081  * A latency of approximately 0.5 ms is required after soft reset.
00082  */
00083 void ADXL362::reset()
00084 {
00085     adxl362.format(8, _SPI_MODE);
00086     cs = false;
00087     // Writing Code 0x52 (representing the letter, R, in ASCII or unicode) to this register immediately resets the ADXL362.
00088     write_reg(SOFT_RESET, 0x52);
00089     cs = true;
00090 
00091 }
00092 
00093 /**
00094  * Writes the reg register with data
00095  * @param reg - ADXL362_register_t register to be written
00096  * @param data - data to be written
00097  */
00098 void ADXL362::write_reg(ADXL362_register_t reg, uint8_t data)
00099 {
00100     adxl362.format(8, _SPI_MODE);
00101     cs = false;
00102     adxl362.write(_WRITE_REG_CMD);
00103     adxl362.write(static_cast<uint8_t>(reg));
00104     adxl362.write(static_cast<uint8_t>(data));
00105     cs = true;
00106 }
00107 
00108 /**
00109  * Reads the reg register
00110  * @param reg -  ADXL362_register_t register to be read
00111  * @return - data read from the register
00112  */
00113 uint8_t ADXL362::read_reg(ADXL362_register_t reg)
00114 {
00115     uint8_t ret_val;
00116     adxl362.format(8, _SPI_MODE);
00117     cs = false;
00118     adxl362.write(_READ_REG_CMD);
00119     adxl362.write(static_cast<uint8_t>(reg));
00120     ret_val = adxl362.write(_DUMMY_BYTE);
00121     cs = true;
00122     return ret_val;
00123 }
00124 
00125 /**
00126  * Writes 16 bit registers to the ADXL362. Performs conversion from Intel to Motorola byte order
00127  * @param reg -  ADXL362_register_t register to be written
00128  * @param data -  data to be written
00129  */
00130 void ADXL362::write_reg_u16(ADXL362_register_t reg, uint16_t data)
00131 {
00132     adxl362.format(8, _SPI_MODE);
00133 
00134     cs = false;
00135     adxl362.write(_WRITE_REG_CMD);
00136     adxl362.write(static_cast<uint8_t>(reg));
00137     adxl362.write(static_cast<uint8_t>(data & 0xff));
00138     adxl362.write(static_cast<uint8_t>((data & 0xff00) >> 8));
00139 
00140     cs = true;
00141 }
00142 
00143 /**
00144  * Reads 16 bit registers from the ADXL362. Performs conversion from Motorola to Intel Byte order
00145  * @param reg - ADXL362_register_t register to be read
00146  * @return - data read from the ADXL362
00147  */
00148 uint16_t ADXL362::read_reg_u16(ADXL362_register_t reg)
00149 {
00150     uint16_t ret_val = 0;
00151     adxl362.format(8, _SPI_MODE);
00152 
00153     cs = false;
00154     adxl362.write(_READ_REG_CMD);
00155     adxl362.write(static_cast<uint8_t>(reg));
00156     ret_val = adxl362.write(_DUMMY_BYTE);
00157     ret_val = ret_val | (adxl362.write(_DUMMY_BYTE) << 8);
00158     cs = true;
00159 
00160     return ret_val;
00161 }
00162 
00163 /**
00164  * Scans the X,Y,Z,T registers for data.
00165  * ADXL362 needs to be in measurement mode to read data
00166  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00167  * @return a 64 bit integer with the following format 0xXXYYZZTT
00168  */
00169 uint64_t ADXL362::scan()
00170 {
00171     uint64_t ret_val = 0;
00172     uint16_t x, y, z, t = 0;
00173 
00174     adxl362.format(8, _SPI_MODE);
00175     cs = false;
00176     adxl362.write(_READ_REG_CMD);
00177     adxl362.write(static_cast<uint8_t>(XDATA_L));
00178 
00179     x = adxl362.write(_DUMMY_BYTE);
00180     x = x | static_cast<uint16_t>(adxl362.write(_DUMMY_BYTE) << 8);
00181     y = adxl362.write(_DUMMY_BYTE);
00182     y = y | static_cast<uint16_t>(adxl362.write(_DUMMY_BYTE) << 8);
00183     z = adxl362.write(_DUMMY_BYTE);
00184     z = z | static_cast<uint16_t>(adxl362.write(_DUMMY_BYTE) << 8);
00185     t = adxl362.write(_DUMMY_BYTE);
00186     t = t | static_cast<uint16_t>(adxl362.write(_DUMMY_BYTE) << 8);
00187 
00188     ret_val = static_cast<uint64_t>(x) << 48;
00189     ret_val |= static_cast<uint64_t>(y) << 32;
00190     ret_val |= static_cast<uint64_t>(z) << 16;
00191     ret_val |= static_cast<uint64_t>(t);
00192     cs = true;
00193     return ret_val;
00194 }
00195 
00196 /**
00197  * Reads the X 8 bit register from the ADXL362
00198  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00199  * @return 8 bit X data
00200  */
00201 uint8_t ADXL362::scanx_u8()
00202 {
00203     return read_reg(XDATA);
00204 }
00205 
00206 /**
00207  * Reads the X 16 bit register from the ADXL362
00208  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00209  * @return 16 bit X data
00210  */
00211 uint16_t ADXL362::scanx()
00212 {
00213     return read_reg_u16(XDATA_L);
00214 }
00215 
00216 /**
00217  * Reads the Y 8 bit register from the ADXL362
00218  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00219  * @return 8 bit Y data
00220  */
00221 uint8_t ADXL362::scany_u8()
00222 {
00223     return read_reg(YDATA);
00224 }
00225 
00226 /**
00227  * Reads the Y 16 bit register from the ADXL362
00228  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00229  * @return 16 bit Y data
00230  */
00231 uint16_t ADXL362::scany()
00232 {
00233     return read_reg_u16(YDATA_L);
00234 }
00235 
00236 /**
00237  * Reads the Z 8 bit register from the ADXL362
00238  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00239  * @return 8 bit Z data
00240  */
00241 uint8_t ADXL362::scanz_u8()
00242 {
00243     return read_reg(ZDATA);
00244 }
00245 
00246 /**
00247  * Reads the Z 16 bit register from the ADXL362
00248  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00249  * @return 16 bit Z data
00250  */
00251 uint16_t ADXL362::scanz()
00252 {
00253     return read_reg_u16(ZDATA_L);
00254 }
00255 
00256 /**
00257  * Reads the T 16 bit register from the ADXL362
00258  * ADXL362 is set in measurement mode using ADXL362::set_mode(ADXL362::MEASUREMENT)
00259  * @return 16 bit T data
00260  */
00261 uint16_t ADXL362::scant()
00262 {
00263     return read_reg_u16(TEMP_L);
00264 }
00265 
00266 /**
00267  * Sets the STANDBY/MEASUREMENT mode of the ADXL362
00268  * @param mode - ADXL362_modes_t STANDBY/MEASUREMENT mode
00269  */
00270 void ADXL362::set_mode(ADXL362_modes_t mode)
00271 {
00272     uint8_t reg_val;
00273     reg_val = read_reg(POWER_CTL);
00274     reg_val = reg_val | static_cast<uint8_t>(mode);
00275     write_reg(POWER_CTL, reg_val);
00276 }
00277 
00278 /**
00279  * Sets the activity threshold registers
00280  * To enable activity/inactivity, the ACT_INACT_CTL reg must also be set
00281  * using the ADXL362::set_act_inact_ctl_reg(uint8_t data) method
00282  * @param threshold - activity threshold in natural format
00283  */
00284 void ADXL362::set_activity_threshold(uint16_t threshold)
00285 {
00286     write_reg_u16(THRESH_ACT_L, threshold);
00287 }
00288 
00289 /**
00290  * Sets the activity time register
00291  * To enable activity/inactivity, the ACT_INACT_CTL reg must also be set
00292  * using the ADXL362::set_act_inact_ctl_reg(uint8_t data) method
00293  * @param time - activity time
00294  */
00295 void ADXL362::set_activity_time(uint8_t time)
00296 {
00297     write_reg(TIME_ACT, time);
00298 }
00299 
00300 /**
00301  * Sets the inactivity threshold register
00302  * To enable activity/inactivity, the ACT_INACT_CTL reg must also be set
00303  * using the ADXL362::set_act_inact_ctl_reg(uint8_t data) method
00304  * @param threshold - inactivity threshold in natural format
00305  */
00306 void ADXL362::set_inactivity_threshold(uint16_t threshold)
00307 {
00308     write_reg_u16(THRESH_INACT_L, threshold);
00309 }
00310 
00311 /**
00312  * Sets the inactivity time register
00313  * To enable activity/inactivity, the ACT_INACT_CTL reg must also be set
00314  * using the ADXL362::set_act_inact_ctl_reg(uint8_t data) method
00315  * @param time - inactivity time in natural format
00316  */
00317 void ADXL362::set_inactivity_time(uint16_t time)
00318 {
00319     write_reg_u16(TIME_INACT_L, time);
00320 }
00321 
00322 /**
00323  * Sets the ACT_INACT_CTL register of the ADXL362
00324  * @param data - data to be written to the register
00325  */
00326 void ADXL362::set_act_inact_ctl_reg(uint8_t data)
00327 {
00328     write_reg(ACT_INACT_CTL, data);
00329 }
00330 
00331 /**
00332  * Configures INT1 output of the ADXL362 for polling use
00333  * @param in - uC pin connected to ADXL362's INT1
00334  * @param data - data to be written to INTMAP1
00335  * @param pull - (optional) configures pullup on In pin
00336  */
00337 void ADXL362::set_polling_interrupt1_pin(PinName in, uint8_t data,
00338         PinMode pull)
00339 {
00340     if ((data & 0x7F) != 0) {
00341         write_reg(INTMAP1, data);
00342         _int1_poll = DigitalIn(in);
00343         _int1_poll.mode(pull);
00344         if (data & 0x80) {
00345             _int1_act_low = true;
00346         } else {
00347             _int1_act_low = false;
00348         }
00349     }
00350 }
00351 
00352 /**
00353  * Configures INT2 output of the ADXL362 for polling use
00354  * @param in - uC pin connected to ADXL362's INT2
00355  * @param data - data to be written to INTMAP2
00356  * @param pull - (optional) configures pullup on In pin
00357  */
00358 void ADXL362::set_polling_interrupt2_pin(PinName in, uint8_t data,
00359         PinMode pull)
00360 {
00361     if ((data & 0x7F) != 0) {
00362         write_reg(INTMAP2, data);
00363         _int2_poll = DigitalIn(in);
00364         _int2_poll.mode(pull);
00365         if (data & 0x80) {
00366             _int2_act_low = true;
00367         } else {
00368             _int2_act_low = false;
00369         }
00370     }
00371 }
00372 
00373 /**
00374  * Gets the active state of the INT1 pin
00375  * @return true if active, false if not active
00376  */
00377 bool ADXL362::get_int1()
00378 {
00379     if(_int1_poll != NC) return (_int1_poll.read() != _int1_act_low);  // boolean XOR
00380     else return (_int1->read() != _int1_act_low);
00381 }
00382 
00383 /**
00384  * Gets the active state of the INT2 pin
00385  * @return true if active, false if not active
00386  */
00387 bool ADXL362::get_int2()
00388 {
00389     if(_int2_poll != NC) return (_int1_poll.read() != _int1_act_low); // boolean XOR
00390     else return (_int2->read() != _int2_act_low);
00391 }
00392 
00393 
00394 /**
00395  * Configures the INT1 pin of the ADXL362 to be used in interrupt mode
00396  * @param in - uC pin connected to ADXL362's INT1
00397  * @param data -  data to be written to INTMAP1
00398  * @param callback_rising - rising edge interrupt callback - can be set to NULL if no callback is required for rising edge
00399  * @param callback_falling - falling edge interrupt callback - can be set to NULL if no callback is required for falling edge
00400  * @param pull - (optional) configures pullup on In pin
00401  */
00402 void ADXL362::set_interrupt1_pin(PinName in, uint8_t data,
00403                                  void (*callback_rising)(void), void (*callback_falling)(void), PinMode pull)
00404 {
00405     if ((data & 0x7F) != 0) {
00406         write_reg(INTMAP1, data);
00407         delete _int1;
00408         _int1 = new InterruptIn(in);
00409         _int1->mode(pull);
00410         if(callback_falling != NULL) _int1->fall(callback_falling);
00411         if(callback_rising != NULL) _int1->rise(callback_rising);
00412         if (data & 0x80) {
00413             _int1_act_low = true;
00414         } else {
00415             _int1_act_low = false;
00416         }
00417     }
00418 }
00419 
00420 
00421 /**
00422  * Configures the INT2 pin of the ADXL362 to be used in interrupt mode
00423  * @param in - uC pin connected to ADXL362's INT2
00424  * @param data -  data to be written to INTMAP2
00425  * @param callback_rising - rising edge interrupt callback - can be set to NULL if no callback is required for rising edge
00426  * @param callback_falling - falling edge interrupt callback - can be set to NULL if no callback is required for falling edge
00427  * @param pull - (optional) configures pullup on In pin
00428  */
00429 void ADXL362::set_interrupt2_pin(PinName in, uint8_t data,
00430                                  void (*callback_rising)(void), void (*callback_falling)(void), PinMode pull)
00431 {
00432     if ((data & 0x7F) != 0) {
00433         write_reg(INTMAP2, data);
00434         delete _int2;
00435         _int2 = new InterruptIn(in);
00436         _int2->mode(pull);
00437         if(callback_falling != NULL) _int2->fall(callback_falling);
00438         if(callback_rising != NULL) _int2->rise(callback_rising);
00439         if (data & 0x80) {
00440             _int2_act_low = true;
00441         } else {
00442             _int2_act_low = false;
00443         }
00444     }
00445 }
00446 
00447 /**
00448  * Enables external interrupt registration for pin configured as INT1
00449  * To enable this interrupt, it must first be configured using ADXL362::set_interrupt1_pin()
00450  */
00451 void ADXL362::enable_interrupt1()
00452 {
00453     _int1->enable_irq();
00454 }
00455 
00456 /**
00457  * Enables external interrupt registration  for pin configured as INT2
00458  * * To enable this interrupt, it must first be configured using ADXL362::set_interrupt2_pin()
00459  */
00460 void ADXL362::enable_interrupt2()
00461 {
00462     _int2->enable_irq();
00463 }
00464 
00465 /**
00466  * Disables external interrupt registration  for pin configured as INT1
00467  */
00468 void ADXL362::disable_interrupt1()
00469 {
00470     _int1->disable_irq();
00471 }
00472 
00473 /**
00474  * Disables external interrupt registration  for pin configured as INT2
00475  */
00476 void ADXL362::disable_interrupt2()
00477 {
00478     _int2->disable_irq();
00479 }
00480 
00481 /**
00482  * Sets the POWER_CTL register
00483  * @param data - data to be written to the register
00484  */
00485 void ADXL362::set_power_ctl_reg(uint8_t data)
00486 {
00487     write_reg(POWER_CTL, data);
00488 }
00489 
00490 /**
00491  * Sets the FILTER_CTL register
00492  * @param data - data to be written to the register
00493  */
00494 void ADXL362::set_filter_ctl_reg(uint8_t data)
00495 {
00496     write_reg(FILTER_CTL, data);
00497 }
00498 
00499 /**
00500  * Reads the STATUS register of the ADXL362
00501  * @return - data in the status register
00502  */
00503 uint8_t ADXL362::read_status()
00504 {
00505     return read_reg(STATUS);
00506 }
00507 
00508 /**
00509  * Reads the FIFO_ENTRIES_L and FIFO_ENTRIES_H register
00510  * @return the number of entries in the FIFO
00511  */
00512 uint16_t ADXL362::fifo_read_nr_of_entries()
00513 {
00514     return read_reg_u16(FIFO_ENTRIES_L);
00515 }
00516 
00517 /**
00518  * Setup for the FIFO
00519  * @param store_temp - boolean, true - temperature will be stored in the fifo. false otherwise
00520  * @param mode - ADXL362_FIFO_modes_t fifo mode
00521  * @param nr_of_entries - number of entries in the FIFO
00522  */
00523 void ADXL362::fifo_setup(bool store_temp, ADXL362_FIFO_modes_t mode, uint16_t nr_of_entries)
00524 {
00525     uint8_t fifo_ctl = static_cast<uint8_t>(mode);
00526     _temp_stored_in_fifo = store_temp;
00527 
00528     fifo_ctl = fifo_ctl | (static_cast<uint8_t>(_temp_stored_in_fifo) << 2);
00529 
00530     if (nr_of_entries > 0xff) {
00531         fifo_ctl = fifo_ctl | static_cast<uint8_t>(AH);
00532     }
00533     write_reg(FIFO_CONTROL, fifo_ctl);
00534     write_reg(FIFO_SAMPLES, static_cast<uint8_t>(nr_of_entries & 0xff));
00535 
00536 }
00537 
00538 /**
00539  * Reads a FIFO entry
00540  * @return FIFO entry
00541  */
00542 uint16_t ADXL362::fifo_read_u16()
00543 {
00544     uint16_t ret_val = 0;
00545     adxl362.format(8, _SPI_MODE);
00546 
00547     cs = false;
00548     adxl362.write(_READ_FIFO_CMD);
00549     ret_val = adxl362.write(_DUMMY_BYTE);
00550     ret_val = (ret_val) | static_cast<uint16_t>(adxl362.write(_DUMMY_BYTE) << 8);
00551     cs = true;
00552 
00553     return ret_val;
00554 }
00555 
00556 /**
00557  * Reads 3(4) bytes from the FIFO(if store_temp was set), assembles the data in the format used by the scan method
00558  * ADXL362::fifo_setup() needs to be called before calling fifo_scan to ensure correct fifo operation
00559  * fifo_scan and fifo_read_u16 should not be used as fifo_read_u16 disaligns the fifo therefore
00560  * fifo_scan will return data from multiple samples
00561  * @return scanned data from the fifo in the 0xXXYYZZTT format
00562  */
00563 uint64_t ADXL362::fifo_scan()
00564 {
00565 
00566     uint64_t ret_val = 0;
00567     uint16_t x = 0, y = 0, z = 0, dummy, t = 0, sample_type;
00568 
00569     adxl362.format(8, _SPI_MODE);
00570     cs = false;
00571     adxl362.write(_READ_FIFO_CMD);
00572     uint8_t samples = (_temp_stored_in_fifo) ? 4 : 3;
00573     for(uint8_t i = 0; i < samples; i++) {
00574         dummy = adxl362.write(_DUMMY_BYTE);
00575         dummy = dummy | static_cast<uint16_t>(adxl362.write(_DUMMY_BYTE) << 8);
00576         sample_type = (dummy & 0xc000) >> 14;
00577         dummy = dummy & 0x3fff;
00578         switch(sample_type) {
00579             case 0: // x
00580                 x = dummy;
00581                 break;
00582             case 1: // y
00583                 y = dummy;
00584                 break;
00585             case 2: // z
00586                 z = dummy;
00587                 break;
00588             case 3: // temp
00589                 t = dummy;
00590                 break;
00591         }
00592 
00593     }
00594 
00595     // format xxyyzztt
00596     ret_val = static_cast<uint64_t> (x) << 48;
00597     ret_val |= static_cast<uint64_t>(y) << 32;
00598     ret_val |= static_cast<uint64_t>(z) << 16;
00599     ret_val |= static_cast<uint64_t>(t);
00600     cs = true;
00601     return ret_val;
00602 }