Kionix KX123 accelerometer C++ driver. Can be used for some extend also with kx022, kx023, kx122, etc. when used features are present in sensor.

Dependents:   kionix-kx123-hello

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);
+}
+