drivers: add driver for ITG320X 3-axis gyroscope
This commit is contained in:
parent
f7d6dd2337
commit
71772cc3b3
@ -273,6 +273,15 @@ ifneq (,$(filter isl29125,$(USEMODULE)))
|
|||||||
FEATURES_REQUIRED += periph_i2c
|
FEATURES_REQUIRED += periph_i2c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter itg320x_int,$(USEMODULE)))
|
||||||
|
USEMODULE += itg320x
|
||||||
|
FEATURES_REQUIRED += periph_gpio_irq
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter itg320x,$(USEMODULE)))
|
||||||
|
FEATURES_REQUIRED += periph_i2c
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter jc42,$(USEMODULE)))
|
ifneq (,$(filter jc42,$(USEMODULE)))
|
||||||
FEATURES_REQUIRED += periph_i2c
|
FEATURES_REQUIRED += periph_i2c
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -150,6 +150,10 @@ ifneq (,$(filter isl29125,$(USEMODULE)))
|
|||||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29125/include
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29125/include
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter itg320x,$(USEMODULE)))
|
||||||
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/itg320x/include
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter jc42,$(USEMODULE)))
|
ifneq (,$(filter jc42,$(USEMODULE)))
|
||||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/jc42/include
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/jc42/include
|
||||||
endif
|
endif
|
||||||
|
|||||||
316
drivers/include/itg320x.h
Normal file
316
drivers/include/itg320x.h
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Gunar Schorcht
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup drivers_itg320x ITG320X 3-axis gyroscope
|
||||||
|
* @ingroup drivers_sensors
|
||||||
|
* @ingroup drivers_saul
|
||||||
|
* @brief Device driver for InvenSense ITG320X 3-axis gyroscope
|
||||||
|
*
|
||||||
|
* The driver can be used with InvenSense ITG3200, ITG3205, and MPU3050.
|
||||||
|
* The latter one can be used only with reduced feature set.
|
||||||
|
*
|
||||||
|
* The driver implements polling mode as well as interrupt mode. Thus,
|
||||||
|
* the application may use two different approaches to retrieve new data,
|
||||||
|
* either
|
||||||
|
*
|
||||||
|
* - periodically fetching the data at a rate lower than the sensor's
|
||||||
|
* output data rate (ODR), or
|
||||||
|
* - fetching the data when the data-ready interrupt is triggered.
|
||||||
|
*
|
||||||
|
* To use the latter approach, module `itg320x_int` has to be enabled and the
|
||||||
|
* GPIO to which the sensor's **INT** output pin is connected has to be
|
||||||
|
* configured.
|
||||||
|
*
|
||||||
|
* This driver provides @ref drivers_saul capabilities.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Device driver for InvenSense ITG320X 3-axis gyroscope
|
||||||
|
*
|
||||||
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ITG320X_H
|
||||||
|
#define ITG320X_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "periph/gpio.h"
|
||||||
|
#include "periph/i2c.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name I2C addresses
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define ITG320X_I2C_ADDRESS_1 (0x68) /**< AD0 pin low */
|
||||||
|
#define ITG320X_I2C_ADDRESS_2 (0x69) /**< AD0 pin high */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** ITG320X chip id defined in Who Am I */
|
||||||
|
#define ITG320X_ID (0x68)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Named return values
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ITG320X_OK = 0, /**< success */
|
||||||
|
ITG320X_ERROR_I2C = -1, /**< I2C communication error */
|
||||||
|
ITG320X_ERROR_WRONG_ID = -2, /**< wrong id read */
|
||||||
|
ITG320X_ERROR_NO_DATA = -3, /**< no data are available */
|
||||||
|
ITG320X_ERROR_RAW_DATA = -4, /**< reading raw data failed */
|
||||||
|
} itg320x_error_codes_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low pass filter bandwidth
|
||||||
|
*
|
||||||
|
* @note Low pass filter bandwidth determines the internal sample rate (ISR).
|
||||||
|
* The internal sample rate (ISR) together with sample rate divider
|
||||||
|
* (ISR_DIV) determines the output data rate ODR = ISR / (ISR_DIV + 1)
|
||||||
|
* where internal sample rate (ISR) is 8 kHz for #ITG320X_LPF_BW_256,
|
||||||
|
* or 1 kHz otherwise.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ITG320X_LPF_BW_256 = 0, /**< 256 Hz, ISR = 8 kHz */
|
||||||
|
ITG320X_LPF_BW_188, /**< 188 Hz, ISR = 1 kHz */
|
||||||
|
ITG320X_LPF_BW_98, /**< 98 Hz, ISR = 1 kHz */
|
||||||
|
ITG320X_LPF_BW_42, /**< 42 Hz, ISR = 1 kHz */
|
||||||
|
ITG320X_LPF_BW_20, /**< 20 Hz, ISR = 1 kHz */
|
||||||
|
ITG320X_LPF_BW_10, /**< 10 Hz, ISR = 1 kHz */
|
||||||
|
ITG320X_LPF_BW_5, /**< 5 Hz, ISR = 1 kHz (default) */
|
||||||
|
} itg320x_lpf_bw_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logic level for INT output pin (ITG320X_REG_INT_CFG<7>)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ITG320X_INT_HIGH = 0x00, /**< INT output is active high (default) */
|
||||||
|
ITG320X_INT_LOW = 0x80, /**< INT output is active low */
|
||||||
|
} itg320x_int_level_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Drive type for INT output pin (ITG320X_REG_INT_CFG<6>)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ITG320X_INT_PUSH_PULL = 0x00, /**< INT output is of type push/pull (default) */
|
||||||
|
ITG320X_INT_OPEN_DRAIN = 0x40 /**< INT output is of type open drain */
|
||||||
|
} itg320x_int_drive_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clock source selection (ITG320X_REG_PWR_MGM<2:0>)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ITG320X_CLK_INTERNAL = 0, /**< Internal oscillator */
|
||||||
|
ITG320X_CLK_PLL_X_GYRO, /**< PLL with X Gyro reference (default) */
|
||||||
|
ITG320X_CLK_PLL_Y_GYRO, /**< PLL with X Gyro reference */
|
||||||
|
ITG320X_CLK_PLL_Z_GYRO, /**< PLL with X Gyro reference */
|
||||||
|
ITG320X_CLK_PLL_32K, /**< PLL with external 32.768 kHz reference */
|
||||||
|
ITG320X_CLK_PLL_19M, /**< PLL with external 19.2 MHz reference */
|
||||||
|
} itg320x_clk_sel_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Angular rate values in tenths of a degree per second
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int16_t x; /**< angular rate x-axis (roll) */
|
||||||
|
int16_t y; /**< angular rate y-axis (pitch) */
|
||||||
|
int16_t z; /**< angular rate y-axis (yaw) */
|
||||||
|
} itg320x_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Raw data set as two complements
|
||||||
|
*
|
||||||
|
* According to the sensor sensitivity of 1/14.375 degrees per second, the
|
||||||
|
* raw data values have to be divided by 14.375 to obtain the measurements
|
||||||
|
* in degrees per second.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int16_t x; /**< angular rate x-axis as 16 bit two's complements (roll) */
|
||||||
|
int16_t y; /**< angular rate y-axis as 16 bit two's complements (pitch) */
|
||||||
|
int16_t z; /**< angular rate z-axis as 16 bit two's complements (yaw) */
|
||||||
|
} itg320x_raw_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ITG320X device initialization parameters
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
i2c_t dev; /**< I2C device (default I2C_DEV(0)) */
|
||||||
|
uint8_t addr; /**< I2C slave address (default #ITG320X_I2C_ADDRESS_1) */
|
||||||
|
|
||||||
|
uint8_t isr_div; /**< Internal sample rate divider ISR_DIV (default 99)
|
||||||
|
ODR = ISR / (ISR_DIV + 1) where internal sample rate
|
||||||
|
is 1 kHz or 8 kHz dependent on the low pass filter
|
||||||
|
bandwidth #lpf_bw */
|
||||||
|
|
||||||
|
itg320x_lpf_bw_t lpf_bw; /**< Low pass filter bandwidth
|
||||||
|
(default #ITG320X_LPF_BW_5, ISR 1 kHz) */
|
||||||
|
itg320x_clk_sel_t clk_sel; /**< Clock source selection
|
||||||
|
(default ITG320X_CLK_PLL_X_GYRO) */
|
||||||
|
|
||||||
|
#if MODULE_ITG320X_INT || DOXYGEN
|
||||||
|
gpio_t int_pin; /**< DRDY interrupt pin: #GPIO_UNDEF if
|
||||||
|
not used */
|
||||||
|
itg320x_int_level_t int_level; /**< Logic level for INT output pin
|
||||||
|
(default #ITG320X_INT_LOW) */
|
||||||
|
itg320x_int_drive_t int_drive; /**< Drive type for INT output pin
|
||||||
|
(default #ITG320X_INT_PUSH_PULL */
|
||||||
|
#endif /* MODULE_ITG320X_INT || DOXYGEN */
|
||||||
|
} itg320x_params_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ITG320X sensor device data structure type
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
itg320x_params_t params; /**< device initialization parameters */
|
||||||
|
} itg320x_t;
|
||||||
|
|
||||||
|
#if MODULE_ITG320X_INT || DOXYGEN
|
||||||
|
/**
|
||||||
|
* @brief ITG320X data ready interrupt (DRDY) callback function type
|
||||||
|
*
|
||||||
|
* Function prototype for the function which is called on DRDY interrupt if
|
||||||
|
* the interrupt is activated by #itg320x_init_int
|
||||||
|
*
|
||||||
|
* @note The @p cb function is called in interrupt context. The application
|
||||||
|
* should do nothing time consuming and not directly access sensor data.
|
||||||
|
*/
|
||||||
|
typedef void (*itg320x_drdy_int_cb_t)(void *);
|
||||||
|
|
||||||
|
#endif /* MODULE_ITG320X_INT || DOXYGEN */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the ITG320X sensor device
|
||||||
|
*
|
||||||
|
* This function resets the sensor and initializes the sensor according to
|
||||||
|
* given initialization parameters. All registers are reset to default values.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor of ITG320X sensor to be initialized
|
||||||
|
* @param[in] params ITG320X initialization parameters
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK on success
|
||||||
|
* @retval ITG320X_ERROR_* a negative error code on error,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_init(itg320x_t *dev, const itg320x_params_t *params);
|
||||||
|
|
||||||
|
#if MODULE_ITG320X_INT || DOXYGEN
|
||||||
|
/**
|
||||||
|
* @brief Initialize and activate the DRDY interrupt of ITG320X sensor device
|
||||||
|
*
|
||||||
|
* This function activates the DRDY interrupt and initializes the pin defined
|
||||||
|
* as the interrupt pin in the initialization parameters of the device. The
|
||||||
|
* @p cb parameter specifies the function, along with an optional argument
|
||||||
|
* @p arg, which is called when a DRDY interrupt is triggered.
|
||||||
|
*
|
||||||
|
* @warning The given callback function @p cb is executed in interrupt context.
|
||||||
|
* Make sure not to call any driver API function in that context.
|
||||||
|
* @note This function is only available when module `itg320x_int` is enabled.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor of ITG320X sensor
|
||||||
|
* @param[in] cb function called when DRDY interrupt is triggered
|
||||||
|
* @param[in] arg argument for the callback function
|
||||||
|
*/
|
||||||
|
int itg320x_init_int(const itg320x_t *dev, itg320x_drdy_int_cb_t cb, void *arg);
|
||||||
|
|
||||||
|
#endif /* MODULE_ITG320X_INT || DOXYGEN */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data-ready status function
|
||||||
|
*
|
||||||
|
* The function checks the status register and returns
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor of ITG320X sensor
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK new data available
|
||||||
|
* @retval ITG320X_ERROR_NO_DATA no new data available
|
||||||
|
* @retval ITG320X_ERROR_* negative error code,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_data_ready(const itg320x_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read one sample of angular rates in tenths of a degree per second
|
||||||
|
*
|
||||||
|
* Raw magnetometer data are read from the sensor and normalized with
|
||||||
|
* respect to full scale +-2000 dps. Angular rate values are given in
|
||||||
|
* tenths of a degrees per second:
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor of ITG320X sensor
|
||||||
|
* @param[out] data result vector in tenths of a degrees per second
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK on success
|
||||||
|
* @retval ITG320X_ERROR_* a negative error code on error,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_read(const itg320x_t *dev, itg320x_data_t *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read one sample of raw sensor data as 16 bit two's complements
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor of ITG320X sensor
|
||||||
|
* @param[out] raw raw data vector
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK on success
|
||||||
|
* @retval ITG320X_ERROR_* a negative error code on error,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_read_raw(const itg320x_t *dev, itg320x_raw_data_t *raw);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read temperature in tenths of a degree Celsius
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor of ITG320X sensor
|
||||||
|
* @param[out] temp temperature tenths of a degree Celsius
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK on success
|
||||||
|
* @retval ITG320X_ERROR_* a negative error code on error,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_read_temp(const itg320x_t *dev, int16_t* temp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Power down the sensor
|
||||||
|
*
|
||||||
|
* Changes the sensor operation mode to sleep mode in which almost all
|
||||||
|
* including the gyros are switched off.
|
||||||
|
*
|
||||||
|
* @param[in] dev Device descriptor of ITG320X device to read from
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK on success
|
||||||
|
* @retval ITG320X_ERROR_* a negative error code on error,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_power_down(itg320x_t *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Power up the sensor
|
||||||
|
*
|
||||||
|
* Swichtes the sensor back into active operation mode. It takes
|
||||||
|
* up to 20 ms since the gyros have to be switched on again.
|
||||||
|
*
|
||||||
|
* @param[in] dev Device descriptor of ITG320X device to read from
|
||||||
|
*
|
||||||
|
* @retval ITG320X_OK on success
|
||||||
|
* @retval ITG320X_ERROR_* a negative error code on error,
|
||||||
|
* see #itg320x_error_codes_t
|
||||||
|
*/
|
||||||
|
int itg320x_power_up(itg320x_t *dev);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ITG320X_H */
|
||||||
|
/** @} */
|
||||||
3
drivers/itg320x/Makefile
Normal file
3
drivers/itg320x/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
MODULE = itg320x
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
106
drivers/itg320x/include/itg320x_params.h
Normal file
106
drivers/itg320x/include/itg320x_params.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Gunar Schorcht
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_itg320x
|
||||||
|
* @brief Default configuration for InvenSense ITG320X 3-axis gyroscope
|
||||||
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||||
|
* @file
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ITG320X_PARAMS_H
|
||||||
|
#define ITG320X_PARAMS_H
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "itg320x.h"
|
||||||
|
#include "saul_reg.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Set default configuration parameters
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef ITG320X_PARAM_DEV
|
||||||
|
#define ITG320X_PARAM_DEV I2C_DEV(0)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_ADDR
|
||||||
|
#define ITG320X_PARAM_ADDR (ITG320X_I2C_ADDRESS_1)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_LPF_BW
|
||||||
|
#define ITG320X_PARAM_LPF_BW (ITG320X_LPF_BW_5)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_ISR_DIV
|
||||||
|
#define ITG320X_PARAM_ISR_DIV (99)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_CLK_SEL
|
||||||
|
#define ITG320X_PARAM_CLK_SEL (ITG320X_CLK_PLL_X_GYRO)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_INT_PIN
|
||||||
|
#define ITG320X_PARAM_INT_PIN (GPIO_UNDEF)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_INT_LEVEL
|
||||||
|
#define ITG320X_PARAM_INT_LEVEL (ITG320X_INT_LOW)
|
||||||
|
#endif
|
||||||
|
#ifndef ITG320X_PARAM_INT_DRIVE
|
||||||
|
#define ITG320X_PARAM_INT_DRIVE (ITG320X_INT_PUSH_PULL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ITG320X_PARAMS
|
||||||
|
#ifdef MODULE_ITG320X_INT
|
||||||
|
#define ITG320X_PARAMS { \
|
||||||
|
.dev = ITG320X_PARAM_DEV, \
|
||||||
|
.addr = ITG320X_PARAM_ADDR, \
|
||||||
|
.lpf_bw = ITG320X_PARAM_LPF_BW, \
|
||||||
|
.isr_div = ITG320X_PARAM_ISR_DIV, \
|
||||||
|
.clk_sel = ITG320X_PARAM_CLK_SEL, \
|
||||||
|
.int_pin = ITG320X_PARAM_INT_PIN, \
|
||||||
|
.int_level = ITG320X_PARAM_INT_LEVEL, \
|
||||||
|
.int_drive = ITG320X_PARAM_INT_DRIVE, \
|
||||||
|
}
|
||||||
|
#else /* MODULE_ITG320X_INT */
|
||||||
|
#define ITG320X_PARAMS { \
|
||||||
|
.dev = ITG320X_PARAM_DEV, \
|
||||||
|
.addr = ITG320X_PARAM_ADDR, \
|
||||||
|
.lpf_bw = ITG320X_PARAM_LPF_BW, \
|
||||||
|
.isr_div = ITG320X_PARAM_ISR_DIV, \
|
||||||
|
.clk_sel = ITG320X_PARAM_CLK_SEL, \
|
||||||
|
}
|
||||||
|
#endif /* MODULE_ITG320X_INT */
|
||||||
|
#endif /* ITG320X_PARAMS */
|
||||||
|
|
||||||
|
#ifndef ITG320X_SAUL_INFO
|
||||||
|
#define ITG320X_SAUL_INFO { .name = "itg320x" }
|
||||||
|
#endif
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate some memory to store the actual configuration
|
||||||
|
*/
|
||||||
|
static const itg320x_params_t itg320x_params[] =
|
||||||
|
{
|
||||||
|
ITG320X_PARAMS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Additional meta information to keep in the SAUL registry
|
||||||
|
*/
|
||||||
|
static const saul_reg_info_t itg320x_saul_info[] =
|
||||||
|
{
|
||||||
|
ITG320X_SAUL_INFO
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ITG320X_PARAMS_H */
|
||||||
|
/** @} */
|
||||||
74
drivers/itg320x/include/itg320x_regs.h
Normal file
74
drivers/itg320x/include/itg320x_regs.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Gunar Schorcht
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_itg320x
|
||||||
|
* @brief Register definitions for InvenSense ITG320X 3-axis gyroscope
|
||||||
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||||
|
* @file
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ITG320X_REGS_H
|
||||||
|
#define ITG320X_REGS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Register addresses
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define ITG320X_REG_WHO_AM_I (0x00)
|
||||||
|
#define ITG320X_REG_SMPLRT_DIV (0x15)
|
||||||
|
#define ITG320X_REG_DLPFS (0x16)
|
||||||
|
#define ITG320X_REG_INT_CFG (0x17)
|
||||||
|
#define ITG320X_REG_INT_STATUS (0x1a)
|
||||||
|
#define ITG320X_REG_TEMP_OUT_H (0x1b)
|
||||||
|
#define ITG320X_REG_TEMP_OUT_L (0x1c)
|
||||||
|
#define ITG320X_REG_GYRO_XOUT_H (0x1d)
|
||||||
|
#define ITG320X_REG_GYRO_XOUT_L (0x1e)
|
||||||
|
#define ITG320X_REG_GYRO_YOUT_H (0x1f)
|
||||||
|
#define ITG320X_REG_GYRO_YOUT_L (0x20)
|
||||||
|
#define ITG320X_REG_GYRO_ZOUT_H (0x21)
|
||||||
|
#define ITG320X_REG_GYRO_ZOUT_L (0x22)
|
||||||
|
#define ITG320X_REG_PWR_MGM (0x3e)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Register structure definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define ITG320X_REG_DLPFS_FS_SEL (0x18) /**< ITG320X_REG_DLPFS<4:3> */
|
||||||
|
#define ITG320X_REG_DLPFS_FS_SEL_VAL (0x18) /**< ITG320X_REG_DLPFS<4:3> = 3 */
|
||||||
|
#define ITG320X_REG_DLPFS_DLPF_CFG (0x07) /**< ITG320X_REG_DLPFS<2:0> */
|
||||||
|
|
||||||
|
#define ITG320X_REG_INT_CFG_ACTL (0x80) /**< ITG320X_REG_INT_CFG<7> */
|
||||||
|
#define ITG320X_REG_INT_CFG_OPEN (0x40) /**< ITG320X_REG_INT_CFG<6> */
|
||||||
|
#define ITG320X_REG_INT_CFG_LATCH_INT (0x20) /**< ITG320X_REG_INT_CFG<5> */
|
||||||
|
#define ITG320X_REG_INT_CFG_ANY_RDY_CLR (0x10) /**< ITG320X_REG_INT_CFG<4> */
|
||||||
|
#define ITG320X_REG_INT_CFG_ITG_RDY_EN (0x04) /**< ITG320X_REG_INT_CFG<2> */
|
||||||
|
#define ITG320X_REG_INT_CFG_RAW_RDY_EN (0x01) /**< ITG320X_REG_INT_CFG<0> */
|
||||||
|
|
||||||
|
#define ITG320X_REG_INT_STATUS_ITG_RDY (0x04) /**< ITG320X_REG_INT_STATUS<2> */
|
||||||
|
#define ITG320X_REG_INT_STATUS_RAW_RDY (0x01) /**< ITG320X_REG_INT_STATUS<0> */
|
||||||
|
|
||||||
|
#define ITG320X_REG_PWR_MGM_H_RESET (0x80) /**< ITG320X_REG_PWR_MGM<7> */
|
||||||
|
#define ITG320X_REG_PWR_MGM_SLEEP (0x40) /**< ITG320X_REG_PWR_MGM<6> */
|
||||||
|
#define ITG320X_REG_PWR_MGM_STBY_XG (0x20) /**< ITG320X_REG_PWR_MGM<5> */
|
||||||
|
#define ITG320X_REG_PWR_MGM_STBY_YG (0x10) /**< ITG320X_REG_PWR_MGM<4> */
|
||||||
|
#define ITG320X_REG_PWR_MGM_STBY_ZG (0x08) /**< ITG320X_REG_PWR_MGM<3> */
|
||||||
|
#define ITG320X_REG_PWR_MGM_CLK_SEL (0x07) /**< ITG320X_REG_PWR_MGM<2:0> */
|
||||||
|
/** @} */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ITG320X_REGS_H */
|
||||||
357
drivers/itg320x/itg320x.c
Normal file
357
drivers/itg320x/itg320x.c
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Gunar Schorcht
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_itg320x
|
||||||
|
* @brief Device driver for the InvenSense ITG320X 3-axis gyroscope
|
||||||
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||||
|
* @file
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "itg320x_regs.h"
|
||||||
|
#include "itg320x.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#if ENABLE_DEBUG
|
||||||
|
|
||||||
|
#define DEBUG_DEV(f, d, ...) \
|
||||||
|
DEBUG("[itg320x] %s i2c dev=%d addr=%02x: " f "\n", \
|
||||||
|
__func__, d->params.dev, d->params.addr, ## __VA_ARGS__);
|
||||||
|
|
||||||
|
#else /* ENABLE_DEBUG */
|
||||||
|
|
||||||
|
#define DEBUG_DEV(f, d, ...)
|
||||||
|
|
||||||
|
#endif /* ENABLE_DEBUG */
|
||||||
|
|
||||||
|
#define ERROR_DEV(f, d, ...) \
|
||||||
|
do { \
|
||||||
|
LOG_ERROR("[itg320x] %s i2c dev=%d addr=%02x: " f "\n", \
|
||||||
|
__func__, d->params.dev, d->params.addr, ## __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXEC_RET(f) \
|
||||||
|
do { \
|
||||||
|
int _r; \
|
||||||
|
if ((_r = f) != ITG320X_OK) { \
|
||||||
|
DEBUG("[itg320x] %s: error code %d\n", __func__, _r); \
|
||||||
|
return _r; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Forward declaration of functions for internal use */
|
||||||
|
|
||||||
|
static int _is_available(const itg320x_t *dev);
|
||||||
|
static int _reset(itg320x_t *dev);
|
||||||
|
|
||||||
|
static int _reg_read(const itg320x_t *dev, uint8_t reg, uint8_t *data, uint16_t len);
|
||||||
|
static int _reg_write(const itg320x_t *dev, uint8_t reg, uint8_t data);
|
||||||
|
static int _update_reg(const itg320x_t *dev, uint8_t reg, uint8_t mask, uint8_t val);
|
||||||
|
|
||||||
|
int itg320x_init(itg320x_t *dev, const itg320x_params_t *params)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
assert(params != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("params=%p", dev, params);
|
||||||
|
|
||||||
|
/* init sensor data structure */
|
||||||
|
dev->params = *params;
|
||||||
|
|
||||||
|
/* check availability of the sensor */
|
||||||
|
EXEC_RET(_is_available(dev));
|
||||||
|
|
||||||
|
/* reset the sensor */
|
||||||
|
EXEC_RET(_reset(dev));
|
||||||
|
|
||||||
|
/* set internal sample rate divider (ISR) from parameters */
|
||||||
|
EXEC_RET(_reg_write(dev, ITG320X_REG_SMPLRT_DIV, params->isr_div));
|
||||||
|
|
||||||
|
/* set full scale always to +-2000 and LPF bandwidth from parameters */
|
||||||
|
EXEC_RET(_reg_write(dev, ITG320X_REG_DLPFS,
|
||||||
|
params->lpf_bw | ITG320X_REG_DLPFS_FS_SEL_VAL));
|
||||||
|
|
||||||
|
/* set clock source selection from parameters */
|
||||||
|
EXEC_RET(_reg_write(dev, ITG320X_REG_PWR_MGM, params->clk_sel));
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MODULE_ITG320X_INT
|
||||||
|
|
||||||
|
int itg320x_init_int(const itg320x_t *dev, itg320x_drdy_int_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
assert(dev->params.int_pin != GPIO_UNDEF);
|
||||||
|
|
||||||
|
DEBUG_DEV("cb=%p, arg=%p", dev, cb, arg);
|
||||||
|
|
||||||
|
if (dev->params.int_level == ITG320X_INT_HIGH) {
|
||||||
|
/* for high active interrupt signal (default) */
|
||||||
|
gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, cb, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* for low active interrupt signal (default) */
|
||||||
|
gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_FALLING, cb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set interrupt configuration as following
|
||||||
|
* - Logic level and drive type used from parameters
|
||||||
|
* - Latching interrupt is enabled
|
||||||
|
* - Latch clear method is reading the status register
|
||||||
|
* - RAW data ready interrupt is enabled
|
||||||
|
*/
|
||||||
|
EXEC_RET(_reg_write(dev, ITG320X_REG_INT_CFG,
|
||||||
|
dev->params.int_level | dev->params.int_drive |
|
||||||
|
ITG320X_REG_INT_CFG_LATCH_INT |
|
||||||
|
ITG320X_REG_INT_STATUS_RAW_RDY |
|
||||||
|
ITG320X_REG_INT_CFG_RAW_RDY_EN));
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MODULE_ITG320X_INT */
|
||||||
|
|
||||||
|
int itg320x_data_ready(const itg320x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("", dev);
|
||||||
|
|
||||||
|
uint8_t reg;
|
||||||
|
EXEC_RET(_reg_read(dev, ITG320X_REG_INT_STATUS, ®, 1));
|
||||||
|
|
||||||
|
return (reg & ITG320X_REG_INT_STATUS_RAW_RDY) ? ITG320X_OK
|
||||||
|
: ITG320X_ERROR_NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itg320x_read(const itg320x_t *dev, itg320x_data_t *data)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("data=%p", dev, data);
|
||||||
|
|
||||||
|
itg320x_raw_data_t raw;
|
||||||
|
|
||||||
|
EXEC_RET(itg320x_read_raw(dev, &raw));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The sensitivity of the sensor is 1/14.375 degree/seconds per LSB
|
||||||
|
* with a tolerance of the scale factor of +-6 %. Scale raw values to
|
||||||
|
* tenths of a degree/seconds according to sensors sensitivity
|
||||||
|
* which corresponds to 8/115 degrees/seconds per LSB.
|
||||||
|
*/
|
||||||
|
data->x = (uint32_t)(raw.x * 80 / 115);
|
||||||
|
data->y = (uint32_t)(raw.y * 80 / 115);
|
||||||
|
data->z = (uint32_t)(raw.z * 80 / 115);
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itg320x_read_raw(const itg320x_t *dev, itg320x_raw_data_t *raw)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
assert(raw != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("raw=%p", dev, raw);
|
||||||
|
|
||||||
|
uint8_t data[6];
|
||||||
|
|
||||||
|
/* read raw data sample */
|
||||||
|
EXEC_RET(_reg_read(dev, ITG320X_REG_GYRO_XOUT_H, data, 6));
|
||||||
|
|
||||||
|
/* data MSB @ lower address */
|
||||||
|
raw->x = (data[0] << 8) | data[1];
|
||||||
|
raw->y = (data[2] << 8) | data[3];
|
||||||
|
raw->z = (data[4] << 8) | data[5];
|
||||||
|
|
||||||
|
#ifdef MODULE_ITG320X_INT
|
||||||
|
/* read status register to clear the interrupt */
|
||||||
|
EXEC_RET(_reg_read(dev, ITG320X_REG_INT_STATUS, data, 1));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itg320x_read_temp(const itg320x_t *dev, int16_t *temp)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
assert(temp != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("temp=%p", dev, temp);
|
||||||
|
|
||||||
|
uint8_t data[2];
|
||||||
|
|
||||||
|
/* read raw temperature */
|
||||||
|
EXEC_RET(_reg_read(dev, ITG320X_REG_TEMP_OUT_H, data, 2));
|
||||||
|
|
||||||
|
/* data MSB @ lower address */
|
||||||
|
*temp = (data[0] << 8) | data[1];
|
||||||
|
/* convert raw temperature data to tenths of a degree Celsius */
|
||||||
|
*temp = (*temp + 13200) / 28 + 350;
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itg320x_power_down(itg320x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("", dev);
|
||||||
|
|
||||||
|
return _update_reg(dev, ITG320X_REG_PWR_MGM, ITG320X_REG_PWR_MGM_SLEEP, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int itg320x_power_up(itg320x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("", dev);
|
||||||
|
|
||||||
|
EXEC_RET(_update_reg(dev, ITG320X_REG_PWR_MGM, ITG320X_REG_PWR_MGM_SLEEP, 0));
|
||||||
|
|
||||||
|
/* wait 20 ms after power-up */
|
||||||
|
xtimer_usleep(20 * US_PER_MS);
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Functions for internal use only */
|
||||||
|
|
||||||
|
static int _reset(itg320x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("", dev);
|
||||||
|
|
||||||
|
/* set the reset flag, it automatically reset by the device */
|
||||||
|
EXEC_RET(_update_reg(dev, ITG320X_REG_PWR_MGM, ITG320X_REG_PWR_MGM_H_RESET, 1));
|
||||||
|
|
||||||
|
/* wait 20 ms after reset */
|
||||||
|
xtimer_usleep(20 * US_PER_MS);
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check the chip ID to test whether sensor is available
|
||||||
|
*/
|
||||||
|
static int _is_available(const itg320x_t *dev)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("", dev);
|
||||||
|
|
||||||
|
uint8_t reg;
|
||||||
|
|
||||||
|
/* read the chip id from ITG320X_REG_ID_X */
|
||||||
|
EXEC_RET(_reg_read(dev, ITG320X_REG_WHO_AM_I, ®, 1));
|
||||||
|
|
||||||
|
if (reg != ITG320X_ID) {
|
||||||
|
DEBUG_DEV("sensor is not available, wrong id %02x, should be %02x",
|
||||||
|
dev, reg, ITG320X_ID);
|
||||||
|
return ITG320X_ERROR_WRONG_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _update_reg(const itg320x_t *dev, uint8_t reg, uint8_t mask, uint8_t val)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("reg=%02x mask=%02x val=%02x", dev, reg, mask, val);
|
||||||
|
|
||||||
|
uint8_t reg_val;
|
||||||
|
uint8_t shift = 0;
|
||||||
|
|
||||||
|
while (!((mask >> shift) & 0x01)) {
|
||||||
|
shift++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read current register value */
|
||||||
|
EXEC_RET(_reg_read(dev, reg, ®_val, 1));
|
||||||
|
|
||||||
|
/* set masked bits to the given value */
|
||||||
|
reg_val = (reg_val & ~mask) | ((val << shift) & mask);
|
||||||
|
|
||||||
|
/* write back new register value */
|
||||||
|
EXEC_RET(_reg_write(dev, reg, reg_val));
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _reg_read(const itg320x_t *dev, uint8_t reg, uint8_t *data, uint16_t len)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(len != 0);
|
||||||
|
|
||||||
|
DEBUG_DEV("read %d bytes from reg 0x%02x", dev, len, reg);
|
||||||
|
|
||||||
|
if (i2c_acquire(dev->params.dev) != 0) {
|
||||||
|
DEBUG_DEV("could not acquire the I2C bus", dev);
|
||||||
|
return ITG320X_ERROR_I2C;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = i2c_read_regs(dev->params.dev, dev->params.addr, reg, data, len, 0);
|
||||||
|
i2c_release(dev->params.dev);
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
DEBUG_DEV("could not read %d bytes from sensor registers "
|
||||||
|
"starting at addr %02x, reason %d (%s)",
|
||||||
|
dev, len, reg, res, strerror(res * -1));
|
||||||
|
return ITG320X_ERROR_I2C;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_DEBUG
|
||||||
|
printf("[itg320x] %s i2c dev=%d addr=%02x: read %d bytes from reg 0x%02x: ",
|
||||||
|
__func__, dev->params.dev, dev->params.addr, len, reg);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
printf("%02x ", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _reg_write(const itg320x_t *dev, uint8_t reg, uint8_t data)
|
||||||
|
{
|
||||||
|
assert(dev != NULL);
|
||||||
|
|
||||||
|
DEBUG_DEV("write 1 byte to reg 0x%02x: 0x%02x", dev, reg, data);
|
||||||
|
|
||||||
|
if (i2c_acquire(dev->params.dev) != 0) {
|
||||||
|
DEBUG_DEV("could not acquire the I2C bus", dev);
|
||||||
|
return ITG320X_ERROR_I2C;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = i2c_write_regs(dev->params.dev, dev->params.addr, reg, &data, 1, 0);
|
||||||
|
i2c_release(dev->params.dev);
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
DEBUG_DEV("could not write to sensor register 0x%02x, reason %d (%s)",
|
||||||
|
dev, reg, res, strerror(res * -1));
|
||||||
|
return ITG320X_ERROR_I2C;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ITG320X_OK;
|
||||||
|
}
|
||||||
59
drivers/itg320x/itg320x_saul.c
Normal file
59
drivers/itg320x/itg320x_saul.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Gunar Schorcht
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_itg320x
|
||||||
|
* @brief ITG320X adaption to the RIOT actuator/sensor interface
|
||||||
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "saul.h"
|
||||||
|
#include "itg320x.h"
|
||||||
|
|
||||||
|
static int read_gyro(const void *dev, phydat_t *res)
|
||||||
|
{
|
||||||
|
itg320x_data_t data;
|
||||||
|
int ret = itg320x_read((const itg320x_t *)dev, &data);
|
||||||
|
if (ret < 0) {
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
/* convert milli-dps to deci-dps */
|
||||||
|
res->val[0] = data.x;
|
||||||
|
res->val[1] = data.y;
|
||||||
|
res->val[2] = data.z;
|
||||||
|
|
||||||
|
res->unit = UNIT_DPS;
|
||||||
|
res->scale = -1;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_temp(const void *dev, phydat_t *res)
|
||||||
|
{
|
||||||
|
int ret = itg320x_read_temp((const itg320x_t *)dev, &res->val[0]);
|
||||||
|
if (ret < 0) {
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
res->unit = UNIT_TEMP_C;
|
||||||
|
res->scale = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const saul_driver_t itg320x_saul_gyro_driver = {
|
||||||
|
.read = read_gyro,
|
||||||
|
.write = saul_notsup,
|
||||||
|
.type = SAUL_SENSE_GYRO,
|
||||||
|
};
|
||||||
|
|
||||||
|
const saul_driver_t itg320x_saul_temp_driver = {
|
||||||
|
.read = read_temp,
|
||||||
|
.write = saul_notsup,
|
||||||
|
.type = SAUL_SENSE_TEMP,
|
||||||
|
};
|
||||||
@ -122,6 +122,9 @@ PSEUDOMODULES += cc1100
|
|||||||
PSEUDOMODULES += cc1100e
|
PSEUDOMODULES += cc1100e
|
||||||
PSEUDOMODULES += cc1101
|
PSEUDOMODULES += cc1101
|
||||||
|
|
||||||
|
# interrupt variant of the ITG320X driver as pseudo module
|
||||||
|
PSEUDOMODULES += itg320x_int
|
||||||
|
|
||||||
# include variants of MPU9X50 drivers as pseudo modules
|
# include variants of MPU9X50 drivers as pseudo modules
|
||||||
PSEUDOMODULES += mpu9150
|
PSEUDOMODULES += mpu9150
|
||||||
PSEUDOMODULES += mpu9250
|
PSEUDOMODULES += mpu9250
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user