diff --git a/docs/images/kxtj3.png b/docs/images/kxtj3.png new file mode 100755 index 00000000..7f0fbfbb Binary files /dev/null and b/docs/images/kxtj3.png differ diff --git a/examples/c++/kxtj3.cxx b/examples/c++/kxtj3.cxx new file mode 100755 index 00000000..609cae95 --- /dev/null +++ b/examples/c++/kxtj3.cxx @@ -0,0 +1,73 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include "kxtj3.hpp" +#include "upm_utilities.h" + +#define SENSOR_ADDR 0x0f +#define I2C_BUS 0 +#define SAMPLE_COUNT 10 + +bool isStopped = false; + +void signal_int_handler(int signo) +{ + if (signo == SIGINT) + isStopped = true; +} + +void print_acceleration_data(upm::KXTJ3 &dev) +{ + float wait_time = dev.GetAccelerationSamplePeriod() * SECOND_IN_MICRO_S; + int sample_counter = SAMPLE_COUNT; + std::vector xyz; + while ((sample_counter-- > 0) && !isStopped) + { + xyz = dev.GetAccelerationVector(); + std::cout << std::fixed << std::setprecision(3) + << xyz[0] << " | " << xyz[1] << " | " << xyz[2] << std::endl; + upm_delay_us(wait_time); + } +} + +int main(int argc, char **argv) +{ + signal(SIGINT, signal_int_handler); + + std::cout << "Sensor init" << std::endl; + upm::KXTJ3 dev(I2C_BUS, SENSOR_ADDR); + + std::cout << "Setting settings:\nODR: 25 Hz\nResolution: " + << "High\nAcceleration range: 16g with 14bits" << std::endl; + dev.SensorInit(KXTJ3_ODR_25, HIGH_RES, KXTJ3_RANGE_16G_14); + std::cout << "Showing acceleration data:" << std::endl; + print_acceleration_data(dev); + + std::cout << "Closing sensor" << std::endl; + return 0; +} diff --git a/examples/c/kxtj3.c b/examples/c/kxtj3.c new file mode 100755 index 00000000..12cbe7ec --- /dev/null +++ b/examples/c/kxtj3.c @@ -0,0 +1,75 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include "kxtj3.h" + +#define SENSOR_ADDR 0x0f +#define I2C_BUS 0 +#define SAMPLE_COUNT 10 + +bool isStopped = false; + +void signal_int_handler(int signo) +{ + if (signo == SIGINT) + isStopped = true; +} + +void print_acceleration_data(kxtj3_context dev) +{ + float wait_time = kxtj3_get_acceleration_sampling_period(dev) * SECOND_IN_MICRO_S; + uint8_t sample_counter = 0; + float x, y, z; + while (sample_counter < SAMPLE_COUNT && !isStopped) + { + kxtj3_get_acceleration_data(dev, &x, &y, &z); + printf("%.02f | %.02f | %.02f\n", x, y, z); + usleep(wait_time); + sample_counter++; + } +} + +int main(int argc, char **argv) +{ + signal(SIGINT, signal_int_handler); + + printf("Sensor init\n"); + kxtj3_context dev = kxtj3_init(I2C_BUS, SENSOR_ADDR); + if (!dev) + { + printf("kxtj3_init() failed.\n"); + return -1; + } + + printf("Setting settings:\nODR: 25 Hz\nResolution: High\nAcceleration range: 16g with 14bits"); + kxtj3_sensor_init(dev, KXTJ3_ODR_25, HIGH_RES, KXTJ3_RANGE_16G_14); + printf("Showing acceleration data:\n"); + print_acceleration_data(dev); + + printf("Closing sensor\n"); + kxtj3_close(dev); + return 0; +} diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index ed246b5e..4b5eb438 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -144,6 +144,7 @@ add_example(Jhd1313m1_Example jhd1313m1) add_example(Jhd1313m1_lcd_Example jhd1313m1) add_example(Joystick12_Example joystick12) add_example(KX122_Example kx122) +add_example(KXTJ3_Example kxtj3) add_example(Lcm1602_i2c_Example lcm1602) add_example(Lcm1602_parallel_Example lcm1602) add_example(LDT0028_Example ldt0028) diff --git a/examples/java/KXTJ3_Example.java b/examples/java/KXTJ3_Example.java new file mode 100755 index 00000000..578230f9 --- /dev/null +++ b/examples/java/KXTJ3_Example.java @@ -0,0 +1,49 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +public class KXTJ3_Example { + + public static void main(String[] args) throws InterruptedException { + + upm_kxtj3.KXTJ3 kxtj3 = new upm_kxtj3.KXTJ3(); + + kxtj3.SensorInit(upm_kxtj3.KXTJ3_ODR_T.KXTJ3_ODR_25, + upm_kxtj3.KXTJ3_RESOLUTION_T.HIGH_RES, + upm_kxtj3.KXTJ3_G_RANGE_T.KXTJ3_RANGE_16G_14); + + float waitTime = kxtj3.GetAccelerationSamplePeriod() * 1000; + int sampleCounter = 10; + System.out.println("Setting settings:\nODR: 25 Hz\nResolution: " + + "High\nAcceleration range: 16g with 14bits"); + System.out.println("Acceleration"); + upm_kxtj3.floatVector xyz; + while (sampleCounter-- > 0) { + xyz = kxtj3.GetAccelerationVector(); + System.out.println("x = " + xyz.get(0) + " y = " + xyz.get(1) + + " z = " + xyz.get(2)); + + Thread.sleep((long) waitTime); + } + } +} \ No newline at end of file diff --git a/examples/javascript/kxtj3.js b/examples/javascript/kxtj3.js new file mode 100755 index 00000000..2c4954ca --- /dev/null +++ b/examples/javascript/kxtj3.js @@ -0,0 +1,54 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +var kxtj3 = require("jsupm_kxtj3"); + +var kxtj3_sensor = new kxtj3.KXTJ3(0x0, 0x0f); + +kxtj3_sensor.SensorInit( + kxtj3.KXTJ3_ODR_25, + kxtj3.HIGH_RES, + kxtj3.KXTJ3_RANGE_16G_14); + +var waitTime = kxtj3_sensor.GetAccelerationSamplePeriod(); +var counter = 10; +console.log("Setting settings:\nODR: 25 Hz\nResolution: \ + High\nAcceleration range: 16g with 14bits"); +console.log("Accerleration: "); +var interval = setInterval(function() { + data = kxtj3_sensor.GetAccelerationVector(); + console.log( + "x: " + data.get(0) + " y: " + data.get(1) + " z: " + data.get(2) + ); + counter--; + if (counter == 0) { + clearInterval(interval); + } +}, waitTime * 1000); + +process.on("SIGINT", function() { + clearInterval(interval); + console.log("Exiting..."); + process.exit(0); +}); diff --git a/examples/python/kxtj3.py b/examples/python/kxtj3.py new file mode 100755 index 00000000..7d7ab530 --- /dev/null +++ b/examples/python/kxtj3.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# The MIT License (MIT) +# +# Author: Assam Boudjelthia +# Copyright (c) 2018 Rohm Semiconductor. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + +import time, sys, signal, atexit +from upm import pyupm_kxtj3 + + +def main(): + kxtj3_sensor = pyupm_kxtj3.KXTJ3(0x0, 0x0f) + + kxtj3_sensor.SensorInit(pyupm_kxtj3.KXTJ3_ODR_25, + pyupm_kxtj3.HIGH_RES, + pyupm_kxtj3.KXTJ3_RANGE_16G_14) + + # Prevent stack printing on CTRL^C + def SIGINTHandler(signum, frame): + raise SystemExit + + def exitHandler(): + print("Exiting") + sys.exit(0) + + atexit.register(exitHandler) + signal.signal(signal.SIGINT, SIGINTHandler) + + sampleCounter = 10 + waitTime = kxtj3_sensor.GetAccelerationSamplePeriod() + print("Setting settings:\nODR: 25 Hz\nResolution: " + "High\nAcceleration range: 16g with 14bits") + print("Acceleration:") + while sampleCounter > 0: + [x, y, z] = kxtj3_sensor.GetAccelerationVector() + + print ("x: %0.02f, y: %0.02f, z: %0.02f" % (x, y, z)) + + time.sleep(waitTime) + sampleCounter -= 1 + + +if __name__ == '__main__': + main() diff --git a/src/kxtj3/CMakeLists.txt b/src/kxtj3/CMakeLists.txt new file mode 100755 index 00000000..f770d9c1 --- /dev/null +++ b/src/kxtj3/CMakeLists.txt @@ -0,0 +1,8 @@ +upm_mixed_module_init (NAME kxtj3 + DESCRIPTION "Tri-Axis Accelerometer" + C_HDR kxtj3.h kxtj3_registers.h + C_SRC kxtj3.c + CPP_HDR kxtj3.hpp + CPP_SRC kxtj3.cxx + CPP_WRAPS_C + REQUIRES mraa) diff --git a/src/kxtj3/kxtj3.c b/src/kxtj3/kxtj3.c new file mode 100755 index 00000000..fd144e40 --- /dev/null +++ b/src/kxtj3/kxtj3.c @@ -0,0 +1,1094 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include "kxtj3.h" + +#define SW_RESET_MAX_LOOP_COUNT 10 +#define SW_RESET_READ_WAIT_MICRO_S 50000 + +#define SELF_TEST_SAMPLE_COUNT 10 +#define SELF_TEST_DIFFERENCE_THRESHOLD 0.5f + +#define DATA_BUFFER_LENGTH 6 + +/** + * @brief Acceleration steps in (g) for each range setting. + * Used to calculate acceleration_scale to convert + * raw data to readable acceleration data. + */ +#define RANGE_2G_8BIT_STEP 0.016f +#define RANGE_4G_8BIT_STEP 0.031f +#define RANGE_8G_8BIT_STEP 0.0625f +#define RANGE_16G_8BIT_STEP 0.125f + +#define RANGE_2G_12BIT_STEP 0.001f +#define RANGE_4G_12BIT_STEP 0.002f +#define RANGE_8G_12BIT_STEP 0.0039f +#define RANGE_16G_12BIT_STEP 0.0078f + +#define RANGE_8G_14BIT_STEP 0.00098f +#define RANGE_16G_14BIT_STEP 0.00195f +#define EARTH_GRAVITY 9.81f + +/** + * @brief Map of ODR register values to ODR in Hz + * used to calculate sampling time in seconds + */ +struct odr_map_t +{ + uint8_t odr_reg_bit; + float odr_in_Hz; +}; + +/** + * @brief ODR register values maping with ODR in Hz + */ +const struct odr_map_t odr_map_in_Hz[] = { + {KXTJ3_ODR_0P781, 0.781f}, + {KXTJ3_ODR_1P563, 1.563f}, + {KXTJ3_ODR_3P125, 3.125f}, + {KXTJ3_ODR_6P25, 6.25f}, + {KXTJ3_ODR_12P5, 12.5f}, + {KXTJ3_ODR_25, 25.0f}, + {KXTJ3_ODR_50, 50.0f}, + {KXTJ3_ODR_100, 100.0f}, + {KXTJ3_ODR_200, 200.0f}, + {KXTJ3_ODR_400, 400.0f}, + {KXTJ3_ODR_800, 800.0f}, + {KXTJ3_ODR_1600, 1600.0f}}; +/** + * @brief ODR register values maping with ODR in Hz for + * wake-up function + */ +const struct odr_map_t odr_map_in_Hz_wakeup[] = { + {KXTJ3_ODR_WAKEUP_0P781, 0.781f}, + {KXTJ3_ODR_WAKEUP_1P563, 1.563f}, + {KXTJ3_ODR_WAKEUP_3P125, 3.125f}, + {KXTJ3_ODR_WAKEUP_6P25, 6.25f}, + {KXTJ3_ODR_WAKEUP_12P5, 12.5f}, + {KXTJ3_ODR_WAKEUP_25, 25.0f}, + {KXTJ3_ODR_WAKEUP_50, 50.0f}, + {KXTJ3_ODR_WAKEUP_100, 100.0f}}; + +/** + * @brief Coordinates structure + */ +struct Coordinates +{ + float x, y, z; +}; + +/** +@brief Inits the I2C connections and returns status of initialization + +@param dev The sensor context +@param bus I2C bus number +@param addr I2C addr of the sensor +@return true if initialization successful or false for failure +*/ +static bool kxtj3_check_mraa_i2c_connection(kxtj3_context dev, int bus, uint8_t addr); + +/** +@brief Checks if the sensor WHO_AM_I value is correct + +@param dev The sensor context +@return true if value correct, or false if mismatch +*/ +static bool kxtj3_check_who_am_i(kxtj3_context dev); + +/** +@brief Calculates the ODR sample time from an ODR register value + +@param odr One of KXTJ3_ODR_T values of ODR register configurations +@return the float time value +*/ +static float kxtj3_odr_val_to_sec(KXTJ3_ODR_T odr); + +/** +@brief Calculates the ODR sample time from an ODR register value for wake-up function + +@param odr One of KXTJ3_ODR_WAKEUP_T values of ODR register configurations for wake-up +@return the float time value +*/ +static float kxtj3_odr_val_to_sec_wakeup(KXTJ3_ODR_WAKEUP_T odr); + +/** +@brief Sets the sensor default values for ODR, resolution (with its scale), +G range (both normal and wake-up modes) + +@param dev The sensor context +*/ +static void kxtj3_set_default_values(const kxtj3_context dev); + +/** +@brief Read the value of a provided register + +@param dev The sensor context +@param reg The register address to read from +@param data A pointer to variable for storing the value read +@return A UPM result +*/ +static upm_result_t kxtj3_read_register(const kxtj3_context dev, uint8_t reg, uint8_t *data); + +/** +@brief Read the values starting from a provided register, of specific length + +@param dev The sensor context +@param reg The register address to start reading from +@param data A pointer to variable for storing the value read +@param len The number of bytes to read +@return A UPM result +*/ +static upm_result_t kxtj3_read_registers(const kxtj3_context dev, uint8_t reg, uint8_t *data, int len); + +/** +@brief Writes a value to a provided register + +@param dev The sensor context +@param reg The register address to write to +@param val byte of data to write +@return A UPM result +*/ +static upm_result_t kxtj3_write_register(const kxtj3_context dev, uint8_t reg, uint8_t val); + +/** +@brief Sets a specific bit on in a provided register + +@param dev The sensor context +@param reg register to write into +@param bit_mask The bit to set, as a register mask +@return A UPM result +*/ +static upm_result_t kxtj3_set_bit_on(const kxtj3_context dev, uint8_t reg, uint8_t bit_mask); + +/** +@brief Clear a specific bit (set off) in a provided register + +@param dev The sensor context +@param reg register address to write into +@param bit_mask The bit to set, as a register mask +@return A UPM result +*/ +static upm_result_t kxtj3_set_bit_off(const kxtj3_context dev, uint8_t reg, uint8_t bit_mask); + +/** +@brief Sets a register value or its bits according to a provided mask + +@param dev The sensor context +@param reg The register address to write to +@param val byte data to write +@param bit_mask The bits or register mask +@return A UPM resutl +*/ +static upm_result_t kxtj3_set_bits_with_mask(const kxtj3_context dev, uint8_t reg, uint8_t val, uint8_t bit_mask); + +/** +@brief Checks whether a given G range setting uses 14-bit mode + +@param g_range One of KXTJ3_G_RANGE_T value for available acceleration settings +@return true if range is 14-bit based, false otherwise +*/ +static bool kxtj3_is_14_bit_range(KXTJ3_G_RANGE_T g_range_mode); + +/** +@brief Maps the acceleration_scale (that is used to calculate the acceleration data in g unit) +with the G range and resolution mode. Changes the acceleration_scale value in sensor context. + +@param dev The sensor context +@param g_range The G range setting, one of KXTJ3_G_RANGE_T values +*/ +static void kxtj3_map_g_range_to_resolution(kxtj3_context dev, KXTJ3_G_RANGE_T g_range); +/** +@brief Calculates the average of coordinates for a sample of data (SELF_TEST_SAMPLE_COUNT). +This is used by the self-test functionality. + +@param dev The sensor context +@return Coordinates struct that contains value of x, y and z +*/ +static struct Coordinates kxtj3_get_sample_averaged_data(kxtj3_context dev); + +/** +@brief Check whether the self-test acceleration data difference is whithin the permitted threshold (0.5g) + +@param before The Coordinates struct before the self-test +@param during The Coordinates struct of the self-test +@return true if difference is below thresold, false otherwise +*/ +static bool kxtj3_check_self_test_difference(struct Coordinates before, struct Coordinates during); + +/** +@brief Checks the digital communication register (DCST_RESP) register value with an expected value + +@param dev The sensor context +@param expected_val The expted byte value of the register +@return true if values match, false otherwise. +*/ +static bool kxtj3_check_digital_communication_reg_value(kxtj3_context dev, uint8_t expected_val); + +/** +@brief Gets the count value from a given time (in seconds) for the wake-up function. +Used by the wake-up motion counter and non-activity counter before anothe wake-up functions. + +@param dev The sensor context +@param time_sec Time in seconds to be converted +@return the count value as a uint8_t +*/ +static uint8_t kxtj3_get_wakeup_count_from_time_sec(kxtj3_context dev, float time_sec); + +/** +@brief Gets the count value from a given acceleration threshold (in g) for the wake-up function. +Used by wake-up threshold counter functionality. + +@param dev The sensor context +@param g_threshold acceleration value in g to be converted +@return the count value as a uint16_t (expected range up to 4096) +*/ +static uint16_t kxtj3_get_wakeup_threshold_count_from_g(kxtj3_context dev, float g_threshold); + +// Register Read/Write helper functions +static upm_result_t kxtj3_read_register(const kxtj3_context dev, uint8_t reg, uint8_t *data) +{ + int value = mraa_i2c_read_byte_data(dev->i2c, reg); + if (value == -1) + { + printf("%s: mraa_i2c_read_byte_data() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + *data = (uint8_t)value; + return UPM_SUCCESS; +} + +static upm_result_t kxtj3_read_registers(const kxtj3_context dev, uint8_t reg, uint8_t *data, int len) +{ + if (mraa_i2c_read_bytes_data(dev->i2c, reg, data, len) != (int)len) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +static upm_result_t kxtj3_write_register(const kxtj3_context dev, uint8_t reg, uint8_t val) +{ + if (mraa_i2c_write_byte_data(dev->i2c, val, reg) != MRAA_SUCCESS) + { + printf("%s: mraa_i2c_write_byte_data() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + return UPM_SUCCESS; +} + +static upm_result_t kxtj3_set_bit_on(const kxtj3_context dev, uint8_t reg, uint8_t bit_mask) +{ + uint8_t reg_value; + if (kxtj3_read_register(dev, reg, ®_value) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + reg_value |= bit_mask; + return kxtj3_write_register(dev, reg, reg_value); +} + +static upm_result_t kxtj3_set_bit_off(const kxtj3_context dev, uint8_t reg, uint8_t bit_mask) +{ + uint8_t reg_value; + if (kxtj3_read_register(dev, reg, ®_value) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + reg_value &= ~bit_mask; + return kxtj3_write_register(dev, reg, reg_value); +} + +static upm_result_t kxtj3_set_bits_with_mask(const kxtj3_context dev, uint8_t reg, uint8_t val, uint8_t bit_mask) +{ + uint8_t reg_val; + if (kxtj3_read_register(dev, reg, ®_val) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + reg_val &= ~bit_mask; + reg_val |= val; + return kxtj3_write_register(dev, reg, reg_val); +} +// End of register Read/Write helper functions + +static bool kxtj3_check_mraa_i2c_connection(kxtj3_context dev, int bus, uint8_t addr) +{ + if (mraa_init() != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed.\n", __FUNCTION__); + kxtj3_close(dev); + return false; + } + + if (!(dev->i2c = mraa_i2c_init(bus))) + { + printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__); + kxtj3_close(dev); + return false; + } + + if (mraa_i2c_address(dev->i2c, addr)) + { + printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__); + kxtj3_close(dev); + return false; + } + + return true; +} + +static bool kxtj3_check_who_am_i(kxtj3_context dev) +{ + uint8_t who_am_i; + kxtj3_get_who_am_i(dev, &who_am_i); + if (who_am_i != KXTJ3_WHO_AM_I_WIA_ID) + { + printf("%s: Wrong WHO AM I received, expected: 0x%x | got: 0x%x\n", __FUNCTION__, + KXTJ3_WHO_AM_I_WIA_ID, who_am_i); + kxtj3_close(dev); + return false; + } + return true; +} + +static float kxtj3_odr_val_to_sec(KXTJ3_ODR_T odr) +{ + for (size_t i = 0; i < (sizeof(odr_map_in_Hz) / sizeof(struct odr_map_t)); i++) + if (odr == odr_map_in_Hz[i].odr_reg_bit) + return (1 / odr_map_in_Hz[i].odr_in_Hz); + + return -1; +} + +static float kxtj3_odr_val_to_sec_wakeup(KXTJ3_ODR_WAKEUP_T odr) +{ + for (size_t i = 0; i < (sizeof(odr_map_in_Hz_wakeup) / sizeof(struct odr_map_t)); i++) + if (odr == odr_map_in_Hz_wakeup[i].odr_reg_bit) + return (1 / odr_map_in_Hz_wakeup[i].odr_in_Hz); + + return -1; +} + +static void kxtj3_set_default_values(const kxtj3_context dev) +{ + dev->g_range_mode = KXTJ3_RANGE_2G; + dev->acceleration_scale = RANGE_2G_8BIT_STEP; + dev->res_mode = LOW_RES; + dev->odr = KXTJ3_ODR_50; + dev->odr_in_sec = kxtj3_odr_val_to_sec(dev->odr); + dev->odr_wakeup = KXTJ3_ODR_WAKEUP_0P781; + dev->odr_in_sec_wakeup = kxtj3_odr_val_to_sec_wakeup(dev->odr_wakeup); +} + +kxtj3_context kxtj3_init(int bus, uint8_t addr) +{ + kxtj3_context dev = (kxtj3_context)malloc(sizeof(struct _kxtj3_context)); + if (!dev) + return NULL; + + dev->i2c = NULL; + dev->interrupt_pin = NULL; + + if (!kxtj3_check_mraa_i2c_connection(dev, bus, addr)) + return NULL; + + if (!kxtj3_check_who_am_i(dev)) + return NULL; + + kxtj3_set_default_values(dev); + + kxtj3_set_odr_wakeup_function(dev, dev->odr_wakeup); + kxtj3_sensor_init(dev, dev->odr, dev->res_mode, dev->g_range_mode); + + return dev; +} + +upm_result_t kxtj3_sensor_init(const kxtj3_context dev, KXTJ3_ODR_T odr, KXTJ3_RESOLUTION_T res, KXTJ3_G_RANGE_T g_range) +{ + assert(dev != NULL); + if (kxtj3_set_sensor_standby(dev) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (kxtj3_set_odr(dev, odr) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + uint8_t g_range_with_res = 0; + if (res) + g_range_with_res |= KXTJ3_CTRL_REG1_RES; + + g_range_with_res |= (g_range & KXTJ3_CTRL_REG1_GSEL_MASK); + if (kxtj3_set_bits_with_mask(dev, KXTJ3_CTRL_REG1, g_range_with_res, + KXTJ3_CTRL_REG1_RES | KXTJ3_CTRL_REG1_GSEL_MASK) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + dev->g_range_mode = g_range; + dev->res_mode = res; + kxtj3_map_g_range_to_resolution(dev, dev->g_range_mode); + + if (kxtj3_set_sensor_active(dev) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t kxtj3_get_who_am_i(const kxtj3_context dev, uint8_t *data) +{ + assert(dev != NULL); + return kxtj3_read_register(dev, KXTJ3_WHO_AM_I, data); +} + +void kxtj3_close(kxtj3_context dev) +{ + assert(dev != NULL); + + if (dev->i2c) + { + mraa_i2c_stop(dev->i2c); + } + + if (dev->interrupt_pin) + kxtj3_uninstall_isr(dev); + + free(dev); +} + +upm_result_t kxtj3_set_sensor_active(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_on(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_PC); +} + +upm_result_t kxtj3_set_sensor_standby(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_off(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_PC); +} + +static void kxtj3_map_g_range_to_resolution(kxtj3_context dev, KXTJ3_G_RANGE_T g_range) +{ + if (dev->res_mode == LOW_RES) + switch (g_range) + { + case KXTJ3_RANGE_2G: + dev->acceleration_scale = RANGE_2G_8BIT_STEP; + break; + case KXTJ3_RANGE_4G: + dev->acceleration_scale = RANGE_4G_8BIT_STEP; + break; + case KXTJ3_RANGE_8G: + dev->acceleration_scale = RANGE_8G_8BIT_STEP; + break; + case KXTJ3_RANGE_16G: + case KXTJ3_RANGE_16G_2: + case KXTJ3_RANGE_16G_3: + dev->acceleration_scale = RANGE_16G_8BIT_STEP; + break; + + case KXTJ3_RANGE_8G_14: + kxtj3_set_resolution(dev, HIGH_RES); + dev->acceleration_scale = RANGE_8G_14BIT_STEP; + break; + case KXTJ3_RANGE_16G_14: + kxtj3_set_resolution(dev, HIGH_RES); + dev->acceleration_scale = RANGE_16G_14BIT_STEP; + break; + } + else + switch (g_range) + { + case KXTJ3_RANGE_2G: + dev->acceleration_scale = RANGE_2G_12BIT_STEP; + break; + case KXTJ3_RANGE_4G: + dev->acceleration_scale = RANGE_4G_12BIT_STEP; + break; + case KXTJ3_RANGE_8G: + dev->acceleration_scale = RANGE_8G_12BIT_STEP; + break; + case KXTJ3_RANGE_16G: + case KXTJ3_RANGE_16G_2: + case KXTJ3_RANGE_16G_3: + dev->acceleration_scale = RANGE_16G_12BIT_STEP; + break; + + case KXTJ3_RANGE_8G_14: + dev->acceleration_scale = RANGE_8G_14BIT_STEP; + break; + case KXTJ3_RANGE_16G_14: + dev->acceleration_scale = RANGE_16G_14BIT_STEP; + break; + } +} + +upm_result_t kxtj3_set_g_range(const kxtj3_context dev, KXTJ3_G_RANGE_T g_range) +{ + assert(dev != NULL); + + if (kxtj3_set_bits_with_mask(dev, KXTJ3_CTRL_REG1, g_range, KXTJ3_CTRL_REG1_GSEL_MASK) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + dev->g_range_mode = g_range; + kxtj3_map_g_range_to_resolution(dev, g_range); + return UPM_SUCCESS; +} + +upm_result_t kxtj3_set_resolution(const kxtj3_context dev, KXTJ3_RESOLUTION_T resolution) +{ + assert(dev != NULL); + + if (resolution == HIGH_RES) + { + if (kxtj3_set_bit_on(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_RES) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + } + else + { + if (kxtj3_set_bit_off(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_RES != UPM_SUCCESS)) + return UPM_ERROR_OPERATION_FAILED; + } + + dev->res_mode = resolution; + kxtj3_map_g_range_to_resolution(dev, dev->g_range_mode); + return UPM_SUCCESS; +} + +upm_result_t kxtj3_set_odr(const kxtj3_context dev, KXTJ3_ODR_T odr) +{ + assert(dev != NULL); + if (kxtj3_set_bits_with_mask(dev, KXTJ3_DATA_CTRL_REG, odr, KXTJ3_DATA_CTRL_REG_OSA_MASK) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + dev->odr = odr; + dev->odr_in_sec = kxtj3_odr_val_to_sec(odr); + + return UPM_SUCCESS; +} + +upm_result_t kxtj3_set_odr_wakeup_function(const kxtj3_context dev, KXTJ3_ODR_WAKEUP_T odr) +{ + assert(dev != NULL); + if (kxtj3_set_bits_with_mask(dev, KXTJ3_CTRL_REG2, odr, KXTJ3_CTRL_REG2_OWUF_MASK) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + dev->odr_wakeup = odr; + dev->odr_in_sec_wakeup = kxtj3_odr_val_to_sec_wakeup(odr); + + return UPM_SUCCESS; +} + +static bool kxtj3_check_digital_communication_reg_value(kxtj3_context dev, uint8_t expected_val) +{ + uint8_t dcst_reg; + if (kxtj3_read_register(dev, KXTJ3_DCST_RESP, &dcst_reg) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (dcst_reg != expected_val) + return false; + + return true; +} + +upm_result_t kxtj3_self_test_digital_communication(kxtj3_context dev) +{ + assert(dev != NULL); + if (!kxtj3_check_digital_communication_reg_value(dev, KXTJ3_DCST_RESP_DCSTR_BEFORE)) + return UPM_ERROR_OPERATION_FAILED; + + if (kxtj3_set_bit_on(dev, KXTJ3_CTRL_REG2, KXTJ3_CTRL_REG2_DCST) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (!kxtj3_check_digital_communication_reg_value(dev, KXTJ3_DCST_RESP_DCSTR_AFTER)) + return UPM_ERROR_OPERATION_FAILED; + + if (!kxtj3_check_digital_communication_reg_value(dev, KXTJ3_DCST_RESP_DCSTR_BEFORE)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +static struct Coordinates kxtj3_get_sample_averaged_data(kxtj3_context dev) +{ + struct Coordinates coordinates_averaged_sample; + coordinates_averaged_sample.x = 0.0f; + coordinates_averaged_sample.y = 0.0f; + coordinates_averaged_sample.z = 0.0f; + + float wait_time = kxtj3_get_acceleration_sampling_period(dev) * SECOND_IN_MICRO_S; + float x, y, z; + for (size_t i = 0; i < SELF_TEST_SAMPLE_COUNT; i++) + { + kxtj3_get_acceleration_data(dev, &x, &y, &z); + coordinates_averaged_sample.x += fabs((x / EARTH_GRAVITY)); + coordinates_averaged_sample.y += fabs((y / EARTH_GRAVITY)); + coordinates_averaged_sample.z += fabs((z / EARTH_GRAVITY)); + usleep(wait_time); + } + + coordinates_averaged_sample.x /= SELF_TEST_SAMPLE_COUNT; + coordinates_averaged_sample.y /= SELF_TEST_SAMPLE_COUNT; + coordinates_averaged_sample.z /= SELF_TEST_SAMPLE_COUNT; + + return coordinates_averaged_sample; +} + +static bool kxtj3_check_self_test_difference(struct Coordinates before, struct Coordinates during) +{ + struct Coordinates difference; + difference.x = fabs(before.x - during.x); + difference.y = fabs(before.y - during.y); + difference.z = fabs(before.z - during.z); + + if (difference.x > SELF_TEST_DIFFERENCE_THRESHOLD) + { + printf("%s: X-asix FAILED, change on X difference: %.2f\n", __FUNCTION__, difference.x); + return false; + } + + if (difference.y > SELF_TEST_DIFFERENCE_THRESHOLD) + { + printf("%s: Y-asix FAILED, change on Y difference: %.2f\n", __FUNCTION__, difference.y); + return false; + } + + if (difference.z > SELF_TEST_DIFFERENCE_THRESHOLD) + { + printf("%s: Z-asix FAILED, change on Z difference: %.2f\n", __FUNCTION__, difference.z); + return false; + } + + return true; +} + +upm_result_t kxtj3_sensor_self_test(kxtj3_context dev) +{ + assert(dev != NULL); + + struct Coordinates coordinates_before_test, coordinates_during_test; + coordinates_before_test = kxtj3_get_sample_averaged_data(dev); + + uint8_t stpol_val; + kxtj3_read_register(dev, KXTJ3_INT_CTRL_REG1, &stpol_val); + + kxtj3_set_sensor_standby(dev); + kxtj3_set_bit_on(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_STPOL); + kxtj3_write_register(dev, KXTJ3_SELF_TEST, KXTJ3_SELF_TEST_MEMS_TEST_ENABLE); + kxtj3_set_bit_off(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_STPOL); + kxtj3_set_sensor_active(dev); + + coordinates_during_test = kxtj3_get_sample_averaged_data(dev); + kxtj3_write_register(dev, KXTJ3_SELF_TEST, KXTJ3_SELF_TEST_MEMS_TEST_DISABLE); + + if (!kxtj3_check_self_test_difference(coordinates_before_test, coordinates_during_test)) + return UPM_ERROR_OPERATION_FAILED; + + kxtj3_set_sensor_standby(dev); + if (kxtj3_self_test_digital_communication(dev) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + return kxtj3_set_sensor_active(dev); +} + +upm_result_t kxtj3_sensor_software_reset(const kxtj3_context dev) +{ + assert(dev != NULL); + if (kxtj3_set_bit_on(dev, KXTJ3_CTRL_REG2, KXTJ3_CTRL_REG2_SRST) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + uint8_t ctrl_reg2_data; + kxtj3_read_register(dev, KXTJ3_CTRL_REG2, &ctrl_reg2_data); + + uint8_t srst_counter = 0; + while ((ctrl_reg2_data & KXTJ3_CTRL_REG2_SRST) != 0x00 && srst_counter < SW_RESET_MAX_LOOP_COUNT) + { + usleep(SW_RESET_READ_WAIT_MICRO_S); + kxtj3_read_register(dev, KXTJ3_CTRL_REG2, &ctrl_reg2_data); + srst_counter++; + } + + if (srst_counter == SW_RESET_MAX_LOOP_COUNT) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +static bool kxtj3_is_14_bit_range(KXTJ3_G_RANGE_T g_range_mode) +{ + return g_range_mode == KXTJ3_RANGE_8G_14 || g_range_mode == KXTJ3_RANGE_16G_14; +} + +upm_result_t kxtj3_get_acceleration_data_raw(const kxtj3_context dev, float *x, float *y, float *z) +{ + uint8_t buffer[DATA_BUFFER_LENGTH]; + if (kxtj3_read_registers(dev, KXTJ3_XOUT_L, buffer, DATA_BUFFER_LENGTH) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (dev->res_mode == HIGH_RES) + { + uint8_t shift_amount = 4; + if (kxtj3_is_14_bit_range(dev->g_range_mode)) + shift_amount = 2; + + if (x) + *x = (float)((int16_t)((buffer[1] << 8) | buffer[0]) >> shift_amount); + if (y) + *y = (float)((int16_t)((buffer[3] << 8) | buffer[2]) >> shift_amount); + if (z) + *z = (float)((int16_t)((buffer[5] << 8) | buffer[4]) >> shift_amount); + } + else + { + if (x) + *x = (float)(int8_t)buffer[1]; + if (y) + *y = (float)(int8_t)buffer[3]; + if (z) + *z = (float)(int8_t)buffer[5]; + } + + return UPM_SUCCESS; +} + +upm_result_t kxtj3_get_acceleration_data(const kxtj3_context dev, float *x, float *y, float *z) +{ + float x_raw, y_raw, z_raw; + + if (kxtj3_get_acceleration_data_raw(dev, &x_raw, &y_raw, &z_raw) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (x) + *x = (x_raw * dev->acceleration_scale) * EARTH_GRAVITY; + if (y) + *y = (y_raw * dev->acceleration_scale) * EARTH_GRAVITY; + if (z) + *z = (z_raw * dev->acceleration_scale) * EARTH_GRAVITY; + + return UPM_SUCCESS; +} + +float kxtj3_get_acceleration_sampling_period(kxtj3_context dev) +{ + return dev->odr_in_sec; +} + +float kxtj3_get_wakeup_sampling_period(kxtj3_context dev) +{ + return dev->odr_in_sec_wakeup; +} + +upm_result_t kxtj3_enable_data_ready_interrupt(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_on(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_DRDYE); +} + +upm_result_t kxtj3_disable_data_ready_interrupt(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_off(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_DRDYE); +} + +upm_result_t kxtj3_enable_wakeup_interrupt(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_on(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_WUFE); +} + +upm_result_t kxtj3_disable_wakeup_interrupt(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_off(dev, KXTJ3_CTRL_REG1, KXTJ3_CTRL_REG1_WUFE); +} + +upm_result_t kxtj3_enable_interrupt_pin(const kxtj3_context dev, KXTJ3_INTERRUPT_POLARITY_T polarity, + KXTJ3_INTERRUPT_RESPONSE_T response_type) +{ + assert(dev != NULL); + uint8_t int_reg_value; + kxtj3_read_register(dev, KXTJ3_INT_CTRL_REG1, &int_reg_value); + + if (polarity) + polarity = KXTJ3_INT_CTRL_REG1_IEA; + if (response_type) + response_type = KXTJ3_INT_CTRL_REG1_IEL; + + int_reg_value &= ~(KXTJ3_INT_CTRL_REG1_IEA | KXTJ3_INT_CTRL_REG1_IEL); + int_reg_value |= (KXTJ3_INT_CTRL_REG1_IEN | polarity | response_type); + + return kxtj3_write_register(dev, KXTJ3_INT_CTRL_REG1, int_reg_value); +} + +upm_result_t kxtj3_disable_interrupt_pin(const kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_off(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_IEN); +} + +upm_result_t kxtj3_set_interrupt_polarity(const kxtj3_context dev, KXTJ3_INTERRUPT_POLARITY_T polarity) +{ + assert(dev != NULL); + if (polarity == ACTIVE_HIGH) + return kxtj3_set_bit_on(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_IEA); + + return kxtj3_set_bit_off(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_IEA); +} + +upm_result_t kxtj3_set_interrupt_response(const kxtj3_context dev, KXTJ3_INTERRUPT_RESPONSE_T response_type) +{ + assert(dev != NULL); + if (response_type == LATCH_UNTIL_CLEARED) + return kxtj3_set_bit_on(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_IEL); + + return kxtj3_set_bit_off(dev, KXTJ3_INT_CTRL_REG1, KXTJ3_INT_CTRL_REG1_IEL); +} + +bool kxtj3_get_interrupt_status(const kxtj3_context dev) +{ + assert(dev != NULL); + uint8_t status_reg_value; + kxtj3_read_register(dev, KXTJ3_STATUS_REG, &status_reg_value); + if (!(status_reg_value & KXTJ3_STATUS_REG_INT)) + return false; + + return true; +} + +upm_result_t kxtj3_read_interrupt_source1_reg(const kxtj3_context dev, uint8_t *reg_value) +{ + assert(dev != NULL); + return kxtj3_read_register(dev, KXTJ3_INT_SOURCE1, reg_value); +} + +KXTJ3_INTERRUPT_SOURCE_T kxtj3_get_interrupt_source(const kxtj3_context dev) +{ + assert(dev != NULL); + if (kxtj3_get_interrupt_status(dev)) + { + uint8_t int_source_reg; + kxtj3_read_interrupt_source1_reg(dev, &int_source_reg); + + int_source_reg &= (KXTJ3_INT_SOURCE1_DRDY | KXTJ3_INT_SOURCE1_WUFS); + switch (int_source_reg) + { + case KXTJ3_INT_SOURCE1_DRDY: + return KXTJ3_DATA_READY_INTERRUPT; + case KXTJ3_INT_SOURCE1_WUFS: + return KXTJ3_WAKEUP_INTERRUPT; + case KXTJ3_INT_SOURCE1_DRDY | KXTJ3_INT_SOURCE1_WUFS: + return KXTJ3_DATA_READY_AND_WAKEUP_INT; + } + } + return NO_INTERRUPT; +} + +upm_result_t kxtj3_install_isr(const kxtj3_context dev, mraa_gpio_edge_t edge, int pin, void (*isr)(void *), void *isr_args) +{ + assert(dev != NULL); + mraa_gpio_context isr_gpio = NULL; + if (!(isr_gpio = mraa_gpio_init(pin))) + { + printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + mraa_gpio_dir(isr_gpio, MRAA_GPIO_IN); + + if (mraa_gpio_isr(isr_gpio, edge, isr, isr_args) != MRAA_SUCCESS) + { + mraa_gpio_close(isr_gpio); + printf("%s: mraa_gpio_isr() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + dev->interrupt_pin = isr_gpio; + return UPM_SUCCESS; +} + +void kxtj3_uninstall_isr(const kxtj3_context dev) +{ + assert(dev != NULL); + mraa_gpio_isr_exit(dev->interrupt_pin); + mraa_gpio_close(dev->interrupt_pin); + dev->interrupt_pin = NULL; +} + +upm_result_t kxtj3_clear_interrupt_information(kxtj3_context dev) +{ + assert(dev != NULL); + uint8_t int_rel_value; + return kxtj3_read_register(dev, KXTJ3_INT_REL, &int_rel_value); +} + +upm_result_t kxtj3_enable_wakeup_single_axis_direction(kxtj3_context dev, KXTJ3_WAKEUP_SOURCE_T axis) +{ + assert(dev != NULL); + return kxtj3_set_bit_on(dev, KXTJ3_INT_CTRL_REG2, axis); +} + +upm_result_t kxtj3_disable_wakeup_single_axis_direction(kxtj3_context dev, KXTJ3_WAKEUP_SOURCE_T axis) +{ + assert(dev != NULL); + return kxtj3_set_bit_off(dev, KXTJ3_INT_CTRL_REG2, axis); +} + +kxtj3_wakeup_axes kxtj3_get_wakeup_axis_and_direction(kxtj3_context dev) +{ + assert(dev != NULL); + + uint8_t int_source2_value; + kxtj3_read_register(dev, KXTJ3_INT_SOURCE2, &int_source2_value); + + kxtj3_wakeup_axes wakeup_axis; + wakeup_axis.X_NEGATIVE = false; + wakeup_axis.X_POSITIVE = false; + wakeup_axis.Y_POSITIVE = false; + wakeup_axis.Y_NEGATIVE = false; + wakeup_axis.Z_POSITIVE = false; + wakeup_axis.Z_NEGATIVE = false; + + if (int_source2_value & KXTJ3_INT_SOURCE2_XPWU) + wakeup_axis.X_POSITIVE = true; + else if (int_source2_value & KXTJ3_INT_SOURCE2_XNWU) + wakeup_axis.X_NEGATIVE = true; + if (int_source2_value & KXTJ3_INT_SOURCE2_YPWU) + wakeup_axis.Y_POSITIVE = true; + else if (int_source2_value & KXTJ3_INT_SOURCE2_YNWU) + wakeup_axis.Y_NEGATIVE = true; + if (int_source2_value & KXTJ3_INT_SOURCE2_ZPWU) + wakeup_axis.Z_POSITIVE = true; + else if (int_source2_value & KXTJ3_INT_SOURCE2_ZNWU) + wakeup_axis.Z_NEGATIVE = true; + + return wakeup_axis; +} + +upm_result_t kxtj3_enable_wakeup_latch(kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_off(dev, KXTJ3_INT_CTRL_REG2, KXTJ3_INT_CTRL_REG2_ULMODE); +} + +upm_result_t kxtj3_disable_wakeup_latch(kxtj3_context dev) +{ + assert(dev != NULL); + return kxtj3_set_bit_on(dev, KXTJ3_INT_CTRL_REG2, KXTJ3_INT_CTRL_REG2_ULMODE); +} + +upm_result_t kxtj3_set_wakeup_motion_counter(kxtj3_context dev, uint8_t count) +{ + assert(dev != NULL); + if (count == 0) + return UPM_ERROR_OPERATION_FAILED; + return kxtj3_write_register(dev, KXTJ3_WAKEUP_COUNTER, count); +} + +static uint8_t kxtj3_get_wakeup_count_from_time_sec(kxtj3_context dev, float time_sec) +{ + return time_sec / dev->odr_in_sec_wakeup; +} + +upm_result_t kxtj3_set_wakeup_motion_time(kxtj3_context dev, float desired_time) +{ + assert(dev != NULL); + uint8_t count = kxtj3_get_wakeup_count_from_time_sec(dev, desired_time); + return kxtj3_set_wakeup_motion_counter(dev, count); +} + +upm_result_t kxtj3_get_wakeup_motion_time(kxtj3_context dev, float *out_time) +{ + assert(dev != NULL); + uint8_t motion_count; + if (kxtj3_read_register(dev, KXTJ3_WAKEUP_COUNTER, &motion_count) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + *out_time = (float)motion_count * dev->odr_in_sec_wakeup; + + return UPM_SUCCESS; +} + +upm_result_t kxtj3_set_wakeup_non_activity_counter(kxtj3_context dev, uint8_t count) +{ + assert(dev != NULL); + if (count == 0) + return UPM_ERROR_OPERATION_FAILED; + return kxtj3_write_register(dev, KXTJ3_NA_COUNTER, count); +} + +upm_result_t kxtj3_set_wakeup_non_activity_time(kxtj3_context dev, float desired_time) +{ + assert(dev != NULL); + uint8_t count = kxtj3_get_wakeup_count_from_time_sec(dev, desired_time); + return kxtj3_set_wakeup_non_activity_counter(dev, count); +} + +upm_result_t kxtj3_get_wakeup_non_activity_time(kxtj3_context dev, float *out_time) +{ + assert(dev != NULL); + uint8_t non_activity_reg_count; + if (kxtj3_read_register(dev, KXTJ3_NA_COUNTER, &non_activity_reg_count) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + *out_time = (float)non_activity_reg_count * dev->odr_in_sec_wakeup; + + return UPM_SUCCESS; +} + +upm_result_t kxtj3_set_wakeup_threshold_counter(kxtj3_context dev, uint16_t count) +{ + assert(dev != NULL); + if (count == 0) + return UPM_ERROR_OPERATION_FAILED; + if (kxtj3_write_register(dev, KXTJ3_WAKEUP_THRESHOLD_H, (uint8_t)(count >> 4)) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (kxtj3_write_register(dev, KXTJ3_WAKEUP_THRESHOLD_L, (uint8_t)(count << 4)) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +static uint16_t kxtj3_get_wakeup_threshold_count_from_g(kxtj3_context dev, float g_threshold) +{ + return g_threshold * 256; +} + +upm_result_t kxtj3_set_wakeup_threshold_g_value(kxtj3_context dev, float g_threshold) +{ + assert(dev != NULL); + uint16_t count = kxtj3_get_wakeup_threshold_count_from_g(dev, g_threshold); + return kxtj3_set_wakeup_threshold_counter(dev, count); +} + +upm_result_t kxtj3_get_wakeup_threshold(kxtj3_context dev, float *out_threshold) +{ + assert(dev != NULL); + uint8_t reg_value_h, reg_value_l; + if (kxtj3_read_register(dev, KXTJ3_WAKEUP_THRESHOLD_H, ®_value_h) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + if (kxtj3_read_register(dev, KXTJ3_WAKEUP_THRESHOLD_L, ®_value_l) != UPM_SUCCESS) + return UPM_ERROR_OPERATION_FAILED; + + *out_threshold = (float)((uint16_t)((reg_value_h << 8) | reg_value_l) >> 4) / 256; + + return UPM_SUCCESS; +} diff --git a/src/kxtj3/kxtj3.cxx b/src/kxtj3/kxtj3.cxx new file mode 100755 index 00000000..1afd3fe6 --- /dev/null +++ b/src/kxtj3/kxtj3.cxx @@ -0,0 +1,315 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +#include "kxtj3.hpp" + +using namespace upm; + +KXTJ3::KXTJ3(int bus, uint8_t addr) : m_kxtj3(kxtj3_init(bus, addr)) +{ + if (!m_kxtj3) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_init() failed"); +} + +KXTJ3::~KXTJ3() +{ + kxtj3_close(m_kxtj3); +} + +void KXTJ3::SensorInit(KXTJ3_ODR_T odr, KXTJ3_RESOLUTION_T resolution, KXTJ3_G_RANGE_T g_range) +{ + if (kxtj3_sensor_init(m_kxtj3, odr, resolution, g_range) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_sensor_init() failed"); +} + +uint8_t KXTJ3::GetWhoAmI() +{ + uint8_t who_am_i; + if (kxtj3_get_who_am_i(m_kxtj3, &who_am_i) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_get_who_am_i() failed"); + + return who_am_i; +} + +void KXTJ3::SensorActive() +{ + if (kxtj3_set_sensor_active(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_sensor_active() failed"); +} + +void KXTJ3::SensorStandby() +{ + if (kxtj3_set_sensor_standby(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_sensor_standby() failed"); +} + +void KXTJ3::SetGRange(KXTJ3_G_RANGE_T g_range) +{ + if (kxtj3_set_g_range(m_kxtj3, g_range) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_g_range() failed"); +} + +void KXTJ3::SetResolution(KXTJ3_RESOLUTION_T resolution) +{ + if (kxtj3_set_resolution(m_kxtj3, resolution) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_resolution() failed"); +} + +void KXTJ3::SetOdr(KXTJ3_ODR_T odr) +{ + if (kxtj3_set_odr(m_kxtj3, odr) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_odr() failed"); +} + +void KXTJ3::SetOdrForWakeup(KXTJ3_ODR_WAKEUP_T odr) +{ + if (kxtj3_set_odr_wakeup_function(m_kxtj3, odr) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_odr_wakeup_function() failed"); +} + +void KXTJ3::SelfTestDigitalCommunication() +{ + if (kxtj3_self_test_digital_communication(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_self_test_digital_communication() failed"); +} + +void KXTJ3::SensorSelfTest() +{ + if (kxtj3_sensor_self_test(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_sensor_self_test() failed"); +} + +void KXTJ3::SensorSoftwareReset() +{ + if (kxtj3_sensor_software_reset(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_sensor_software_reset() failed"); +} + +std::vector KXTJ3::GetAccelerationRawVector() +{ + std::vector xyz(3); + if (kxtj3_get_acceleration_data_raw(m_kxtj3, &xyz[0], &xyz[1], &xyz[2]) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_get_acceleration_data_raw() failed"); + + return xyz; +} + +std::vector KXTJ3::GetAccelerationVector() +{ + std::vector xyz(3); + if (kxtj3_get_acceleration_data(m_kxtj3, &xyz[0], &xyz[1], &xyz[2]) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_get_acceleration_data() failed"); + + return xyz; +} + +float KXTJ3::GetAccelerationSamplePeriod() +{ + return kxtj3_get_acceleration_sampling_period(m_kxtj3); +} + +float KXTJ3::GetWakeUpSamplePeriod() +{ + return kxtj3_get_wakeup_sampling_period(m_kxtj3); +} + +void KXTJ3::EnableDataReadyInterrupt() +{ + if (kxtj3_enable_data_ready_interrupt(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_enable_data_ready_interrupt() failed"); +} + +void KXTJ3::DisableDataReadyInterrupt() +{ + if (kxtj3_disable_data_ready_interrupt(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_disable_data_ready_interrupt() failed"); +} + +void KXTJ3::EnableWakeUpInterrupt() +{ + if (kxtj3_enable_wakeup_interrupt(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_enable_wakeup_interrupt() failed"); +} + +void KXTJ3::DisableWakeUpInterrupt() +{ + if (kxtj3_disable_wakeup_interrupt(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_disable_wakeup_interrupt() failed"); +} + +void KXTJ3::EnableInterruptPin(KXTJ3_INTERRUPT_POLARITY_T polarity, KXTJ3_INTERRUPT_RESPONSE_T response_type) +{ + if (kxtj3_enable_interrupt_pin(m_kxtj3, polarity, response_type) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_enable_interrupt_pin() failed"); +} + +void KXTJ3::DisableInterruptPin() +{ + if (kxtj3_disable_interrupt_pin(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_disable_interrupt_pin() failed"); +} + +void KXTJ3::SetInterruptPolarity(KXTJ3_INTERRUPT_POLARITY_T polarity) +{ + if (kxtj3_set_interrupt_polarity(m_kxtj3, polarity) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_interrupt_polarity() failed"); +} + +void KXTJ3::SetInerruptResponse(KXTJ3_INTERRUPT_RESPONSE_T response_type) +{ + if (kxtj3_set_interrupt_response(m_kxtj3, response_type) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_interrupt_response() failed"); +} + +bool KXTJ3::GetInterruptStatus() +{ + return kxtj3_get_interrupt_status(m_kxtj3); +} + +uint8_t KXTJ3::ReadInterruptSource1() +{ + uint8_t reg_value; + if (kxtj3_read_interrupt_source1_reg(m_kxtj3, ®_value) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_read_interrupt_source1_reg() failed"); + + return reg_value; +} + +KXTJ3_INTERRUPT_SOURCE_T KXTJ3::GetInterruptSource() +{ + return kxtj3_get_interrupt_source(m_kxtj3); +} + +void KXTJ3::InstallIsr(mraa_gpio_edge_t edge, int pin, void (*isr)(void *), void *isr_args) +{ + if (kxtj3_install_isr(m_kxtj3, edge, pin, isr, isr_args) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_install_isr() failed"); +} + +void KXTJ3::UninstallIsr() +{ + kxtj3_uninstall_isr(m_kxtj3); +} + +void KXTJ3::ClearInterrupt() +{ + if (kxtj3_clear_interrupt_information(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_clear_interrupt_information() failed"); +} + +void KXTJ3::EnableWakeUpSingleAxisDirection(KXTJ3_WAKEUP_SOURCE_T axis) +{ + if (kxtj3_enable_wakeup_single_axis_direction(m_kxtj3, axis) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_enable_wakeup_single_axis_direction() failed"); +} + +void KXTJ3::DisableWakeUpSingleAxisDirection(KXTJ3_WAKEUP_SOURCE_T axis) +{ + if (kxtj3_disable_wakeup_single_axis_direction(m_kxtj3, axis) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_disable_wakeup_single_axis_direction() failed"); +} + +kxtj3_wakeup_axes KXTJ3::GetWakeUpAxisDirection() +{ + return kxtj3_get_wakeup_axis_and_direction(m_kxtj3); +} + +void KXTJ3::EnableWakeUpLatch() +{ + if (kxtj3_enable_wakeup_latch(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_enable_wakeup_latch() failed"); +} + +void KXTJ3::DisableWakeUpLatch() +{ + if (kxtj3_disable_wakeup_latch(m_kxtj3) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_disable_wakeup_latch() failed"); +} + +void KXTJ3::SetWakeUpMotionCounter(uint8_t count) +{ + if (kxtj3_set_wakeup_motion_counter(m_kxtj3, count) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_wakeup_motion_counter() failed"); +} + +void KXTJ3::SetWakeUpMotionTime(float desired_time) +{ + if (kxtj3_set_wakeup_motion_time(m_kxtj3, desired_time) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_wakeup_motion_time() failed"); +} + +float KXTJ3::GetWakeUpMotionTime() +{ + float out_time; + if (kxtj3_get_wakeup_motion_time(m_kxtj3, &out_time) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_get_wakeup_motion_time() failed"); + + return out_time; +} + +void KXTJ3::SetWakeUpNonActivityCounter(uint8_t count) +{ + if (kxtj3_set_wakeup_non_activity_counter(m_kxtj3, count) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_wakeup_non_activity_counter() failed"); +} + +void KXTJ3::SetWakeUpNonActivityTime(float desired_time) +{ + if (kxtj3_set_wakeup_non_activity_time(m_kxtj3, desired_time) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_wakeup_non_activity_time() failed"); +} + +float KXTJ3::GetWakeUpNonActivityTime() +{ + float out_time; + if (kxtj3_get_wakeup_non_activity_time(m_kxtj3, &out_time) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_get_wakeup_non_activity_time() failed"); + + return out_time; +} + +void KXTJ3::SetWakeUpThresholdCounter(uint16_t count) +{ + if (kxtj3_set_wakeup_threshold_counter(m_kxtj3, count) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_wakeup_threshold_counter() failed"); +} + +void KXTJ3::SetWakeUpThresholdGRange(float g_threshold) +{ + if (kxtj3_set_wakeup_threshold_g_value(m_kxtj3, g_threshold) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_set_wakeup_threshold_g_value() failed"); +} + +float KXTJ3::GetWakeUpThresholdGRange() +{ + float out_threshold; + if (kxtj3_get_wakeup_threshold(m_kxtj3, &out_threshold) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + "kxtj3_get_wakeup_threshold() failed"); + + return out_threshold; +} \ No newline at end of file diff --git a/src/kxtj3/kxtj3.h b/src/kxtj3/kxtj3.h new file mode 100755 index 00000000..bac24122 --- /dev/null +++ b/src/kxtj3/kxtj3.h @@ -0,0 +1,746 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +#include +#include +#include + +#include "kxtj3_registers.h" + + /** + * @brief C API for the kxtj3 driver + * @defgroup kxtj3 libupm-kxtj3 + * @ingroup Kionix i2c accelerometer + * + * @include kxtj3.c + */ + + /** + * @library kxtj3 + * @sensor kxtj3 + * @comname tri-axis accelerometer + * @type accelerometer + * @man Kionix + * @con i2c + * + * @brief C API for the kxtj3 driver + * + * @image html kxtj3.png + */ + +#define SECOND_IN_MICRO_S 1000000 + + /** + * @brief Resolution types + */ + typedef enum + { + LOW_RES, + HIGH_RES + } KXTJ3_RESOLUTION_T; + + /** + * @brief Interrupt polarity types + */ + typedef enum + { + ACTIVE_LOW, + ACTIVE_HIGH + + } KXTJ3_INTERRUPT_POLARITY_T; + + /** + * @brief Interrupt response types + */ + typedef enum + { + LATCH_UNTIL_CLEARED, + TRANSMIT_ONE_PULSE + } KXTJ3_INTERRUPT_RESPONSE_T; + + /** + * @brief Interrupt sources + */ + typedef enum + { + NO_INTERRUPT, + KXTJ3_DATA_READY_INTERRUPT = KXTJ3_INT_SOURCE1_DRDY, + KXTJ3_WAKEUP_INTERRUPT = KXTJ3_INT_SOURCE1_WUFS, + KXTJ3_DATA_READY_AND_WAKEUP_INT = KXTJ3_INT_SOURCE1_DRDY | KXTJ3_INT_SOURCE1_WUFS + } KXTJ3_INTERRUPT_SOURCE_T; + + /** + * @brief Acceleration ranges + */ + typedef enum + { + KXTJ3_RANGE_2G = KXTJ3_CTRL_REG1_GSEL_2G, + KXTJ3_RANGE_4G = KXTJ3_CTRL_REG1_GSEL_4G, + KXTJ3_RANGE_8G = KXTJ3_CTRL_REG1_GSEL_8G, + KXTJ3_RANGE_8G_14 = KXTJ3_CTRL_REG1_GSEL_8G_14, + KXTJ3_RANGE_16G = KXTJ3_CTRL_REG1_GSEL_16G, + KXTJ3_RANGE_16G_2 = KXTJ3_CTRL_REG1_GSEL_16G2, + KXTJ3_RANGE_16G_3 = KXTJ3_CTRL_REG1_GSEL_16G3, + KXTJ3_RANGE_16G_14 = KXTJ3_CTRL_REG1_GSEL_16G_14 + } KXTJ3_G_RANGE_T; + + /** + * @brief Output Data Rates for normal mode + */ + typedef enum + { + KXTJ3_ODR_0P781 = KXTJ3_DATA_CTRL_REG_OSA_0P781, + KXTJ3_ODR_1P563 = KXTJ3_DATA_CTRL_REG_OSA_1P563, + KXTJ3_ODR_3P125 = KXTJ3_DATA_CTRL_REG_OSA_3P125, + KXTJ3_ODR_6P25 = KXTJ3_DATA_CTRL_REG_OSA_6P25, + KXTJ3_ODR_12P5 = KXTJ3_DATA_CTRL_REG_OSA_12P5, + KXTJ3_ODR_25 = KXTJ3_DATA_CTRL_REG_OSA_25, + KXTJ3_ODR_50 = KXTJ3_DATA_CTRL_REG_OSA_50, + KXTJ3_ODR_100 = KXTJ3_DATA_CTRL_REG_OSA_100, + KXTJ3_ODR_200 = KXTJ3_DATA_CTRL_REG_OSA_200, + KXTJ3_ODR_400 = KXTJ3_DATA_CTRL_REG_OSA_400, + KXTJ3_ODR_800 = KXTJ3_DATA_CTRL_REG_OSA_800, + KXTJ3_ODR_1600 = KXTJ3_DATA_CTRL_REG_OSA_1600 + } KXTJ3_ODR_T; + + /** + * @brief Output Data Rates for wake-up function + */ + typedef enum + { + KXTJ3_ODR_WAKEUP_0P781 = KXTJ3_CTRL_REG2_OWUF_0P781, + KXTJ3_ODR_WAKEUP_1P563 = KXTJ3_CTRL_REG2_OWUF_1P563, + KXTJ3_ODR_WAKEUP_3P125 = KXTJ3_CTRL_REG2_OWUF_3P125, + KXTJ3_ODR_WAKEUP_6P25 = KXTJ3_CTRL_REG2_OWUF_6P25, + KXTJ3_ODR_WAKEUP_12P5 = KXTJ3_CTRL_REG2_OWUF_12P5, + KXTJ3_ODR_WAKEUP_25 = KXTJ3_CTRL_REG2_OWUF_25, + KXTJ3_ODR_WAKEUP_50 = KXTJ3_CTRL_REG2_OWUF_50, + KXTJ3_ODR_WAKEUP_100 = KXTJ3_CTRL_REG2_OWUF_100 + } KXTJ3_ODR_WAKEUP_T; + + /** + * @brief Wake-up source axis and direction + */ + typedef enum + { + X_NEGATIVE = KXTJ3_INT_CTRL_REG2_XNWU, + X_POSITIVE = KXTJ3_INT_CTRL_REG2_XPWU, + Y_NEGATIVE = KXTJ3_INT_CTRL_REG2_YNWU, + Y_POSITIVE = KXTJ3_INT_CTRL_REG2_YPWU, + Z_NEGATIVE = KXTJ3_INT_CTRL_REG2_ZNWU, + Z_POSITIVE = KXTJ3_INT_CTRL_REG2_ZPWU + } KXTJ3_WAKEUP_SOURCE_T; + + /** + * @brief Use it to get axis and direction for wake-up function + */ + typedef struct + { + bool X_NEGATIVE, + X_POSITIVE, + Y_NEGATIVE, + Y_POSITIVE, + Z_NEGATIVE, + Z_POSITIVE; + } kxtj3_wakeup_axes; + + /** + * @brief Sensor context + */ + typedef struct _kxtj3_context + { + mraa_i2c_context i2c; + KXTJ3_RESOLUTION_T res_mode; + KXTJ3_G_RANGE_T g_range_mode; + float acceleration_scale; + KXTJ3_ODR_T odr; + float odr_in_sec; + KXTJ3_ODR_WAKEUP_T odr_wakeup; + float odr_in_sec_wakeup; + mraa_gpio_context interrupt_pin; + } * kxtj3_context; + + /** +@brief KXTJ3 initialization. Sets sensor default values and put it to active state. + +@param bus I2C bus to use +@param addr I2C address of the sensor +@return The sensor context, or NULL if an error occurs +*/ + kxtj3_context kxtj3_init(int bus, uint8_t addr); + + /** +@brief Intilializes the sensor with the given resolution and acceleration range + +This gets called during the kxtj3_init(), so it will not need to be called unless the sensor is reset + +Sensor is automatically set into standby mode during the initialization +Sensor is set to active mode after initialization + +Be cautious not to set resolution to LOW_RES along with g_range as 14-bits modes + +@param dev The sensor context +@param odr Output Data Rate, One of the KXTJ3_ODR_T values +@param res Resolution mode, One of the KXTJ3_RESOLUTION_T values. LOW_RES valid only for ODR <= 200 Hz. +@param g_range Acceleration range, One of the KXTJ3_G_RANGE_T values +@return UPM result +*/ + upm_result_t kxtj3_sensor_init(const kxtj3_context dev, KXTJ3_ODR_T odr, KXTJ3_RESOLUTION_T res, KXTJ3_G_RANGE_T g_range); + + /** +@brief Gets "who am I" value of the sensor + +@param dev The sensor context +@param data Pointer to a uint8_t variable to store the value +@return UPM result +*/ + upm_result_t kxtj3_get_who_am_i(const kxtj3_context dev, uint8_t *data); + + /** +@brief KXTJ3 destructor +Closes the I2C context, and removes interrupts +Frees memory of the kxtj3_context + +@param dev The sensor context +*/ + void kxtj3_close(kxtj3_context dev); + + /** +@brief Sets the sensor to active mode + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_set_sensor_active(const kxtj3_context dev); + + /** +@brief Sets the sensor to the standby mode + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_set_sensor_standby(const kxtj3_context dev); + + /** +@brief Sets the acceleration range of the sensor + +Sensor needs to be in standby mode when setting the acceleration range value + +Be cautious not to set g_range to 14-bits modes with the resolution being on LOW_RES. +If the acceleration range is not compatible with resolution mode, the resolution is set automatically +to the compatible value. + +@param dev The sensor context +@param g_range One of the KXTJ3_G_RANGE_T values +@return UPM result +*/ + upm_result_t kxtj3_set_g_range(const kxtj3_context dev, KXTJ3_G_RANGE_T g_range); + + /** +@brief Sets the resolution of the sensor. High resolution (14 bits and 12 bits) or low resolution (8 bits). + +LOW_RES valid only for ODR <= 200 Hz + +Be cautious not to set resolution to LOW_RES with the G_RANG being on 14-bits modes. +If the resolution mode is not compatible with acceleration range, the resolution is set automatically +to the compatible value. + +Sensor needs to be in standby mode when setting the sensor resolution + +@param dev The sensor context +@param resolution One of the KXTJ3_RESOLUTION_T values +@return UPM result +*/ + upm_result_t kxtj3_set_resolution(const kxtj3_context dev, KXTJ3_RESOLUTION_T resolution); + + /** +@brief Sets the ODR of the sensor + +Sensor needs to be in standby mode when setting the ODR + +@param dev The sensor context +@param odr One of the KXTJ3_ODR_T values +@return UPM result +*/ + upm_result_t kxtj3_set_odr(const kxtj3_context dev, KXTJ3_ODR_T odr); + + /** +@brief Sets the ODR of the wakeup function of the sensor + +Sensor needs to be in standby mode when setting the ODR + +@param dev The sensor context +@param odr One of the KXTJ3_ODR_WAKEUP_T values +@return UPM result +*/ + upm_result_t kxtj3_set_odr_wakeup_function(const kxtj3_context dev, KXTJ3_ODR_WAKEUP_T odr); + + /** +@brief Performs a self-test for digital communication of the sensor. The test sets DCST bit in +CTRL_REG2, then checks the DCST_RESP register for a 0xAA, after the register is read, its +value is 0x55 and DCST bit is cleared. + +This function is called by kxtj3_sensor_self_test also + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_self_test_digital_communication(kxtj3_context dev); + + /** +@brief Performs a self-test of the sensor. The test applies an electrostatic force to the sensor, +simulating input acceleration. The test compares samples from all axis before and after +applying the electrostatic force to the sensor. If the amount of acceleration increases according +to the values defined in TABLE 1 of the datasheet (0.5 g), the test passes. + +The function prints out the values before and during test and the average difference for each axis + +See the datasheet for more information + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_sensor_self_test(const kxtj3_context dev); + + /** +@brief Performs a sensor software reset. The software reset clears the RAM of the sensor and resets all registers +to pre-defined values. + +You should call kxtj3_sensor_init() after the software reset + +See the datasheet for more details + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_sensor_software_reset(const kxtj3_context dev); + + /** +@brief Gets raw accelerometer data from the sensor + +@param dev The sensor context +@param x Pointer to a floating point variable to store the x-axis value. Set to NULL if not wanted. +@param y Pointer to a floating point variable to store the y-axis value. Set to NULL if not wanted. +@param z Pointer to a floating point variable to store the z-axis value. Set to NULL if not wanted. +@return UPM result +*/ + upm_result_t kxtj3_get_acceleration_data_raw(const kxtj3_context dev, float *x, float *y, float *z); + + /** +@brief Gets converted (m/s^2) accelerometer data from the sensor + +@param dev The sensor context +@param x Pointer to a floating point variable to store the x-axis value. Set to NULL if not wanted. +@param y Pointer to a floating point variable to store the y-axis value. Set to NULL if not wanted. +@param z Pointer to a floating point variable to store the z-axis value. Set to NULL if not wanted. +*/ + upm_result_t kxtj3_get_acceleration_data(const kxtj3_context dev, float *x, float *y, float *z); + + /** +@brief Gets the duration of one sample period (in seconds) for getting the acceleration data depending on +the sampling rate of the sensor + +@param dev The sensor context +@return Floating point value of the sampling period +*/ + float kxtj3_get_acceleration_sampling_period(kxtj3_context dev); + + /** +Gets the duration of one sample period (in seconds) for the wakeup function depending on +the sampling rate of the sensor wakeup function + +@param dev The sensor context +@return Floating point value of the sampling period +*/ + float kxtj3_get_wakeup_sampling_period(kxtj3_context dev); + + /** +@brief Enables the data ready interrupt. Availability of new acceleration data is +reflected as an interrupt. + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@return UPM result + */ + upm_result_t kxtj3_enable_data_ready_interrupt(const kxtj3_context dev); + + /** +@brief Disables the data ready interrupt + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_disable_data_ready_interrupt(const kxtj3_context dev); + + /** +@brief Enables the wakeup function (motion detection) + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@return UPM result + */ + upm_result_t kxtj3_enable_wakeup_interrupt(const kxtj3_context dev); + + /** +@brief Disables the wakeup function (motion detection) + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@return UPM result + */ + upm_result_t kxtj3_disable_wakeup_interrupt(const kxtj3_context dev); + + /** +@brief Enables interrupts on the interrupt pin, sets polarity and response types + +Polarity ACTIVE_HIGH or ACTIVE_LOW + +Response either latch until cleared by reading INT_REL register, or transmit one pulse +Pulse width of 0.03-0.05ms + +For Wakeup function, the response type is always latched unless set wakeup latch off + +Sensor needs to be in standby mode when enabling the interrupt + +See datasheet for more details + +@param dev The sensor context +@param polarity Select the polarity of the interrupt. One of the KXTJ3_INTERRUPT_POLARITY_T values. +@param response_type Select the response type of the interrupt. One of the KXTJ3_INTERRUPT_RESPONSE_T values. +@return UPM result +*/ + upm_result_t kxtj3_enable_interrupt_pin(const kxtj3_context dev, KXTJ3_INTERRUPT_POLARITY_T polarity, KXTJ3_INTERRUPT_RESPONSE_T response_type); + + /** +@brief Disables interrupts on the interrupt pin of the sensor + +Sensor needs to be in standby mode when disabling the interrupt pin + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_disable_interrupt_pin(const kxtj3_context dev); + + /** +@brief Sets the polarity of the interrupt pin + +Polarity ACTIVE_HIGH or ACTIVE_LOW + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@param polarity Select the polarity of the interrupt. One of the KXTJ3_INTERRUPT_POLARITY_T values. +@return UPM result +*/ + upm_result_t kxtj3_set_interrupt_polarity(const kxtj3_context dev, KXTJ3_INTERRUPT_POLARITY_T polarity); + + /** +@brief Sets the response type of the interrupt pin + +Response either latch until cleared by reading INT_REL register, or transmit one pulse +Pulse width of 0.03-0.05ms + +For Wakeup function, the response type is always latched unless set wakeup latch off + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param response_type Select the response type of the interrupt. One of the KXTJ3_INTERRUPT_RESPONSE_T values. +@return UPM result +*/ + upm_result_t kxtj3_set_interrupt_response(const kxtj3_context dev, KXTJ3_INTERRUPT_RESPONSE_T response_type); + + /** +@brief Gets the status of the interrupts. (Has an interrupt occured). + +See datasheet for more details + +@param dev The sensor context +@return Return true if an interrupt event has occured (DRDY or WUFS is 1), returns false if no interrupts have occured +*/ + bool kxtj3_get_interrupt_status(const kxtj3_context dev); + + /** +@brief Gets the source of the interrupt +The value stored is one or more of the KXTJ3_INTERRUPT_SOURCE_T values + +See datasheet for more details + +@param dev The sensor context +@param reg_value Pointer to a uint8_t variable to store the value +@return UPM result +*/ + upm_result_t kxtj3_read_interrupt_source1_reg(const kxtj3_context dev, uint8_t *reg_value); + + /** +@brief Gets the source of the interrupt + +See datasheet for more details + +@param dev The sensor context +@return One of the KXTJ3_INTERRUPT_SOURCE_T values/types +*/ + KXTJ3_INTERRUPT_SOURCE_T kxtj3_get_interrupt_source(const kxtj3_context dev); + + /** +@brief Installs an interrupt handler to be executed when an interrupt is detected on the interrupt pin + +@param dev The sensor context +@param edge One of the mraa_gpio_edge_t values, Interrupt trigger edge +@param pin The GPIO pin to use as the interrupt pin +@param isr Pointer to the function to be called, when the interrupt occurs +@param isr_args The arguments to be passed to the function +@return UPM result +*/ + upm_result_t kxtj3_install_isr(const kxtj3_context dev, mraa_gpio_edge_t edge, int pin, void (*isr)(void *), void *isr_args); + + /** +@brief Uninstalls a previously installed interrupt handler for interrupt pin + +@param dev The sensor context +@return UPM result +*/ + void kxtj3_uninstall_isr(const kxtj3_context dev); + + /** +@brief Clears latching interrupts information of Wakeup (with axis and direction information) and Data Ready + +See datasheet for more details + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_clear_interrupt_information(kxtj3_context dev); + + /** +@brief Enables wakeup interrupt for the given axis (axis with direction) + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@param axis The axis to enable, takes one of KXTJ3_WAKEUP_SOURCE_T value +@return UPM result + */ + upm_result_t kxtj3_enable_wakeup_single_axis_direction(kxtj3_context dev, KXTJ3_WAKEUP_SOURCE_T axis); + + /** +@brief Disables wakeup interrupt for the given axis (axis with direction) + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@param axis The axis to enable, takes one of KXTJ3_WAKEUP_SOURCE_T value +@return UPM result + */ + upm_result_t kxtj3_disable_wakeup_single_axis_direction(kxtj3_context dev, KXTJ3_WAKEUP_SOURCE_T axis); + + /** +@brief Gets the source axis and direction of motion detection of the wakeup function interrupt + +See datasheet for more details + +@param dev The sensor context +@return A kxtj3_wakeup_axes struct with values of true/false for a wakeup for each axis and its direction +*/ + kxtj3_wakeup_axes kxtj3_get_wakeup_axis_and_direction(kxtj3_context dev); + + /** +@brief Enables the Unlached mode motion interrupt (ULMODE). This mode is always by default enabled. + +When this bit is set, the wakeup interrupt has to be cleared manually +(cannot use interrupt response with pulse) + +Sensor must be in standby mode before performing this action + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_enable_wakeup_latch(kxtj3_context dev); + + /** +@brief Disables the Unlached mode motion interrupt (ULMODE). This mode is always by default enabled +(cannot use interrupt response with pulse). + +The wakeup threshold is advised to not be very low to avoid interrupt being triggered in +an almost continuous manner + +Sensor must be in standby mode before performing this action + +When this bit is cleared, and the interrupt response type is set to Pulse, then upon a wakeup event +the wakeup interrupt signal will pulse and return low, but only once. Then, the interrupt +output will not reset until data is read or interrupt cleared. + +@param dev The sensor context +@return UPM result +*/ + upm_result_t kxtj3_disable_wakeup_latch(kxtj3_context dev); + + /** +@brief Sets the timer counter of motion before sending a wakeup interrupt + +The count is limited to values from 1 to 255 + +Every count is calculated as (1 / Wakeup_ODR_FREQUENCY) where Wakeup_ODR_FREQUENCY +is the current odr_in_Hz value from odr_map_in_Hz_wakeup value + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param count The timer count from 1 to 255 +@return UPM result + */ + upm_result_t kxtj3_set_wakeup_motion_counter(kxtj3_context dev, uint8_t count); + + /** +@brief Sets the timer of motion before sending a wakeup interrupt + +the desired time should be such that (0 < desired_time * wakeup_odr_frequency <= 255) + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param desired_time The desired time in seconds +@return UPM result + */ + upm_result_t kxtj3_set_wakeup_motion_time(kxtj3_context dev, float desired_time); + + /** +@brief Gets the current count value of the timer of motion before sending a wakeup interrupt + +@param dev The sensor context +@param out_time Pointer to a float variable to store the time value in seconds +@return UPM result + */ + upm_result_t kxtj3_get_wakeup_motion_time(kxtj3_context dev, float *out_time); + + /** +@brief Sets the timer counter of non-activity before sending another wakeup interrupt + +The count is limited to values from 1 to 255 + +Every count is calculated as (1 / Wakeup_ODR_FREQUENCY) where Wakeup_ODR_FREQUENCY +is the current odr_in_Hz value from odr_map_in_Hz_wakeup value + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param count The timer count from 1 to 255 +@return UPM result + */ + upm_result_t kxtj3_set_wakeup_non_activity_counter(kxtj3_context dev, uint8_t count); + + /** +@brief Sets the timer of non-activity before sending another wakeup interrupt + +the desired time should be such that (0 < desired_time * wakeup_odr_frequency <= 255) + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param desired_time The desired time in seconds +@return UPM result + */ + upm_result_t kxtj3_set_wakeup_non_activity_time(kxtj3_context dev, float desired_time); + + /** +@brief Gets the current count value of the timer of non-activity before sending another wakeup interrupt + +@param dev The sensor context +@param out_time Pointer to a float variable to store the time value in seconds +@return UPM result + */ + upm_result_t kxtj3_get_wakeup_non_activity_time(kxtj3_context dev, float *out_time); + + /** +@brief Sets the threshold counter for acceleration difference before sending a wakeup interrupt + +The count is limited to values from 1 to 4096, that it is 16g threshold with (3.9mg/count) +It is advised to not set the threshold to a very low value which may cause bad behaviour +in the wakeup interrupt + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param count The timer count from 1 to 4096, that it is 16g threshold with (3.9mg/count) +@return UPM result + */ + upm_result_t kxtj3_set_wakeup_threshold_counter(kxtj3_context dev, uint16_t count); + + /** +@brief Sets the threshold g value for acceleration difference before sending a wakeup interrupt + +The count is limited to values up to 16g, with steps of 3.9mg. It is advised to not set +the threshold to a very low value which may cause bad behaviour in the wakeup interrupt + +Sensor must be in standby mode before performing this action + +See datasheet for more details + +@param dev The sensor context +@param g_threshold The acceleration threshold (in g) in g, from 3.9mg to 16g, steps of 3.9mg/count +@return UPM result + */ + upm_result_t kxtj3_set_wakeup_threshold_g_value(kxtj3_context dev, float g_threshold); + + /** +@brief Gets the current threshold difference value before sending wakeup interrupt + +@param dev The sensor context +@param out_threshold Pointer to a float variable to store the threshold value in g +@return UPM result + */ + upm_result_t kxtj3_get_wakeup_threshold(kxtj3_context dev, float *out_threshold); + +#ifdef __cplusplus +} +#endif diff --git a/src/kxtj3/kxtj3.hpp b/src/kxtj3/kxtj3.hpp new file mode 100755 index 00000000..f7074d35 --- /dev/null +++ b/src/kxtj3/kxtj3.hpp @@ -0,0 +1,565 @@ +/* +* The MIT License (MIT) +* +* Author: Assam Boudjelthia +* Copyright (c) 2018 Rohm Semiconductor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +* the Software, and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include + +#include "kxtj3.h" + +/** + * @brief C API for the kxtj3 driver + * @defgroup kxtj3 libupm-kxtj3 + * @ingroup Kionix i2c accelerometer + * + * @include kxtj3.cxx + */ + +/** + * @library kxtj3 + * @sensor kxtj3 + * @comname tri-axis accelerometer + * @type accelerometer + * @man Kionix + * @con i2c + * + * @brief C++ API for the kxtj3 driver + * + * @image html kxtj3.png + */ + +namespace upm +{ +class KXTJ3 +{ +public: + /** + * @brief KXTJ3 constructor + * + * If no errors occur, the device is initialized with default values and set to active state + * + * @param bus I2C bus + * @param addr I2C address of the sensor + * @throws std::runtime_error on initialization failure + */ + KXTJ3(int bus = 0x00, uint8_t addr = 0x0f); + + /** + * @brief KXTJ3 destructor + * + * Closes the I2C context, and removes interrupts + * Frees memory of the kxtj3_context + * + * @throws std::runtime_error on initialization failure + */ + virtual ~KXTJ3(); + + /** + * @brief Initializes the sensor with given sampling rate, resolution and acceleration range. + * This gets called in the constructor, so it will not need to be called unless the device is reset. + * + * Sensor is set to standby mode during the initialization and back to active after initialization. + * + * @param odr One of the KXTJ3_ODR_T values + * @param resolution One of the KXTJ3_RESOLUTION_T values + * @param g_range One of the KXTJ3_G_RANGE_T values + * @throws std::runtime_error on failure + */ + void SensorInit(KXTJ3_ODR_T odr, KXTJ3_RESOLUTION_T resolution, KXTJ3_G_RANGE_T g_range); + + /** + * @brief Gets "who am I" value of the sensor + * + * @return Who am I value of the sensor + * @throws std::runtime_error on failure + */ + uint8_t GetWhoAmI(); + + /** + * @brief Sets the sensor to active mode + * + * @throws std::runtime_error on failure + */ + void SensorActive(); + + /** + * @brief Sets the sensor to standby mode + + * @throws std::runtime_error on failure + */ + void SensorStandby(); + + /** + * @brief Sets the acceleration range of the sensor + * + * Sensor needs to be in standby mode when setting the acceleration range value + * + * Be cautious not to set g_range to 14-bits modes with the resolution being on LOW_RES + * + * @param g_range One of the KXTJ3_G_RANGE_T values + * @throws std::runtime_error on failure + */ + void SetGRange(KXTJ3_G_RANGE_T g_range); + + /** + * @brief Sets the resolution of the sensor. High resolution (14 bits and 12 bits) or low resolution (8 bits). + * + * LOW_RES valid only for ODR <= 200 Hz + * + * Be cautious not to set resolution to LOW_RES with the G_RANG being on 14-bits modes + * + * Sensor needs to be in standby mode when setting the sensor resolution + * + * @param resolution One of the KXTJ3_RESOLUTION_T values + * @throws std::runtime_error on failure + */ + void SetResolution(KXTJ3_RESOLUTION_T resolution); + + /** + * @brief Sets the ODR of the sensor + * + * Sensor needs to be in standby mode when setting the ODR + * + * @param odr One of the KXTJ3_ODR_T values + * @throws std::runtime_error on failure + */ + void SetOdr(KXTJ3_ODR_T odr); + + /** + * @brief Sets the ODR of the wakeup function of the sensor + * + * Sensor needs to be in standby mode when setting the ODR + * + * @param odr One of the KXTJ3_ODR_WAKEUP_T values + * @throws std::runtime_error on failure + */ + void SetOdrForWakeup(KXTJ3_ODR_WAKEUP_T odr); + + /** + * @brief Performs a self-test for digital communication of the sensor. The test sets DCST bit in + * CTRL_REG2, then checks the DCST_RESP register for a 0xAA, after the register is read, its + * value is 0x55 and DCST bit is cleared. + * + * This method is called by SensorSelfTest also + * + * Sensor must be in standby mode before performing this action + * + * @throws std::runtime_error on failure + */ + void SelfTestDigitalCommunication(); + + /** + * @brief Performs a self-test of the sensor. The test applies an electrostatic force to the sensor, + * simulating input acceleration. The test compares samples from all axis before and after + * applying the electrostatic force to the sensor. If the amount of acceleration increases according + * to the values defined in TABLE 1 of the datasheet (0.5 g), the test passes. + * + * The method prints out the values before and during test and the average difference for each axis + * + * See the datasheet for more information + * + * @throws std::runtime_error on failure + */ + void SensorSelfTest(); + + /** + * @brief Performs a sensor software reset. The software reset clears the RAM of the sensor and resets all registers + * to pre-defined values. + * + * You should call kxtj3_sensor_init() after the software reset + * + * See the datasheet for more details + * + * @throws std::runtime_error on failure + */ + void SensorSoftwareReset(); + + /** + * Gets raw acceleration data from the sensor. + * + * @return Acceleration vector [x, y, z] + * @throws std::runtime_error on failure. + */ + std::vector GetAccelerationRawVector(); + + /** + * Gets acceleration data in (m/s^2) from the sensor. + * + * @return Acceleration vector [x, y, z] + * @throws std::runtime_error on failure. + */ + std::vector GetAccelerationVector(); + + /** + * @brief Gets the duration of one sample period (in seconds) for getting the acceleration data depending on + * the sampling rate of the sensor + * + * @return Floating point value of the sampling period + * @throws std::runtime_error on failure + */ + float GetAccelerationSamplePeriod(); + + /** + * @brief Gets the duration of one sample period (in seconds) for the wakeup function depending on + * the sampling rate of the sensor wakeup function + * + * @return Floating point value of the sampling period + * @throws std::runtime_error on failure + */ + float GetWakeUpSamplePeriod(); + + /** + * @brief Enables the data ready interrupt. Availability of new acceleration data is + * reflected as an interrupt. + * + * Sensor must be in standby mode before performing this action + * + * @throws std::runtime_error on failure + */ + void EnableDataReadyInterrupt(); + + /** + * @brief Disables the data ready interrupt + * + * Sensor must be in standby mode before performing this action + * + * @throws std::runtime_error on failure + */ + void DisableDataReadyInterrupt(); + + /** + * @brief Enables the wakeup function (motion detection) + * + * Sensor must be in standby mode before performing this action + * + * @throws std::runtime_error on failure + */ + void EnableWakeUpInterrupt(); + + /** + * @brief Disables the wakeup function (motion detection) + * + * Sensor must be in standby mode before performing this action + * + * @throws std::runtime_error on failure + */ + void DisableWakeUpInterrupt(); + + /** + * @brief Enables interrupts on the interrupt pin, sets polarity and response types. + * Polarity ACTIVE_HIGH or ACTIVE_LOW. + * Response either latch until cleared by reading INT_REL register, or transmit one pulse + * Pulse width of 0.03-0.05ms. + * + * For Wakeup function, the response type is always latched unless set wakeup latch off + * Sensor needs to be in standby mode when enabling the interrupt + * + * See datasheet for more details + * + * @param polarity Select the polarity of the interrupt. One of the KXTJ3_INTERRUPT_POLARITY_T values. + * @param response_type Select the response type of the interrupt. One of the KXTJ3_INTERRUPT_RESPONSE_T values. + * @throws std::runtime_error on failure + */ + void EnableInterruptPin(KXTJ3_INTERRUPT_POLARITY_T polarity, KXTJ3_INTERRUPT_RESPONSE_T response_type); + + /** + * @brief Disables interrupts on the interrupt pin of the sensor + * + * Sensor needs to be in standby mode when disabling the interrupt pin + * + * @throws std::runtime_error on failure + */ + void DisableInterruptPin(); + + /** + * @brief Sets the polarity of the interrupt pin + * + * Polarity ACTIVE_HIGH or ACTIVE_LOW + * + * Sensor must be in standby mode before performing this action + * + * @param polarity Select the polarity of the interrupt. One of the KXTJ3_INTERRUPT_POLARITY_T values. + * @throws std::runtime_error on failure + */ + void SetInterruptPolarity(KXTJ3_INTERRUPT_POLARITY_T polarity); + + /** + * @brief Sets the response type of the interrupt pin + * + * Response either latch until cleared by reading INT_REL register, or transmit one pulse + * Pulse width of 0.03-0.05ms + * + * For Wakeup function, the response type is always latched unless set wakeup latch off + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param response_type Select the response type of the interrupt. One of the KXTJ3_INTERRUPT_RESPONSE_T values + * @throws std::runtime_error on failure + */ + void SetInerruptResponse(KXTJ3_INTERRUPT_RESPONSE_T response_type); + + /** + * @brief Gets the status of the interrupts. (Has an interrupt occured) + * + * See datasheet for more details + * + * @return Return true if an interrupt event has occured (DRDY or WUFS is 1), + * returns false if no interrupts have occured + */ + bool GetInterruptStatus(); + + /** + * @brief Gets the source of the interrupt + * The value stored is one or more of the KXTJ3_INTERRUPT_SOURCE_T values + * + * See datasheet for more details + * + * @return Value of the interrupt source register + * @throws std::runtime_error on failure + */ + uint8_t ReadInterruptSource1(); + + /** + * @brief Gets the source of the interrupt + * + * See datasheet for more details + * + * @return One of the KXTJ3_INTERRUPT_SOURCE_T values/types + */ + KXTJ3_INTERRUPT_SOURCE_T GetInterruptSource(); + + /** + * @brief Installs an interrupt handler to be executed when an interrupt is detected on the interrupt pin + + * @param edge One of the mraa_gpio_edge_t values. Interrupt trigger edge. + * @param pin The GPIO pin to use as the interrupt pin + * @param isr Pointer to the method to be called, when the interrupt occurs + * @param isr_args The arguments to be passed to the method + * @return std::runtime_error on failure + */ + void InstallIsr(mraa_gpio_edge_t edge, int pin, void (*isr)(void *), void *isr_args); + + /** + * @brief Uninstalls a previously installed interrupt handler for interrupt pin + * + * @throws std::runtime_error on failure + */ + void UninstallIsr(); + + /** + * @brief Clears latching interrupts information of Wakeup (with axis and direction information) and Data Ready + * + * See datasheet for more details + * + * @throws std::runtime_error on failure + */ + void ClearInterrupt(); + + /** + * @brief Enables wakeup interrupt for the given axis (axis with direction) + * + * Sensor must be in standby mode before performing this action + * + * @param axis The axis to enable, takes one of KXTJ3_WAKEUP_SOURCE_T value + * @throws std::runtime_error on failure + */ + void EnableWakeUpSingleAxisDirection(KXTJ3_WAKEUP_SOURCE_T axis); + + /** + * @brief Disables wakeup interrupt for the given axis (axis with direction) + * + * Sensor must be in standby mode before performing this action + * + * @param axis The axis to enable, takes one of KXTJ3_WAKEUP_SOURCE_T value + * @throws std::runtime_error on failure + */ + void DisableWakeUpSingleAxisDirection(KXTJ3_WAKEUP_SOURCE_T axis); + + /** + * @brief Gets the source axis and direction of motion detection of the wakeup function interrupt + * + * See datasheet for more details + * + * @return A kxtj3_wakeup_axes struct with values of true/false + * for a wakeup for each axis and its direction + */ + kxtj3_wakeup_axes GetWakeUpAxisDirection(); + + /** + * @brief Enables the Unlached mode motion interrupt (ULMODE). This mode is always by default enabled. + * + * When this bit is set, the wakeup interrupt has to be cleared manually + * (cannot use interrupt response with pulse) + * + * Sensor must be in standby mode before performing this action + * + * @throws std::runtime_error on failure + */ + void EnableWakeUpLatch(); + + /** + * @brief Disables the Unlached mode motion interrupt (ULMODE). This mode is always by default enabled. + * (cannot use interrupt response with pulse) + * + * The wakeup threshold is advised to not be very low to avoid interrupt being triggered in + * an almost continuous manner + * + * Sensor must be in standby mode before performing this action + * + * When this bit is cleared, and the interrupt response type is set to Pulse, then upon a wakeup event + * the wakeup interrupt signal will pulse and return low, but only once. Then, the interrupt + * output will not reset until data is read or interrupt cleared. + + * @throws std::runtime_error on failure + */ + void DisableWakeUpLatch(); + + /** + * @brief Sets the timer counter of motion before sending a wakeup interrupt + * + * The count is limited to values from 1 to 255 + * + * Every count is calculated as (1 / Wakeup_ODR_FREQUENCY) where Wakeup_ODR_FREQUENCY + * is the current odr_in_Hz value from odr_map_in_Hz_wakeup value + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param count The timer count from 1 to 255 + * @throws std::runtime_error on failure + */ + void SetWakeUpMotionCounter(uint8_t count); + + /** + * @brief Sets the timer of motion before sending a wakeup interrupt + * + * the desired time should be such that (0 < desired_time * wakeup_odr_frequency <= 255) + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param desired_time The desired time in seconds + * @throws std::runtime_error on failure + */ + void SetWakeUpMotionTime(float desired_time); + + /** + * @brief Get the current count value of the timer of motion before sending a wakeup interrupt + * + * @return Time value in seconds + * @throws std::runtime_error on failure + */ + float GetWakeUpMotionTime(); + + /** + * @brief Sets the timer counter of non-activity before sending another wakeup interrupt + * + * The count is limited to values from 1 to 255 + * + * Every count is calculated as (1 / Wakeup_ODR_FREQUENCY) where Wakeup_ODR_FREQUENCY + * is the current odr_in_Hz value from odr_map_in_Hz_wakeup value + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param count The timer count from 1 to 255 + * @throws std::runtime_error on failure + */ + void SetWakeUpNonActivityCounter(uint8_t count); + + /** + * @brief Sets the timer of non-activity before sending another wakeup interrupt + * + * the desired time should be such that (0 < desired_time * wakeup_odr_frequency <= 255) + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param desired_time The desired time in seconds + * @throws std::runtime_error on failure + */ + void SetWakeUpNonActivityTime(float desired_time); + + /** + * @brief Get the current count value of the timer of non-activity before sending another wakeup interrupt + * + * @return Time value in seconds + * @throws std::runtime_error on failure + */ + float GetWakeUpNonActivityTime(); + + /** + * @brief Sets the threshold counter for acceleration difference before sending a wakeup interrupt + * + * The count is limited to values from 1 to 4096, that it is 16g threshold with (3.9mg/count) + * It is advised to not set the threshold to a very low value which may cause bad behaviour + * in the wakeup interrupt + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param count The timer count from 1 to 4096, that it is 16g threshold with (3.9mg/count) + * @throws std::runtime_error on failure + */ + void SetWakeUpThresholdCounter(uint16_t count); + + /** + * @brief Sets the threshold g value for acceleration difference before sending a wakeup interrupt + * + * The count is limited to values up to 16g, with steps of 3.9mg. It is advised to not set + * the threshold to a very low value which may cause bad behaviour in the wakeup interrupt + * + * Sensor must be in standby mode before performing this action + * + * See datasheet for more details + * + * @param g_threshold The acceleration threshold (in g) in g, from 3.9mg to 16g, steps of 3.9mg/count. + * @throws std::runtime_error on failure + */ + void SetWakeUpThresholdGRange(float g_threshold); + + /** + * @brief Get the current threshold difference value before sending wakeup interrupt + * + * @return Threshold value in g + * @throws std::runtime_error on failure + */ + float GetWakeUpThresholdGRange(); + +private: + kxtj3_context m_kxtj3; + + /* Disable implicit copy and assignment operators */ + KXTJ3(const KXTJ3 &) = delete; + KXTJ3 &operator=(const KXTJ3 &) = delete; +}; +} // namespace upm diff --git a/src/kxtj3/kxtj3.i b/src/kxtj3/kxtj3.i new file mode 100644 index 00000000..6f60f499 --- /dev/null +++ b/src/kxtj3/kxtj3.i @@ -0,0 +1,20 @@ +%include "../common_top.i" + +/* BEGIN Java syntax ------------------------------------------------------- */ +#ifdef SWIGJAVA +JAVA_JNI_LOADLIBRARY(javaupm_kxtj3) +#endif +/* END Java syntax */ + +/* BEGIN Common SWIG syntax ------------------------------------------------- */ +%include "std_vector.i" +%template(floatVector) std::vector; + +%apply float *OUTPUT {float *x, float *y, float *z}; + +%{ +#include "kxtj3.hpp" +%} +%include "kxtj3.h" +%include "kxtj3.hpp" +/* END Common SWIG syntax */ diff --git a/src/kxtj3/kxtj3.json b/src/kxtj3/kxtj3.json new file mode 100755 index 00000000..3010938f --- /dev/null +++ b/src/kxtj3/kxtj3.json @@ -0,0 +1,72 @@ +{ + "Library": "KXTJ3", + "Description": "Kionix KXTJ3 tri-axis accelerometer sensor library", + "Sensor Class": { + "KXTJ3": { + "Name": "Kionix KXTJ3 tri-axis accelerometer sensor", + "Description": "This is the UPM Module for the Kionix KXTJ3 accelerometer sensor. The Kionix KXTJ3 sensor is a multifunctional sensor that provides multiple functionalities. The sensor provides an extended g-range up to +/- 16g, higher resolution embedded wake-up function down to 3.9mg, and a flexible interrupt circuitry. The KXTJ3 sense element offers lower noise performance, exceptional shock resiliency, stable performance over temperature, and virtually eliminates offset and sensitivity shifts from reflow.", + "Categories": [ + "acceleration" + ], + "Connections": [ + "i2c" + ], + "Project Type": [ + "prototyping", + "commercial" + ], + "Manufacturers": [ + "Kionix" + ], + "Image": "kxtj3.png", + "Examples": { + "C++": [ + "kxtj3.cxx" + ], + "C": [ + "kxtj3.c" + ], + "Java": [ + "KXTJ3_Example.java" + ], + "Python": [ + "kxtj3.py" + ], + "Node.js": [ + "kxtj3.js" + ] + }, + "Specifications": { + "Supply Voltage (VDD)": { + "unit": "V", + "min": 1.71, + "typical": 2.5, + "max": 3.6 + }, + "I/O Pads Supply Voltage (IO_VDD)": { + "unit": "V", + "min": 1.7, + "max": 3.6 + }, + "Supply Current": { + "unit": "uA", + "min": 0.9, + "max": 155 + }, + "Operating Temperature": { + "unit": "°C", + "min": -40, + "max": 85 + } + }, + "Urls": { + "Product Pages": [ + "http://www.kionix.com/product/KXTJ3-1057" + ], + "Datasheets": [ + "http://kionixfs.kionix.com/en/datasheet/KXTJ3-1057-Specifications-Rev-3.0.pdf" + ] + } + } + } +} diff --git a/src/kxtj3/kxtj3_registers.h b/src/kxtj3/kxtj3_registers.h new file mode 100755 index 00000000..ea2d4440 --- /dev/null +++ b/src/kxtj3/kxtj3_registers.h @@ -0,0 +1,204 @@ +/* +The MIT License (MIT) +Copyright (c) 2017 Kionix Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __KXTJ3_REGISTERS_H__ +#define __KXTJ3_REGISTERS_H__ +/* registers */ +// output register x +#define KXTJ3_XOUT_L 0x06 +#define KXTJ3_XOUT_H 0x07 +// output register y +#define KXTJ3_YOUT_L 0x08 +#define KXTJ3_YOUT_H 0x09 +// output register z +#define KXTJ3_ZOUT_L 0x0A +#define KXTJ3_ZOUT_H 0x0B +// This register can be used to verify proper integrated circuit functionality +#define KXTJ3_DCST_RESP 0x0C +// This register can be used for supplier recognition, as it can be factory written to a known byte value. +#define KXTJ3_WHO_AM_I 0x0F +// This register reports which function caused an interrupt. +#define KXTJ3_INT_SOURCE1 0x16 +// This register reports the axis and direction of detected motion +#define KXTJ3_INT_SOURCE2 0x17 +// This register reports the status of the interrupt +#define KXTJ3_STATUS_REG 0x18 +#define KXTJ3_INT_REL 0x1A +// Read/write control register that controls the main feature set +#define KXTJ3_CTRL_REG1 0x1B +// Read/write control register that provides more feature set control +#define KXTJ3_CTRL_REG2 0x1D +// This register controls the settings for the physical interrupt pin +#define KXTJ3_INT_CTRL_REG1 0x1E +// This register controls which axis and direction of detected motion can cause an interrupt +#define KXTJ3_INT_CTRL_REG2 0x1F +// Read/write control register that configures the acceleration outputs +#define KXTJ3_DATA_CTRL_REG 0x21 +#define KXTJ3_WAKEUP_COUNTER 0x29 +#define KXTJ3_NA_COUNTER 0x2A +// When 0xCA is written to this register, the MEMS self-test function is enabled +#define KXTJ3_SELF_TEST 0x3A +#define KXTJ3_WAKEUP_THRESHOLD_H 0x6A +#define KXTJ3_WAKEUP_THRESHOLD_L 0x6B +// This register can be used for supplier recognition, as it can be factory written to a known byte value. +#define KXCJC_WHO_AM_I 0x0F +/* registers bits */ +// before set +#define KXTJ3_DCST_RESP_DCSTR_BEFORE (0x55 << 0) +// after set +#define KXTJ3_DCST_RESP_DCSTR_AFTER (0xAA << 0) +// WHO_AM_I -value for KXTJ3 +#define KXTJ3_WHO_AM_I_WIA_ID (0x35 << 0) +// indicates that new acceleration data +#define KXTJ3_INT_SOURCE1_DRDY (0x01 << 4) +// Wake up +#define KXTJ3_INT_SOURCE1_WUFS (0x01 << 1) +// x- +#define KXTJ3_INT_SOURCE2_XNWU (0x01 << 5) +// x+ +#define KXTJ3_INT_SOURCE2_XPWU (0x01 << 4) +// y- +#define KXTJ3_INT_SOURCE2_YNWU (0x01 << 3) +// y+ +#define KXTJ3_INT_SOURCE2_YPWU (0x01 << 2) +// z- +#define KXTJ3_INT_SOURCE2_ZNWU (0x01 << 1) +// z+ +#define KXTJ3_INT_SOURCE2_ZPWU (0x01 << 0) +// reports the combined (OR) interrupt information of DRDY and WUFS in the interrupt source register +#define KXTJ3_STATUS_REG_INT (0x01 << 4) +// controls the operating mode of the KXTJ3 +#define KXTJ3_CTRL_REG1_PC (0x01 << 7) +// determines the performance mode of the KXTJ3 +#define KXTJ3_CTRL_REG1_RES (0x01 << 6) +// enables the reporting of the availability of new acceleration data as an interrupt +#define KXTJ3_CTRL_REG1_DRDYE (0x01 << 5) +// 2g range +#define KXTJ3_CTRL_REG1_GSEL_2G (0x00 << 2) +// 16g range +#define KXTJ3_CTRL_REG1_GSEL_16G (0x01 << 2) +// 4g range +#define KXTJ3_CTRL_REG1_GSEL_4G (0x02 << 2) +// 16g range +#define KXTJ3_CTRL_REG1_GSEL_16G2 (0x03 << 2) +// 8g range +#define KXTJ3_CTRL_REG1_GSEL_8G (0x04 << 2) +// 16g range +#define KXTJ3_CTRL_REG1_GSEL_16G3 (0x05 << 2) +// 8g range with 14b resolution +#define KXTJ3_CTRL_REG1_GSEL_8G_14 (0x06 << 2) +// 16g range with 14b resolution +#define KXTJ3_CTRL_REG1_GSEL_16G_14 (0x07 << 2) +// enables 14-bit mode if GSEL = '11' +#define KXTJ3_CTRL_REG1_EN16G (0x01 << 2) +// enables the Wake Up (motion detect) function. +#define KXTJ3_CTRL_REG1_WUFE (0x01 << 1) +// initiates software reset +#define KXTJ3_CTRL_REG2_SRST (0x01 << 7) +// initiates the digital communication self-test function. +#define KXTJ3_CTRL_REG2_DCST (0x01 << 4) +// 0.78Hz +#define KXTJ3_CTRL_REG2_OWUF_0P781 (0x00 << 0) +// 1.563Hz +#define KXTJ3_CTRL_REG2_OWUF_1P563 (0x01 << 0) +// 3.125Hz +#define KXTJ3_CTRL_REG2_OWUF_3P125 (0x02 << 0) +// 6.25Hz +#define KXTJ3_CTRL_REG2_OWUF_6P25 (0x03 << 0) +// 12.5Hz +#define KXTJ3_CTRL_REG2_OWUF_12P5 (0x04 << 0) +// 25Hz +#define KXTJ3_CTRL_REG2_OWUF_25 (0x05 << 0) +// 50Hz +#define KXTJ3_CTRL_REG2_OWUF_50 (0x06 << 0) +// 100Hz +#define KXTJ3_CTRL_REG2_OWUF_100 (0x07 << 0) +// enables/disables the physical interrupt pin +#define KXTJ3_INT_CTRL_REG1_IEN (0x01 << 5) +// sets the polarity of the physical interrupt pin +#define KXTJ3_INT_CTRL_REG1_IEA (0x01 << 4) +// sets the response of the physical interrupt pin +#define KXTJ3_INT_CTRL_REG1_IEL (0x01 << 3) +// selftest polarity +#define KXTJ3_INT_CTRL_REG1_STPOL (0x01 << 1) +// Unlatched mode motion interrupt; 0=disabled,1=enabled +#define KXTJ3_INT_CTRL_REG2_ULMODE (0x01 << 7) +// x- +#define KXTJ3_INT_CTRL_REG2_XNWU (0x01 << 5) +// x+ +#define KXTJ3_INT_CTRL_REG2_XPWU (0x01 << 4) +// y- +#define KXTJ3_INT_CTRL_REG2_YNWU (0x01 << 3) +// y+ +#define KXTJ3_INT_CTRL_REG2_YPWU (0x01 << 2) +// z- +#define KXTJ3_INT_CTRL_REG2_ZNWU (0x01 << 1) +// z+ +#define KXTJ3_INT_CTRL_REG2_ZPWU (0x01 << 0) +// 12.5Hz +#define KXTJ3_DATA_CTRL_REG_OSA_12P5 (0x00 << 0) +// 25Hz +#define KXTJ3_DATA_CTRL_REG_OSA_25 (0x01 << 0) +// 50Hz +#define KXTJ3_DATA_CTRL_REG_OSA_50 (0x02 << 0) +// 100Hz +#define KXTJ3_DATA_CTRL_REG_OSA_100 (0x03 << 0) +// 200Hz +#define KXTJ3_DATA_CTRL_REG_OSA_200 (0x04 << 0) +// 400Hz +#define KXTJ3_DATA_CTRL_REG_OSA_400 (0x05 << 0) +// 800Hz +#define KXTJ3_DATA_CTRL_REG_OSA_800 (0x06 << 0) +// 1600Hz +#define KXTJ3_DATA_CTRL_REG_OSA_1600 (0x07 << 0) +// 0.78Hz +#define KXTJ3_DATA_CTRL_REG_OSA_0P781 (0x08 << 0) +// 1.563Hz +#define KXTJ3_DATA_CTRL_REG_OSA_1P563 (0x09 << 0) +// 3.125Hz +#define KXTJ3_DATA_CTRL_REG_OSA_3P125 (0x0A << 0) +// 6.25Hz +#define KXTJ3_DATA_CTRL_REG_OSA_6P25 (0x0B << 0) +// charge on +#define KXTJ3_SELF_TEST_MEMS_TEST_ENABLE (0xCA << 0) +// charge off +#define KXTJ3_SELF_TEST_MEMS_TEST_DISABLE (0x00 << 0) +// WHO_AM_I -value for KXCJC +#define KXCJC_WHO_AM_I_WIA_ID (0x36 << 0) +/*registers bit masks */ + +#define KXTJ3_DCST_RESP_DCSTR_MASK 0xFF + +#define KXTJ3_WHO_AM_I_WIA_MASK 0xFF +// selects the acceleration range of the accelerometer outputs +#define KXTJ3_CTRL_REG1_GSEL_MASK 0x1C +// sets the Output Data Rate for the Wake Up function +#define KXTJ3_CTRL_REG2_OWUF_MASK 0x07 +// sets the output data rate (ODR) +#define KXTJ3_DATA_CTRL_REG_OSA_MASK 0x0F + +#define KXTJ3_SELF_TEST_MEMS_TEST_MASK 0xFF + +#define KXCJC_WHO_AM_I_WIA_MASK 0xFF +#endif