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, committed 2016-10-06
- Comitter:
- MikkoZ
- Date:
- Thu Oct 06 10:23:48 2016 +0000
- Parent:
- 1:f328083fb80b
- Child:
- 3:4fd5361ed180
- Commit message:
- Added many features for setting up and reading the sensor registers via driver functions.
Changed in this revision
--- 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);
+}
+
--- a/kx123.h Fri Sep 30 11:52:29 2016 +0000
+++ b/kx123.h Thu Oct 06 10:23:48 2016 +0000
@@ -24,6 +24,7 @@
* Kionix KX123 accelerometer i2c driver. For some extend can be used also with
* kx012, kx022, kx023, kx23h, kx112, kx122, kx124, kx222 and kx224. Driver uses
* RegisterWriter -class as (i2c) hardware abstraction layer.
+* Note that when doing setup, sensor has to be in setup mode, not in operating mode.
*/
class KX123
{
@@ -32,11 +33,53 @@
KX123(RegisterWriter &i2c_obj, uint8_t sad = KX123_DEFAULT_SLAVE_ADDRESS, uint8_t wai = KX123_WHO_AM_I_WAI_ID);
~KX123();
+ bool start_setup_mode(void);
+ bool start_measurement_mode(void);
bool set_defaults(void);
+ bool getresults_highpass(uint16_t* buf);
bool getresults_raw(int16_t* buf);
bool getresults_g(float* buf);
+
+ bool get_tilt(enum e_axis* current_previous);
+ bool get_tap_interrupt_axis(enum e_axis* axis);
+ bool get_detected_motion_axis(enum e_axis* axis);
+ bool set_tilt_axis_mask(uint8_t cnltl2_tilt_mask);
+
+ bool get_interrupt_reason(enum e_interrupt_reason* int_reason);
+
+ bool has_interrupt_occured();
+ void clear_interrupt();
+ void soft_reset();
+ bool self_test();
+
+ bool set_cntl3_odrs(uint8_t tilt_position_odr, uint8_t directional_tap_odr, uint8_t motion_wuf_odr); //0xff for DONT_SET
+ bool set_odcntl(bool iir_filter_off, uint8_t lowpass_filter_freq_half, uint8_t odr);
+ bool 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);
+ bool 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);
+ bool set_int1_interrupt_reason(uint8_t interrupt_reason);
+ bool set_int2_interrupt_reason(uint8_t interrupt_reason);
+
+ bool set_motion_detect_axis(uint8_t xxyyzz, bool axis_and_combination_enabled = false);
+ bool set_tap_axis(uint8_t xxyyzz);
+/**
+* Note that not all sensor setup registers are exposed with this driver yet.
+* There are also setup registers for motion detect, tap/double tap detect, free
+* fall detect, tilt hysteresis, low power and FIFO.
+*/
+
private:
+ bool setup_mode_on;
void set_tilt_position_defaults();
RegisterWriter i2c_rw;
--- a/kx123_registers.h Fri Sep 30 11:52:29 2016 +0000
+++ b/kx123_registers.h Thu Oct 06 10:23:48 2016 +0000
@@ -19,6 +19,29 @@
#define KX123_DEFAULT_SLAVE_ADDRESS 0x1F
#define KX123_SECONDARY_SLAVE_ADDRESS 0x1E
+enum e_axis {
+ KX123_X_N = (uint8_t) (0x01 << 5),
+ KX123_X_P = (uint8_t) (0x01 << 4),
+ KX123_Y_N = (uint8_t) (0x01 << 3),
+ KX123_Y_P = (uint8_t) (0x01 << 2),
+ KX123_Z_N = (uint8_t) (0x01 << 1),
+ KX123_Z_P = (uint8_t) (0x01 << 0)
+ };
+
+#define KX123_AXIS_MASK 0x3f
+
+enum e_interrupt_reason {
+ KX123_FREEFALL = (uint8_t) (0x01 << 7),
+ KX122_BUFFER_FULL = (uint8_t) (0x01 << 6),
+ KX122_WATERMARK = (uint8_t) (0x01 << 5),
+ KX122_DATAREADY = (uint8_t) (0x01 << 4),
+ KX122_DOUBLE_TAP = (uint8_t) (0x02 << 2),
+ KX122_SINGLE_TAP = (uint8_t) (0x01 << 2),
+ KX122_MOTION_INTERRUPT = (uint8_t) (0x01 << 1),
+ KX122_TILT_CHANGED = (uint8_t) (0x01 << 0)
+ };
+
+
/* registers */
// x- hp filter output
#define KX122_XHP_L 0x00
Rohm/Kionix KX123-6000 | Accelerometer