Nils Schulte 0bab1469a3 ch32v003 changes
- memset crashes (why?)
- FIFO buffer to big for RAM
2025-08-22 08:21:37 +02:00

545 lines
21 KiB
C

/*
*
* Copyright (c) [2018] by InvenSense, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/** @defgroup Driver Driver
* @brief High-level functions to drive the device
* @{
*/
/** @file inv_imu_driver.h */
#ifndef _INV_IMU_DRIVER_H_
#define _INV_IMU_DRIVER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "imu/inv_imu_defs.h"
#include "imu/inv_imu_transport.h"
/** Max FSR values for accel */
#if INV_IMU_HFSR_SUPPORTED
#define ACCEL_CONFIG0_FS_SEL_MAX ACCEL_CONFIG0_FS_SEL_32g
#else
#define ACCEL_CONFIG0_FS_SEL_MAX ACCEL_CONFIG0_FS_SEL_16g
#endif
/** Max user offset value for accel (mg) */
#define ACCEL_OFFUSER_MAX_MG 1000
/** Accel start-up time */
#define ACC_STARTUP_TIME_US 10000
#if INV_IMU_IS_GYRO_SUPPORTED
/** Max FSR values for gyro */
#if INV_IMU_HFSR_SUPPORTED
#define GYRO_CONFIG0_FS_SEL_MAX GYRO_CONFIG0_FS_SEL_4000dps
#else
#define GYRO_CONFIG0_FS_SEL_MAX GYRO_CONFIG0_FS_SEL_2000dps
#endif
/** Max user offset value for gyro (dps) */
#define GYRO_OFFUSER_MAX_DPS 64
/** Gyro start-up time */
#define GYR_STARTUP_TIME_US 70000
#endif
/** Max buffer size mirrored from FIFO at polling time */
// #define FIFO_MIRRORING_SIZE 16 * 258 // packet size * max_count = 4kB
#define FIFO_MIRRORING_SIZE 258
/** Sensor identifier for UI control function */
enum inv_imu_sensor {
INV_SENSOR_ACCEL, /**< Accelerometer */
#if INV_IMU_IS_GYRO_SUPPORTED
INV_SENSOR_GYRO, /**< Gyroscope */
INV_SENSOR_FSYNC_EVENT, /**< FSYNC */
#else
INV_SENSOR_RESERVED1,
INV_SENSOR_RESERVED2,
#endif
INV_SENSOR_TEMPERATURE, /**< Chip temperature */
INV_SENSOR_DMP_PEDOMETER_EVENT, /**< Pedometer: step detected */
INV_SENSOR_DMP_PEDOMETER_COUNT, /**< Pedometer: step counter */
INV_SENSOR_DMP_TILT, /**< Tilt */
INV_SENSOR_DMP_FF, /**< FreeFall */
INV_SENSOR_DMP_LOWG, /**< Low G */
INV_SENSOR_DMP_SMD, /**< Significant Motion Detection */
INV_SENSOR_MAX
};
/** Configure FIFO usage */
typedef enum {
INV_IMU_FIFO_DISABLED = 0, /**< FIFO is disabled and data source is sensors registers */
INV_IMU_FIFO_ENABLED = 1, /**< FIFO is used as data source */
} INV_IMU_FIFO_CONFIG_t;
/** Sensor event structure definition */
typedef struct {
int sensor_mask;
uint16_t timestamp_fsync;
int16_t accel[3];
#if INV_IMU_IS_GYRO_SUPPORTED
int16_t gyro[3];
#endif
int16_t temperature;
int8_t accel_high_res[3];
#if INV_IMU_IS_GYRO_SUPPORTED
int8_t gyro_high_res[3];
#endif
} inv_imu_sensor_event_t;
/** IMU driver states definition */
typedef struct inv_imu_device {
/** Transport layer.
* @warning Must be the first one of inv_imu_device_t
*/
inv_imu_transport_t transport;
/** callback executed by:
* * inv_imu_get_data_from_fifo (if FIFO is used).
* * inv_imu_get_data_from_registers (if FIFO isn't used).
* May be NULL if above API are not used by application
*/
void (*sensor_event_cb)(inv_imu_sensor_event_t *event);
uint8_t fifo_data[FIFO_MIRRORING_SIZE]; /**< FIFO mirroring memory area */
uint8_t dmp_is_on; /**< DMP started status */
uint8_t endianness_data; /**< Data endianness configuration */
uint8_t fifo_highres_enabled; /**< Highres mode configuration */
INV_IMU_FIFO_CONFIG_t fifo_is_used; /**< FIFO configuration */
#if INV_IMU_IS_GYRO_SUPPORTED
uint64_t gyro_start_time_us; /**< Gyro start time to discard first samples */
#endif
uint64_t accel_start_time_us; /**< Accel start time to discard first samples */
} inv_imu_device_t;
/** Interrupt enum state for INT1, INT2, and IBI */
typedef enum { INV_IMU_DISABLE = 0, INV_IMU_ENABLE } inv_imu_interrupt_value;
/** Interrupt definition */
typedef struct {
inv_imu_interrupt_value INV_UI_FSYNC;
inv_imu_interrupt_value INV_UI_DRDY;
inv_imu_interrupt_value INV_FIFO_THS;
inv_imu_interrupt_value INV_FIFO_FULL;
inv_imu_interrupt_value INV_SMD;
inv_imu_interrupt_value INV_WOM_X;
inv_imu_interrupt_value INV_WOM_Y;
inv_imu_interrupt_value INV_WOM_Z;
inv_imu_interrupt_value INV_FF;
inv_imu_interrupt_value INV_LOWG;
inv_imu_interrupt_value INV_STEP_DET;
inv_imu_interrupt_value INV_STEP_CNT_OVFL;
inv_imu_interrupt_value INV_TILT_DET;
} inv_imu_interrupt_parameter_t;
/** INT1 pin configuration */
typedef struct {
INT_CONFIG_INT1_POLARITY_t int_polarity;
INT_CONFIG_INT1_MODE_t int_mode;
INT_CONFIG_INT1_DRIVE_CIRCUIT_t int_drive;
} inv_imu_int1_pin_config_t;
/** INT2 pin configuration */
typedef struct {
INT_CONFIG_INT2_POLARITY_t int_polarity;
INT_CONFIG_INT2_MODE_t int_mode;
INT_CONFIG_INT2_DRIVE_CIRCUIT_t int_drive;
} inv_imu_int2_pin_config_t;
/** @brief Initializes device.
* @param[in] s Pointer to device.
* @param[in] serif Pointer on serial interface structure.
* @param[in] sensor_event_cb Callback executed when a new sensor event is available. *
* @return 0 on success, negative value on error.
*/
int inv_imu_init(inv_imu_device_t *s, const struct inv_imu_serif *serif,
void (*sensor_event_cb)(inv_imu_sensor_event_t *event));
/** @brief Reset device by reloading OTPs.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_device_reset(inv_imu_device_t *s);
/** @brief return WHOAMI value.
* @param[in] s Pointer to device.
* @param[out] who_am_i WHOAMI for device.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_who_am_i(inv_imu_device_t *s, uint8_t *who_am_i);
/** @brief Enable/put accel in low power mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_enable_accel_low_power_mode(inv_imu_device_t *s);
/** @brief Enable/put accel in low noise mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_enable_accel_low_noise_mode(inv_imu_device_t *s);
/** @brief Disable all 3 axes of accel.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_disable_accel(inv_imu_device_t *s);
/** @brief Configure accel Output Data Rate.
* @param[in] s Pointer to device.
* @param[in] frequency The requested frequency.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_accel_frequency(inv_imu_device_t *s, const ACCEL_CONFIG0_ODR_t frequency);
/** @brief Set accel Low-Power averaging value.
* @param[in] s Pointer to device.
* @param[in] acc_avg Requested averaging value.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_accel_lp_avg(inv_imu_device_t *s, ACCEL_CONFIG1_ACCEL_FILT_AVG_t acc_avg);
/** @brief Set accel Low-Noise bandwidth value.
* @param[in] s Pointer to device.
* @param[in] acc_bw Requested averaging value.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_accel_ln_bw(inv_imu_device_t *s, ACCEL_CONFIG1_ACCEL_FILT_BW_t acc_bw);
/** @brief Set accel full scale range.
* @param[in] s Pointer to device.
* @param[in] accel_fsr_g Requested full scale range.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_accel_fsr(inv_imu_device_t *s, ACCEL_CONFIG0_FS_SEL_t accel_fsr_g);
/** @brief Access accel full scale range.
* @param[in] s Pointer to device.
* @param[out] accel_fsr_g Current full scale range.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_accel_fsr(inv_imu_device_t *s, ACCEL_CONFIG0_FS_SEL_t *accel_fsr_g);
#if INV_IMU_IS_GYRO_SUPPORTED
/** @brief Enable/put gyro in low noise mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_enable_gyro_low_noise_mode(inv_imu_device_t *s);
/** @brief Disable all 3 axes of gyro.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_disable_gyro(inv_imu_device_t *s);
/** @brief Configure gyro Output Data Rate.
* @param[in] s Pointer to device.
* @param[in] frequency The requested frequency.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_gyro_frequency(inv_imu_device_t *s, const GYRO_CONFIG0_ODR_t frequency);
/** @brief Set gyro Low-Noise bandwidth value.
* @param[in] s Pointer to device.
* @param[in] gyr_bw Requested averaging value.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_gyro_ln_bw(inv_imu_device_t *s, GYRO_CONFIG1_GYRO_FILT_BW_t gyr_bw);
/** @brief Set gyro full scale range.
* @param[in] s Pointer to device.
* @param[in] gyro_fsr_dps Requested full scale range.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_gyro_fsr(inv_imu_device_t *s, GYRO_CONFIG0_FS_SEL_t gyro_fsr_dps);
/** @brief Access gyro full scale range.
* @param[in] s Pointer to device.
* @param[out] gyro_fsr_dps Current full scale range.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_gyro_fsr(inv_imu_device_t *s, GYRO_CONFIG0_FS_SEL_t *gyro_fsr_dps);
/** @brief Enable fsync tagging functionality.
* * Enables fsync.
* * Enables timestamp to registers. Once fsync is enabled fsync counter is pushed to
* FIFO instead of timestamp. So timestamp is made available in registers. Note that
* this increase power consumption.
* * Enables fsync related interrupt.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_enable_fsync(inv_imu_device_t *s);
/** @brief Disable fsync tagging functionality.
* * Disables fsync.
* * Disables timestamp to registers. Once fsync is disabled timestamp is pushed to FIFO
* instead of fsync counter. So in order to decrease power consumption, timestamp is no
* more available in registers.
* * Disables fsync related interrupt.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_disable_fsync(inv_imu_device_t *s);
#endif
/** @brief Configure SPI slew-rate.
* @param[in] s Pointer to device.
* @param[in] slew_rate Requested slew-rate.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_spi_slew_rate(inv_imu_device_t *s, const DRIVE_CONFIG3_SPI_SLEW_RATE_t slew_rate);
/** @brief Configure INT1 pin behavior.
* @param[in] s Pointer to device.
* @param[in] conf Structure with the requested configuration.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_pin_config_int1(inv_imu_device_t *s, const inv_imu_int1_pin_config_t *conf);
/** @brief Configure INT2 pin behavior.
* @param[in] s Pointer to device.
* @param[in] conf Structure with the requested configuration.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_pin_config_int2(inv_imu_device_t *s, const inv_imu_int2_pin_config_t *conf);
/** @brief Configure which interrupt source can trigger INT1.
* @param[in] s Pointer to device.
* @param[in] it Structure with the corresponding state to manage INT1.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_config_int1(inv_imu_device_t *s, const inv_imu_interrupt_parameter_t *it);
/** @brief Retrieve interrupts configuration.
* @param[in] s Pointer to device.
* @param[out] it Structure with the corresponding state to manage INT1.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_config_int1(inv_imu_device_t *s, inv_imu_interrupt_parameter_t *it);
/** @brief Configure which interrupt source can trigger INT2.
* @param[in] s Pointer to device.
* @param[in] it Structure with the corresponding state to INT2.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_config_int2(inv_imu_device_t *s, const inv_imu_interrupt_parameter_t *it);
/** @brief Retrieve interrupts configuration.
* @param[in] s Pointer to device.
* @param[out] it Structure with the corresponding state to manage INT2.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_config_int2(inv_imu_device_t *s, inv_imu_interrupt_parameter_t *it);
/** @brief Read all data registers.
* Then it calls sensor_event_cb function passed at init for each packet.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_data_from_registers(inv_imu_device_t *s);
/** @brief Read FIFO frame count.
* @param[in] s Pointer to device.
* @param[out] frame_count Number of frame available in the FIFO.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_frame_count(inv_imu_device_t *s, uint16_t *frame_count);
/** @brief Decode FIFO frame.
* @param[in] s Pointer to device.
* @param[in] frame FIFO frame data.
* @param[out] event Data content coded as an event.
* @return 0 on success, negative value on error.
*/
int inv_imu_decode_fifo_frame(inv_imu_device_t *s, const uint8_t *frame,
inv_imu_sensor_event_t *event);
/** @brief Read all available packets from the FIFO.
* For each packet function builds a sensor event containing packet data
* and validity information. Then it calls sensor_event_cb function passed
* at init for each packet.
* @param[in] s Pointer to device.
* @return Number of valid packets read on success, negative value on error.
*/
int inv_imu_get_data_from_fifo(inv_imu_device_t *s);
/** @brief Converts ODR's enum to period in us.
* @param[in] odr_bitfield ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enum.
* @return The corresponding period in us.
*/
uint32_t inv_imu_convert_odr_bitfield_to_us(uint32_t odr_bitfield);
/** @brief Set timestamp resolution.
* @param[in] s Pointer to device.
* @param[in] timestamp_resol Requested timestamp resolution.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_timestamp_resolution(inv_imu_device_t * s,
const TMST_CONFIG1_RESOL_t timestamp_resol);
/** @brief Reset IMU FIFO.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_reset_fifo(inv_imu_device_t *s);
/** @brief Enable 20 bits raw data in FIFO.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_enable_high_resolution_fifo(inv_imu_device_t *s);
/** @brief Disable 20 bits raw data in FIFO.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_disable_high_resolution_fifo(inv_imu_device_t *s);
/** @brief Configure FIFO.
* @param[in] s Pointer to device.
* @param[in] fifo_config FIFO configuration method.
* Enabled: data are pushed to FIFO and FIFO THS interrupt is set.
* Disabled: data are not pushed to FIFO and DRDY interrupt is set.
* @return 0 on success, negative value on error.
*/
int inv_imu_configure_fifo(inv_imu_device_t *s, INV_IMU_FIFO_CONFIG_t fifo_config);
/** @brief Get timestamp resolution
* @param[in] s Pointer to device.
* @return The timestamp resolution in us or 0 in case of error
*/
uint32_t inv_imu_get_timestamp_resolution_us(inv_imu_device_t *s);
/** @brief Enable Wake On Motion.
* @param[in] s Pointer to device.
* @param[in] wom_x_th Threshold value for the Wake on Motion Interrupt for X-axis accel.
* @param[in] wom_y_th Threshold value for the Wake on Motion Interrupt for Y-axis accel.
* @param[in] wom_z_th Threshold value for the Wake on Motion Interrupt for Z-axis accel.
* @param[in] wom_int Select which mode between AND/OR is used to generate interrupt.
* @param[in] wom_dur Select the number of over-threshold events to wait before generating
* interrupt.
* @return 0 on success, negative value on error.
*/
int inv_imu_configure_wom(inv_imu_device_t *s, const uint8_t wom_x_th, const uint8_t wom_y_th,
const uint8_t wom_z_th, WOM_CONFIG_WOM_INT_MODE_t wom_int,
WOM_CONFIG_WOM_INT_DUR_t wom_dur);
/** @brief Enable Wake On Motion.
* WoM requests to have the accelerometer enabled to work.
* As a consequence FIFO water-mark interrupt is disabled to only trigger WoM interrupts.
* To have good performance, it's recommended to set accel ODR to 20 ms and in Low Power
* Mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_enable_wom(inv_imu_device_t *s);
/** @brief Disable Wake On Motion.
* Fifo water-mark interrupt is re-enabled when WoM is disabled.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_disable_wom(inv_imu_device_t *s);
/** @brief Start DMP for APEX algorithms and self-test.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_start_dmp(inv_imu_device_t *s);
/** @brief Resume DMP operations.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_resume_dmp(struct inv_imu_device *s);
/** @brief Reset DMP for APEX algorithms and self-test.
* @param[in] s Pointer to device.
* @param[in] sram_reset Reset mode for the SRAM.
* @return 0 on success, negative value on error.
*/
int inv_imu_reset_dmp(inv_imu_device_t *s, const APEX_CONFIG0_DMP_MEM_RESET_t sram_reset);
/** @brief Set the UI endianness and set the inv_device endianness field.
* @param[in] s Pointer to device.
* @param[in] endianness Endianness to be set.
* @return 0 on success, negative value on error.
*/
int inv_imu_set_endianness(inv_imu_device_t *s, INTF_CONFIG0_DATA_ENDIAN_t endianness);
/** @brief Read the UI endianness and set the inv_device endianness field.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_get_endianness(inv_imu_device_t *s);
/** @brief Configure FIFO decimation.
* @param[in] s Pointer to device.
* @param[in] dec_factor Requested decimation factor value from 2 to 256.
* @return 0 on success, negative value on error.
*/
int inv_imu_configure_fifo_data_rate(inv_imu_device_t *s, FDR_CONFIG_FDR_SEL_t dec_factor);
/** @brief Return driver version x.y.z-suffix as a char array
* @return driver version a char array "x.y.z-suffix"
*/
const char *inv_imu_get_version(void);
/** @brief Converts two bytes in one unsigned half-word depending on endianness
* @param[in] endianness IMU's endianness.
* @param[in] in Pointer to input.
* @param[out] out Pointer to output.
*/
static inline void format_u16_data(uint8_t endianness, const uint8_t *in, uint16_t *out)
{
*out = (uint16_t)(endianness == INTF_CONFIG0_DATA_BIG_ENDIAN ? (in[0] << 8) | in[1] :
(in[1] << 8) | in[0]);
}
/** @brief Converts two bytes in one signed half-word depending on endianness
* @param[in] endianness IMU's endianness.
* @param[in] in Pointer to input.
* @param[out] out Pointer to output.
*/
static inline void format_s16_data(uint8_t endianness, const uint8_t *in, int16_t *out)
{
*out = (int16_t)(endianness == INTF_CONFIG0_DATA_BIG_ENDIAN ? (in[0] << 8) | in[1] :
(in[1] << 8) | in[0]);
}
#if INV_IMU_HFSR_SUPPORTED
/** @brief Write 'size' bytes pointed by 'data' in SRAM at offset given in parameters.
* @param[in] data pointer to data to be written in SRAM
* @param[in] offset offset in bytes from SRAM start address where data should be written
* @param[in] size number of bytes to write
* @return 0 in case of success, negative value on error.
*/
int inv_imu_write_sram(struct inv_imu_device *s, const uint8_t *data, uint32_t offset,
uint32_t size);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_DRIVER_H_ */
/** @} */