mirror of
https://github.com/eclipse/upm.git
synced 2025-03-26 02:10:02 +03:00

The hardcoded frequency of 10kHz was much slower than the capacity of the device Signed-off-by: Antoine W. Campagna <AntoineW@Campagna.org> Signed-off-by: Noel Eck <noel.eck@intel.com>
1094 lines
29 KiB
C
1094 lines
29 KiB
C
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Author: Samuli Rissanen <samuli.rissanen@hotmail.com>
|
|
* 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 "kx122.h"
|
|
|
|
//Used to set the bit required for SPI reading
|
|
#define SPI_READ 0x80
|
|
|
|
//Used to mask the read bit required for SPI writing
|
|
#define SPI_WRITE 0x7F
|
|
|
|
//Used to determine amount of samples in the buffer.
|
|
#define LOW_RES_SAMPLE_MODIFIER 3
|
|
#define HIGH_RES_SAMPLE_MODIFIER 6
|
|
|
|
//Mask for software reset
|
|
#define KX122_CNTL2_SRST_MASK 0x80
|
|
|
|
//Masks for interrupt control registers
|
|
#define KX122_INC1_MASK 0xFB
|
|
#define KX122_INC4_MASK 0xF7
|
|
#define KX122_INC5_MASK 0xFB
|
|
#define KX122_INC6_MASK 0xF7
|
|
|
|
//Acceleration data buffer length
|
|
#define BUFFER_LEN 6
|
|
|
|
//Acceleration per decimal value for each acceleration ranges
|
|
#define RANGE_2G_G 0.00006f
|
|
#define RANGE_4G_G 0.00012f
|
|
#define RANGE_8G_G 0.00024f
|
|
|
|
//Acceleration scaling between high and low resolution modes
|
|
#define RANGE_RES_SCALE 260
|
|
|
|
//Maximum loop iterations, used in software reset and self testing
|
|
#define MAX_LOOP_COUNT 100
|
|
|
|
//Sensor self-test defines
|
|
#define SELF_TEST_LOOP_WAIT_TIME 10000
|
|
#define SELF_TEST_MAX_DIFFERENCE 0.75f
|
|
#define SELF_TEST_MIN_XY_DIFFERENCE 0.25f
|
|
#define SELF_TEST_MIN_Z_DIFFERENCE 0.20f
|
|
|
|
//Maximum amount of samples in the buffer for high and low resolutions
|
|
#define MAX_BUFFER_SAMPLES_LOW_RES 681
|
|
#define MAX_BUFFER_SAMPLES_HIGH_RES 340
|
|
|
|
//Earth gravity constant (m/s^2)
|
|
#define GRAVITY 9.81f
|
|
/**
|
|
Enables the chip select on the chip_select GPIO pin.
|
|
Chip select is active low.
|
|
|
|
@param dev The device context.
|
|
*/
|
|
static void kx122_chip_select_on(const kx122_context dev);
|
|
|
|
/**
|
|
Disables the chip select on the chip_select GPIO pin.
|
|
|
|
@param dev The device context.
|
|
*/
|
|
static void kx122_chip_select_off(const kx122_context dev);
|
|
|
|
/**
|
|
Reads a register.
|
|
|
|
@param dev The device context.
|
|
@param reg The register to read.
|
|
@param data Pointer to a uint8_t variable to store the value.
|
|
@return UPM result
|
|
*/
|
|
static upm_result_t kx122_read_register(const kx122_context dev, uint8_t reg, uint8_t *data);
|
|
|
|
/**
|
|
Reads multiple continous registers.
|
|
|
|
@param dev The device context.
|
|
@param reg The start register.
|
|
@param buffer Pointer to a uint8_t buffer to store the values.
|
|
@param len Amount of bytes to read.
|
|
@return UPM result
|
|
*/
|
|
static upm_result_t kx122_read_registers(const kx122_context dev, uint8_t reg, uint8_t *buffer, uint len);
|
|
|
|
/**
|
|
Writes to a register.
|
|
|
|
@param dev The device context.
|
|
@param reg The register to write to.
|
|
@param val The value to write to the register.
|
|
@return UPM result
|
|
*/
|
|
static upm_result_t kx122_write_register(const kx122_context dev, uint8_t reg, uint8_t val);
|
|
|
|
/**
|
|
Writes to a register using a bitmask.
|
|
|
|
@param dev The device context.
|
|
@param reg The register to write to.
|
|
@param val The value to write to the register.
|
|
@param bit_mask The bitmask to be used.
|
|
@return UPM result.
|
|
*/
|
|
static upm_result_t kx122_set_bit_pattern(const kx122_context dev, uint8_t reg, uint8_t val, uint8_t bit_mask);
|
|
|
|
/**
|
|
Sets a specific bit on (1) in a register.
|
|
|
|
@param dev The device context.
|
|
@param reg The register to write to.
|
|
@param val The value to write to the register.
|
|
@return UPM result.
|
|
*/
|
|
static upm_result_t kx122_set_bit_on(const kx122_context dev, uint8_t reg, uint8_t val);
|
|
|
|
/**
|
|
Sets a specific bit off (0) in a register.
|
|
|
|
@param dev The device context.
|
|
@param reg The register to write to.
|
|
@param val The value to write to the register.
|
|
@return UPM result.
|
|
*/
|
|
static upm_result_t kx122_set_bit_off(const kx122_context dev, uint8_t reg, uint8_t val);
|
|
|
|
/**
|
|
Sets the default internal variable values.
|
|
|
|
@param dev The device context.
|
|
*/
|
|
static void kx122_set_default_values(const kx122_context dev);
|
|
|
|
/**
|
|
Sets acceleration scale of sensor and the buffer.
|
|
|
|
@param dev The device context.
|
|
@param grange One of the KX122_RANGE_T values.
|
|
*/
|
|
static void kx122_map_grange(const kx122_context dev, KX122_RANGE_T grange);
|
|
|
|
kx122_context kx122_init(int bus, int addr, int chip_select_pin, int spi_bus_frequency)
|
|
{
|
|
kx122_context dev = (kx122_context)malloc(sizeof(struct _kx122_context));
|
|
|
|
if(!dev){
|
|
return NULL;
|
|
}
|
|
|
|
dev->using_spi = false;
|
|
|
|
dev->i2c = NULL;
|
|
dev->spi = NULL;
|
|
dev->chip_select = NULL;
|
|
|
|
dev->gpio1 = NULL;
|
|
dev->gpio2 = NULL;
|
|
|
|
if(mraa_init() != MRAA_SUCCESS){
|
|
printf("%s: mraa_init() failed.\n", __FUNCTION__);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
|
|
if(addr == -1){
|
|
dev->using_spi = true;
|
|
}
|
|
|
|
if(dev->using_spi){
|
|
|
|
if (spi_bus_frequency > 10000000){ // KX122 has a maximum SPI bus speed of 10MHz
|
|
printf("%s: bus frequency too high - KX122 has a maximum SPI bus speed of 10MHz.\n", __FUNCTION__);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(dev->spi = mraa_spi_init(bus))){
|
|
printf("%s: mraa_spi_init() failed.\n", __FUNCTION__);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(dev->chip_select = mraa_gpio_init(chip_select_pin))){
|
|
printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
|
|
mraa_gpio_dir(dev->chip_select,MRAA_GPIO_OUT);
|
|
mraa_spi_mode(dev->spi,MRAA_SPI_MODE0);
|
|
|
|
if (mraa_spi_frequency(dev->spi, spi_bus_frequency)){
|
|
printf("%s: mraa_spi_frequency() failed.\n", __FUNCTION__);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
}
|
|
else{ //Using I2C
|
|
if (!(dev->i2c = mraa_i2c_init(bus))){
|
|
printf("%s: mraa_i2c_init() failed, used bus: %d\n", __FUNCTION__,bus);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
|
|
if (mraa_i2c_address(dev->i2c, addr)){
|
|
printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
uint8_t who_am_i;
|
|
kx122_get_who_am_i(dev,&who_am_i);
|
|
|
|
if(who_am_i != KX122_WHO_AM_I_WIA_ID){
|
|
printf("%s: Wrong WHO AM I received, expected: 0x%x | got: 0x%x\n", __FUNCTION__,KX122_WHO_AM_I_WIA_ID,who_am_i);
|
|
kx122_close(dev);
|
|
return NULL;
|
|
}
|
|
|
|
kx122_set_default_values(dev);
|
|
|
|
kx122_device_init(dev,KX122_ODR_50,HIGH_RES,KX122_RANGE_2G);
|
|
return dev;
|
|
}
|
|
|
|
void kx122_close(kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
kx122_uninstall_isr(dev,INT1);
|
|
kx122_uninstall_isr(dev,INT2);
|
|
|
|
if(dev->i2c){
|
|
mraa_i2c_stop(dev->i2c);
|
|
}
|
|
if(dev->spi){
|
|
mraa_spi_stop(dev->spi);
|
|
}
|
|
if(dev->chip_select){
|
|
mraa_gpio_close(dev->chip_select);
|
|
}
|
|
free(dev);
|
|
}
|
|
|
|
static void kx122_chip_select_on(const kx122_context dev)
|
|
{
|
|
if(dev->chip_select){
|
|
mraa_gpio_write(dev->chip_select,0);
|
|
}
|
|
}
|
|
|
|
static void kx122_chip_select_off(const kx122_context dev)
|
|
{
|
|
if(dev->chip_select){
|
|
mraa_gpio_write(dev->chip_select,1);
|
|
}
|
|
}
|
|
|
|
//Register operations
|
|
static upm_result_t kx122_read_register(const kx122_context dev, uint8_t reg, uint8_t *data)
|
|
{
|
|
if(dev->using_spi){
|
|
reg |= SPI_READ;
|
|
|
|
uint8_t spi_data[2] = {reg,0};
|
|
|
|
kx122_chip_select_on(dev);
|
|
|
|
if(mraa_spi_transfer_buf(dev->spi,spi_data,spi_data,(sizeof(spi_data) / sizeof(uint8_t))) != MRAA_SUCCESS){
|
|
printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__);
|
|
|
|
kx122_chip_select_off(dev);
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
*data = spi_data[1];
|
|
|
|
kx122_chip_select_off(dev);
|
|
return UPM_SUCCESS;
|
|
}
|
|
else{
|
|
int value = mraa_i2c_read_byte_data(dev->i2c,reg);
|
|
|
|
if(value != -1){
|
|
*data = (uint8_t) value;
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
printf("%s: mraa_i2c_read_byte_data() failed, reading from register 0x%x\n",__FUNCTION__, reg);
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
}
|
|
|
|
static upm_result_t kx122_read_registers(const kx122_context dev, uint8_t reg, uint8_t *buffer, uint len)
|
|
{
|
|
if(dev->using_spi){
|
|
reg |= SPI_READ;
|
|
|
|
uint8_t spi_data_buffer[len + 1];
|
|
spi_data_buffer[0] = reg;
|
|
|
|
kx122_chip_select_on(dev);
|
|
|
|
if(mraa_spi_transfer_buf(dev->spi,spi_data_buffer,spi_data_buffer,
|
|
(sizeof(spi_data_buffer) / sizeof(uint8_t))) != MRAA_SUCCESS){
|
|
printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__);
|
|
|
|
kx122_chip_select_off(dev);
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
buffer[i] = spi_data_buffer[i + 1];
|
|
}
|
|
|
|
kx122_chip_select_off(dev);
|
|
return UPM_SUCCESS;
|
|
}
|
|
else{
|
|
uint8_t data_buffer[len];
|
|
if(mraa_i2c_read_bytes_data(dev->i2c,reg,data_buffer,len) != (int)len){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
else{
|
|
for(size_t i = 0; i < len; i++){
|
|
buffer[i] = data_buffer[i];
|
|
}
|
|
return UPM_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
static upm_result_t kx122_write_register(const kx122_context dev, uint8_t reg, uint8_t val)
|
|
{
|
|
if(dev->using_spi){
|
|
reg &= SPI_WRITE;
|
|
uint8_t spi_data[2] = {reg,val};
|
|
|
|
kx122_chip_select_on(dev);
|
|
if(mraa_spi_transfer_buf(dev->spi,spi_data,NULL,(sizeof(spi_data) / sizeof(uint8_t))) != MRAA_SUCCESS){
|
|
printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__);
|
|
|
|
kx122_chip_select_off(dev);
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
kx122_chip_select_off(dev);
|
|
return UPM_SUCCESS;
|
|
}
|
|
else{
|
|
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 kx122_set_bit_pattern(const kx122_context dev, uint8_t reg, uint8_t val, uint8_t bit_mask)
|
|
{
|
|
uint8_t reg_val;
|
|
|
|
if(kx122_read_register(dev,reg,®_val) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
reg_val &= ~bit_mask;
|
|
reg_val |= val;
|
|
return kx122_write_register(dev,reg,reg_val);
|
|
}
|
|
|
|
static upm_result_t kx122_set_bit_on(const kx122_context dev, uint8_t reg, uint8_t val)
|
|
{
|
|
uint8_t reg_val;
|
|
|
|
if(kx122_read_register(dev,reg,®_val) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
reg_val |= val;
|
|
return kx122_write_register(dev,reg,reg_val);
|
|
}
|
|
|
|
static upm_result_t kx122_set_bit_off(const kx122_context dev, uint8_t reg, uint8_t val)
|
|
{
|
|
uint8_t reg_val;
|
|
|
|
if(kx122_read_register(dev,reg,®_val) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
reg_val &= ~val;
|
|
return kx122_write_register(dev,reg,reg_val);
|
|
}
|
|
|
|
static void kx122_set_default_values(const kx122_context dev)
|
|
{
|
|
dev->accel_scale = RANGE_2G_G;
|
|
dev->grange_mode = KX122_RANGE_2G;
|
|
dev->res_mode = HIGH_RES;
|
|
|
|
dev->buffer_accel_scale = RANGE_2G_G;
|
|
dev->buffer_res = LOW_RES;
|
|
dev->buffer_mode = KX122_FIFO_MODE;
|
|
}
|
|
|
|
static void kx122_map_grange(const kx122_context dev, KX122_RANGE_T grange)
|
|
{
|
|
switch (grange) {
|
|
case KX122_RANGE_2G:
|
|
dev->accel_scale = RANGE_2G_G;
|
|
dev->buffer_accel_scale = RANGE_2G_G;
|
|
break;
|
|
case KX122_RANGE_4G:
|
|
dev->accel_scale = RANGE_4G_G;
|
|
dev->buffer_accel_scale = RANGE_4G_G;
|
|
break;
|
|
case KX122_RANGE_8G:
|
|
dev->accel_scale = RANGE_8G_G;
|
|
dev->buffer_accel_scale = RANGE_8G_G;
|
|
break;
|
|
}
|
|
|
|
if(dev->res_mode == LOW_RES){
|
|
dev->accel_scale *= RANGE_RES_SCALE;
|
|
}
|
|
if(dev->buffer_res == LOW_RES){
|
|
dev->buffer_accel_scale *= RANGE_RES_SCALE;
|
|
}
|
|
|
|
dev->grange_mode = grange;
|
|
}
|
|
|
|
float kx122_get_sample_period(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
|
|
odr_item odr_map[16] = {
|
|
{KX122_ODR_0P781,0.781f},{KX122_ODR_1P563,1.563f},{KX122_ODR_3P125,3.125f},{KX122_ODR_6P25,6.25f},
|
|
{KX122_ODR_12P5,12.5f},{KX122_ODR_25,25},{KX122_ODR_50,50},{KX122_ODR_100,100},{KX122_ODR_200,200},
|
|
{KX122_ODR_400,400},{KX122_ODR_800,800},{KX122_ODR_1600,1600},{KX122_ODR_3200,3200},{KX122_ODR_6400,6400},
|
|
{KX122_ODR_12800,128000},{KX122_ODR_25600,25600}
|
|
};
|
|
|
|
uint8_t reg_val;
|
|
|
|
kx122_read_register(dev,KX122_ODCNTL, ®_val);
|
|
reg_val = reg_val & KX122_ODCNTL_OSA_MASK;
|
|
|
|
for (size_t i = 0; i < (sizeof(odr_map) / sizeof(odr_item)); i++) {
|
|
if(reg_val == odr_map[i].odr_value){
|
|
return (1 / odr_map[i].odr_decimal);
|
|
}
|
|
}
|
|
return -1; //Return -1 if failed
|
|
}
|
|
//Driver functions
|
|
upm_result_t kx122_device_init(const kx122_context dev, KX122_ODR_T odr, KX122_RES_T res, KX122_RANGE_T grange)
|
|
{
|
|
assert(dev != NULL);
|
|
kx122_set_sensor_standby(dev);
|
|
|
|
if(kx122_set_odr(dev,odr) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
if(kx122_set_resolution(dev,res) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
if(kx122_set_grange(dev,grange) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
kx122_set_sensor_active(dev);
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
upm_result_t kx122_get_who_am_i(const kx122_context dev, uint8_t *data)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_read_register(dev,KX112_WHO_AM_I,data);
|
|
}
|
|
|
|
upm_result_t kx122_set_sensor_standby(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_CNTL1,KX122_CNTL1_PC1);
|
|
}
|
|
|
|
upm_result_t kx122_set_sensor_active(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
upm_result_t result = kx122_set_bit_on(dev,KX122_CNTL1,KX122_CNTL1_PC1);
|
|
|
|
usleep((kx122_get_sample_period(dev) * 1.5f) * MICRO_S); //Sleep 1.5/ODR
|
|
|
|
return result;
|
|
}
|
|
|
|
upm_result_t kx122_get_acceleration_data_raw(const kx122_context dev, float *x, float *y, float *z)
|
|
{
|
|
assert(dev != NULL);
|
|
|
|
uint8_t buffer[BUFFER_LEN];
|
|
|
|
if(kx122_read_registers(dev,KX122_XOUT_L,buffer,BUFFER_LEN) != UPM_SUCCESS){
|
|
printf("%s: kx122_read_registers() failed to read %d bytes\n",__FUNCTION__, BUFFER_LEN);
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
if(dev->res_mode == HIGH_RES){
|
|
if(x){
|
|
*x = (float)((int16_t)(buffer[1] << 8) | buffer[0]);
|
|
}
|
|
if(y){
|
|
*y = (float)((int16_t)(buffer[3] << 8) | buffer[2]);
|
|
}
|
|
if(z){
|
|
*z = (float)((int16_t)(buffer[5] << 8) | buffer[4]);
|
|
}
|
|
}
|
|
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 kx122_get_acceleration_data(const kx122_context dev, float *x, float *y, float *z)
|
|
{
|
|
float x_raw,y_raw,z_raw;
|
|
|
|
if(kx122_get_acceleration_data_raw(dev,&x_raw,&y_raw,&z_raw) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
if(x){
|
|
*x = (x_raw * dev->accel_scale) * GRAVITY;
|
|
}
|
|
if(y){
|
|
*y = (y_raw * dev->accel_scale) * GRAVITY;
|
|
}
|
|
if(z){
|
|
*z = (z_raw * dev->accel_scale) * GRAVITY;
|
|
}
|
|
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
upm_result_t kx122_sensor_software_reset(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
if(kx122_set_bit_on(dev,KX122_CNTL2,KX122_CNTL2_SRST) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
int counter = 0;
|
|
uint8_t reg_val;
|
|
|
|
kx122_read_register(dev,KX122_CNTL2, ®_val);
|
|
|
|
while((reg_val & KX122_CNTL2_SRST_MASK) != 0x00 && counter < MAX_LOOP_COUNT){
|
|
if(kx122_read_register(dev,KX122_CNTL2, ®_val) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
usleep(100000);
|
|
counter++;
|
|
}
|
|
|
|
if(counter == MAX_LOOP_COUNT){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
kx122_set_default_values(dev);
|
|
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
upm_result_t kx122_enable_iir(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_ODCNTL,KX122_ODCNTL_IIR_BYPASS_BYPASS);
|
|
}
|
|
|
|
upm_result_t kx122_disable_iir(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_on(dev,KX122_ODCNTL,KX122_ODCNTL_IIR_BYPASS_BYPASS);
|
|
}
|
|
|
|
upm_result_t kx122_self_test(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
float x,y,z;
|
|
|
|
float x_before_test_avg = 0, x_during_test_avg = 0;
|
|
float y_before_test_avg = 0, y_during_test_avg = 0;
|
|
float z_before_test_avg = 0, z_during_test_avg = 0;
|
|
|
|
for (size_t i = 0; i < MAX_LOOP_COUNT; i++) {
|
|
kx122_get_acceleration_data(dev,&x,&y,&z);
|
|
x_before_test_avg += fabs((x / GRAVITY));
|
|
y_before_test_avg += fabs((y / GRAVITY));
|
|
z_before_test_avg += fabs((z / GRAVITY));
|
|
usleep(SELF_TEST_LOOP_WAIT_TIME);
|
|
}
|
|
|
|
kx122_write_register(dev,KX122_SELF_TEST,KX122_SELF_TEST_MEMS_TEST_ON);
|
|
|
|
for (size_t i = 0; i < MAX_LOOP_COUNT; i++) {
|
|
kx122_get_acceleration_data(dev,&x,&y,&z);
|
|
x_during_test_avg += fabs((x / GRAVITY));
|
|
y_during_test_avg += fabs((y / GRAVITY));
|
|
z_during_test_avg += fabs((z / GRAVITY));
|
|
usleep(SELF_TEST_LOOP_WAIT_TIME);
|
|
}
|
|
|
|
kx122_write_register(dev,KX122_SELF_TEST,KX122_SELF_TEST_MEMS_TEST_OFF);
|
|
|
|
x_before_test_avg /= MAX_LOOP_COUNT;
|
|
x_during_test_avg /= MAX_LOOP_COUNT;
|
|
|
|
y_before_test_avg /= MAX_LOOP_COUNT;
|
|
y_during_test_avg /= MAX_LOOP_COUNT;
|
|
|
|
z_before_test_avg /= MAX_LOOP_COUNT;
|
|
z_during_test_avg /= MAX_LOOP_COUNT;
|
|
|
|
bool success = true;
|
|
float difference;
|
|
//X-AXIS
|
|
difference = fabs(x_during_test_avg - x_before_test_avg);
|
|
difference = ceilf(difference * 100) / 100;
|
|
|
|
if(difference >= SELF_TEST_MIN_XY_DIFFERENCE && difference <= SELF_TEST_MAX_DIFFERENCE){
|
|
printf("X-AXIS OK DIFFERENCE %.02f\n",difference);
|
|
}
|
|
else{
|
|
printf("X-AXIS FAILED, DIFFERENCE %.02f\n", difference);
|
|
success = false;
|
|
}
|
|
//Y-AXIS
|
|
difference = fabs(y_during_test_avg - y_before_test_avg);
|
|
difference = ceilf(difference * 100) / 100;
|
|
if(difference >= SELF_TEST_MIN_XY_DIFFERENCE && difference <= SELF_TEST_MAX_DIFFERENCE){
|
|
printf("Y-AXIS OK DIFFERENCE %.02f\n",difference);
|
|
}
|
|
else{
|
|
printf("Y-AXIS FAILED, DIFFERENCE %.02f\n", difference);
|
|
success = false;
|
|
}
|
|
//Z-AXIS
|
|
difference = fabs(z_during_test_avg - z_before_test_avg);
|
|
difference = ceilf(difference * 100) / 100;
|
|
if(difference >= SELF_TEST_MIN_Z_DIFFERENCE && difference <= SELF_TEST_MAX_DIFFERENCE){
|
|
printf("Z-AXIS OK DIFFERENCE %.02f\n",difference);
|
|
}
|
|
else{
|
|
printf("Z-AXIS FAILED, DIFFERENCE %.02f\n", difference);
|
|
success = false;
|
|
}
|
|
|
|
if(success){
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
upm_result_t kx122_set_odr(const kx122_context dev, KX122_ODR_T odr)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_pattern(dev,KX122_ODCNTL,odr,KX122_ODCNTL_OSA_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_set_grange(const kx122_context dev, KX122_RANGE_T grange)
|
|
{
|
|
assert(dev != NULL);
|
|
kx122_map_grange(dev,grange);
|
|
|
|
return kx122_set_bit_pattern(dev,KX122_CNTL1,grange,KX122_CNTL1_GSEL_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_set_resolution(const kx122_context dev, KX122_RES_T res)
|
|
{
|
|
assert(dev != NULL);
|
|
|
|
dev->res_mode = res;
|
|
kx122_map_grange(dev,dev->grange_mode);
|
|
|
|
if(res == HIGH_RES){
|
|
return kx122_set_bit_on(dev,KX122_CNTL1,KX122_CNTL1_RES);
|
|
}
|
|
else{
|
|
return kx122_set_bit_off(dev,KX122_CNTL1,KX122_CNTL1_RES);
|
|
}
|
|
}
|
|
|
|
upm_result_t kx122_set_bw(const kx122_context dev, LPRO_STATE_T lpro)
|
|
{
|
|
assert(dev != NULL);
|
|
if(lpro == ODR_9){
|
|
return kx122_set_bit_off(dev, KX122_ODCNTL, KX122_ODCNTL_LPRO_ODR_2);
|
|
}
|
|
else{
|
|
return kx122_set_bit_on(dev, KX122_ODCNTL, KX122_ODCNTL_LPRO_ODR_2);
|
|
}
|
|
}
|
|
|
|
upm_result_t kx122_set_average(const kx122_context dev, KX122_AVG_T avg)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_pattern(dev,KX122_LP_CNTL,avg,KX122_LP_CNTL_AVC_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_install_isr(const kx122_context dev, mraa_gpio_edge_t edge,KX122_INTERRUPT_PIN_T intp, int pin, void (*isr)(void *), void *arg)
|
|
{
|
|
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, arg)){
|
|
mraa_gpio_close(isr_gpio);
|
|
printf("%s: mraa_gpio_isr() failed.\n", __FUNCTION__);
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
if(intp == INT1){
|
|
dev->gpio1 = isr_gpio;
|
|
}
|
|
else{
|
|
dev->gpio2 = isr_gpio;
|
|
}
|
|
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
void kx122_uninstall_isr(const kx122_context dev, KX122_INTERRUPT_PIN_T intp)
|
|
{
|
|
assert(dev != NULL);
|
|
if(intp == INT1 && dev->gpio1){
|
|
mraa_gpio_isr_exit(dev->gpio1);
|
|
mraa_gpio_close(dev->gpio1);
|
|
dev->gpio1 = NULL;
|
|
}
|
|
else if(intp == INT2 && dev->gpio2){
|
|
mraa_gpio_isr_exit(dev->gpio2);
|
|
mraa_gpio_close(dev->gpio2);
|
|
dev->gpio2 = NULL;
|
|
}
|
|
}
|
|
|
|
upm_result_t kx122_enable_interrupt1(const kx122_context dev, KX122_INTERRUPT_POLARITY_T polarity)
|
|
{
|
|
assert(dev != NULL);
|
|
|
|
uint8_t bits = KX122_INC1_PWSEL1_50US_10US | KX122_INC1_IEL1 | KX122_INC1_IEN1;
|
|
if(polarity == ACTIVE_HIGH){
|
|
bits |= KX122_INC1_IEA1;
|
|
}
|
|
|
|
return kx122_set_bit_pattern(dev,KX122_INC1,bits,KX122_INC1_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_enable_interrupt2(const kx122_context dev, KX122_INTERRUPT_POLARITY_T polarity)
|
|
{
|
|
assert(dev != NULL);
|
|
|
|
uint8_t bits = KX122_INC5_PWSEL2_50US_10US | KX122_INC5_IEL2 | KX122_INC5_IEN2;
|
|
if(polarity == ACTIVE_HIGH){
|
|
bits |= KX122_INC5_IEA2;
|
|
}
|
|
|
|
return kx122_set_bit_pattern(dev,KX122_INC5,bits,KX122_INC5_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_disable_interrupt1(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_INC1,KX122_INC1_IEN1);
|
|
}
|
|
|
|
upm_result_t kx122_disable_interrupt2(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_INC5,KX122_INC5_IEN2);
|
|
}
|
|
|
|
upm_result_t kx122_route_interrupt1(const kx122_context dev, uint8_t bits)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_pattern(dev,KX122_INC4,bits,KX122_INC4_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_route_interrupt2(const kx122_context dev, uint8_t bits)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_pattern(dev,KX122_INC6,bits,KX122_INC6_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_enable_data_ready_interrupt(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_on(dev,KX122_CNTL1,KX122_CNTL1_DRDYE);
|
|
}
|
|
|
|
upm_result_t kx122_disable_data_ready_interrupt(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_CNTL1,KX122_CNTL1_DRDYE);
|
|
}
|
|
|
|
upm_result_t kx122_enable_buffer_full_interrupt(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_on(dev,KX122_BUF_CNTL2,KX122_BUF_CNTL2_BFIE);
|
|
}
|
|
|
|
upm_result_t kx122_disable_buffer_full_interrupt(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_BUF_CNTL2,KX122_BUF_CNTL2_BFIE);
|
|
}
|
|
|
|
upm_result_t kx122_get_interrupt_source(const kx122_context dev, uint8_t *data)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_read_register(dev,KX122_INS2,data);
|
|
}
|
|
|
|
upm_result_t kx122_clear_interrupt(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
uint8_t reg_val;
|
|
|
|
return kx122_read_register(dev,KX122_INT_REL,®_val);
|
|
}
|
|
|
|
bool kx122_get_interrupt_status(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
uint8_t reg_val;
|
|
|
|
if(kx122_read_register(dev,KX122_STATUS_REG,®_val) != UPM_SUCCESS){
|
|
printf("%s: kx122_read_register() failed.\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
if(reg_val != 0x00){
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
upm_result_t kx122_enable_buffer(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_on(dev,KX122_BUF_CNTL2,KX122_BUF_CNTL2_BUFE);
|
|
}
|
|
|
|
upm_result_t kx122_disable_buffer(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_set_bit_off(dev,KX122_BUF_CNTL2,KX122_BUF_CNTL2_BUFE);
|
|
}
|
|
|
|
upm_result_t kx122_buffer_init(const kx122_context dev, uint samples, KX122_RES_T res, KX122_BUFFER_MODE_T mode)
|
|
{
|
|
assert(dev != NULL);
|
|
kx122_set_sensor_standby(dev);
|
|
|
|
if(kx122_set_buffer_threshold(dev,samples) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
if(kx122_set_buffer_resolution(dev,res) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
if(kx122_set_buffer_mode(dev,mode) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
kx122_enable_buffer(dev);
|
|
kx122_set_sensor_active(dev);
|
|
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
upm_result_t kx122_set_buffer_resolution(const kx122_context dev, KX122_RES_T res)
|
|
{
|
|
assert(dev != NULL);
|
|
dev->buffer_res = res;
|
|
kx122_map_grange(dev,dev->grange_mode);
|
|
|
|
if(res == HIGH_RES){
|
|
return kx122_set_bit_on(dev,KX122_BUF_CNTL2,KX122_BUF_CNTL2_BRES);
|
|
}
|
|
return kx122_set_bit_off(dev, KX122_BUF_CNTL2, KX122_BUF_CNTL2_BRES);
|
|
}
|
|
|
|
upm_result_t kx122_set_buffer_threshold(const kx122_context dev, uint samples)
|
|
{
|
|
assert(dev != NULL);
|
|
if(dev->buffer_res == LOW_RES && samples > MAX_BUFFER_SAMPLES_LOW_RES){
|
|
samples = MAX_BUFFER_SAMPLES_LOW_RES;
|
|
}
|
|
else if(dev->buffer_res == HIGH_RES && samples > MAX_BUFFER_SAMPLES_HIGH_RES){
|
|
samples = MAX_BUFFER_SAMPLES_HIGH_RES;
|
|
}
|
|
|
|
uint16_t bits = (uint16_t)samples;
|
|
|
|
uint8_t temp = (uint8_t) (bits & 0x00FF);//Get first 8 bits and set them to BUF_CNTL1
|
|
|
|
if(kx122_write_register(dev,KX122_BUF_CNTL1,temp) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
temp = (uint8_t)((bits & 0x0300) >> 6); //Get last 2 bits and set them to BUF_CNTL2
|
|
|
|
return kx122_set_bit_pattern(dev,KX122_BUF_CNTL2,temp,KX122_BUF_CNTL2_SMP_TH8_9_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_set_buffer_mode(const kx122_context dev, KX122_BUFFER_MODE_T mode)
|
|
{
|
|
assert(dev != NULL);
|
|
dev->buffer_mode = mode;
|
|
|
|
return kx122_set_bit_pattern(dev,KX122_BUF_CNTL2,mode,KX122_BUF_CNTL2_BUF_M_MASK);
|
|
}
|
|
|
|
upm_result_t kx122_clear_buffer(const kx122_context dev)
|
|
{
|
|
assert(dev != NULL);
|
|
return kx122_write_register(dev,KX122_BUF_CLEAR,0xFF); //Writing anything to the register clears the buffer
|
|
}
|
|
|
|
upm_result_t kx122_get_buffer_status(const kx122_context dev, uint *samples)
|
|
{
|
|
uint8_t reg_val;
|
|
uint16_t temp; //Using only 10 bits
|
|
|
|
if(kx122_read_register(dev,KX122_BUF_STATUS_2,®_val) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
temp = (reg_val & 0x0007) << 8; //Get 3 MSb from BUF_STATUS 2
|
|
|
|
if(kx122_read_register(dev,KX122_BUF_STATUS_1, ®_val) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
temp = (temp + (reg_val & 0x00FF)); //Get rest of the bits from BUF_STATUS 1
|
|
|
|
//Get the amount of samples
|
|
if(dev->buffer_res == LOW_RES){
|
|
//3 axis / sample
|
|
*samples = ((uint)(int16_t)temp) / 3;
|
|
}
|
|
else{
|
|
//3 axis * MSB/LSB / sample
|
|
*samples = ((uint)(int16_t)temp) / 6;
|
|
}
|
|
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
upm_result_t kx122_read_buffer_samples_raw(const kx122_context dev, uint len, float *x_array, float *y_array, float *z_array)
|
|
{
|
|
assert(dev != NULL);
|
|
if(dev->buffer_res == LOW_RES){
|
|
len *= LOW_RES_SAMPLE_MODIFIER; //3 axis / sample
|
|
}
|
|
else{
|
|
len *= HIGH_RES_SAMPLE_MODIFIER; //3 axis * 2 bytes / sample
|
|
}
|
|
|
|
uint8_t buffer[len];
|
|
|
|
if(kx122_read_registers(dev,KX122_BUF_READ,buffer,len) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
if(dev->buffer_res == HIGH_RES){
|
|
for (size_t i = 0; i < len; i+= HIGH_RES_SAMPLE_MODIFIER) {
|
|
if(dev->buffer_mode != KX122_FILO_MODE){
|
|
if(x_array){
|
|
x_array[i / HIGH_RES_SAMPLE_MODIFIER] = (float)((int16_t) (buffer[i + 1] << 8) | buffer[i]);
|
|
}
|
|
if(y_array){
|
|
y_array[i / HIGH_RES_SAMPLE_MODIFIER] = (float)((int16_t) (buffer[i + 3] << 8) | buffer[i + 2]);
|
|
}
|
|
if(z_array){
|
|
z_array[i / HIGH_RES_SAMPLE_MODIFIER] = (float)((int16_t) (buffer[i + 5] << 8) | buffer[i + 4]);
|
|
}
|
|
}
|
|
else{
|
|
if(x_array){
|
|
x_array[i / HIGH_RES_SAMPLE_MODIFIER] = (float)((int16_t) (buffer[i + 4] << 8) | buffer[i + 5]);
|
|
}
|
|
if(y_array){
|
|
y_array[i / HIGH_RES_SAMPLE_MODIFIER] = (float)((int16_t) (buffer[i + 2] << 8) | buffer[i + 3]);
|
|
}
|
|
if(z_array){
|
|
z_array[i / HIGH_RES_SAMPLE_MODIFIER] = (float)((int16_t) (buffer[i] << 8) | buffer[i + 1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else{ //Low resolution
|
|
for (size_t i = 0; i < len; i+= LOW_RES_SAMPLE_MODIFIER) {
|
|
if(dev->buffer_mode != KX122_FILO_MODE){
|
|
if(x_array){
|
|
x_array[i / LOW_RES_SAMPLE_MODIFIER] = (float)(int8_t)buffer[i];
|
|
}
|
|
if(y_array){
|
|
y_array[i / LOW_RES_SAMPLE_MODIFIER] = (float)(int8_t)buffer[i + 1];
|
|
}
|
|
if(z_array){
|
|
z_array[i / LOW_RES_SAMPLE_MODIFIER] = (float)(int8_t)buffer[i + 2];
|
|
}
|
|
}
|
|
else{
|
|
if(x_array){
|
|
x_array[i / LOW_RES_SAMPLE_MODIFIER] = (float)(int8_t)buffer[i + 2];
|
|
}
|
|
if(y_array){
|
|
y_array[i / LOW_RES_SAMPLE_MODIFIER] = (float)(int8_t)buffer[i + 1];
|
|
}
|
|
if(z_array){
|
|
z_array[i / LOW_RES_SAMPLE_MODIFIER] = (float)(int8_t)buffer[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return UPM_SUCCESS;
|
|
}
|
|
|
|
upm_result_t kx122_read_buffer_samples(const kx122_context dev, uint len, float *x_array, float *y_array, float *z_array)
|
|
{
|
|
assert(dev != NULL);
|
|
if(kx122_read_buffer_samples_raw(dev,len,x_array,y_array,z_array) != UPM_SUCCESS){
|
|
return UPM_ERROR_OPERATION_FAILED;
|
|
}
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
if(x_array){
|
|
x_array[i] = (x_array[i] * dev->buffer_accel_scale) * GRAVITY;
|
|
}
|
|
if(y_array){
|
|
y_array[i] = (y_array[i] * dev->buffer_accel_scale) * GRAVITY;
|
|
}
|
|
if(z_array){
|
|
z_array[i] = (z_array[i] * dev->buffer_accel_scale) * GRAVITY;
|
|
}
|
|
}
|
|
|
|
return UPM_SUCCESS;
|
|
}
|