Kionix KX123 accelerometer C++ driver. Can be used for some extend also with kx022, kx023, kx122, etc. when used features are present in sensor.
Fork of kionix-kx123-driver by
Diff: kx123.cpp
- Revision:
- 2:62891556d47b
- Parent:
- 1:f328083fb80b
- Child:
- 3:4fd5361ed180
--- a/kx123.cpp Fri Sep 30 11:52:29 2016 +0000 +++ b/kx123.cpp Thu Oct 06 10:23:48 2016 +0000 @@ -28,12 +28,31 @@ KX123::KX123(RegisterWriter &i2c_obj, uint8_t sad, uint8_t wai) : i2c_rw(i2c_obj) { _sad = sad; _wai = wai; + setup_mode_on = false; } KX123::~KX123(){ } /** +* Start setup/stand-by mode and shut off measurements. +* @return true on error, false on ok +*/ +bool KX123::start_setup_mode(void){ + setup_mode_on = true; + return i2c_rw.change_bits(_sad, KX122_CNTL1, KX122_CNTL1_PC1, KX122_CNTL1_PC1); +} + +/** +* Start operating/measurement mode. Setup is not allowed while in this mode. +* @return true on error, false on ok +*/ +bool KX123::start_measurement_mode(void){ + setup_mode_on = false; + return i2c_rw.change_bits(_sad, KX122_CNTL1, KX122_CNTL1_PC1, 0); +} + +/** * Check if sensor is connected, setup defaults to sensor and start measuring. * @return true on error, false on ok */ @@ -85,6 +104,7 @@ //First set CNTL1 PC1-bit to stand-by mode, after that setup can be made i2c_rw.write_register(_sad, KX122_CNTL1, 0 ); + setup_mode_on = true; //set_tilt_position_defaults(); @@ -92,6 +112,7 @@ i2c_rw.write_register(_sad, KX122_ODCNTL, KX122_ODCNTL_OSA_25600); //Setup G-range and 8/16-bit resolution + set CNTL1 PC1-bit to operating mode (also WUF_EN, TP_EN and DT_EN) i2c_rw.write_register(_sad, KX122_CNTL1, ( KX122_CNTL1_PC1 | KX122_CNTL1_GSEL_8G | KX122_CNTL1_RES ) ); + setup_mode_on = false; //resolution_divider = 32768/2; //KX122_CNTL1_GSEL_2G //resolution_divider = 32768/4; //KX122_CNTL1_GSEL_4G @@ -102,9 +123,10 @@ /** -* CNTL PC1-bit has to be set to stand-by before this command. +* Setup default settings for a tilt position **/ void KX123::set_tilt_position_defaults(){ + if (setup_mode_on == false) return; //CNTL3: Tilt position control, directional tap control and motion wakeup control i2c_rw.write_register(_sad, KX122_CNTL3, ( KX122_CNTL3_OTP_50 | KX122_CNTL3_OTDT_400 ) ); //TILT_TIMER: Setup tilt position timer (~=filter) @@ -114,6 +136,26 @@ /** +* Get filtered uint16_t XYZ-values from sensor +* @param *buf to uint16_t[3] for results +* @return true on error, false on read ok. +**/ +bool KX123::getresults_highpass(uint16_t* buf) { + #define RESULTS_LEN 6 + uint8_t tmp[RESULTS_LEN]; //XYZ (lhlhlh) + uint8_t read_bytes; + + read_bytes = i2c_rw.read_register(_sad, KX122_XHP_L, &tmp[0], sizeof(tmp)); + if (read_bytes != RESULTS_LEN){ + return true; + } + buf[0] = ( tmp[1] << 8 ) | tmp[0]; //X + buf[1] = ( tmp[3] << 8 ) | tmp[2]; //Y + buf[2] = ( tmp[5] << 8 ) | tmp[4]; //Z + return false; +} + +/** * Get raw uint16_t XYZ-values from sensor * @param *buf to uint16_t[3] for results * @return true on error, false on read ok. @@ -155,4 +197,319 @@ return false; } +/** +* Get axes of current tilt and previous tilt +* @param *current_previous space for storing 2 (uint8_t) values +* @return true on error +*/ +bool KX123::get_tilt(enum e_axis* current_previous){ + #define GET_TILT_READ_LEN 2 + uint8_t read_bytes; + read_bytes = i2c_rw.read_register(_sad, KX122_TSCP, (uint8_t*)current_previous, GET_TILT_READ_LEN); + + return (read_bytes != GET_TILT_READ_LEN); +} + +/** +* Get axis of triggered tap/double tap interrupt from INS1 +* @param *axis space for storing 1 (uint8_t) value in e_axis format +* @return true on error +*/ +bool KX123::get_tap_interrupt_axis(enum e_axis* axis){ + #define GET_TAP_READ_LEN 1 + uint8_t read_bytes; + + read_bytes = i2c_rw.read_register(_sad, KX122_INS1, (uint8_t*)axis, GET_TAP_READ_LEN); + + return (read_bytes != GET_TAP_READ_LEN); +} + +/** +* Get axis of triggered motion detect interrupt from INS3 +* @param *axis space for storing 1 (uint8_t) value in e_axis format +* @return true on error +*/ +bool KX123::get_detected_motion_axis(enum e_axis* axis){ + #define GET_MOTION_READ_LEN 1 + uint8_t read_bytes; + + read_bytes = i2c_rw.read_register(_sad, KX122_INS3, (uint8_t*)axis, GET_MOTION_READ_LEN); + + return (read_bytes != GET_MOTION_READ_LEN); +} + +/** +* Set axis of triggered motion detect interrupt from CNTL2 +* @param cnltl2_tilt_mask Orred e_axis values for axes directions to cause interrupt +* @return true on error or setup mode off +*/ +bool KX123::set_tilt_axis_mask(uint8_t cnltl2_tilt_mask){ + if (setup_mode_on == false) return true; + //MSb 00 == no_action + return i2c_rw.write_register(_sad, KX122_CNTL2, (cnltl2_tilt_mask & KX123_AXIS_MASK) ); +} + +/** +* get cause of interrupt trigger from INS2 +* @param *int_reason space for storing 1 (uint8_t) value in e_interrupt_reason format +* @return true on error +*/ +bool KX123::get_interrupt_reason(enum e_interrupt_reason* int_reason){ + #define INT_REASON_LEN 1 + uint8_t read_bytes; + + read_bytes = i2c_rw.read_register(_sad, KX122_INS2, (uint8_t*)int_reason, INT_REASON_LEN); + + return (read_bytes != INT_REASON_LEN); +} + +/** +* Check from sensor register if interrupt has occured. Usable feature when +* multiple sensor interrupts are connected to same interrupt pin. +* @return true when interrupt has occured. False on read fail and no interrupt. +*/ +bool KX123::has_interrupt_occured(){ + uint8_t status_reg; + uint8_t read_bytes; + + read_bytes = i2c_rw.read_register(_sad, KX122_INS2, &status_reg, 1); + return ((read_bytes == 1) && (status_reg & KX122_STATUS_REG_INT)); +} + +/** +* Clear interrupt flag when latched. (==Interrupt release) Doesn't work for FIFO +* Buffer Full or FIFO Watermark -interrupts. +*/ +void KX123::clear_interrupt(){ + uint8_t value_discarded; + + i2c_rw.read_register(_sad, KX122_INT_REL, &value_discarded, 1); + + return; +} + +/** +* Initiate software reset and RAM reboot routine and wait untill finished. +*/ +void KX123::soft_reset(){ + uint8_t reset_ongoing; + + i2c_rw.change_bits(_sad, KX122_CNTL2, KX122_CNTL2_SRST, KX122_CNTL2_SRST ); + do{ + uint8_t cntl2, read_bytes; + + read_bytes = i2c_rw.read_register(_sad, KX122_CNTL2, &cntl2, 1); + reset_ongoing = ((read_bytes == 0) || (cntl2 & KX122_CNTL2_SRST)); + } while (reset_ongoing); + + return; +} + +/** +* Verify proper integrated circuit functionality +* @return true on test fail or setup mode off, false on test ok. +**/ +bool KX123::self_test(){ + uint8_t cotr_value; + bool read_ok; + + if (setup_mode_on == false) return true; + //first read to make sure COTR is in default value + read_ok = i2c_rw.read_register(_sad, KX122_COTR, &cotr_value, 1); + read_ok = i2c_rw.read_register(_sad, KX122_COTR, &cotr_value, 1); + if ((cotr_value != 0x55) || (!read_ok) ){ + return true; + } + i2c_rw.change_bits(_sad, KX122_CNTL2, KX122_CNTL2_COTC, KX122_CNTL2_COTC ); + read_ok = i2c_rw.read_register(_sad, KX122_COTR, &cotr_value, 1); + if ((cotr_value != 0xAA) || (!read_ok) ){ + return true; + } + return false; +} + +/** +* Setup ODR values for Tilt Position, Directional Tap and Motion Detect. +* @param tilt_position_odr KX122_CNTL3_OTP_* -value or 0xff to skip. +* @param directional_tap_odr KX122_CNTL3_OTDT_* -value or 0xff to skip. +* @param motion_wuf_odr KX122_CNTL3_OWUF_* -value or 0xff to skip. +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::set_cntl3_odrs(uint8_t tilt_position_odr, uint8_t directional_tap_odr, uint8_t motion_wuf_odr){ + uint8_t cntl3; + bool read_ok; + + if (setup_mode_on == false) return true; + + read_ok = i2c_rw.read_register(_sad, KX122_CNTL3, &cntl3, 1); + if(!read_ok) return true; + + if (tilt_position_odr != 0xff){ + cntl3 = (cntl3 & ~KX122_CNTL3_OTP_MASK) | (tilt_position_odr & KX122_CNTL3_OTP_MASK); + } + if (directional_tap_odr != 0xff){ + cntl3 = (cntl3 & ~KX122_CNTL3_OTDT_MASK) | (directional_tap_odr & KX122_CNTL3_OTDT_MASK); + } + if (motion_wuf_odr != 0xff){ + cntl3 = (cntl3 & ~KX122_CNTL3_OWUF_MASK) | (motion_wuf_odr & KX122_CNTL3_OWUF_MASK); + } + return i2c_rw.write_register(_sad, KX122_CNTL3, cntl3); +} + +/** +* Setup ODR value, IIR-filter on/off and lowpass filter corner frequency. +* @param iir_filter_off False to filter ON or true to filter OFF. +* @param lowpass_filter_freq_half Filter corner frequency setup. False to ODR/9. True to ODR/2. +* @param odr Output Data Rate using KX122_ODCNTL_OSA_* -definitions. +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::set_odcntl(bool iir_filter_off, uint8_t lowpass_filter_freq_half, uint8_t odr){ + uint8_t odcntl; + + if (setup_mode_on == false) return true; + + odcntl = (odr & KX122_ODCNTL_OSA_MASK); + if (iir_filter_off){ + odcntl = (odcntl | KX122_ODCNTL_IIR_BYPASS); + } + if (lowpass_filter_freq_half){ + odcntl = (odcntl | KX122_ODCNTL_LPRO); + } + + return i2c_rw.write_register(_sad, KX122_ODCNTL, odcntl); +} + +/** +* Setup physical int1 pin, selftest polarity and SPI 3-wire on/off. +* @param pwsel Pulse width configuration in KX122_INC1_PWSEL1_* values +* @param physical_int_pin_enabled +* @param physical_int_pin_active_high (default true) +* @param physical_int_pin_latch_disabled +* @param self_test_polarity_positive +* @param spi3wire_enabled Use 3 wires instead of 4. +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::int1_setup(uint8_t pwsel, + bool physical_int_pin_enabled, + bool physical_int_pin_active_high, + bool physical_int_pin_latch_disabled, + bool self_test_polarity_positive, + bool spi3wire_enabled){ + + uint8_t inc1; + + if (setup_mode_on == false) return true; + + inc1 = (pwsel & KX122_INC1_PWSEL1_MASK); + if (physical_int_pin_enabled){ + inc1 = (inc1 | KX122_INC1_IEN1); + } + if (physical_int_pin_active_high){ + inc1 = (inc1 | KX122_INC1_IEA1); + } + if (physical_int_pin_latch_disabled){ + inc1 = (inc1 | KX122_INC1_IEL1); + } + if (self_test_polarity_positive){ + inc1 = (inc1 | KX122_INC1_STPOL); + } + if (spi3wire_enabled){ + inc1 = (inc1 | KX122_INC1_SPI3E); + } + return i2c_rw.write_register(_sad, KX122_INC1, inc1); +} + + +/** +* Setup physical int2 pin and int1/2 autoclear. +* @param pwsel Pulse width configuration in KX122_INC1_PWSEL1_* values +* @param physical_int_pin_enabled +* @param physical_int_pin_active_high (default true) +* @param physical_int_pin_latch_disabled +* @param aclr2_enabled +* @param aclr1_enabled +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::int2_setup(uint8_t pwsel, + bool physical_int_pin_enabled, + bool physical_int_pin_active_high, + bool physical_int_pin_latch_disabled, + bool aclr2_enabled, + bool aclr1_enabled){ + + uint8_t inc5; + + if (setup_mode_on == false) return true; + + inc5 = (pwsel & KX122_INC5_PWSEL2_MASK); + if (physical_int_pin_enabled){ + inc5 = (inc5 | KX122_INC5_IEN2); + } + if (physical_int_pin_active_high){ + inc5 = (inc5 | KX122_INC5_IEA2); + } + if (physical_int_pin_latch_disabled){ + inc5 = (inc5 | KX122_INC5_IEL2); + } + if (aclr2_enabled){ + inc5 = (inc5 | KX122_INC5_ACLR2); + } + if (aclr1_enabled){ + inc5 = (inc5 | KX122_INC5_ACLR1); + } + return i2c_rw.write_register(_sad, KX122_INC5, inc5); +} + +/** +* Select interrupt reasons that can trigger interrupt for int1. +* @param interrupt_reason One or more e_interrupt_reason -values except doubletap. +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::set_int1_interrupt_reason(uint8_t interrupt_reason){ + if (setup_mode_on == false) return true; + return i2c_rw.write_register(_sad, KX122_INC4, interrupt_reason); +} + +/** +* Select interrupt reasons that can trigger interrupt for int2. +* @param interrupt_reason One or more e_interrupt_reason -values except doubletap. +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::set_int2_interrupt_reason(uint8_t interrupt_reason){ + if (setup_mode_on == false) return true; + return i2c_rw.write_register(_sad, KX122_INC6, interrupt_reason); +} + +/** +* Select axis that are monitored for motion detect interrupt. +* @param xxyyzz combination of e_axis -values for enabling axis +* @param axis_and_combination_enabled true for AND or false for OR +* +* true for AND configuration = (XN || XP) && (YN || YP) && (ZN || ZP) +* +* false for OR configuration = (XN || XP || YN || TP || ZN || ZP) +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::set_motion_detect_axis(uint8_t xxyyzz, bool axis_and_combination_enabled){ + uint8_t inc2; + + if (setup_mode_on == false) return true; + + inc2 = (xxyyzz & KX122_INC2_WUE_MASK); + if (axis_and_combination_enabled){ + inc2 = (inc2 | KX122_INC2_AOI_AND); + } + return i2c_rw.write_register(_sad, KX122_INC2, inc2); +} + +/** +* Select axis that are monitored for tap/doubletap interrupt. +* @param xxyyzz combination of e_axis -values for enabling axis +* @return true on error or setup mode off, false on setup ok. +**/ +bool KX123::set_tap_axis(uint8_t xxyyzz){ + if (setup_mode_on == false) return true; + return i2c_rw.write_register(_sad, KX122_INC3, xxyyzz); +} +