git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9627 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
Giovanni Di Sirio 2016-06-16 07:44:08 +00:00
parent c4995095ee
commit 77a63206e7
16 changed files with 8258 additions and 8258 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,273 +1,273 @@
/*
ChibiOS - Copyright (C) 2016 Giovanni Di Sirio
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file m25q.h
* @brief Micron serial flash driver header.
*
* @addtogroup m25q
* @{
*/
#ifndef M25Q_H
#define M25Q_H
#include "hal_jesd216_flash.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Version identification
* @{
*/
/**
* @brief M25Q driver version string.
*/
#define EX_M25Q_VERSION "1.0.0"
/**
* @brief M25Q driver version major number.
*/
#define EX_M25Q_MAJOR 1
/**
* @brief M25Q driver version minor number.
*/
#define EX_M25Q__MINOR 0
/**
* @brief M25Q driver version patch number.
*/
#define EX_M25Q_PATCH 0
/** @} */
/**
* @name Command codes
* @{
*/
#define M25Q_CMD_RESET_ENABLE 0x66
#define M25Q_CMD_RESET_MEMORY 0x99
#define M25Q_CMD_READ_ID 0x9F
#define M25Q_CMD_MULTIPLE_IO_READ_ID 0xAF
#define M25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A
#define M25Q_CMD_READ 0x03
#define M25Q_CMD_FAST_READ 0x0B
#define M25Q_CMD_WRITE_ENABLE 0x06
#define M25Q_CMD_WRITE_DISABLE 0x04
#define M25Q_CMD_READ_STATUS_REGISTER 0x05
#define M25Q_CMD_WRITE_STATUS_REGISTER 0x01
#define M25Q_CMD_READ_LOCK_REGISTER 0xE8
#define M25Q_CMD_WRITE_LOCK_REGISTER 0xE5
#define M25Q_CMD_READ_FLAG_STATUS_REGISTER 0x70
#define M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER 0x50
#define M25Q_CMD_READ_NV_CONFIGURATION_REGISTER 0xB5
#define M25Q_CMD_WRITE_NV_CONFIGURATION_REGISTER 0xB1
#define M25Q_CMD_READ_V_CONF_REGISTER 0x85
#define M25Q_CMD_WRITE_V_CONF_REGISTER 0x81
#define M25Q_CMD_READ_ENHANCED_V_CONF_REGISTER 0x65
#define M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER 0x61
#define M25Q_CMD_PAGE_PROGRAM 0x02
#define M25Q_CMD_SUBSECTOR_ERASE 0x20
#define M25Q_CMD_SECTOR_ERASE 0xD8
#define M25Q_CMD_BULK_ERASE 0xC7
#define M25Q_CMD_PROGRAM_ERASE_RESUME 0x7A
#define M25Q_CMD_PROGRAM_ERASE_SUSPEND 0x75
#define M25Q_CMD_READ_OTP_ARRAY 0x4B
#define M25Q_CMD_PROGRAM_OTP_ARRAY 0x42
/** @} */
/**
* @name Flags status register bits
* @{
*/
#define M25Q_FLAGS_PROGRAM_ERASE 0x80U
#define M25Q_FLAGS_ERASE_SUSPEND 0x40U
#define M25Q_FLAGS_ERASE_ERROR 0x20U
#define M25Q_FLAGS_PROGRAM_ERROR 0x10U
#define M25Q_FLAGS_VPP_ERROR 0x08U
#define M25Q_FLAGS_PROGRAM_SUSPEND 0x04U
#define M25Q_FLAGS_PROTECTION_ERROR 0x02U
#define M25Q_FLAGS_RESERVED 0x01U
#define M25Q_FLAGS_ALL_ERRORS (M25Q_FLAGS_ERASE_ERROR | \
M25Q_FLAGS_PROGRAM_ERROR | \
M25Q_FLAGS_VPP_ERROR | \
M25Q_FLAGS_PROTECTION_ERROR)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief Number of dummy cycles for fast read (1..15).
* @details This is the number of dummy cycles to be used for fast read
* operations.
*/
#if !defined(M25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__)
#define M25Q_READ_DUMMY_CYCLES 8
#endif
/**
* @brief Switch QSPI bus width on initialization.
* @details A bus width initialization is performed by writing the
* Enhanced Volatile Configuration Register. If the flash
* device is configured using the Non Volatile Configuration
* Register then this option is not required.
* @note This option is only valid in QSPI bus modes.
*/
#if !defined(M25Q_SWITCH_WIDTH) || defined(__DOXYGEN__)
#define M25Q_SWITCH_WIDTH TRUE
#endif
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the flash waiting
* routines releasing some extra CPU time for threads with lower
* priority, this may slow down the driver a bit however.
*/
#if !defined(M25Q_NICE_WAITING) || defined(__DOXYGEN__)
#define M25Q_NICE_WAITING TRUE
#endif
/**
* @brief Uses 4kB sub-sectors rather than 64kB sectors.
*/
#if !defined(M25Q_USE_SUB_SECTORS) || defined(__DOXYGEN__)
#define M25Q_USE_SUB_SECTORS FALSE
#endif
/**
* @brief Supported JEDEC manufacturer identifiers.
*/
#if !defined(M25Q_SUPPORTED_MANUFACTURE_IDS) || defined(__DOXYGEN__)
#define M25Q_SUPPORTED_MANUFACTURE_IDS {0x20}
#endif
/**
* @brief Supported memory type identifiers.
*/
#if !defined(M25Q_SUPPORTED_MEMORY_TYPE_IDS) || defined(__DOXYGEN__)
#define M25Q_SUPPORTED_MEMORY_TYPE_IDS {0xBA, 0xBB}
#endif
/**
* @brief Size of the compare buffer.
* @details This buffer is allocated in the stack frame of the function
* @p flashVerifyErase() and its size must be a power of two.
* Larger buffers lead to better verify performance but increase
* stack usage for that function.
*/
#if !defined(M25Q_COMPARE_BUFFER_SIZE) || defined(__DOXYGEN__)
#define M25Q_COMPARE_BUFFER_SIZE 32
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (M25Q_READ_DUMMY_CYCLES < 1) || (M25Q_READ_DUMMY_CYCLES > 15)
#error "invalid M25Q_READ_DUMMY_CYCLES value (1..15)"
#endif
#if (M25Q_COMPARE_BUFFER_SIZE & (M25Q_COMPARE_BUFFER_SIZE - 1)) != 0
#error "invalid M25Q_COMPARE_BUFFER_SIZE value"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a M25Q configuration structure.
*/
typedef struct {
_jesd216_config
} M25QConfig;
/**
* @brief @p M25Q specific methods.
*/
#define _m25q_methods \
_jesd216_flash_methods
/**
* @extends JESD216FlashVMT
*
* @brief @p M25Q virtual methods table.
*/
struct M25QDriverVMT {
_m25q_methods
};
/**
* @extends JESD216Flash
*
* @brief Type of M25Q flash class.
*/
typedef struct {
/**
* @brief M25QDriver Virtual Methods Table.
*/
const struct M25QDriverVMT *vmt;
_jesd216_flash_data
/**
* @brief Current configuration data.
*/
const M25QConfig *config;
/**
* @brief Device ID and unique ID.
*/
uint8_t device_id[20];
} M25QDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void m25qObjectInit(M25QDriver *devp);
void m25qStart(M25QDriver *devp, const M25QConfig *config);
void m25qStop(M25QDriver *devp);
#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
#if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
void m25qMemoryMap(M25QDriver *devp, uint8_t ** addrp);
void m25qMemoryUnmap(M25QDriver *devp);
#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
#ifdef __cplusplus
}
#endif
#endif /* M25Q_H */
/** @} */
/*
ChibiOS - Copyright (C) 2016 Giovanni Di Sirio
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file m25q.h
* @brief Micron serial flash driver header.
*
* @addtogroup m25q
* @{
*/
#ifndef M25Q_H
#define M25Q_H
#include "hal_jesd216_flash.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Version identification
* @{
*/
/**
* @brief M25Q driver version string.
*/
#define EX_M25Q_VERSION "1.0.0"
/**
* @brief M25Q driver version major number.
*/
#define EX_M25Q_MAJOR 1
/**
* @brief M25Q driver version minor number.
*/
#define EX_M25Q__MINOR 0
/**
* @brief M25Q driver version patch number.
*/
#define EX_M25Q_PATCH 0
/** @} */
/**
* @name Command codes
* @{
*/
#define M25Q_CMD_RESET_ENABLE 0x66
#define M25Q_CMD_RESET_MEMORY 0x99
#define M25Q_CMD_READ_ID 0x9F
#define M25Q_CMD_MULTIPLE_IO_READ_ID 0xAF
#define M25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A
#define M25Q_CMD_READ 0x03
#define M25Q_CMD_FAST_READ 0x0B
#define M25Q_CMD_WRITE_ENABLE 0x06
#define M25Q_CMD_WRITE_DISABLE 0x04
#define M25Q_CMD_READ_STATUS_REGISTER 0x05
#define M25Q_CMD_WRITE_STATUS_REGISTER 0x01
#define M25Q_CMD_READ_LOCK_REGISTER 0xE8
#define M25Q_CMD_WRITE_LOCK_REGISTER 0xE5
#define M25Q_CMD_READ_FLAG_STATUS_REGISTER 0x70
#define M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER 0x50
#define M25Q_CMD_READ_NV_CONFIGURATION_REGISTER 0xB5
#define M25Q_CMD_WRITE_NV_CONFIGURATION_REGISTER 0xB1
#define M25Q_CMD_READ_V_CONF_REGISTER 0x85
#define M25Q_CMD_WRITE_V_CONF_REGISTER 0x81
#define M25Q_CMD_READ_ENHANCED_V_CONF_REGISTER 0x65
#define M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER 0x61
#define M25Q_CMD_PAGE_PROGRAM 0x02
#define M25Q_CMD_SUBSECTOR_ERASE 0x20
#define M25Q_CMD_SECTOR_ERASE 0xD8
#define M25Q_CMD_BULK_ERASE 0xC7
#define M25Q_CMD_PROGRAM_ERASE_RESUME 0x7A
#define M25Q_CMD_PROGRAM_ERASE_SUSPEND 0x75
#define M25Q_CMD_READ_OTP_ARRAY 0x4B
#define M25Q_CMD_PROGRAM_OTP_ARRAY 0x42
/** @} */
/**
* @name Flags status register bits
* @{
*/
#define M25Q_FLAGS_PROGRAM_ERASE 0x80U
#define M25Q_FLAGS_ERASE_SUSPEND 0x40U
#define M25Q_FLAGS_ERASE_ERROR 0x20U
#define M25Q_FLAGS_PROGRAM_ERROR 0x10U
#define M25Q_FLAGS_VPP_ERROR 0x08U
#define M25Q_FLAGS_PROGRAM_SUSPEND 0x04U
#define M25Q_FLAGS_PROTECTION_ERROR 0x02U
#define M25Q_FLAGS_RESERVED 0x01U
#define M25Q_FLAGS_ALL_ERRORS (M25Q_FLAGS_ERASE_ERROR | \
M25Q_FLAGS_PROGRAM_ERROR | \
M25Q_FLAGS_VPP_ERROR | \
M25Q_FLAGS_PROTECTION_ERROR)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief Number of dummy cycles for fast read (1..15).
* @details This is the number of dummy cycles to be used for fast read
* operations.
*/
#if !defined(M25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__)
#define M25Q_READ_DUMMY_CYCLES 8
#endif
/**
* @brief Switch QSPI bus width on initialization.
* @details A bus width initialization is performed by writing the
* Enhanced Volatile Configuration Register. If the flash
* device is configured using the Non Volatile Configuration
* Register then this option is not required.
* @note This option is only valid in QSPI bus modes.
*/
#if !defined(M25Q_SWITCH_WIDTH) || defined(__DOXYGEN__)
#define M25Q_SWITCH_WIDTH TRUE
#endif
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the flash waiting
* routines releasing some extra CPU time for threads with lower
* priority, this may slow down the driver a bit however.
*/
#if !defined(M25Q_NICE_WAITING) || defined(__DOXYGEN__)
#define M25Q_NICE_WAITING TRUE
#endif
/**
* @brief Uses 4kB sub-sectors rather than 64kB sectors.
*/
#if !defined(M25Q_USE_SUB_SECTORS) || defined(__DOXYGEN__)
#define M25Q_USE_SUB_SECTORS FALSE
#endif
/**
* @brief Supported JEDEC manufacturer identifiers.
*/
#if !defined(M25Q_SUPPORTED_MANUFACTURE_IDS) || defined(__DOXYGEN__)
#define M25Q_SUPPORTED_MANUFACTURE_IDS {0x20}
#endif
/**
* @brief Supported memory type identifiers.
*/
#if !defined(M25Q_SUPPORTED_MEMORY_TYPE_IDS) || defined(__DOXYGEN__)
#define M25Q_SUPPORTED_MEMORY_TYPE_IDS {0xBA, 0xBB}
#endif
/**
* @brief Size of the compare buffer.
* @details This buffer is allocated in the stack frame of the function
* @p flashVerifyErase() and its size must be a power of two.
* Larger buffers lead to better verify performance but increase
* stack usage for that function.
*/
#if !defined(M25Q_COMPARE_BUFFER_SIZE) || defined(__DOXYGEN__)
#define M25Q_COMPARE_BUFFER_SIZE 32
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (M25Q_READ_DUMMY_CYCLES < 1) || (M25Q_READ_DUMMY_CYCLES > 15)
#error "invalid M25Q_READ_DUMMY_CYCLES value (1..15)"
#endif
#if (M25Q_COMPARE_BUFFER_SIZE & (M25Q_COMPARE_BUFFER_SIZE - 1)) != 0
#error "invalid M25Q_COMPARE_BUFFER_SIZE value"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a M25Q configuration structure.
*/
typedef struct {
_jesd216_config
} M25QConfig;
/**
* @brief @p M25Q specific methods.
*/
#define _m25q_methods \
_jesd216_flash_methods
/**
* @extends JESD216FlashVMT
*
* @brief @p M25Q virtual methods table.
*/
struct M25QDriverVMT {
_m25q_methods
};
/**
* @extends JESD216Flash
*
* @brief Type of M25Q flash class.
*/
typedef struct {
/**
* @brief M25QDriver Virtual Methods Table.
*/
const struct M25QDriverVMT *vmt;
_jesd216_flash_data
/**
* @brief Current configuration data.
*/
const M25QConfig *config;
/**
* @brief Device ID and unique ID.
*/
uint8_t device_id[20];
} M25QDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void m25qObjectInit(M25QDriver *devp);
void m25qStart(M25QDriver *devp, const M25QConfig *config);
void m25qStop(M25QDriver *devp);
#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
#if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
void m25qMemoryMap(M25QDriver *devp, uint8_t ** addrp);
void m25qMemoryUnmap(M25QDriver *devp);
#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
#ifdef __cplusplus
}
#endif
#endif /* M25Q_H */
/** @} */

View File

@ -1,482 +1,482 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file l3gd20.c
* @brief L3GD20 MEMS interface module code.
*
* @addtogroup l3gd20
* @{
*/
#include "hal.h"
#include "l3gd20.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define L3GD20_SENS_250DPS ((float)0.00875f)
#define L3GD20_SENS_500DPS ((float)0.01750f)
#define L3GD20_SENS_2000DPS ((float)0.07000f)
#define L3GD20_DI ((uint8_t)0xFF)
#define L3GD20_DI_0 ((uint8_t)0x01)
#define L3GD20_DI_1 ((uint8_t)0x02)
#define L3GD20_DI_2 ((uint8_t)0x04)
#define L3GD20_DI_3 ((uint8_t)0x08)
#define L3GD20_DI_4 ((uint8_t)0x10)
#define L3GD20_DI_5 ((uint8_t)0x20)
#define L3GD20_DI_6 ((uint8_t)0x40)
#define L3GD20_DI_7 ((uint8_t)0x80)
#define L3GD20_AD ((uint8_t)0x3F)
#define L3GD20_AD_0 ((uint8_t)0x01)
#define L3GD20_AD_1 ((uint8_t)0x02)
#define L3GD20_AD_2 ((uint8_t)0x04)
#define L3GD20_AD_3 ((uint8_t)0x08)
#define L3GD20_AD_4 ((uint8_t)0x10)
#define L3GD20_AD_5 ((uint8_t)0x20)
#define L3GD20_MS ((uint8_t)0x40)
#define L3GD20_RW ((uint8_t)0x80)
#define L3GD20_AD_WHO_AM_I ((uint8_t)0x0F)
#define L3GD20_AD_CTRL_REG1 ((uint8_t)0x20)
#define L3GD20_AD_CTRL_REG2 ((uint8_t)0x21)
#define L3GD20_AD_CTRL_REG3 ((uint8_t)0x22)
#define L3GD20_AD_CTRL_REG4 ((uint8_t)0x23)
#define L3GD20_AD_CTRL_REG5 ((uint8_t)0x24)
#define L3GD20_AD_REFERENCE ((uint8_t)0x25)
#define L3GD20_AD_OUT_TEMP ((uint8_t)0x26)
#define L3GD20_AD_STATUS_REG ((uint8_t)0x27)
#define L3GD20_AD_OUT_X_L ((uint8_t)0x28)
#define L3GD20_AD_OUT_X_H ((uint8_t)0x29)
#define L3GD20_AD_OUT_Y_L ((uint8_t)0x2A)
#define L3GD20_AD_OUT_Y_H ((uint8_t)0x2B)
#define L3GD20_AD_OUT_Z_L ((uint8_t)0x2C)
#define L3GD20_AD_OUT_Z_H ((uint8_t)0x2D)
#define L3GD20_AD_FIFO_CTRL_REG ((uint8_t)0x2E)
#define L3GD20_AD_FIFO_SRC_REG ((uint8_t)0x2F)
#define L3GD20_AD_INT1_CFG ((uint8_t)0x30)
#define L3GD20_AD_INT1_SRC ((uint8_t)0x31)
#define L3GD20_AD_INT1_TSH_XH ((uint8_t)0x32)
#define L3GD20_AD_INT1_TSH_XL ((uint8_t)0x33)
#define L3GD20_AD_INT1_TSH_YH ((uint8_t)0x34)
#define L3GD20_AD_INT1_TSH_YL ((uint8_t)0x35)
#define L3GD20_AD_INT1_TSH_ZH ((uint8_t)0x36)
#define L3GD20_AD_INT1_TSH_ZL ((uint8_t)0x37)
#define L3GD20_AD_INT1_DURATION ((uint8_t)0x38)
#define L3GD20_CTRL_REG4_FS_MASK ((uint8_t)0x30)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief L3GD20 Power Mode
*/
typedef enum {
L3GD20_PM_POWER_DOWN = 0x00, /**< Power down enabled. */
L3GD20_PM_SLEEP_NORMAL = 0x08 /**< Normal operation mode. */
}l3gd20_pm_t;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if (L3GD20_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief Reads a generic register value using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @return register value.
*/
static uint8_t l3gd20SPIReadRegister(SPIDriver *spip, uint8_t reg) {
uint8_t txbuf[2] = {L3GD20_RW | reg, 0xFF};
uint8_t rxbuf[2] = {0x00, 0x00};
spiSelect(spip);
spiExchange(spip, 2, txbuf, rxbuf);
spiUnselect(spip);
return rxbuf[1];
}
/**
* @brief Writes a value into a generic register using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @param[in] value register value.
*/
static void l3gd20SPIWriteRegister(SPIDriver *spip, uint8_t reg,
uint8_t value) {
switch (reg) {
default:
/* Reserved register must not be written, according to the datasheet
* this could permanently damage the device.
*/
osalDbgAssert(FALSE, "l3gd20SPIWriteRegister(), reserved register");
case L3GD20_AD_WHO_AM_I:
case L3GD20_AD_OUT_TEMP :
case L3GD20_AD_STATUS_REG:
case L3GD20_AD_OUT_X_L:
case L3GD20_AD_OUT_X_H:
case L3GD20_AD_OUT_Y_L:
case L3GD20_AD_OUT_Y_H:
case L3GD20_AD_OUT_Z_L:
case L3GD20_AD_OUT_Z_H:
case L3GD20_AD_FIFO_SRC_REG:
case L3GD20_AD_INT1_SRC:
/* Read only registers cannot be written, the command is ignored.*/
return;
case L3GD20_AD_CTRL_REG1:
case L3GD20_AD_CTRL_REG2:
case L3GD20_AD_CTRL_REG3:
case L3GD20_AD_CTRL_REG4:
case L3GD20_AD_CTRL_REG5:
case L3GD20_AD_REFERENCE:
case L3GD20_AD_FIFO_CTRL_REG:
case L3GD20_AD_INT1_CFG:
case L3GD20_AD_INT1_TSH_XH:
case L3GD20_AD_INT1_TSH_XL:
case L3GD20_AD_INT1_TSH_YH:
case L3GD20_AD_INT1_TSH_YL:
case L3GD20_AD_INT1_TSH_ZH:
case L3GD20_AD_INT1_TSH_ZL:
case L3GD20_AD_INT1_DURATION:
spiSelect(spip);
uint8_t txbuf[2] = {reg, value};
spiSend(spip, 2, txbuf);
spiUnselect(spip);
}
}
#endif /* L3GD20_USE_SPI */
/*
* Interface implementation.
*/
static size_t get_axes_number(void *ip) {
osalDbgCheck(ip != NULL);
return L3GD20_NUMBER_OF_AXES;
}
static msg_t read_raw(void *ip, int32_t axes[L3GD20_NUMBER_OF_AXES]) {
int16_t tmp;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"read_raw(), invalid state");
#if L3GD20_USE_SPI
osalDbgAssert((((L3GD20Driver *)ip)->config->spip->state == SPI_READY),
"read_raw(), channel not ready");
#if L3GD20_SHARED_SPI
spiAcquireBus(((L3GD20Driver *)ip)->config->spip);
spiStart(((L3GD20Driver *)ip)->config->spip,
((L3GD20Driver *)ip)->config->spicfg);
#endif /* L3GD20_SHARED_SPI */
if(((L3GD20Driver *)ip)->config->axesenabling & L3GD20_AE_X){
tmp = l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_X_L);
tmp += l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_X_H) << 8;
axes[0] = (int32_t)tmp + ((L3GD20Driver *)ip)->bias[0];
}
if(((L3GD20Driver *)ip)->config->axesenabling & L3GD20_AE_Y){
tmp = l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Y_L);
tmp += l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Y_H) << 8;
axes[1] = (int32_t)tmp + ((L3GD20Driver *)ip)->bias[1];
}
if(((L3GD20Driver *)ip)->config->axesenabling & L3GD20_AE_Z){
tmp = l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Z_L);
tmp += l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Z_H) << 8;
axes[2] = (int32_t)tmp + ((L3GD20Driver *)ip)->bias[2];
}
#if L3GD20_SHARED_SPI
spiReleaseBus(((L3GD20Driver *)ip)->config->spip);
#endif /* L3GD20_SHARED_SPI */
#endif /* L3GD20_USE_SPI */
return MSG_OK;
}
static msg_t read_cooked(void *ip, float axes[]) {
uint32_t i;
int32_t raw[L3GD20_NUMBER_OF_AXES];
msg_t msg;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"read_cooked(), invalid state");
msg = read_raw(ip, raw);
for(i = 0; i < L3GD20_NUMBER_OF_AXES ; i++){
axes[i] = raw[i] * ((L3GD20Driver *)ip)->sensitivity[i];
}
return msg;
}
static msg_t sample_bias(void *ip) {
uint32_t i, j;
int32_t raw[L3GD20_NUMBER_OF_AXES];
int32_t buff[L3GD20_NUMBER_OF_AXES] = {0, 0, 0};
osalDbgCheck(ip != NULL);
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"sample_bias(), invalid state");
for(i = 0; i < L3GD20_BIAS_ACQ_TIMES; i++){
read_raw(ip, raw);
for(j = 0; j < L3GD20_NUMBER_OF_AXES; j++){
buff[j] += raw[j];
}
osalThreadSleepMicroseconds(L3GD20_BIAS_SETTLING_uS);
}
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++){
((L3GD20Driver *)ip)->bias[i] = buff[i] / L3GD20_BIAS_ACQ_TIMES;
}
return MSG_OK;
}
static msg_t set_bias(void *ip, int32_t *bp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (bp !=NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY) ||
(((L3GD20Driver *)ip)->state == L3GD20_STOP),
"set_bias(), invalid state");
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++) {
((L3GD20Driver *)ip)->bias[i] = bp[i];
}
return MSG_OK;
}
static msg_t reset_bias(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY) ||
(((L3GD20Driver *)ip)->state == L3GD20_STOP),
"reset_bias(), invalid state");
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->bias[i] = 0;
return MSG_OK;
}
static msg_t set_sensivity(void *ip, float *sp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (sp !=NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"set_sensivity(), invalid state");
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++) {
((L3GD20Driver *)ip)->sensitivity[i] = sp[i];
}
return MSG_OK;
}
static msg_t reset_sensivity(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"reset_sensivity(), invalid state");
if(((L3GD20Driver *)ip)->config->fullscale == L3GD20_FS_250DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->sensitivity[i] = L3GD20_SENS_250DPS;
else if(((L3GD20Driver *)ip)->config->fullscale == L3GD20_FS_500DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->sensitivity[i] = L3GD20_SENS_500DPS;
else if(((L3GD20Driver *)ip)->config->fullscale == L3GD20_FS_2000DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->sensitivity[i] = L3GD20_SENS_2000DPS;
else {
osalDbgAssert(FALSE, "reset_sensivity(), full scale issue");
return MSG_RESET;
}
return MSG_OK;
}
static msg_t get_temperature(void *ip, float* tempp) {
#if L3GD20_USE_SPI
osalDbgAssert((((L3GD20Driver *)ip)->config->spip->state == SPI_READY),
"read_raw(), channel not ready");
#if L3GD20_SHARED_SPI
spiAcquireBus(((L3GD20Driver *)ip)->config->spip);
spiStart(((L3GD20Driver *)ip)->config->spip,
((L3GD20Driver *)ip)->config->spicfg);
#endif /* L3GD20_SHARED_SPI */
*tempp = (int8_t)l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_TEMP);
#if L3GD20_SHARED_SPI
spiReleaseBus(((L3GD20Driver *)ip)->config->spip);
#endif /* L3GD20_SHARED_SPI */
#endif /* L3GD20_USE_SPI */
return MSG_OK;
}
static const struct BaseSensorVMT vmt_basesensor = {
get_axes_number, read_raw, read_cooked
};
static const struct BaseGyroscopeVMT vmt_basegyroscope = {
get_axes_number, read_raw, read_cooked,
sample_bias, set_bias, reset_bias,
set_sensivity, reset_sensivity
};
static const struct L3GD20VMT vmt_l3gd20 = {
get_axes_number, read_raw, read_cooked,
sample_bias, set_bias, reset_bias,
set_sensivity, reset_sensivity, get_temperature
};
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an instance.
*
* @param[out] devp pointer to the @p L3GD20Driver object
*
* @init
*/
void l3gd20ObjectInit(L3GD20Driver *devp) {
uint32_t i;
devp->vmt_basesensor = &vmt_basesensor;
devp->vmt_basegyroscope = &vmt_basegyroscope;
devp->vmt_l3gd20 = &vmt_l3gd20;
devp->config = NULL;
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->bias[i] = 0;
devp->state = L3GD20_STOP;
}
/**
* @brief Configures and activates L3GD20 Complex Driver peripheral.
*
* @param[in] devp pointer to the @p L3GD20Driver object
* @param[in] config pointer to the @p L3GD20Config object
*
* @api
*/
void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config) {
uint32_t i;
osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY),
"l3gd20Start(), invalid state");
devp->config = config;
#if L3GD20_USE_SPI
#if L3GD20_SHARED_SPI
spiAcquireBus((devp)->config->spip);
#endif /* L3GD20_SHARED_SPI */
spiStart((devp)->config->spip,
(devp)->config->spicfg);
l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1,
devp->config->axesenabling |
L3GD20_PM_SLEEP_NORMAL |
devp->config->outputdatarate);
l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG4,
devp->config->fullscale |
devp->config->blockdataupdate |
devp->config->endianness);
#if L3GD20_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* L3GD20_SHARED_SPI */
#endif /* L3GD20_USE_SPI */
/* Storing sensitivity information according to full scale value */
if(devp->config->fullscale == L3GD20_FS_250DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = L3GD20_SENS_250DPS;
else if(devp->config->fullscale == L3GD20_FS_500DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = L3GD20_SENS_500DPS;
else if(devp->config->fullscale == L3GD20_FS_2000DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = L3GD20_SENS_2000DPS;
else
osalDbgAssert(FALSE, "l3gd20Start(), full scale issue");
/* This is the Gyroscope transient recovery time */
osalThreadSleepMilliseconds(10);
devp->state = L3GD20_READY;
}
/**
* @brief Deactivates the L3GD20 Complex Driver peripheral.
*
* @param[in] devp pointer to the @p L3GD20Driver object
*
* @api
*/
void l3gd20Stop(L3GD20Driver *devp) {
osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY),
"l3gd20Stop(), invalid state");
#if (L3GD20_USE_SPI)
if (devp->state == L3GD20_STOP) {
#if L3GD20_SHARED_SPI
spiAcquireBus((devp)->config->spip);
spiStart((devp)->config->spip,
(devp)->config->spicfg);
#endif /* L3GD20_SHARED_SPI */
l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1,
L3GD20_PM_POWER_DOWN | L3GD20_AE_DISABLED);
spiStop((devp)->config->spip);
#if L3GD20_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* L3GD20_SHARED_SPI */
}
#endif /* L3GD20_USE_SPI */
devp->state = L3GD20_STOP;
}
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file l3gd20.c
* @brief L3GD20 MEMS interface module code.
*
* @addtogroup l3gd20
* @{
*/
#include "hal.h"
#include "l3gd20.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define L3GD20_SENS_250DPS ((float)0.00875f)
#define L3GD20_SENS_500DPS ((float)0.01750f)
#define L3GD20_SENS_2000DPS ((float)0.07000f)
#define L3GD20_DI ((uint8_t)0xFF)
#define L3GD20_DI_0 ((uint8_t)0x01)
#define L3GD20_DI_1 ((uint8_t)0x02)
#define L3GD20_DI_2 ((uint8_t)0x04)
#define L3GD20_DI_3 ((uint8_t)0x08)
#define L3GD20_DI_4 ((uint8_t)0x10)
#define L3GD20_DI_5 ((uint8_t)0x20)
#define L3GD20_DI_6 ((uint8_t)0x40)
#define L3GD20_DI_7 ((uint8_t)0x80)
#define L3GD20_AD ((uint8_t)0x3F)
#define L3GD20_AD_0 ((uint8_t)0x01)
#define L3GD20_AD_1 ((uint8_t)0x02)
#define L3GD20_AD_2 ((uint8_t)0x04)
#define L3GD20_AD_3 ((uint8_t)0x08)
#define L3GD20_AD_4 ((uint8_t)0x10)
#define L3GD20_AD_5 ((uint8_t)0x20)
#define L3GD20_MS ((uint8_t)0x40)
#define L3GD20_RW ((uint8_t)0x80)
#define L3GD20_AD_WHO_AM_I ((uint8_t)0x0F)
#define L3GD20_AD_CTRL_REG1 ((uint8_t)0x20)
#define L3GD20_AD_CTRL_REG2 ((uint8_t)0x21)
#define L3GD20_AD_CTRL_REG3 ((uint8_t)0x22)
#define L3GD20_AD_CTRL_REG4 ((uint8_t)0x23)
#define L3GD20_AD_CTRL_REG5 ((uint8_t)0x24)
#define L3GD20_AD_REFERENCE ((uint8_t)0x25)
#define L3GD20_AD_OUT_TEMP ((uint8_t)0x26)
#define L3GD20_AD_STATUS_REG ((uint8_t)0x27)
#define L3GD20_AD_OUT_X_L ((uint8_t)0x28)
#define L3GD20_AD_OUT_X_H ((uint8_t)0x29)
#define L3GD20_AD_OUT_Y_L ((uint8_t)0x2A)
#define L3GD20_AD_OUT_Y_H ((uint8_t)0x2B)
#define L3GD20_AD_OUT_Z_L ((uint8_t)0x2C)
#define L3GD20_AD_OUT_Z_H ((uint8_t)0x2D)
#define L3GD20_AD_FIFO_CTRL_REG ((uint8_t)0x2E)
#define L3GD20_AD_FIFO_SRC_REG ((uint8_t)0x2F)
#define L3GD20_AD_INT1_CFG ((uint8_t)0x30)
#define L3GD20_AD_INT1_SRC ((uint8_t)0x31)
#define L3GD20_AD_INT1_TSH_XH ((uint8_t)0x32)
#define L3GD20_AD_INT1_TSH_XL ((uint8_t)0x33)
#define L3GD20_AD_INT1_TSH_YH ((uint8_t)0x34)
#define L3GD20_AD_INT1_TSH_YL ((uint8_t)0x35)
#define L3GD20_AD_INT1_TSH_ZH ((uint8_t)0x36)
#define L3GD20_AD_INT1_TSH_ZL ((uint8_t)0x37)
#define L3GD20_AD_INT1_DURATION ((uint8_t)0x38)
#define L3GD20_CTRL_REG4_FS_MASK ((uint8_t)0x30)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief L3GD20 Power Mode
*/
typedef enum {
L3GD20_PM_POWER_DOWN = 0x00, /**< Power down enabled. */
L3GD20_PM_SLEEP_NORMAL = 0x08 /**< Normal operation mode. */
}l3gd20_pm_t;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if (L3GD20_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief Reads a generic register value using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @return register value.
*/
static uint8_t l3gd20SPIReadRegister(SPIDriver *spip, uint8_t reg) {
uint8_t txbuf[2] = {L3GD20_RW | reg, 0xFF};
uint8_t rxbuf[2] = {0x00, 0x00};
spiSelect(spip);
spiExchange(spip, 2, txbuf, rxbuf);
spiUnselect(spip);
return rxbuf[1];
}
/**
* @brief Writes a value into a generic register using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @param[in] value register value.
*/
static void l3gd20SPIWriteRegister(SPIDriver *spip, uint8_t reg,
uint8_t value) {
switch (reg) {
default:
/* Reserved register must not be written, according to the datasheet
* this could permanently damage the device.
*/
osalDbgAssert(FALSE, "l3gd20SPIWriteRegister(), reserved register");
case L3GD20_AD_WHO_AM_I:
case L3GD20_AD_OUT_TEMP :
case L3GD20_AD_STATUS_REG:
case L3GD20_AD_OUT_X_L:
case L3GD20_AD_OUT_X_H:
case L3GD20_AD_OUT_Y_L:
case L3GD20_AD_OUT_Y_H:
case L3GD20_AD_OUT_Z_L:
case L3GD20_AD_OUT_Z_H:
case L3GD20_AD_FIFO_SRC_REG:
case L3GD20_AD_INT1_SRC:
/* Read only registers cannot be written, the command is ignored.*/
return;
case L3GD20_AD_CTRL_REG1:
case L3GD20_AD_CTRL_REG2:
case L3GD20_AD_CTRL_REG3:
case L3GD20_AD_CTRL_REG4:
case L3GD20_AD_CTRL_REG5:
case L3GD20_AD_REFERENCE:
case L3GD20_AD_FIFO_CTRL_REG:
case L3GD20_AD_INT1_CFG:
case L3GD20_AD_INT1_TSH_XH:
case L3GD20_AD_INT1_TSH_XL:
case L3GD20_AD_INT1_TSH_YH:
case L3GD20_AD_INT1_TSH_YL:
case L3GD20_AD_INT1_TSH_ZH:
case L3GD20_AD_INT1_TSH_ZL:
case L3GD20_AD_INT1_DURATION:
spiSelect(spip);
uint8_t txbuf[2] = {reg, value};
spiSend(spip, 2, txbuf);
spiUnselect(spip);
}
}
#endif /* L3GD20_USE_SPI */
/*
* Interface implementation.
*/
static size_t get_axes_number(void *ip) {
osalDbgCheck(ip != NULL);
return L3GD20_NUMBER_OF_AXES;
}
static msg_t read_raw(void *ip, int32_t axes[L3GD20_NUMBER_OF_AXES]) {
int16_t tmp;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"read_raw(), invalid state");
#if L3GD20_USE_SPI
osalDbgAssert((((L3GD20Driver *)ip)->config->spip->state == SPI_READY),
"read_raw(), channel not ready");
#if L3GD20_SHARED_SPI
spiAcquireBus(((L3GD20Driver *)ip)->config->spip);
spiStart(((L3GD20Driver *)ip)->config->spip,
((L3GD20Driver *)ip)->config->spicfg);
#endif /* L3GD20_SHARED_SPI */
if(((L3GD20Driver *)ip)->config->axesenabling & L3GD20_AE_X){
tmp = l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_X_L);
tmp += l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_X_H) << 8;
axes[0] = (int32_t)tmp + ((L3GD20Driver *)ip)->bias[0];
}
if(((L3GD20Driver *)ip)->config->axesenabling & L3GD20_AE_Y){
tmp = l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Y_L);
tmp += l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Y_H) << 8;
axes[1] = (int32_t)tmp + ((L3GD20Driver *)ip)->bias[1];
}
if(((L3GD20Driver *)ip)->config->axesenabling & L3GD20_AE_Z){
tmp = l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Z_L);
tmp += l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_Z_H) << 8;
axes[2] = (int32_t)tmp + ((L3GD20Driver *)ip)->bias[2];
}
#if L3GD20_SHARED_SPI
spiReleaseBus(((L3GD20Driver *)ip)->config->spip);
#endif /* L3GD20_SHARED_SPI */
#endif /* L3GD20_USE_SPI */
return MSG_OK;
}
static msg_t read_cooked(void *ip, float axes[]) {
uint32_t i;
int32_t raw[L3GD20_NUMBER_OF_AXES];
msg_t msg;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"read_cooked(), invalid state");
msg = read_raw(ip, raw);
for(i = 0; i < L3GD20_NUMBER_OF_AXES ; i++){
axes[i] = raw[i] * ((L3GD20Driver *)ip)->sensitivity[i];
}
return msg;
}
static msg_t sample_bias(void *ip) {
uint32_t i, j;
int32_t raw[L3GD20_NUMBER_OF_AXES];
int32_t buff[L3GD20_NUMBER_OF_AXES] = {0, 0, 0};
osalDbgCheck(ip != NULL);
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"sample_bias(), invalid state");
for(i = 0; i < L3GD20_BIAS_ACQ_TIMES; i++){
read_raw(ip, raw);
for(j = 0; j < L3GD20_NUMBER_OF_AXES; j++){
buff[j] += raw[j];
}
osalThreadSleepMicroseconds(L3GD20_BIAS_SETTLING_uS);
}
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++){
((L3GD20Driver *)ip)->bias[i] = buff[i] / L3GD20_BIAS_ACQ_TIMES;
}
return MSG_OK;
}
static msg_t set_bias(void *ip, int32_t *bp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (bp !=NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY) ||
(((L3GD20Driver *)ip)->state == L3GD20_STOP),
"set_bias(), invalid state");
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++) {
((L3GD20Driver *)ip)->bias[i] = bp[i];
}
return MSG_OK;
}
static msg_t reset_bias(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY) ||
(((L3GD20Driver *)ip)->state == L3GD20_STOP),
"reset_bias(), invalid state");
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->bias[i] = 0;
return MSG_OK;
}
static msg_t set_sensivity(void *ip, float *sp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (sp !=NULL));
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"set_sensivity(), invalid state");
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++) {
((L3GD20Driver *)ip)->sensitivity[i] = sp[i];
}
return MSG_OK;
}
static msg_t reset_sensivity(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((L3GD20Driver *)ip)->state == L3GD20_READY),
"reset_sensivity(), invalid state");
if(((L3GD20Driver *)ip)->config->fullscale == L3GD20_FS_250DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->sensitivity[i] = L3GD20_SENS_250DPS;
else if(((L3GD20Driver *)ip)->config->fullscale == L3GD20_FS_500DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->sensitivity[i] = L3GD20_SENS_500DPS;
else if(((L3GD20Driver *)ip)->config->fullscale == L3GD20_FS_2000DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
((L3GD20Driver *)ip)->sensitivity[i] = L3GD20_SENS_2000DPS;
else {
osalDbgAssert(FALSE, "reset_sensivity(), full scale issue");
return MSG_RESET;
}
return MSG_OK;
}
static msg_t get_temperature(void *ip, float* tempp) {
#if L3GD20_USE_SPI
osalDbgAssert((((L3GD20Driver *)ip)->config->spip->state == SPI_READY),
"read_raw(), channel not ready");
#if L3GD20_SHARED_SPI
spiAcquireBus(((L3GD20Driver *)ip)->config->spip);
spiStart(((L3GD20Driver *)ip)->config->spip,
((L3GD20Driver *)ip)->config->spicfg);
#endif /* L3GD20_SHARED_SPI */
*tempp = (int8_t)l3gd20SPIReadRegister(((L3GD20Driver *)ip)->config->spip,
L3GD20_AD_OUT_TEMP);
#if L3GD20_SHARED_SPI
spiReleaseBus(((L3GD20Driver *)ip)->config->spip);
#endif /* L3GD20_SHARED_SPI */
#endif /* L3GD20_USE_SPI */
return MSG_OK;
}
static const struct BaseSensorVMT vmt_basesensor = {
get_axes_number, read_raw, read_cooked
};
static const struct BaseGyroscopeVMT vmt_basegyroscope = {
get_axes_number, read_raw, read_cooked,
sample_bias, set_bias, reset_bias,
set_sensivity, reset_sensivity
};
static const struct L3GD20VMT vmt_l3gd20 = {
get_axes_number, read_raw, read_cooked,
sample_bias, set_bias, reset_bias,
set_sensivity, reset_sensivity, get_temperature
};
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an instance.
*
* @param[out] devp pointer to the @p L3GD20Driver object
*
* @init
*/
void l3gd20ObjectInit(L3GD20Driver *devp) {
uint32_t i;
devp->vmt_basesensor = &vmt_basesensor;
devp->vmt_basegyroscope = &vmt_basegyroscope;
devp->vmt_l3gd20 = &vmt_l3gd20;
devp->config = NULL;
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->bias[i] = 0;
devp->state = L3GD20_STOP;
}
/**
* @brief Configures and activates L3GD20 Complex Driver peripheral.
*
* @param[in] devp pointer to the @p L3GD20Driver object
* @param[in] config pointer to the @p L3GD20Config object
*
* @api
*/
void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config) {
uint32_t i;
osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY),
"l3gd20Start(), invalid state");
devp->config = config;
#if L3GD20_USE_SPI
#if L3GD20_SHARED_SPI
spiAcquireBus((devp)->config->spip);
#endif /* L3GD20_SHARED_SPI */
spiStart((devp)->config->spip,
(devp)->config->spicfg);
l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1,
devp->config->axesenabling |
L3GD20_PM_SLEEP_NORMAL |
devp->config->outputdatarate);
l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG4,
devp->config->fullscale |
devp->config->blockdataupdate |
devp->config->endianness);
#if L3GD20_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* L3GD20_SHARED_SPI */
#endif /* L3GD20_USE_SPI */
/* Storing sensitivity information according to full scale value */
if(devp->config->fullscale == L3GD20_FS_250DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = L3GD20_SENS_250DPS;
else if(devp->config->fullscale == L3GD20_FS_500DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = L3GD20_SENS_500DPS;
else if(devp->config->fullscale == L3GD20_FS_2000DPS)
for(i = 0; i < L3GD20_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = L3GD20_SENS_2000DPS;
else
osalDbgAssert(FALSE, "l3gd20Start(), full scale issue");
/* This is the Gyroscope transient recovery time */
osalThreadSleepMilliseconds(10);
devp->state = L3GD20_READY;
}
/**
* @brief Deactivates the L3GD20 Complex Driver peripheral.
*
* @param[in] devp pointer to the @p L3GD20Driver object
*
* @api
*/
void l3gd20Stop(L3GD20Driver *devp) {
osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY),
"l3gd20Stop(), invalid state");
#if (L3GD20_USE_SPI)
if (devp->state == L3GD20_STOP) {
#if L3GD20_SHARED_SPI
spiAcquireBus((devp)->config->spip);
spiStart((devp)->config->spip,
(devp)->config->spicfg);
#endif /* L3GD20_SHARED_SPI */
l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1,
L3GD20_PM_POWER_DOWN | L3GD20_AE_DISABLED);
spiStop((devp)->config->spip);
#if L3GD20_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* L3GD20_SHARED_SPI */
}
#endif /* L3GD20_USE_SPI */
devp->state = L3GD20_STOP;
}
/** @} */

View File

@ -1,330 +1,330 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file l3gd20.h
* @brief L3GD20 MEMS interface module header.
*
* @{
*/
#ifndef _L3GD20_H_
#define _L3GD20_H_
#include "hal_gyroscope.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief L3GD20 number of axes.
*/
#define L3GD20_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief L3GD20 SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p TRUE.
*/
#if !defined(L3GD20_USE_SPI) || defined(__DOXYGEN__)
#define L3GD20_USE_SPI TRUE
#endif
/**
* @brief L3GD20 I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(L3GD20_USE_I2C) || defined(__DOXYGEN__)
#define L3GD20_USE_I2C FALSE
#endif
/**
* @brief L3GD20 shared SPI switch.
* @details If set to @p TRUE the device acquires SPI bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION
*/
#if !defined(L3GD20_SHARED_SPI) || defined(__DOXYGEN__)
#define L3GD20_SHARED_SPI FALSE
#endif
/**
* @brief Number of acquisitions for bias removal
* @details This is the number of acquisitions performed to compute the
* bias. A repetition is required in order to remove noise.
*/
#if !defined(L3GD20_BIAS_ACQ_TIMES) || defined(__DOXYGEN__)
#define L3GD20_BIAS_ACQ_TIMES 50
#endif
/**
* @brief Settling time for bias removal
* @details This is the time between each bias acquisition.
*/
#if !defined(L3GD20_BIAS_SETTLING_uS) || defined(__DOXYGEN__)
#define L3GD20_BIAS_SETTLING_uS 5000
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(L3GD20_USE_SPI ^ L3GD20_USE_I2C)
#error "L3GD20_USE_SPI and L3GD20_USE_I2C cannot be both true or both false"
#endif
#if L3GD20_USE_SPI && !HAL_USE_SPI
#error "L3GD20_USE_SPI requires HAL_USE_SPI"
#endif
#if L3GD20_USE_I2C && !HAL_USE_I2C
#error "L3GD20_USE_I2C requires HAL_USE_I2C"
#endif
#if L3GD20_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
#error "L3GD20_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name L3GD20 data structures and types
* @{
*/
/**
* @brief L3GD20 full scale
*/
typedef enum {
L3GD20_FS_250DPS = 0x00, /**< Full scale 250 degree per second. */
L3GD20_FS_500DPS = 0x10, /**< Full scale 500 degree per second. */
L3GD20_FS_2000DPS = 0x20 /**< Full scale 2000 degree per second. */
}l3gd20_fs_t;
/**
* @brief L3GD20 output data rate and bandwidth
*/
typedef enum {
L3GD20_ODR_95HZ_FC_12_5 = 0x00, /**< ODR 95 Hz, BW 12.5 Hz. */
L3GD20_ODR_95HZ_FC_25 = 0x10, /**< ODR 95 Hz, BW 25Hz. */
L3GD20_ODR_190HZ_FC_12_5 = 0x40, /**< ODR 190 Hz, BW 12.5 Hz. */
L3GD20_ODR_190HZ_FC_25 = 0x50, /**< ODR 190 Hz, BW 25 Hz. */
L3GD20_ODR_190HZ_FC_50 = 0x60, /**< ODR 190 Hz, BW 50 Hz. */
L3GD20_ODR_190HZ_FC_70 = 0x70, /**< ODR 190 Hz, BW 70 Hz. */
L3GD20_ODR_380HZ_FC_20 = 0x80, /**< ODR 380 Hz, BW 20 Hz. */
L3GD20_ODR_380HZ_FC_25 = 0x90, /**< ODR 380 Hz, BW 25 Hz. */
L3GD20_ODR_380HZ_FC_50 = 0xA0, /**< ODR 380 Hz, BW 50 Hz. */
L3GD20_ODR_380HZ_FC_100 = 0xB0, /**< ODR 380 Hz, BW 100 Hz. */
L3GD20_ODR_760HZ_FC_30 = 0xC0, /**< ODR 760 Hz, BW 30 Hz. */
L3GD20_ODR_760HZ_FC_35 = 0xD0, /**< ODR 760 Hz, BW 35 Hz. */
L3GD20_ODR_760HZ_FC_50 = 0xE0, /**< ODR 760 Hz, BW 50 Hz. */
L3GD20_ODR_760HZ_FC_100 = 0xF0 /**< ODR 760 Hz, BW 100 Hz. */
}l3gd20_odr_t;
/**
* @brief L3GD20 axes enabling
*/
typedef enum {
L3GD20_AE_DISABLED = 0x00, /**< All axes disabled. */
L3GD20_AE_X = 0x01, /**< Only X-axis enabled. */
L3GD20_AE_Y = 0x02, /**< Only Y-axis enabled. */
L3GD20_AE_XY = 0x03, /**< X and Y axes enabled. */
L3GD20_AE_Z = 0x04, /**< Only Z-axis enabled. */
L3GD20_AE_XZ = 0x05, /**< X and Z axes enabled. */
L3GD20_AE_YZ = 0x06, /**< Y and Z axes enabled. */
L3GD20_AE_XYZ = 0x07 /**< All axes enabled. */
}l3gd20_ae_t;
/**
* @brief L3GD20 block data update
*/
typedef enum {
L3GD20_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
L3GD20_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */
}l3gd20_bdu_t;
/**
* @brief L3GD20 endianness
*/
typedef enum {
L3GD20_END_LITTLE = 0x00, /**< Little endian. */
L3GD20_END_BIG = 0x40 /**< Big endian. */
}l3gd20_end_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
L3GD20_UNINIT = 0, /**< Not initialized. */
L3GD20_STOP = 1, /**< Stopped. */
L3GD20_READY = 2, /**< Ready. */
} l3gd20_state_t;
/**
* @brief L3GD20 configuration structure.
*/
typedef struct {
#if (L3GD20_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this L3GD20.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this L3GD20.
*/
const SPIConfig *spicfg;
#endif /* L3GD20_USE_SPI */
#if (L3GD20_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this L3GD20.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this L3GD20.
*/
const I2CConfig *i2ccfg;
#endif /* L3GD20_USE_I2C */
/**
* @brief L3GD20 full scale value.
*/
l3gd20_fs_t fullscale;
/**
* @brief L3GD20 output data rate selection.
*/
l3gd20_odr_t outputdatarate;
/**
* @brief L3GD20 axes enabling.
*/
l3gd20_ae_t axesenabling;
/**
* @brief L3GD20 block data update.
*/
l3gd20_bdu_t blockdataupdate;
/**
* @brief L3GD20 endianness.
*/
l3gd20_end_t endianness;
} L3GD20Config;
/**
* @brief Structure representing a L3GD20 driver.
*/
typedef struct L3GD20Driver L3GD20Driver;
/**
* @brief @p L3GD20 specific methods.
*/
#define _l3gd20_methods \
_base_gyroscope_methods \
/* Retrieve the temperature of L3GD20 chip.*/ \
msg_t (*get_temperature)(void *instance, float* temperature);
/**
* @extends BaseGyroscopeVMT
*
* @brief @p L3GD20 virtual methods table.
*/
struct L3GD20VMT {
_l3gd20_methods
};
/**
* @brief @p L3GD20Driver specific data.
*/
#define _l3gd20_data \
_base_gyroscope_data \
/* Driver state.*/ \
l3gd20_state_t state; \
/* Current configuration data.*/ \
const L3GD20Config *config; \
/* Current sensitivity.*/ \
float sensitivity[L3GD20_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[L3GD20_NUMBER_OF_AXES];
/**
* @extends BaseGyroscope
*
* @brief L3GD20 3-axis gyroscope class.
* @details This class extends @p BaseGyroscope by adding physical
* driver implementation.
*/
struct L3GD20Driver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseGyroscope Virtual Methods Table. */
const struct BaseGyroscopeVMT *vmt_basegyroscope;
/** @brief L3GD20 Virtual Methods Table. */
const struct L3GD20VMT *vmt_l3gd20;
_l3gd20_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU
*
* @param[in] ip pointer to a @p BaseGyroscope class.
* @param[out] temp the MEMS temperature as single precision floating.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define gyroscopeGetTemp(ip, tpp) \
(ip)->vmt_l3gd20->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void l3gd20ObjectInit(L3GD20Driver *devp);
void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config);
void l3gd20Stop(L3GD20Driver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _L3GD20_H_ */
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file l3gd20.h
* @brief L3GD20 MEMS interface module header.
*
* @{
*/
#ifndef _L3GD20_H_
#define _L3GD20_H_
#include "hal_gyroscope.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief L3GD20 number of axes.
*/
#define L3GD20_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief L3GD20 SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p TRUE.
*/
#if !defined(L3GD20_USE_SPI) || defined(__DOXYGEN__)
#define L3GD20_USE_SPI TRUE
#endif
/**
* @brief L3GD20 I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(L3GD20_USE_I2C) || defined(__DOXYGEN__)
#define L3GD20_USE_I2C FALSE
#endif
/**
* @brief L3GD20 shared SPI switch.
* @details If set to @p TRUE the device acquires SPI bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION
*/
#if !defined(L3GD20_SHARED_SPI) || defined(__DOXYGEN__)
#define L3GD20_SHARED_SPI FALSE
#endif
/**
* @brief Number of acquisitions for bias removal
* @details This is the number of acquisitions performed to compute the
* bias. A repetition is required in order to remove noise.
*/
#if !defined(L3GD20_BIAS_ACQ_TIMES) || defined(__DOXYGEN__)
#define L3GD20_BIAS_ACQ_TIMES 50
#endif
/**
* @brief Settling time for bias removal
* @details This is the time between each bias acquisition.
*/
#if !defined(L3GD20_BIAS_SETTLING_uS) || defined(__DOXYGEN__)
#define L3GD20_BIAS_SETTLING_uS 5000
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(L3GD20_USE_SPI ^ L3GD20_USE_I2C)
#error "L3GD20_USE_SPI and L3GD20_USE_I2C cannot be both true or both false"
#endif
#if L3GD20_USE_SPI && !HAL_USE_SPI
#error "L3GD20_USE_SPI requires HAL_USE_SPI"
#endif
#if L3GD20_USE_I2C && !HAL_USE_I2C
#error "L3GD20_USE_I2C requires HAL_USE_I2C"
#endif
#if L3GD20_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
#error "L3GD20_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name L3GD20 data structures and types
* @{
*/
/**
* @brief L3GD20 full scale
*/
typedef enum {
L3GD20_FS_250DPS = 0x00, /**< Full scale 250 degree per second. */
L3GD20_FS_500DPS = 0x10, /**< Full scale 500 degree per second. */
L3GD20_FS_2000DPS = 0x20 /**< Full scale 2000 degree per second. */
}l3gd20_fs_t;
/**
* @brief L3GD20 output data rate and bandwidth
*/
typedef enum {
L3GD20_ODR_95HZ_FC_12_5 = 0x00, /**< ODR 95 Hz, BW 12.5 Hz. */
L3GD20_ODR_95HZ_FC_25 = 0x10, /**< ODR 95 Hz, BW 25Hz. */
L3GD20_ODR_190HZ_FC_12_5 = 0x40, /**< ODR 190 Hz, BW 12.5 Hz. */
L3GD20_ODR_190HZ_FC_25 = 0x50, /**< ODR 190 Hz, BW 25 Hz. */
L3GD20_ODR_190HZ_FC_50 = 0x60, /**< ODR 190 Hz, BW 50 Hz. */
L3GD20_ODR_190HZ_FC_70 = 0x70, /**< ODR 190 Hz, BW 70 Hz. */
L3GD20_ODR_380HZ_FC_20 = 0x80, /**< ODR 380 Hz, BW 20 Hz. */
L3GD20_ODR_380HZ_FC_25 = 0x90, /**< ODR 380 Hz, BW 25 Hz. */
L3GD20_ODR_380HZ_FC_50 = 0xA0, /**< ODR 380 Hz, BW 50 Hz. */
L3GD20_ODR_380HZ_FC_100 = 0xB0, /**< ODR 380 Hz, BW 100 Hz. */
L3GD20_ODR_760HZ_FC_30 = 0xC0, /**< ODR 760 Hz, BW 30 Hz. */
L3GD20_ODR_760HZ_FC_35 = 0xD0, /**< ODR 760 Hz, BW 35 Hz. */
L3GD20_ODR_760HZ_FC_50 = 0xE0, /**< ODR 760 Hz, BW 50 Hz. */
L3GD20_ODR_760HZ_FC_100 = 0xF0 /**< ODR 760 Hz, BW 100 Hz. */
}l3gd20_odr_t;
/**
* @brief L3GD20 axes enabling
*/
typedef enum {
L3GD20_AE_DISABLED = 0x00, /**< All axes disabled. */
L3GD20_AE_X = 0x01, /**< Only X-axis enabled. */
L3GD20_AE_Y = 0x02, /**< Only Y-axis enabled. */
L3GD20_AE_XY = 0x03, /**< X and Y axes enabled. */
L3GD20_AE_Z = 0x04, /**< Only Z-axis enabled. */
L3GD20_AE_XZ = 0x05, /**< X and Z axes enabled. */
L3GD20_AE_YZ = 0x06, /**< Y and Z axes enabled. */
L3GD20_AE_XYZ = 0x07 /**< All axes enabled. */
}l3gd20_ae_t;
/**
* @brief L3GD20 block data update
*/
typedef enum {
L3GD20_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
L3GD20_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */
}l3gd20_bdu_t;
/**
* @brief L3GD20 endianness
*/
typedef enum {
L3GD20_END_LITTLE = 0x00, /**< Little endian. */
L3GD20_END_BIG = 0x40 /**< Big endian. */
}l3gd20_end_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
L3GD20_UNINIT = 0, /**< Not initialized. */
L3GD20_STOP = 1, /**< Stopped. */
L3GD20_READY = 2, /**< Ready. */
} l3gd20_state_t;
/**
* @brief L3GD20 configuration structure.
*/
typedef struct {
#if (L3GD20_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this L3GD20.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this L3GD20.
*/
const SPIConfig *spicfg;
#endif /* L3GD20_USE_SPI */
#if (L3GD20_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this L3GD20.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this L3GD20.
*/
const I2CConfig *i2ccfg;
#endif /* L3GD20_USE_I2C */
/**
* @brief L3GD20 full scale value.
*/
l3gd20_fs_t fullscale;
/**
* @brief L3GD20 output data rate selection.
*/
l3gd20_odr_t outputdatarate;
/**
* @brief L3GD20 axes enabling.
*/
l3gd20_ae_t axesenabling;
/**
* @brief L3GD20 block data update.
*/
l3gd20_bdu_t blockdataupdate;
/**
* @brief L3GD20 endianness.
*/
l3gd20_end_t endianness;
} L3GD20Config;
/**
* @brief Structure representing a L3GD20 driver.
*/
typedef struct L3GD20Driver L3GD20Driver;
/**
* @brief @p L3GD20 specific methods.
*/
#define _l3gd20_methods \
_base_gyroscope_methods \
/* Retrieve the temperature of L3GD20 chip.*/ \
msg_t (*get_temperature)(void *instance, float* temperature);
/**
* @extends BaseGyroscopeVMT
*
* @brief @p L3GD20 virtual methods table.
*/
struct L3GD20VMT {
_l3gd20_methods
};
/**
* @brief @p L3GD20Driver specific data.
*/
#define _l3gd20_data \
_base_gyroscope_data \
/* Driver state.*/ \
l3gd20_state_t state; \
/* Current configuration data.*/ \
const L3GD20Config *config; \
/* Current sensitivity.*/ \
float sensitivity[L3GD20_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[L3GD20_NUMBER_OF_AXES];
/**
* @extends BaseGyroscope
*
* @brief L3GD20 3-axis gyroscope class.
* @details This class extends @p BaseGyroscope by adding physical
* driver implementation.
*/
struct L3GD20Driver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseGyroscope Virtual Methods Table. */
const struct BaseGyroscopeVMT *vmt_basegyroscope;
/** @brief L3GD20 Virtual Methods Table. */
const struct L3GD20VMT *vmt_l3gd20;
_l3gd20_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU
*
* @param[in] ip pointer to a @p BaseGyroscope class.
* @param[out] temp the MEMS temperature as single precision floating.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define gyroscopeGetTemp(ip, tpp) \
(ip)->vmt_l3gd20->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void l3gd20ObjectInit(L3GD20Driver *devp);
void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config);
void l3gd20Stop(L3GD20Driver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _L3GD20_H_ */
/** @} */

View File

@ -1,429 +1,429 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis302dl.c
* @brief LIS302DL MEMS interface module code.
*
* @addtogroup lis302dl
* @{
*/
#include "hal.h"
#include "lis302dl.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define LIS302DL_SENS_2G ((float)18.0f)
#define LIS302DL_SENS_8G ((float)72.0f)
#define LIS302DL_DI ((uint8_t)0xFF)
#define LIS302DL_DI_0 ((uint8_t)0x01)
#define LIS302DL_DI_1 ((uint8_t)0x02)
#define LIS302DL_DI_2 ((uint8_t)0x04)
#define LIS302DL_DI_3 ((uint8_t)0x08)
#define LIS302DL_DI_4 ((uint8_t)0x10)
#define LIS302DL_DI_5 ((uint8_t)0x20)
#define LIS302DL_DI_6 ((uint8_t)0x40)
#define LIS302DL_DI_7 ((uint8_t)0x80)
#define LIS302DL_AD ((uint8_t)0x3F)
#define LIS302DL_AD_0 ((uint8_t)0x01)
#define LIS302DL_AD_1 ((uint8_t)0x02)
#define LIS302DL_AD_2 ((uint8_t)0x04)
#define LIS302DL_AD_3 ((uint8_t)0x08)
#define LIS302DL_AD_4 ((uint8_t)0x10)
#define LIS302DL_AD_5 ((uint8_t)0x20)
#define LIS302DL_MS ((uint8_t)0x40)
#define LIS302DL_RW ((uint8_t)0x80)
#define LIS302DL_AD_WHO_AM_I ((uint8_t)0x0F)
#define LIS302DL_AD_CTRL_REG1 ((uint8_t)0x20)
#define LIS302DL_AD_CTRL_REG2 ((uint8_t)0x21)
#define LIS302DL_AD_CTRL_REG3 ((uint8_t)0x22)
#define LIS302DL_AD_HP_FILER_RESET ((uint8_t)0x23)
#define LIS302DL_AD_STATUS_REG ((uint8_t)0x27)
#define LIS302DL_AD_OUT_X ((uint8_t)0x29)
#define LIS302DL_AD_OUT_Y ((uint8_t)0x2B)
#define LIS302DL_AD_OUT_Z ((uint8_t)0x2D)
#define LIS302DL_AD_FF_WU_CFG_1 ((uint8_t)0x30)
#define LIS302DL_AD_FF_WU_SRC_1 ((uint8_t)0x31)
#define LIS302DL_AD_FF_WU_THS_1 ((uint8_t)0x32)
#define LIS302DL_AD_FF_WU_DURATION_1 ((uint8_t)0x33)
#define LIS302DL_AD_FF_WU_CFG_2 ((uint8_t)0x34)
#define LIS302DL_AD_FF_WU_SRC_2 ((uint8_t)0x35)
#define LIS302DL_AD_FF_WU_THS_2 ((uint8_t)0x36)
#define LIS302DL_AD_FF_WU_DURATION_2 ((uint8_t)0x37)
#define LIS302DL_AD_CLICK_CFG ((uint8_t)0x38)
#define LIS302DL_AD_CLICK_SRC ((uint8_t)0x39)
#define LIS302DL_AD_CLICK_THSY_X ((uint8_t)0x3B)
#define LIS302DL_AD_CLICK_THSZ ((uint8_t)0x3C)
#define LIS302DL_AD_CLICK_TIME_LIMIT ((uint8_t)0x3D)
#define LIS302DL_AD_CLICK_LATENCY ((uint8_t)0x3E)
#define LIS302DL_AD_CLICK_WINDOW ((uint8_t)0x3F)
#define LIS302DL_CTRL_REG1_FS_MASK ((uint8_t)0x20)
#define TO_G ((float)0.001f)
#define TO_SI ((float)0.00981f)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief LIS302DL Power Mode
*/
typedef enum {
LIS302DL_PM_POWER_DOWN = 0x00, /**< Power down enabled. */
LIS302DL_PM_SLEEP_NORMAL = 0x40 /**< Normal operation mode. */
}lis302dl_pm_t;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if (LIS302DL_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief Reads a generic register value using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @return register value.
*/
static uint8_t lis302dlSPIReadRegister(SPIDriver *spip, uint8_t reg) {
uint8_t txbuf[2] = {LIS302DL_RW | reg, 0xFF};
uint8_t rxbuf[2] = {0x00, 0x00};
spiSelect(spip);
spiExchange(spip, 2, txbuf, rxbuf);
spiUnselect(spip);
return rxbuf[1];
}
/**
* @brief Writes a value into a generic register using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @param[in] value register value.
*/
static void lis302dlSPIWriteRegister(SPIDriver *spip, uint8_t reg,
uint8_t value) {
switch (reg) {
default:
/* Reserved register must not be written, according to the datasheet
* this could permanently damage the device.
*/
osalDbgAssert(FALSE, "lis302dlSPIWriteRegister(), reserved register");
case LIS302DL_AD_WHO_AM_I:
case LIS302DL_AD_HP_FILER_RESET:
case LIS302DL_AD_STATUS_REG:
case LIS302DL_AD_OUT_X:
case LIS302DL_AD_OUT_Y:
case LIS302DL_AD_OUT_Z:
case LIS302DL_AD_FF_WU_SRC_1:
case LIS302DL_AD_FF_WU_SRC_2:
case LIS302DL_AD_CLICK_SRC:
/* Read only registers cannot be written, the command is ignored.*/
return;
case LIS302DL_AD_CTRL_REG1:
case LIS302DL_AD_CTRL_REG2:
case LIS302DL_AD_CTRL_REG3:
case LIS302DL_AD_FF_WU_CFG_1:
case LIS302DL_AD_FF_WU_THS_1:
case LIS302DL_AD_FF_WU_DURATION_1:
case LIS302DL_AD_FF_WU_CFG_2:
case LIS302DL_AD_FF_WU_THS_2:
case LIS302DL_AD_FF_WU_DURATION_2:
case LIS302DL_AD_CLICK_CFG:
case LIS302DL_AD_CLICK_THSY_X:
case LIS302DL_AD_CLICK_THSZ:
case LIS302DL_AD_CLICK_TIME_LIMIT:
case LIS302DL_AD_CLICK_LATENCY:
case LIS302DL_AD_CLICK_WINDOW:
spiSelect(spip);
uint8_t txbuf[2] = {reg, value};
spiSend(spip, 2, txbuf);
spiUnselect(spip);
}
}
#endif /* LIS302DL_USE_SPI */
/*
* Interface implementation.
*/
static size_t get_axes_number(void *ip) {
osalDbgCheck(ip != NULL);
return LIS302DL_NUMBER_OF_AXES;
}
static msg_t read_raw(void *ip, int32_t axes[LIS302DL_NUMBER_OF_AXES]) {
int8_t tmp;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"read_raw(), invalid state");
#if LIS302DL_USE_SPI
osalDbgAssert((((LIS302DLDriver *)ip)->config->spip->state == SPI_READY),
"read_raw(), channel not ready");
#if LIS302DL_SHARED_SPI
spiAcquireBus(((LIS302DLDriver *)ip)->config->spip);
spiStart(((LIS302DLDriver *)ip)->config->spip,
((LIS302DLDriver *)ip)->config->spicfg);
#endif /* LIS302DL_SHARED_SPI */
if(((LIS302DLDriver *)ip)->config->axesenabling & LIS302DL_AE_X){
tmp = lis302dlSPIReadRegister(((LIS302DLDriver *)ip)->config->spip,
LIS302DL_AD_OUT_X);
axes[0] = tmp + ((LIS302DLDriver *)ip)->bias[0];
}
if(((LIS302DLDriver *)ip)->config->axesenabling & LIS302DL_AE_Y){
tmp = lis302dlSPIReadRegister(((LIS302DLDriver *)ip)->config->spip,
LIS302DL_AD_OUT_Y);
axes[1] = tmp + ((LIS302DLDriver *)ip)->bias[1];
}
if(((LIS302DLDriver *)ip)->config->axesenabling & LIS302DL_AE_Z){
tmp = lis302dlSPIReadRegister(((LIS302DLDriver *)ip)->config->spip,
LIS302DL_AD_OUT_Z);
axes[2] = tmp + ((LIS302DLDriver *)ip)->bias[2];
}
#if LIS302DL_SHARED_SPI
spiReleaseBus(((LIS302DLDriver *)ip)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
#endif /* LIS302DL_USE_SPI */
return MSG_OK;
}
static msg_t read_cooked(void *ip, float axes[]) {
uint32_t i;
int32_t raw[LIS302DL_NUMBER_OF_AXES];
msg_t msg;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"read_cooked(), invalid state");
msg = read_raw(ip, raw);
for(i = 0; i < LIS302DL_NUMBER_OF_AXES ; i++){
axes[i] = raw[i] * ((LIS302DLDriver *)ip)->sensitivity[i];
if(((LIS302DLDriver *)ip)->config->unit == LIS302DL_ACC_UNIT_G){
axes[i] *= TO_G;
}
else if(((LIS302DLDriver *)ip)->config->unit == LIS302DL_ACC_UNIT_SI){
axes[i] *= TO_SI;
}
}
return msg;
}
static msg_t set_bias(void *ip, int32_t *bp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (bp !=NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY) ||
(((LIS302DLDriver *)ip)->state == LIS302DL_STOP),
"set_bias(), invalid state");
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++) {
((LIS302DLDriver *)ip)->bias[i] = bp[i];
}
return MSG_OK;
}
static msg_t reset_bias(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY) ||
(((LIS302DLDriver *)ip)->state == LIS302DL_STOP),
"reset_bias(), invalid state");
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
((LIS302DLDriver *)ip)->bias[i] = 0;
return MSG_OK;
}
static msg_t set_sensivity(void *ip, float *sp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (sp !=NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"set_sensivity(), invalid state");
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++) {
((LIS302DLDriver *)ip)->sensitivity[i] = sp[i];
}
return MSG_OK;
}
static msg_t reset_sensivity(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"reset_sensivity(), invalid state");
if(((LIS302DLDriver *)ip)->config->fullscale == LIS302DL_FS_2G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
((LIS302DLDriver *)ip)->sensitivity[i] = LIS302DL_SENS_2G;
else if(((LIS302DLDriver *)ip)->config->fullscale == LIS302DL_FS_8G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
((LIS302DLDriver *)ip)->sensitivity[i] = LIS302DL_SENS_8G;
else {
osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
return MSG_RESET;
}
return MSG_OK;
}
static const struct BaseSensorVMT vmt_basesensor = {
get_axes_number, read_raw, read_cooked
};
static const struct BaseAccelerometerVMT vmt_baseaccelerometer = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity
};
static const struct LIS302DLVMT vmt_lis302dl = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity
};
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an instance.
*
* @param[out] devp pointer to the @p LIS302DLDriver object
*
* @init
*/
void lis302dlObjectInit(LIS302DLDriver *devp) {
uint32_t i;
devp->vmt_basesensor = &vmt_basesensor;
devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
devp->vmt_lis302dl = &vmt_lis302dl;
devp->config = NULL;
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
devp->bias[i] = 0;
devp->state = LIS302DL_STOP;
}
/**
* @brief Configures and activates LIS302DL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS302DLDriver object
* @param[in] config pointer to the @p LIS302DLConfig object
*
* @api
*/
void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config) {
uint32_t i;
osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == LIS302DL_STOP) || (devp->state == LIS302DL_READY),
"lis302dlStart(), invalid state");
devp->config = config;
#if LIS302DL_USE_SPI
#if LIS302DL_SHARED_SPI
spiAcquireBus((devp)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
spiStart((devp)->config->spip,
(devp)->config->spicfg);
lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1,
LIS302DL_PM_SLEEP_NORMAL |
devp->config->axesenabling |
devp->config->fullscale |
devp->config->outputdatarate);
lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG2,
devp->config->highpass);
#if LIS302DL_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
#endif /* LIS302DL_USE_SPI */
/* Storing sensitivity information according to full scale value */
if(devp->config->fullscale == LIS302DL_FS_2G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS302DL_SENS_2G;
else if(devp->config->fullscale == LIS302DL_FS_8G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS302DL_SENS_8G;
else {
osalDbgAssert(FALSE, "lis302dlStart(), accelerometer full scale issue");
}
/* This is the Accelerometer transient recovery time */
osalThreadSleepMilliseconds(10);
devp->state = LIS302DL_READY;
}
/**
* @brief Deactivates the LIS302DL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS302DLDriver object
*
* @api
*/
void lis302dlStop(LIS302DLDriver *devp) {
osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == LIS302DL_STOP) || (devp->state == LIS302DL_READY),
"lis302dlStop(), invalid state");
#if (LIS302DL_USE_SPI)
if (devp->state == LIS302DL_STOP) {
#if LIS302DL_SHARED_SPI
spiAcquireBus((devp)->config->spip);
spiStart((devp)->config->spip,
(devp)->config->spicfg);
#endif /* LIS302DL_SHARED_SPI */
lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1,
LIS302DL_PM_POWER_DOWN | LIS302DL_AE_DISABLED);
spiStop((devp)->config->spip);
#if LIS302DL_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
}
#endif /* LIS302DL_USE_SPI */
devp->state = LIS302DL_STOP;
}
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis302dl.c
* @brief LIS302DL MEMS interface module code.
*
* @addtogroup lis302dl
* @{
*/
#include "hal.h"
#include "lis302dl.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define LIS302DL_SENS_2G ((float)18.0f)
#define LIS302DL_SENS_8G ((float)72.0f)
#define LIS302DL_DI ((uint8_t)0xFF)
#define LIS302DL_DI_0 ((uint8_t)0x01)
#define LIS302DL_DI_1 ((uint8_t)0x02)
#define LIS302DL_DI_2 ((uint8_t)0x04)
#define LIS302DL_DI_3 ((uint8_t)0x08)
#define LIS302DL_DI_4 ((uint8_t)0x10)
#define LIS302DL_DI_5 ((uint8_t)0x20)
#define LIS302DL_DI_6 ((uint8_t)0x40)
#define LIS302DL_DI_7 ((uint8_t)0x80)
#define LIS302DL_AD ((uint8_t)0x3F)
#define LIS302DL_AD_0 ((uint8_t)0x01)
#define LIS302DL_AD_1 ((uint8_t)0x02)
#define LIS302DL_AD_2 ((uint8_t)0x04)
#define LIS302DL_AD_3 ((uint8_t)0x08)
#define LIS302DL_AD_4 ((uint8_t)0x10)
#define LIS302DL_AD_5 ((uint8_t)0x20)
#define LIS302DL_MS ((uint8_t)0x40)
#define LIS302DL_RW ((uint8_t)0x80)
#define LIS302DL_AD_WHO_AM_I ((uint8_t)0x0F)
#define LIS302DL_AD_CTRL_REG1 ((uint8_t)0x20)
#define LIS302DL_AD_CTRL_REG2 ((uint8_t)0x21)
#define LIS302DL_AD_CTRL_REG3 ((uint8_t)0x22)
#define LIS302DL_AD_HP_FILER_RESET ((uint8_t)0x23)
#define LIS302DL_AD_STATUS_REG ((uint8_t)0x27)
#define LIS302DL_AD_OUT_X ((uint8_t)0x29)
#define LIS302DL_AD_OUT_Y ((uint8_t)0x2B)
#define LIS302DL_AD_OUT_Z ((uint8_t)0x2D)
#define LIS302DL_AD_FF_WU_CFG_1 ((uint8_t)0x30)
#define LIS302DL_AD_FF_WU_SRC_1 ((uint8_t)0x31)
#define LIS302DL_AD_FF_WU_THS_1 ((uint8_t)0x32)
#define LIS302DL_AD_FF_WU_DURATION_1 ((uint8_t)0x33)
#define LIS302DL_AD_FF_WU_CFG_2 ((uint8_t)0x34)
#define LIS302DL_AD_FF_WU_SRC_2 ((uint8_t)0x35)
#define LIS302DL_AD_FF_WU_THS_2 ((uint8_t)0x36)
#define LIS302DL_AD_FF_WU_DURATION_2 ((uint8_t)0x37)
#define LIS302DL_AD_CLICK_CFG ((uint8_t)0x38)
#define LIS302DL_AD_CLICK_SRC ((uint8_t)0x39)
#define LIS302DL_AD_CLICK_THSY_X ((uint8_t)0x3B)
#define LIS302DL_AD_CLICK_THSZ ((uint8_t)0x3C)
#define LIS302DL_AD_CLICK_TIME_LIMIT ((uint8_t)0x3D)
#define LIS302DL_AD_CLICK_LATENCY ((uint8_t)0x3E)
#define LIS302DL_AD_CLICK_WINDOW ((uint8_t)0x3F)
#define LIS302DL_CTRL_REG1_FS_MASK ((uint8_t)0x20)
#define TO_G ((float)0.001f)
#define TO_SI ((float)0.00981f)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief LIS302DL Power Mode
*/
typedef enum {
LIS302DL_PM_POWER_DOWN = 0x00, /**< Power down enabled. */
LIS302DL_PM_SLEEP_NORMAL = 0x40 /**< Normal operation mode. */
}lis302dl_pm_t;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if (LIS302DL_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief Reads a generic register value using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @return register value.
*/
static uint8_t lis302dlSPIReadRegister(SPIDriver *spip, uint8_t reg) {
uint8_t txbuf[2] = {LIS302DL_RW | reg, 0xFF};
uint8_t rxbuf[2] = {0x00, 0x00};
spiSelect(spip);
spiExchange(spip, 2, txbuf, rxbuf);
spiUnselect(spip);
return rxbuf[1];
}
/**
* @brief Writes a value into a generic register using SPI.
* @pre The SPI interface must be initialized and the driver started.
*
* @param[in] spip pointer to the SPI interface
* @param[in] reg register number
* @param[in] value register value.
*/
static void lis302dlSPIWriteRegister(SPIDriver *spip, uint8_t reg,
uint8_t value) {
switch (reg) {
default:
/* Reserved register must not be written, according to the datasheet
* this could permanently damage the device.
*/
osalDbgAssert(FALSE, "lis302dlSPIWriteRegister(), reserved register");
case LIS302DL_AD_WHO_AM_I:
case LIS302DL_AD_HP_FILER_RESET:
case LIS302DL_AD_STATUS_REG:
case LIS302DL_AD_OUT_X:
case LIS302DL_AD_OUT_Y:
case LIS302DL_AD_OUT_Z:
case LIS302DL_AD_FF_WU_SRC_1:
case LIS302DL_AD_FF_WU_SRC_2:
case LIS302DL_AD_CLICK_SRC:
/* Read only registers cannot be written, the command is ignored.*/
return;
case LIS302DL_AD_CTRL_REG1:
case LIS302DL_AD_CTRL_REG2:
case LIS302DL_AD_CTRL_REG3:
case LIS302DL_AD_FF_WU_CFG_1:
case LIS302DL_AD_FF_WU_THS_1:
case LIS302DL_AD_FF_WU_DURATION_1:
case LIS302DL_AD_FF_WU_CFG_2:
case LIS302DL_AD_FF_WU_THS_2:
case LIS302DL_AD_FF_WU_DURATION_2:
case LIS302DL_AD_CLICK_CFG:
case LIS302DL_AD_CLICK_THSY_X:
case LIS302DL_AD_CLICK_THSZ:
case LIS302DL_AD_CLICK_TIME_LIMIT:
case LIS302DL_AD_CLICK_LATENCY:
case LIS302DL_AD_CLICK_WINDOW:
spiSelect(spip);
uint8_t txbuf[2] = {reg, value};
spiSend(spip, 2, txbuf);
spiUnselect(spip);
}
}
#endif /* LIS302DL_USE_SPI */
/*
* Interface implementation.
*/
static size_t get_axes_number(void *ip) {
osalDbgCheck(ip != NULL);
return LIS302DL_NUMBER_OF_AXES;
}
static msg_t read_raw(void *ip, int32_t axes[LIS302DL_NUMBER_OF_AXES]) {
int8_t tmp;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"read_raw(), invalid state");
#if LIS302DL_USE_SPI
osalDbgAssert((((LIS302DLDriver *)ip)->config->spip->state == SPI_READY),
"read_raw(), channel not ready");
#if LIS302DL_SHARED_SPI
spiAcquireBus(((LIS302DLDriver *)ip)->config->spip);
spiStart(((LIS302DLDriver *)ip)->config->spip,
((LIS302DLDriver *)ip)->config->spicfg);
#endif /* LIS302DL_SHARED_SPI */
if(((LIS302DLDriver *)ip)->config->axesenabling & LIS302DL_AE_X){
tmp = lis302dlSPIReadRegister(((LIS302DLDriver *)ip)->config->spip,
LIS302DL_AD_OUT_X);
axes[0] = tmp + ((LIS302DLDriver *)ip)->bias[0];
}
if(((LIS302DLDriver *)ip)->config->axesenabling & LIS302DL_AE_Y){
tmp = lis302dlSPIReadRegister(((LIS302DLDriver *)ip)->config->spip,
LIS302DL_AD_OUT_Y);
axes[1] = tmp + ((LIS302DLDriver *)ip)->bias[1];
}
if(((LIS302DLDriver *)ip)->config->axesenabling & LIS302DL_AE_Z){
tmp = lis302dlSPIReadRegister(((LIS302DLDriver *)ip)->config->spip,
LIS302DL_AD_OUT_Z);
axes[2] = tmp + ((LIS302DLDriver *)ip)->bias[2];
}
#if LIS302DL_SHARED_SPI
spiReleaseBus(((LIS302DLDriver *)ip)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
#endif /* LIS302DL_USE_SPI */
return MSG_OK;
}
static msg_t read_cooked(void *ip, float axes[]) {
uint32_t i;
int32_t raw[LIS302DL_NUMBER_OF_AXES];
msg_t msg;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"read_cooked(), invalid state");
msg = read_raw(ip, raw);
for(i = 0; i < LIS302DL_NUMBER_OF_AXES ; i++){
axes[i] = raw[i] * ((LIS302DLDriver *)ip)->sensitivity[i];
if(((LIS302DLDriver *)ip)->config->unit == LIS302DL_ACC_UNIT_G){
axes[i] *= TO_G;
}
else if(((LIS302DLDriver *)ip)->config->unit == LIS302DL_ACC_UNIT_SI){
axes[i] *= TO_SI;
}
}
return msg;
}
static msg_t set_bias(void *ip, int32_t *bp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (bp !=NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY) ||
(((LIS302DLDriver *)ip)->state == LIS302DL_STOP),
"set_bias(), invalid state");
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++) {
((LIS302DLDriver *)ip)->bias[i] = bp[i];
}
return MSG_OK;
}
static msg_t reset_bias(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY) ||
(((LIS302DLDriver *)ip)->state == LIS302DL_STOP),
"reset_bias(), invalid state");
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
((LIS302DLDriver *)ip)->bias[i] = 0;
return MSG_OK;
}
static msg_t set_sensivity(void *ip, float *sp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (sp !=NULL));
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"set_sensivity(), invalid state");
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++) {
((LIS302DLDriver *)ip)->sensitivity[i] = sp[i];
}
return MSG_OK;
}
static msg_t reset_sensivity(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS302DLDriver *)ip)->state == LIS302DL_READY),
"reset_sensivity(), invalid state");
if(((LIS302DLDriver *)ip)->config->fullscale == LIS302DL_FS_2G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
((LIS302DLDriver *)ip)->sensitivity[i] = LIS302DL_SENS_2G;
else if(((LIS302DLDriver *)ip)->config->fullscale == LIS302DL_FS_8G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
((LIS302DLDriver *)ip)->sensitivity[i] = LIS302DL_SENS_8G;
else {
osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
return MSG_RESET;
}
return MSG_OK;
}
static const struct BaseSensorVMT vmt_basesensor = {
get_axes_number, read_raw, read_cooked
};
static const struct BaseAccelerometerVMT vmt_baseaccelerometer = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity
};
static const struct LIS302DLVMT vmt_lis302dl = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity
};
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an instance.
*
* @param[out] devp pointer to the @p LIS302DLDriver object
*
* @init
*/
void lis302dlObjectInit(LIS302DLDriver *devp) {
uint32_t i;
devp->vmt_basesensor = &vmt_basesensor;
devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
devp->vmt_lis302dl = &vmt_lis302dl;
devp->config = NULL;
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
devp->bias[i] = 0;
devp->state = LIS302DL_STOP;
}
/**
* @brief Configures and activates LIS302DL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS302DLDriver object
* @param[in] config pointer to the @p LIS302DLConfig object
*
* @api
*/
void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config) {
uint32_t i;
osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == LIS302DL_STOP) || (devp->state == LIS302DL_READY),
"lis302dlStart(), invalid state");
devp->config = config;
#if LIS302DL_USE_SPI
#if LIS302DL_SHARED_SPI
spiAcquireBus((devp)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
spiStart((devp)->config->spip,
(devp)->config->spicfg);
lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1,
LIS302DL_PM_SLEEP_NORMAL |
devp->config->axesenabling |
devp->config->fullscale |
devp->config->outputdatarate);
lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG2,
devp->config->highpass);
#if LIS302DL_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
#endif /* LIS302DL_USE_SPI */
/* Storing sensitivity information according to full scale value */
if(devp->config->fullscale == LIS302DL_FS_2G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS302DL_SENS_2G;
else if(devp->config->fullscale == LIS302DL_FS_8G)
for(i = 0; i < LIS302DL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS302DL_SENS_8G;
else {
osalDbgAssert(FALSE, "lis302dlStart(), accelerometer full scale issue");
}
/* This is the Accelerometer transient recovery time */
osalThreadSleepMilliseconds(10);
devp->state = LIS302DL_READY;
}
/**
* @brief Deactivates the LIS302DL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS302DLDriver object
*
* @api
*/
void lis302dlStop(LIS302DLDriver *devp) {
osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == LIS302DL_STOP) || (devp->state == LIS302DL_READY),
"lis302dlStop(), invalid state");
#if (LIS302DL_USE_SPI)
if (devp->state == LIS302DL_STOP) {
#if LIS302DL_SHARED_SPI
spiAcquireBus((devp)->config->spip);
spiStart((devp)->config->spip,
(devp)->config->spicfg);
#endif /* LIS302DL_SHARED_SPI */
lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1,
LIS302DL_PM_POWER_DOWN | LIS302DL_AE_DISABLED);
spiStop((devp)->config->spip);
#if LIS302DL_SHARED_SPI
spiReleaseBus((devp)->config->spip);
#endif /* LIS302DL_SHARED_SPI */
}
#endif /* LIS302DL_USE_SPI */
devp->state = LIS302DL_STOP;
}
/** @} */

View File

@ -1,302 +1,302 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis302dl.h
* @brief LIS302DL MEMS interface module header.
*
* @{
*/
#ifndef _LIS302DL_H_
#define _LIS302DL_H_
#include "hal_accelerometer.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LIS302DL number of axes.
*/
#define LIS302DL_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief LIS302DL SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p TRUE.
*/
#if !defined(LIS302DL_USE_SPI) || defined(__DOXYGEN__)
#define LIS302DL_USE_SPI TRUE
#endif
/**
* @brief LIS302DL I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(LIS302DL_USE_I2C) || defined(__DOXYGEN__)
#define LIS302DL_USE_I2C FALSE
#endif
/**
* @brief LIS302DL shared SPI switch.
* @details If set to @p TRUE the device acquires SPI bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION.
*/
#if !defined(LIS302DL_SHARED_SPI) || defined(__DOXYGEN__)
#define LIS302DL_SHARED_SPI FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(LIS302DL_USE_SPI ^ LIS302DL_USE_I2C)
#error "LIS302DL_USE_SPI and LIS302DL_USE_I2C cannot be both true or both false"
#endif
#if LIS302DL_USE_SPI && !HAL_USE_SPI
#error "LIS302DL_USE_SPI requires HAL_USE_SPI"
#endif
#if LIS302DL_USE_I2C && !HAL_USE_I2C
#error "LIS302DL_USE_I2C requires HAL_USE_I2C"
#endif
#if LIS302DL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
#error "LIS302DL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LIS302DL data structures and types
* @{
*/
/**
* @brief LIS302DL full scale.
*/
typedef enum {
LIS302DL_FS_2G = 0x00, /**< Full scale ±2g. */
LIS302DL_FS_8G = 0x20 /**< Full scale ±8g. */
}lis302dl_fs_t;
/**
* @brief LIS302DL output data rate and bandwidth.
*/
typedef enum {
LIS302DL_ODR_100HZ = 0x00, /**< ODR 100 Hz. */
LIS302DL_ODR_400HZ = 0x80 /**< ODR 400 Hz. */
}lis302dl_odr_t;
/**
* @brief LIS302DL high pass filtering.
*/
typedef enum {
LIS302DL_HP_DISABLED = 0x00, /**< HP bypassed. */
LIS302DL_HP_0 = 0x10, /**< HP cutoff 2Hz (ODR 100Hz) or 8Hz */
LIS302DL_HP_1 = 0x11, /**< HP cutoff 1Hz or 4Hz */
LIS302DL_HP_2 = 0x12, /**< HP cutoff 0.5Hz or 2Hz */
LIS302DL_HP_3 = 0x13 /**< HP cutoff 0.25Hz or 1Hz */
}lis302dl_hp_t;
/**
* @brief LIS302DL axes enabling.
*/
typedef enum {
LIS302DL_AE_DISABLED = 0x00, /**< All axes disabled. */
LIS302DL_AE_X = 0x01, /**< Only X-axis enabled. */
LIS302DL_AE_Y = 0x02, /**< Only Y-axis enabled. */
LIS302DL_AE_XY = 0x03, /**< X and Y axes enabled. */
LIS302DL_AE_Z = 0x04, /**< Only Z-axis enabled. */
LIS302DL_AE_XZ = 0x05, /**< X and Z axes enabled. */
LIS302DL_AE_YZ = 0x06, /**< Y and Z axes enabled. */
LIS302DL_AE_XYZ = 0x07 /**< All axes enabled. */
}lis302dl_ae_t;
/**
* @brief LIS302DL accelerometer subsystem unit.
*/
typedef enum {
LIS302DL_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
LIS302DL_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
LIS302DL_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
} lis302dl_acc_unit_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LIS302DL_UNINIT = 0, /**< Not initialized. */
LIS302DL_STOP = 1, /**< Stopped. */
LIS302DL_READY = 2, /**< Ready. */
} lis302dl_state_t;
/**
* @brief LIS302DL configuration structure.
*/
typedef struct {
#if (LIS302DL_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LIS302DL.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LIS302DL.
*/
const SPIConfig *spicfg;
#endif /* LIS302DL_USE_SPI */
#if (LIS302DL_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LIS302DL.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LIS302DL.
*/
const I2CConfig *i2ccfg;
#endif /* LIS302DL_USE_I2C */
/**
* @brief LIS302DL full scale value.
*/
lis302dl_fs_t fullscale;
/**
* @brief LIS302DL output data rate selection.
*/
lis302dl_odr_t outputdatarate;
/**
* @brief LIS302DL high pass filtering
*/
lis302dl_hp_t highpass;
/**
* @brief LIS302DL axes enabling.
*/
lis302dl_ae_t axesenabling;
/**
* @brief LIS302DL unit for cooked data.
*/
lis302dl_acc_unit_t unit;
} LIS302DLConfig;
/**
* @brief Structure representing a LIS302DL driver.
*/
typedef struct LIS302DLDriver LIS302DLDriver;
/**
* @brief @p LIS302DL specific methods.
*/
#define _lis302dl_methods \
_base_accelerometer_methods
/**
* @extends BaseAccelerometerVMT.
*
* @brief @p LIS302DL virtual methods table.
*/
struct LIS302DLVMT {
_lis302dl_methods
};
/**
* @brief @p LIS302DLDriver specific data.
*/
#define _lis302dl_data \
_base_accelerometer_data \
/* Driver state.*/ \
lis302dl_state_t state; \
/* Current configuration data.*/ \
const LIS302DLConfig *config; \
/* Current sensitivity.*/ \
float sensitivity[LIS302DL_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[LIS302DL_NUMBER_OF_AXES];
/**
* @extends BaseAccelerometer.
*
* @brief LIS302DL 3-axis accelerometer class.
* @details This class extends @p BaseAccelerometer by adding physical
* driver implementation.
*/
struct LIS302DLDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseAccelerometer Virtual Methods Table. */
const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
/** @brief LIS302DL Virtual Methods Table. */
const struct LIS302DLVMT *vmt_lis302dl;
_lis302dl_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU.
*
* @param[in] ip pointer to a @p BaseAccelerometer class.
* @param[out] temp the MEMS temperature as single precision floating.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define accelerometerGetTemp(ip, tpp) \
(ip)->vmt_lis302dl->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lis302dlObjectInit(LIS302DLDriver *devp);
void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config);
void lis302dlStop(LIS302DLDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LIS302DL_H_ */
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis302dl.h
* @brief LIS302DL MEMS interface module header.
*
* @{
*/
#ifndef _LIS302DL_H_
#define _LIS302DL_H_
#include "hal_accelerometer.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LIS302DL number of axes.
*/
#define LIS302DL_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief LIS302DL SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p TRUE.
*/
#if !defined(LIS302DL_USE_SPI) || defined(__DOXYGEN__)
#define LIS302DL_USE_SPI TRUE
#endif
/**
* @brief LIS302DL I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(LIS302DL_USE_I2C) || defined(__DOXYGEN__)
#define LIS302DL_USE_I2C FALSE
#endif
/**
* @brief LIS302DL shared SPI switch.
* @details If set to @p TRUE the device acquires SPI bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION.
*/
#if !defined(LIS302DL_SHARED_SPI) || defined(__DOXYGEN__)
#define LIS302DL_SHARED_SPI FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(LIS302DL_USE_SPI ^ LIS302DL_USE_I2C)
#error "LIS302DL_USE_SPI and LIS302DL_USE_I2C cannot be both true or both false"
#endif
#if LIS302DL_USE_SPI && !HAL_USE_SPI
#error "LIS302DL_USE_SPI requires HAL_USE_SPI"
#endif
#if LIS302DL_USE_I2C && !HAL_USE_I2C
#error "LIS302DL_USE_I2C requires HAL_USE_I2C"
#endif
#if LIS302DL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
#error "LIS302DL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LIS302DL data structures and types
* @{
*/
/**
* @brief LIS302DL full scale.
*/
typedef enum {
LIS302DL_FS_2G = 0x00, /**< Full scale ±2g. */
LIS302DL_FS_8G = 0x20 /**< Full scale ±8g. */
}lis302dl_fs_t;
/**
* @brief LIS302DL output data rate and bandwidth.
*/
typedef enum {
LIS302DL_ODR_100HZ = 0x00, /**< ODR 100 Hz. */
LIS302DL_ODR_400HZ = 0x80 /**< ODR 400 Hz. */
}lis302dl_odr_t;
/**
* @brief LIS302DL high pass filtering.
*/
typedef enum {
LIS302DL_HP_DISABLED = 0x00, /**< HP bypassed. */
LIS302DL_HP_0 = 0x10, /**< HP cutoff 2Hz (ODR 100Hz) or 8Hz */
LIS302DL_HP_1 = 0x11, /**< HP cutoff 1Hz or 4Hz */
LIS302DL_HP_2 = 0x12, /**< HP cutoff 0.5Hz or 2Hz */
LIS302DL_HP_3 = 0x13 /**< HP cutoff 0.25Hz or 1Hz */
}lis302dl_hp_t;
/**
* @brief LIS302DL axes enabling.
*/
typedef enum {
LIS302DL_AE_DISABLED = 0x00, /**< All axes disabled. */
LIS302DL_AE_X = 0x01, /**< Only X-axis enabled. */
LIS302DL_AE_Y = 0x02, /**< Only Y-axis enabled. */
LIS302DL_AE_XY = 0x03, /**< X and Y axes enabled. */
LIS302DL_AE_Z = 0x04, /**< Only Z-axis enabled. */
LIS302DL_AE_XZ = 0x05, /**< X and Z axes enabled. */
LIS302DL_AE_YZ = 0x06, /**< Y and Z axes enabled. */
LIS302DL_AE_XYZ = 0x07 /**< All axes enabled. */
}lis302dl_ae_t;
/**
* @brief LIS302DL accelerometer subsystem unit.
*/
typedef enum {
LIS302DL_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
LIS302DL_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
LIS302DL_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
} lis302dl_acc_unit_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LIS302DL_UNINIT = 0, /**< Not initialized. */
LIS302DL_STOP = 1, /**< Stopped. */
LIS302DL_READY = 2, /**< Ready. */
} lis302dl_state_t;
/**
* @brief LIS302DL configuration structure.
*/
typedef struct {
#if (LIS302DL_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LIS302DL.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LIS302DL.
*/
const SPIConfig *spicfg;
#endif /* LIS302DL_USE_SPI */
#if (LIS302DL_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LIS302DL.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LIS302DL.
*/
const I2CConfig *i2ccfg;
#endif /* LIS302DL_USE_I2C */
/**
* @brief LIS302DL full scale value.
*/
lis302dl_fs_t fullscale;
/**
* @brief LIS302DL output data rate selection.
*/
lis302dl_odr_t outputdatarate;
/**
* @brief LIS302DL high pass filtering
*/
lis302dl_hp_t highpass;
/**
* @brief LIS302DL axes enabling.
*/
lis302dl_ae_t axesenabling;
/**
* @brief LIS302DL unit for cooked data.
*/
lis302dl_acc_unit_t unit;
} LIS302DLConfig;
/**
* @brief Structure representing a LIS302DL driver.
*/
typedef struct LIS302DLDriver LIS302DLDriver;
/**
* @brief @p LIS302DL specific methods.
*/
#define _lis302dl_methods \
_base_accelerometer_methods
/**
* @extends BaseAccelerometerVMT.
*
* @brief @p LIS302DL virtual methods table.
*/
struct LIS302DLVMT {
_lis302dl_methods
};
/**
* @brief @p LIS302DLDriver specific data.
*/
#define _lis302dl_data \
_base_accelerometer_data \
/* Driver state.*/ \
lis302dl_state_t state; \
/* Current configuration data.*/ \
const LIS302DLConfig *config; \
/* Current sensitivity.*/ \
float sensitivity[LIS302DL_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[LIS302DL_NUMBER_OF_AXES];
/**
* @extends BaseAccelerometer.
*
* @brief LIS302DL 3-axis accelerometer class.
* @details This class extends @p BaseAccelerometer by adding physical
* driver implementation.
*/
struct LIS302DLDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseAccelerometer Virtual Methods Table. */
const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
/** @brief LIS302DL Virtual Methods Table. */
const struct LIS302DLVMT *vmt_lis302dl;
_lis302dl_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU.
*
* @param[in] ip pointer to a @p BaseAccelerometer class.
* @param[out] temp the MEMS temperature as single precision floating.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define accelerometerGetTemp(ip, tpp) \
(ip)->vmt_lis302dl->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lis302dlObjectInit(LIS302DLDriver *devp);
void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config);
void lis302dlStop(LIS302DLDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LIS302DL_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,326 +1,326 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis3dsh.h
* @brief LIS3DSH MEMS interface module header.
*
* @{
*/
#ifndef _LIS3DSH_H_
#define _LIS3DSH_H_
#include "hal_accelerometer.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LIS3DSH number of axes.
*/
#define LIS3DSH_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options.
* @{
*/
/**
* @brief LIS3DSH SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p TRUE.
*/
#if !defined(LIS3DSH_USE_SPI) || defined(__DOXYGEN__)
#define LIS3DSH_USE_SPI TRUE
#endif
/**
* @brief LIS3DSH I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(LIS3DSH_USE_I2C) || defined(__DOXYGEN__)
#define LIS3DSH_USE_I2C FALSE
#endif
/**
* @brief LIS3DSH shared SPI switch.
* @details If set to @p TRUE the device acquires SPI bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION.
*/
#if !defined(LIS3DSH_SHARED_SPI) || defined(__DOXYGEN__)
#define LIS3DSH_SHARED_SPI FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(LIS3DSH_USE_SPI ^ LIS3DSH_USE_I2C)
#error "LIS3DSH_USE_SPI and LIS3DSH_USE_I2C cannot be both true or both false"
#endif
#if LIS3DSH_USE_SPI && !HAL_USE_SPI
#error "LIS3DSH_USE_SPI requires HAL_USE_SPI"
#endif
#if LIS3DSH_USE_I2C && !HAL_USE_I2C
#error "LIS3DSH_USE_I2C requires HAL_USE_I2C"
#endif
#if LIS3DSH_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
#error "LIS3DSH_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LIS3DSH data structures and types
* @{
*/
/**
* @brief LIS3DSH full scale.
*/
typedef enum {
LIS3DSH_FS_2G = 0x00, /**< Full scale ±2g. */
LIS3DSH_FS_4G = 0x08, /**< Full scale ±4g. */
LIS3DSH_FS_6G = 0x10, /**< Full scale ±6g. */
LIS3DSH_FS_8G = 0x18, /**< Full scale ±8g. */
LIS3DSH_FS_16G = 0x20 /**< Full scale ±16g. */
}lis3dsh_fs_t;
/**
* @brief LIS3DSH output data rate.
*/
typedef enum {
LIS3DSH_ODR_PD = 0x00, /**< ODR 100 Hz. */
LIS3DSH_ODR_3_125HZ = 0x10, /**< ODR 3.125 Hz. */
LIS3DSH_ODR_6_25HZ = 0x20, /**< ODR 6.25 Hz. */
LIS3DSH_ODR_12_5HZ = 0x30, /**< ODR 12.5 Hz. */
LIS3DSH_ODR_25HZ = 0x40, /**< ODR 25 Hz. */
LIS3DSH_ODR_50HZ = 0x50, /**< ODR 50 Hz. */
LIS3DSH_ODR_100HZ = 0x60, /**< ODR 100 Hz. */
LIS3DSH_ODR_400HZ = 0x70, /**< ODR 400 Hz. */
LIS3DSH_ODR_800HZ = 0x80, /**< ODR 800 Hz. */
LIS3DSH_ODR_1600HZ = 0x90 /**< ODR 1600 Hz. */
}lis3dsh_odr_t;
/**
* @brief LIS3DSH anti-aliasing bandwidth.
*/
typedef enum {
LIS3DSH_BW_800HZ = 0x00, /**< AA filter BW 800Hz. */
LIS3DSH_BW_200HZ = 0x40, /**< AA filter BW 200Hz. */
LIS3DSH_BW_400HZ = 0x80, /**< AA filter BW 400Hz. */
LIS3DSH_BW_50HZ = 0xC0 /**< AA filter BW 50Hz. */
}lis3dsh_bw_t;
/**
* @brief LIS3DSH axes enabling.
*/
typedef enum {
LIS3DSH_AE_DISABLED = 0x00, /**< All axes disabled. */
LIS3DSH_AE_X = 0x01, /**< Only X-axis enabled. */
LIS3DSH_AE_Y = 0x02, /**< Only Y-axis enabled. */
LIS3DSH_AE_XY = 0x03, /**< X and Y axes enabled. */
LIS3DSH_AE_Z = 0x04, /**< Only Z-axis enabled. */
LIS3DSH_AE_XZ = 0x05, /**< X and Z axes enabled. */
LIS3DSH_AE_YZ = 0x06, /**< Y and Z axes enabled. */
LIS3DSH_AE_XYZ = 0x07 /**< All axes enabled. */
}lis3dsh_ae_t;
/**
* @brief LIS3DSH block data update.
*/
typedef enum {
LIS3DSH_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
LIS3DSH_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */
} lis3dsh_bdu_t;
/**
* @brief LIS3DSH accelerometer subsystem unit.
*/
typedef enum {
LIS3DSH_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
LIS3DSH_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
LIS3DSH_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
} lis3dsh_acc_unit_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LIS3DSH_UNINIT = 0, /**< Not initialized. */
LIS3DSH_STOP = 1, /**< Stopped. */
LIS3DSH_READY = 2, /**< Ready. */
} lis3dsh_state_t;
/**
* @brief LIS3DSH configuration structure.
*/
typedef struct {
#if (LIS3DSH_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LIS3DSH.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LIS3DSH.
*/
const SPIConfig *spicfg;
#endif /* LIS3DSH_USE_SPI */
#if (LIS3DSH_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LIS3DSH.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LIS3DSH.
*/
const I2CConfig *i2ccfg;
#endif /* LIS3DSH_USE_I2C */
/**
* @brief LIS3DSH full scale value.
*/
lis3dsh_fs_t fullscale;
/**
* @brief LIS3DSH output data rate selection.
*/
lis3dsh_odr_t outputdatarate;
/**
* @brief LIS3DSH anti-aliasing bandwidth.
*/
lis3dsh_bw_t antialiasing;
/**
* @brief LIS3DSH axes enabling.
*/
lis3dsh_ae_t axesenabling;
/**
* @brief LIS3DSH block data update.
*/
lis3dsh_bdu_t blockdataupdate;
/**
* @brief LIS3DSH unit for cooked data.
*/
lis3dsh_acc_unit_t unit;
} LIS3DSHConfig;
/**
* @brief Structure representing a LIS3DSH driver.
*/
typedef struct LIS3DSHDriver LIS3DSHDriver;
/**
* @brief @p LIS3DSH specific methods.
*/
#define _lis3dsh_methods \
_base_accelerometer_methods \
/* Retrieve the temperature of L3GD20 chip.*/ \
msg_t (*get_temperature)(void *instance, int8_t* temperature);
/**
* @extends BaseAccelerometerVMT
*
* @brief @p LIS3DSH virtual methods table.
*/
struct LIS3DSHVMT {
_lis3dsh_methods
};
/**
* @brief @p LIS3DSHDriver specific data.
*/
#define _lis3dsh_data \
_base_accelerometer_data \
/* Driver state.*/ \
lis3dsh_state_t state; \
/* Current configuration data.*/ \
const LIS3DSHConfig *config; \
/* Current sensitivity.*/ \
float sensitivity[LIS3DSH_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[LIS3DSH_NUMBER_OF_AXES];
/**
* @extends BaseAccelerometer
*
* @brief LIS3DSH 3-axis accelerometer class.
* @details This class extends @p BaseAccelerometer by adding physical
* driver implementation.
*/
struct LIS3DSHDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseAccelerometer Virtual Methods Table. */
const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
/** @brief LIS3DSH Virtual Methods Table. */
const struct LIS3DSHVMT *vmt_lis3dsh;
_lis3dsh_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU
* @note Value is raw since there is a lack of information in datasheet.
*
* @param[in] ip pointer to a @p BaseAccelerometer class.
* @param[out] temp the MEMS temperature as raw data.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define accelerometerGetTemp(ip, tpp) \
(ip)->vmt_lis3dsh->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lis3dshObjectInit(LIS3DSHDriver *devp);
void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config);
void lis3dshStop(LIS3DSHDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LIS3DSH_H_ */
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis3dsh.h
* @brief LIS3DSH MEMS interface module header.
*
* @{
*/
#ifndef _LIS3DSH_H_
#define _LIS3DSH_H_
#include "hal_accelerometer.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LIS3DSH number of axes.
*/
#define LIS3DSH_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options.
* @{
*/
/**
* @brief LIS3DSH SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p TRUE.
*/
#if !defined(LIS3DSH_USE_SPI) || defined(__DOXYGEN__)
#define LIS3DSH_USE_SPI TRUE
#endif
/**
* @brief LIS3DSH I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p FALSE.
*/
#if !defined(LIS3DSH_USE_I2C) || defined(__DOXYGEN__)
#define LIS3DSH_USE_I2C FALSE
#endif
/**
* @brief LIS3DSH shared SPI switch.
* @details If set to @p TRUE the device acquires SPI bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION.
*/
#if !defined(LIS3DSH_SHARED_SPI) || defined(__DOXYGEN__)
#define LIS3DSH_SHARED_SPI FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(LIS3DSH_USE_SPI ^ LIS3DSH_USE_I2C)
#error "LIS3DSH_USE_SPI and LIS3DSH_USE_I2C cannot be both true or both false"
#endif
#if LIS3DSH_USE_SPI && !HAL_USE_SPI
#error "LIS3DSH_USE_SPI requires HAL_USE_SPI"
#endif
#if LIS3DSH_USE_I2C && !HAL_USE_I2C
#error "LIS3DSH_USE_I2C requires HAL_USE_I2C"
#endif
#if LIS3DSH_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
#error "LIS3DSH_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LIS3DSH data structures and types
* @{
*/
/**
* @brief LIS3DSH full scale.
*/
typedef enum {
LIS3DSH_FS_2G = 0x00, /**< Full scale ±2g. */
LIS3DSH_FS_4G = 0x08, /**< Full scale ±4g. */
LIS3DSH_FS_6G = 0x10, /**< Full scale ±6g. */
LIS3DSH_FS_8G = 0x18, /**< Full scale ±8g. */
LIS3DSH_FS_16G = 0x20 /**< Full scale ±16g. */
}lis3dsh_fs_t;
/**
* @brief LIS3DSH output data rate.
*/
typedef enum {
LIS3DSH_ODR_PD = 0x00, /**< ODR 100 Hz. */
LIS3DSH_ODR_3_125HZ = 0x10, /**< ODR 3.125 Hz. */
LIS3DSH_ODR_6_25HZ = 0x20, /**< ODR 6.25 Hz. */
LIS3DSH_ODR_12_5HZ = 0x30, /**< ODR 12.5 Hz. */
LIS3DSH_ODR_25HZ = 0x40, /**< ODR 25 Hz. */
LIS3DSH_ODR_50HZ = 0x50, /**< ODR 50 Hz. */
LIS3DSH_ODR_100HZ = 0x60, /**< ODR 100 Hz. */
LIS3DSH_ODR_400HZ = 0x70, /**< ODR 400 Hz. */
LIS3DSH_ODR_800HZ = 0x80, /**< ODR 800 Hz. */
LIS3DSH_ODR_1600HZ = 0x90 /**< ODR 1600 Hz. */
}lis3dsh_odr_t;
/**
* @brief LIS3DSH anti-aliasing bandwidth.
*/
typedef enum {
LIS3DSH_BW_800HZ = 0x00, /**< AA filter BW 800Hz. */
LIS3DSH_BW_200HZ = 0x40, /**< AA filter BW 200Hz. */
LIS3DSH_BW_400HZ = 0x80, /**< AA filter BW 400Hz. */
LIS3DSH_BW_50HZ = 0xC0 /**< AA filter BW 50Hz. */
}lis3dsh_bw_t;
/**
* @brief LIS3DSH axes enabling.
*/
typedef enum {
LIS3DSH_AE_DISABLED = 0x00, /**< All axes disabled. */
LIS3DSH_AE_X = 0x01, /**< Only X-axis enabled. */
LIS3DSH_AE_Y = 0x02, /**< Only Y-axis enabled. */
LIS3DSH_AE_XY = 0x03, /**< X and Y axes enabled. */
LIS3DSH_AE_Z = 0x04, /**< Only Z-axis enabled. */
LIS3DSH_AE_XZ = 0x05, /**< X and Z axes enabled. */
LIS3DSH_AE_YZ = 0x06, /**< Y and Z axes enabled. */
LIS3DSH_AE_XYZ = 0x07 /**< All axes enabled. */
}lis3dsh_ae_t;
/**
* @brief LIS3DSH block data update.
*/
typedef enum {
LIS3DSH_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
LIS3DSH_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */
} lis3dsh_bdu_t;
/**
* @brief LIS3DSH accelerometer subsystem unit.
*/
typedef enum {
LIS3DSH_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
LIS3DSH_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
LIS3DSH_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
} lis3dsh_acc_unit_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LIS3DSH_UNINIT = 0, /**< Not initialized. */
LIS3DSH_STOP = 1, /**< Stopped. */
LIS3DSH_READY = 2, /**< Ready. */
} lis3dsh_state_t;
/**
* @brief LIS3DSH configuration structure.
*/
typedef struct {
#if (LIS3DSH_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LIS3DSH.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LIS3DSH.
*/
const SPIConfig *spicfg;
#endif /* LIS3DSH_USE_SPI */
#if (LIS3DSH_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LIS3DSH.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LIS3DSH.
*/
const I2CConfig *i2ccfg;
#endif /* LIS3DSH_USE_I2C */
/**
* @brief LIS3DSH full scale value.
*/
lis3dsh_fs_t fullscale;
/**
* @brief LIS3DSH output data rate selection.
*/
lis3dsh_odr_t outputdatarate;
/**
* @brief LIS3DSH anti-aliasing bandwidth.
*/
lis3dsh_bw_t antialiasing;
/**
* @brief LIS3DSH axes enabling.
*/
lis3dsh_ae_t axesenabling;
/**
* @brief LIS3DSH block data update.
*/
lis3dsh_bdu_t blockdataupdate;
/**
* @brief LIS3DSH unit for cooked data.
*/
lis3dsh_acc_unit_t unit;
} LIS3DSHConfig;
/**
* @brief Structure representing a LIS3DSH driver.
*/
typedef struct LIS3DSHDriver LIS3DSHDriver;
/**
* @brief @p LIS3DSH specific methods.
*/
#define _lis3dsh_methods \
_base_accelerometer_methods \
/* Retrieve the temperature of L3GD20 chip.*/ \
msg_t (*get_temperature)(void *instance, int8_t* temperature);
/**
* @extends BaseAccelerometerVMT
*
* @brief @p LIS3DSH virtual methods table.
*/
struct LIS3DSHVMT {
_lis3dsh_methods
};
/**
* @brief @p LIS3DSHDriver specific data.
*/
#define _lis3dsh_data \
_base_accelerometer_data \
/* Driver state.*/ \
lis3dsh_state_t state; \
/* Current configuration data.*/ \
const LIS3DSHConfig *config; \
/* Current sensitivity.*/ \
float sensitivity[LIS3DSH_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[LIS3DSH_NUMBER_OF_AXES];
/**
* @extends BaseAccelerometer
*
* @brief LIS3DSH 3-axis accelerometer class.
* @details This class extends @p BaseAccelerometer by adding physical
* driver implementation.
*/
struct LIS3DSHDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseAccelerometer Virtual Methods Table. */
const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
/** @brief LIS3DSH Virtual Methods Table. */
const struct LIS3DSHVMT *vmt_lis3dsh;
_lis3dsh_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU
* @note Value is raw since there is a lack of information in datasheet.
*
* @param[in] ip pointer to a @p BaseAccelerometer class.
* @param[out] temp the MEMS temperature as raw data.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define accelerometerGetTemp(ip, tpp) \
(ip)->vmt_lis3dsh->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lis3dshObjectInit(LIS3DSHDriver *devp);
void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config);
void lis3dshStop(LIS3DSHDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LIS3DSH_H_ */
/** @} */

View File

@ -1,483 +1,483 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis3mdl.c
* @brief LIS3MDL MEMS interface module code.
*
* @addtogroup lis3mdl
* @{
*/
#include "hal.h"
#include "lis3mdl.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define LIS3MDL_SENS_4GA ((float)6842.0f)
#define LIS3MDL_SENS_8GA ((float)3421.0f)
#define LIS3MDL_SENS_12GA ((float)2281.0f)
#define LIS3MDL_SENS_16GA ((float)1711.0f)
#define LIS3MDL_TEMP_SENS ((float)8.0f)
#define LIS3MDL_DI ((uint8_t)0xFF)
#define LIS3MDL_DI_0 ((uint8_t)0x01)
#define LIS3MDL_DI_1 ((uint8_t)0x02)
#define LIS3MDL_DI_2 ((uint8_t)0x04)
#define LIS3MDL_DI_3 ((uint8_t)0x08)
#define LIS3MDL_DI_4 ((uint8_t)0x10)
#define LIS3MDL_DI_5 ((uint8_t)0x20)
#define LIS3MDL_DI_6 ((uint8_t)0x40)
#define LIS3MDL_DI_7 ((uint8_t)0x80)
#define LIS3MDL_AD ((uint8_t)0x3F)
#define LIS3MDL_AD_0 ((uint8_t)0x01)
#define LIS3MDL_AD_1 ((uint8_t)0x02)
#define LIS3MDL_AD_2 ((uint8_t)0x04)
#define LIS3MDL_AD_3 ((uint8_t)0x08)
#define LIS3MDL_AD_4 ((uint8_t)0x10)
#define LIS3MDL_AD_5 ((uint8_t)0x20)
#define LIS3MDL_AD_6 ((uint8_t)0x40)
#define LIS3MDL_RW ((uint8_t)0x80)
#define LIS3MDL_AD_WHO_AM_I ((uint8_t)0x0F)
#define LIS3MDL_AD_CTRL_REG1 ((uint8_t)0x20)
#define LIS3MDL_AD_CTRL_REG2 ((uint8_t)0x21)
#define LIS3MDL_AD_CTRL_REG3 ((uint8_t)0x22)
#define LIS3MDL_AD_CTRL_REG4 ((uint8_t)0x23)
#define LIS3MDL_AD_CTRL_REG5 ((uint8_t)0x24)
#define LIS3MDL_AD_STATUS_REG ((uint8_t)0x27)
#define LIS3MDL_AD_OUT_X_L ((uint8_t)0x28)
#define LIS3MDL_AD_OUT_X_H ((uint8_t)0x29)
#define LIS3MDL_AD_OUT_Y_L ((uint8_t)0x2A)
#define LIS3MDL_AD_OUT_Y_H ((uint8_t)0x2B)
#define LIS3MDL_AD_OUT_Z_L ((uint8_t)0x2C)
#define LIS3MDL_AD_OUT_Z_H ((uint8_t)0x2D)
#define LIS3MDL_AD_TEMP_OUT_L ((uint8_t)0x2E)
#define LIS3MDL_AD_TEMP_OUT_H ((uint8_t)0x2F)
#define LIS3MDL_AD_INT_CFG ((uint8_t)0x30)
#define LIS3MDL_AD_INT_SOURCE ((uint8_t)0x31)
#define LIS3MDL_AD_INT_THS_L ((uint8_t)0x32)
#define LIS3MDL_AD_INT_THS_H ((uint8_t)0x33)
#define LIS3MDL_CTRL_REG2_FS_MASK ((uint8_t)0x60)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief Reads registers value using I2C.
* @pre The I2C interface must be initialized and the driver started.
*
* @param[in] i2cp pointer to the I2C interface
* @param[in] sad slave address without R bit
* @param[in] reg first sub-register address
* @return the read value.
*/
uint8_t lis3mdlI2CReadRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t reg,
msg_t* msgp) {
msg_t msg;
#if defined(STM32F103_MCUCONF)
uint8_t rxbuf[2];
msg = i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, 2,
TIME_INFINITE);
if(msgp != NULL){
*msgp = msg;
}
return rxbuf[0];
#else
uint8_t txbuf, rxbuf;
txbuf = reg;
msg = i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, &rxbuf, 1,
TIME_INFINITE);
if(msgp != NULL){
*msgp = msg;
}
return rxbuf;
#endif
}
/**
* @brief Writes a value into a register using I2C.
* @pre The I2C interface must be initialized and the driver started.
*
* @param[in] i2cp pointer to the I2C interface
* @param[in] sad slave address without R bit
* @param[in] sub sub-register address
* @param[in] value the value to be written
* @return the operation status.
*/
msg_t lis3mdlI2CWriteRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t reg,
uint8_t value) {
uint8_t rxbuf;
uint8_t txbuf[2];
switch (reg) {
default:
/* Reserved register must not be written, according to the datasheet
* this could permanently damage the device.
*/
chDbgAssert(FALSE, "lis3mdlI2CWriteRegister(), reserved register");
case LIS3MDL_AD_WHO_AM_I:
case LIS3MDL_AD_STATUS_REG:
case LIS3MDL_AD_OUT_X_L:
case LIS3MDL_AD_OUT_X_H:
case LIS3MDL_AD_OUT_Y_L:
case LIS3MDL_AD_OUT_Y_H:
case LIS3MDL_AD_OUT_Z_L:
case LIS3MDL_AD_OUT_Z_H:
case LIS3MDL_AD_TEMP_OUT_L:
case LIS3MDL_AD_TEMP_OUT_H:
case LIS3MDL_AD_INT_SOURCE:
case LIS3MDL_AD_INT_THS_L:
case LIS3MDL_AD_INT_THS_H:
/* Read only registers cannot be written, the command is ignored.*/
return MSG_RESET;
case LIS3MDL_AD_CTRL_REG1:
case LIS3MDL_AD_CTRL_REG2:
case LIS3MDL_AD_CTRL_REG3:
case LIS3MDL_AD_CTRL_REG4:
case LIS3MDL_AD_CTRL_REG5:
case LIS3MDL_AD_INT_CFG:
txbuf[0] = reg;
txbuf[1] = value;
return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
break;
}
}
#endif /* LIS3MDL_USE_I2C */
/*
* Interface implementation.
*/
static size_t get_axes_number(void *ip) {
osalDbgCheck(ip != NULL);
return LIS3MDL_NUMBER_OF_AXES;
}
static msg_t read_raw(void *ip, int32_t axes[LIS3MDL_NUMBER_OF_AXES]) {
uint16_t tmp;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"read_raw(), invalid state");
#if LIS3MDL_USE_I2C
osalDbgAssert((((LIS3MDLDriver *)ip)->config->i2cp->state == I2C_READY),
"read_raw(), channel not ready");
#if LIS3MDL_SHARED_I2C
i2cAcquireBus(((LIS3MDLDriver *)ip)->config->i2cp);
i2cStart(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->i2ccfg);
#endif /* LIS3MDL_SHARED_I2C */
tmp = lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_X_L, NULL);
tmp += lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_X_H, NULL) << 8;
axes[0] = (int32_t)tmp - ((LIS3MDLDriver *)ip)->bias[0];
tmp = lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Y_L, NULL);
tmp += lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Y_H, NULL) << 8;
axes[1] = (int32_t)tmp - ((LIS3MDLDriver *)ip)->bias[1];
tmp = lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Z_L, NULL);
tmp += lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Z_H, NULL) << 8;
axes[2] = (int32_t)tmp - ((LIS3MDLDriver *)ip)->bias[2];
#if LIS3MDL_SHARED_I2C
i2cReleaseBus(((LIS3MDLDriver *)ip)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
#endif /* LIS3MDL_USE_I2C */
return MSG_OK;
}
static msg_t read_cooked(void *ip, float axes[]) {
uint32_t i;
int32_t raw[LIS3MDL_NUMBER_OF_AXES];
msg_t msg;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"read_cooked(), invalid state");
msg = read_raw(ip, raw);
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES ; i++){
axes[i] = raw[i] / ((LIS3MDLDriver *)ip)->sensitivity[i];
}
return msg;
}
static msg_t set_bias(void *ip, int32_t *bp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (bp !=NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY) ||
(((LIS3MDLDriver *)ip)->state == LIS3MDL_STOP),
"set_bias(), invalid state");
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++) {
((LIS3MDLDriver *)ip)->bias[i] = bp[i];
}
return MSG_OK;
}
static msg_t reset_bias(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY) ||
(((LIS3MDLDriver *)ip)->state == LIS3MDL_STOP),
"reset_bias(), invalid state");
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->bias[i] = 0;
return MSG_OK;
}
static msg_t set_sensivity(void *ip, float *sp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (sp !=NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"set_sensivity(), invalid state");
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++) {
((LIS3MDLDriver *)ip)->sensitivity[i] = sp[i];
}
return MSG_OK;
}
static msg_t reset_sensivity(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"reset_sensivity(), invalid state");
if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_4GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_4GA;
else if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_8GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_8GA;
else if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_12GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_12GA;
else if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_16GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_16GA;
else {
osalDbgAssert(FALSE, "reset_sensivity(), compass full scale issue");
return MSG_RESET;
}
return MSG_OK;
}
static msg_t get_temperature(void *ip, float* tempp) {
int16_t temp;
#if LIS3MDL_USE_I2C
osalDbgAssert((((LIS3MDLDriver *)ip)->config->i2cp->state == I2C_READY),
"gyro_read_raw(), channel not ready");
#if LIS3MDL_SHARED_I2C
i2cAcquireBus(((LIS3MDLDriver *)ip)->config->i2cp);
i2cStart(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->i2ccfg);
#endif /* LIS3MDL_SHARED_I2C */
temp = (int16_t)(lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_TEMP_OUT_L, NULL));
temp += (int16_t)(lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_TEMP_OUT_H, NULL) << 8);
#if LIS3MDL_SHARED_I2C
i2cReleaseBus(((LIS3MDLDriver *)ip)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
#endif /* LIS3MDL_USE_I2C */
*tempp = (float)temp / LIS3MDL_TEMP_SENS;
return MSG_OK;
}
static const struct BaseSensorVMT vmt_basesensor = {
get_axes_number, read_raw, read_cooked
};
static const struct BaseCompassVMT vmt_basecompass = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity
};
static const struct LIS3MDLVMT vmt_lis3mdl = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity,
get_temperature
};
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an instance.
*
* @param[out] devp pointer to the @p LIS3MDLDriver object
*
* @init
*/
void lis3mdlObjectInit(LIS3MDLDriver *devp) {
uint32_t i;
devp->vmt_basesensor = &vmt_basesensor;
devp->vmt_basecompass = &vmt_basecompass;
devp->vmt_lis3mdl = &vmt_lis3mdl;
devp->config = NULL;
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->bias[i] = 0;
devp->state = LIS3MDL_STOP;
}
/**
* @brief Configures and activates LIS3MDL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS3MDLDriver object
* @param[in] config pointer to the @p LIS3MDLConfig object
*
* @api
*/
void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config) {
uint32_t i;
osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY),
"lis3mdlStart(), invalid state");
devp->config = config;
#if LIS3MDL_USE_I2C
#if LIS3MDL_SHARED_I2C
i2cAcquireBus((devp)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
i2cStart((devp)->config->i2cp,
(devp)->config->i2ccfg);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG1,
devp->config->temperature |
devp->config->outputdatarate |
devp->config->operationmodexy);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG2,
devp->config->fullscale);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG3,
devp->config->conversionmode);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG4,
devp->config->operationmodez |
devp->config->endianness);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG5,
devp->config->blockdataupdate);
#if LIS3MDL_SHARED_I2C
i2cReleaseBus((devp)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
#endif /* LIS3MDL_USE_I2C */
/* Storing sensitivity information according to full scale value */
if(devp->config->fullscale == LIS3MDL_FS_4GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_4GA;
else if(devp->config->fullscale == LIS3MDL_FS_8GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_8GA;
else if(devp->config->fullscale == LIS3MDL_FS_12GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_12GA;
else if(devp->config->fullscale == LIS3MDL_FS_16GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_16GA;
else
osalDbgAssert(FALSE, "lis3mdlStart(), compass full scale issue");
devp->state = LIS3MDL_READY;
}
/**
* @brief Deactivates the LIS3MDL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS3MDLDriver object
*
* @api
*/
void lis3mdlStop(LIS3MDLDriver *devp) {
osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY),
"lis3mdlStop(), invalid state");
#if (LIS3MDL_USE_I2C)
if (devp->state == LIS3MDL_STOP) {
#if LIS3MDL_SHARED_I2C
i2cAcquireBus((devp)->config->i2cp);
i2cStart((devp)->config->i2cp,
(devp)->config->i2ccfg);
#endif /* LIS3MDL_SHARED_I2C */
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG3,
LIS3MDL_MD_POWER_DOWN);
i2cStop((devp)->config->i2cp);
#if LIS3MDL_SHARED_I2C
i2cReleaseBus((devp)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
}
#endif /* LIS3MDL_USE_I2C */
devp->state = LIS3MDL_STOP;
}
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis3mdl.c
* @brief LIS3MDL MEMS interface module code.
*
* @addtogroup lis3mdl
* @{
*/
#include "hal.h"
#include "lis3mdl.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define LIS3MDL_SENS_4GA ((float)6842.0f)
#define LIS3MDL_SENS_8GA ((float)3421.0f)
#define LIS3MDL_SENS_12GA ((float)2281.0f)
#define LIS3MDL_SENS_16GA ((float)1711.0f)
#define LIS3MDL_TEMP_SENS ((float)8.0f)
#define LIS3MDL_DI ((uint8_t)0xFF)
#define LIS3MDL_DI_0 ((uint8_t)0x01)
#define LIS3MDL_DI_1 ((uint8_t)0x02)
#define LIS3MDL_DI_2 ((uint8_t)0x04)
#define LIS3MDL_DI_3 ((uint8_t)0x08)
#define LIS3MDL_DI_4 ((uint8_t)0x10)
#define LIS3MDL_DI_5 ((uint8_t)0x20)
#define LIS3MDL_DI_6 ((uint8_t)0x40)
#define LIS3MDL_DI_7 ((uint8_t)0x80)
#define LIS3MDL_AD ((uint8_t)0x3F)
#define LIS3MDL_AD_0 ((uint8_t)0x01)
#define LIS3MDL_AD_1 ((uint8_t)0x02)
#define LIS3MDL_AD_2 ((uint8_t)0x04)
#define LIS3MDL_AD_3 ((uint8_t)0x08)
#define LIS3MDL_AD_4 ((uint8_t)0x10)
#define LIS3MDL_AD_5 ((uint8_t)0x20)
#define LIS3MDL_AD_6 ((uint8_t)0x40)
#define LIS3MDL_RW ((uint8_t)0x80)
#define LIS3MDL_AD_WHO_AM_I ((uint8_t)0x0F)
#define LIS3MDL_AD_CTRL_REG1 ((uint8_t)0x20)
#define LIS3MDL_AD_CTRL_REG2 ((uint8_t)0x21)
#define LIS3MDL_AD_CTRL_REG3 ((uint8_t)0x22)
#define LIS3MDL_AD_CTRL_REG4 ((uint8_t)0x23)
#define LIS3MDL_AD_CTRL_REG5 ((uint8_t)0x24)
#define LIS3MDL_AD_STATUS_REG ((uint8_t)0x27)
#define LIS3MDL_AD_OUT_X_L ((uint8_t)0x28)
#define LIS3MDL_AD_OUT_X_H ((uint8_t)0x29)
#define LIS3MDL_AD_OUT_Y_L ((uint8_t)0x2A)
#define LIS3MDL_AD_OUT_Y_H ((uint8_t)0x2B)
#define LIS3MDL_AD_OUT_Z_L ((uint8_t)0x2C)
#define LIS3MDL_AD_OUT_Z_H ((uint8_t)0x2D)
#define LIS3MDL_AD_TEMP_OUT_L ((uint8_t)0x2E)
#define LIS3MDL_AD_TEMP_OUT_H ((uint8_t)0x2F)
#define LIS3MDL_AD_INT_CFG ((uint8_t)0x30)
#define LIS3MDL_AD_INT_SOURCE ((uint8_t)0x31)
#define LIS3MDL_AD_INT_THS_L ((uint8_t)0x32)
#define LIS3MDL_AD_INT_THS_H ((uint8_t)0x33)
#define LIS3MDL_CTRL_REG2_FS_MASK ((uint8_t)0x60)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief Reads registers value using I2C.
* @pre The I2C interface must be initialized and the driver started.
*
* @param[in] i2cp pointer to the I2C interface
* @param[in] sad slave address without R bit
* @param[in] reg first sub-register address
* @return the read value.
*/
uint8_t lis3mdlI2CReadRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t reg,
msg_t* msgp) {
msg_t msg;
#if defined(STM32F103_MCUCONF)
uint8_t rxbuf[2];
msg = i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, 2,
TIME_INFINITE);
if(msgp != NULL){
*msgp = msg;
}
return rxbuf[0];
#else
uint8_t txbuf, rxbuf;
txbuf = reg;
msg = i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, &rxbuf, 1,
TIME_INFINITE);
if(msgp != NULL){
*msgp = msg;
}
return rxbuf;
#endif
}
/**
* @brief Writes a value into a register using I2C.
* @pre The I2C interface must be initialized and the driver started.
*
* @param[in] i2cp pointer to the I2C interface
* @param[in] sad slave address without R bit
* @param[in] sub sub-register address
* @param[in] value the value to be written
* @return the operation status.
*/
msg_t lis3mdlI2CWriteRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t reg,
uint8_t value) {
uint8_t rxbuf;
uint8_t txbuf[2];
switch (reg) {
default:
/* Reserved register must not be written, according to the datasheet
* this could permanently damage the device.
*/
chDbgAssert(FALSE, "lis3mdlI2CWriteRegister(), reserved register");
case LIS3MDL_AD_WHO_AM_I:
case LIS3MDL_AD_STATUS_REG:
case LIS3MDL_AD_OUT_X_L:
case LIS3MDL_AD_OUT_X_H:
case LIS3MDL_AD_OUT_Y_L:
case LIS3MDL_AD_OUT_Y_H:
case LIS3MDL_AD_OUT_Z_L:
case LIS3MDL_AD_OUT_Z_H:
case LIS3MDL_AD_TEMP_OUT_L:
case LIS3MDL_AD_TEMP_OUT_H:
case LIS3MDL_AD_INT_SOURCE:
case LIS3MDL_AD_INT_THS_L:
case LIS3MDL_AD_INT_THS_H:
/* Read only registers cannot be written, the command is ignored.*/
return MSG_RESET;
case LIS3MDL_AD_CTRL_REG1:
case LIS3MDL_AD_CTRL_REG2:
case LIS3MDL_AD_CTRL_REG3:
case LIS3MDL_AD_CTRL_REG4:
case LIS3MDL_AD_CTRL_REG5:
case LIS3MDL_AD_INT_CFG:
txbuf[0] = reg;
txbuf[1] = value;
return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
break;
}
}
#endif /* LIS3MDL_USE_I2C */
/*
* Interface implementation.
*/
static size_t get_axes_number(void *ip) {
osalDbgCheck(ip != NULL);
return LIS3MDL_NUMBER_OF_AXES;
}
static msg_t read_raw(void *ip, int32_t axes[LIS3MDL_NUMBER_OF_AXES]) {
uint16_t tmp;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"read_raw(), invalid state");
#if LIS3MDL_USE_I2C
osalDbgAssert((((LIS3MDLDriver *)ip)->config->i2cp->state == I2C_READY),
"read_raw(), channel not ready");
#if LIS3MDL_SHARED_I2C
i2cAcquireBus(((LIS3MDLDriver *)ip)->config->i2cp);
i2cStart(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->i2ccfg);
#endif /* LIS3MDL_SHARED_I2C */
tmp = lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_X_L, NULL);
tmp += lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_X_H, NULL) << 8;
axes[0] = (int32_t)tmp - ((LIS3MDLDriver *)ip)->bias[0];
tmp = lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Y_L, NULL);
tmp += lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Y_H, NULL) << 8;
axes[1] = (int32_t)tmp - ((LIS3MDLDriver *)ip)->bias[1];
tmp = lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Z_L, NULL);
tmp += lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_OUT_Z_H, NULL) << 8;
axes[2] = (int32_t)tmp - ((LIS3MDLDriver *)ip)->bias[2];
#if LIS3MDL_SHARED_I2C
i2cReleaseBus(((LIS3MDLDriver *)ip)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
#endif /* LIS3MDL_USE_I2C */
return MSG_OK;
}
static msg_t read_cooked(void *ip, float axes[]) {
uint32_t i;
int32_t raw[LIS3MDL_NUMBER_OF_AXES];
msg_t msg;
osalDbgCheck((ip != NULL) && (axes != NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"read_cooked(), invalid state");
msg = read_raw(ip, raw);
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES ; i++){
axes[i] = raw[i] / ((LIS3MDLDriver *)ip)->sensitivity[i];
}
return msg;
}
static msg_t set_bias(void *ip, int32_t *bp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (bp !=NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY) ||
(((LIS3MDLDriver *)ip)->state == LIS3MDL_STOP),
"set_bias(), invalid state");
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++) {
((LIS3MDLDriver *)ip)->bias[i] = bp[i];
}
return MSG_OK;
}
static msg_t reset_bias(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY) ||
(((LIS3MDLDriver *)ip)->state == LIS3MDL_STOP),
"reset_bias(), invalid state");
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->bias[i] = 0;
return MSG_OK;
}
static msg_t set_sensivity(void *ip, float *sp) {
uint32_t i;
osalDbgCheck((ip != NULL) && (sp !=NULL));
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"set_sensivity(), invalid state");
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++) {
((LIS3MDLDriver *)ip)->sensitivity[i] = sp[i];
}
return MSG_OK;
}
static msg_t reset_sensivity(void *ip) {
uint32_t i;
osalDbgCheck(ip != NULL);
osalDbgAssert((((LIS3MDLDriver *)ip)->state == LIS3MDL_READY),
"reset_sensivity(), invalid state");
if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_4GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_4GA;
else if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_8GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_8GA;
else if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_12GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_12GA;
else if(((LIS3MDLDriver *)ip)->config->fullscale == LIS3MDL_FS_16GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
((LIS3MDLDriver *)ip)->sensitivity[i] = LIS3MDL_SENS_16GA;
else {
osalDbgAssert(FALSE, "reset_sensivity(), compass full scale issue");
return MSG_RESET;
}
return MSG_OK;
}
static msg_t get_temperature(void *ip, float* tempp) {
int16_t temp;
#if LIS3MDL_USE_I2C
osalDbgAssert((((LIS3MDLDriver *)ip)->config->i2cp->state == I2C_READY),
"gyro_read_raw(), channel not ready");
#if LIS3MDL_SHARED_I2C
i2cAcquireBus(((LIS3MDLDriver *)ip)->config->i2cp);
i2cStart(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->i2ccfg);
#endif /* LIS3MDL_SHARED_I2C */
temp = (int16_t)(lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_TEMP_OUT_L, NULL));
temp += (int16_t)(lis3mdlI2CReadRegister(((LIS3MDLDriver *)ip)->config->i2cp,
((LIS3MDLDriver *)ip)->config->slaveaddress,
LIS3MDL_AD_TEMP_OUT_H, NULL) << 8);
#if LIS3MDL_SHARED_I2C
i2cReleaseBus(((LIS3MDLDriver *)ip)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
#endif /* LIS3MDL_USE_I2C */
*tempp = (float)temp / LIS3MDL_TEMP_SENS;
return MSG_OK;
}
static const struct BaseSensorVMT vmt_basesensor = {
get_axes_number, read_raw, read_cooked
};
static const struct BaseCompassVMT vmt_basecompass = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity
};
static const struct LIS3MDLVMT vmt_lis3mdl = {
get_axes_number, read_raw, read_cooked,
set_bias, reset_bias, set_sensivity, reset_sensivity,
get_temperature
};
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an instance.
*
* @param[out] devp pointer to the @p LIS3MDLDriver object
*
* @init
*/
void lis3mdlObjectInit(LIS3MDLDriver *devp) {
uint32_t i;
devp->vmt_basesensor = &vmt_basesensor;
devp->vmt_basecompass = &vmt_basecompass;
devp->vmt_lis3mdl = &vmt_lis3mdl;
devp->config = NULL;
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->bias[i] = 0;
devp->state = LIS3MDL_STOP;
}
/**
* @brief Configures and activates LIS3MDL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS3MDLDriver object
* @param[in] config pointer to the @p LIS3MDLConfig object
*
* @api
*/
void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config) {
uint32_t i;
osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY),
"lis3mdlStart(), invalid state");
devp->config = config;
#if LIS3MDL_USE_I2C
#if LIS3MDL_SHARED_I2C
i2cAcquireBus((devp)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
i2cStart((devp)->config->i2cp,
(devp)->config->i2ccfg);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG1,
devp->config->temperature |
devp->config->outputdatarate |
devp->config->operationmodexy);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG2,
devp->config->fullscale);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG3,
devp->config->conversionmode);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG4,
devp->config->operationmodez |
devp->config->endianness);
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG5,
devp->config->blockdataupdate);
#if LIS3MDL_SHARED_I2C
i2cReleaseBus((devp)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
#endif /* LIS3MDL_USE_I2C */
/* Storing sensitivity information according to full scale value */
if(devp->config->fullscale == LIS3MDL_FS_4GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_4GA;
else if(devp->config->fullscale == LIS3MDL_FS_8GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_8GA;
else if(devp->config->fullscale == LIS3MDL_FS_12GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_12GA;
else if(devp->config->fullscale == LIS3MDL_FS_16GA)
for(i = 0; i < LIS3MDL_NUMBER_OF_AXES; i++)
devp->sensitivity[i] = LIS3MDL_SENS_16GA;
else
osalDbgAssert(FALSE, "lis3mdlStart(), compass full scale issue");
devp->state = LIS3MDL_READY;
}
/**
* @brief Deactivates the LIS3MDL Complex Driver peripheral.
*
* @param[in] devp pointer to the @p LIS3MDLDriver object
*
* @api
*/
void lis3mdlStop(LIS3MDLDriver *devp) {
osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY),
"lis3mdlStop(), invalid state");
#if (LIS3MDL_USE_I2C)
if (devp->state == LIS3MDL_STOP) {
#if LIS3MDL_SHARED_I2C
i2cAcquireBus((devp)->config->i2cp);
i2cStart((devp)->config->i2cp,
(devp)->config->i2ccfg);
#endif /* LIS3MDL_SHARED_I2C */
lis3mdlI2CWriteRegister(devp->config->i2cp,
devp->config->slaveaddress,
LIS3MDL_AD_CTRL_REG3,
LIS3MDL_MD_POWER_DOWN);
i2cStop((devp)->config->i2cp);
#if LIS3MDL_SHARED_I2C
i2cReleaseBus((devp)->config->i2cp);
#endif /* LIS3MDL_SHARED_I2C */
}
#endif /* LIS3MDL_USE_I2C */
devp->state = LIS3MDL_STOP;
}
/** @} */

View File

@ -1,368 +1,368 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis3mdl.h
* @brief LIS3MDL MEMS interface module header.
*
* @{
*/
#ifndef _LIS3MDL_H_
#define _LIS3MDL_H_
#include "hal_compass.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LIS3MDL number of axes.
*/
#define LIS3MDL_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief LIS3MDL SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p FALSE.
*/
#if !defined(LIS3MDL_USE_SPI) || defined(__DOXYGEN__)
#define LIS3MDL_USE_SPI FALSE
#endif
/**
* @brief LIS3MDL I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p TRUE.
*/
#if !defined(LIS3MDL_USE_I2C) || defined(__DOXYGEN__)
#define LIS3MDL_USE_I2C TRUE
#endif
/**
* @brief LIS3MDL shared I2C switch.
* @details If set to @p TRUE the device acquires I2C bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION
*/
#if !defined(LIS3MDL_SHARED_I2C) || defined(__DOXYGEN__)
#define LIS3MDL_SHARED_I2C FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(LIS3MDL_USE_SPI ^ LIS3MDL_USE_I2C)
#error "LIS3MDL_USE_SPI and LIS3MDL_USE_I2C cannot be both true or both false"
#endif
#if LIS3MDL_USE_SPI && !HAL_USE_SPI
#error "LIS3MDL_USE_SPI requires HAL_USE_SPI"
#endif
#if LIS3MDL_USE_I2C && !HAL_USE_I2C
#error "LIS3MDL_USE_I2C requires HAL_USE_I2C"
#endif
#if LIS3MDL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
#error "LIS3MDL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LIS3MDL data structures and types
* @{
*/
/**
* @brief LIS3MDL slave address
*/
typedef enum {
LIS3MDL_SAD_GND = 0x1C, /**< Slave Address when SA1 is to GND */
LIS3MDL_SAD_VCC = 0x1E /**< Slave Address when SA1 is to VCC */
}lis3mdl_sad_t;
/**
* @brief LIS3MDL full scale
*/
typedef enum {
LIS3MDL_FS_4GA = 0x00, /**< ±4 Gauss */
LIS3MDL_FS_8GA = 0x02, /**< ±8 Gauss */
LIS3MDL_FS_12GA = 0x04, /**< ±12 Gauss */
LIS3MDL_FS_16GA = 0x0C /**< ±16 Gauss */
}lis3mdl_fs_t;
/**
* @brief LIS3MDL output data rate
*/
typedef enum {
LIS3MDL_ODR_0_625HZ = 0x00, /**< Output Data Rate = 0.625 Hz */
LIS3MDL_ODR_1_25HZ = 0x04, /**< Output Data Rate = 1.25 Hz */
LIS3MDL_ODR_2_5HZ = 0x08, /**< Output Data Rate = 2.5 Hz */
LIS3MDL_ODR_5HZ = 0x0C, /**< Output Data Rate = 5 Hz */
LIS3MDL_ODR_10HZ = 0x10, /**< Output Data Rate = 10 Hz */
LIS3MDL_ODR_20HZ = 0x14, /**< Output Data Rate = 20 Hz */
LIS3MDL_ODR_40HZ = 0x18, /**< Output Data Rate = 40 Hz */
LIS3MDL_ODR_80HZ = 0x1C /**< Output Data Rate = 80 Hz */
}lis3mdl_odr_t;
/**
* @brief LIS3MDL low power mode configuration
*/
typedef enum {
LIS3MDL_LP_DISABLED = 0x00, /**< Low Power mode disabled */
LIS3MDL_LP_ENABLED = 0x20 /**< Low Power mode enabled */
}lis3mdl_lp_t;
/**
* @brief LIS3MDL conversion mode
*/
typedef enum {
LIS3MDL_MD_CONTINUOUS = 0x00, /**< Continuous conversion mode */
LIS3MDL_MD_SINGLE = 0x01, /**< Single conversion mode */
LIS3MDL_MD_POWER_DOWN = 0x02 /**< Power down mode */
}lis3mdl_md_t;
/**
* @brief LIS3MDL operation mode for X and Y axes
*/
typedef enum {
LIS3MDL_OMXY_LOW_POWER = 0x00, /**< X-Y axes low power mode */
LIS3MDL_OMXY_MEDIUM = 0x20, /**< X-Y axes medium performance mode */
LIS3MDL_OMXY_HIGH = 0x40, /**< X-Y axes high performance mode */
LIS3MDL_OMXY_ULTRA = 0x60 /**< X-Y axes ultra performance mode */
}lis3mdl_omxy_t;
/**
* @brief LIS3MDL operation mode for Z axis
*/
typedef enum {
LIS3MDL_OMZ_LOW_POWER = 0x00, /**< Z axis low power mode */
LIS3MDL_OMZ_MEDIUM = 0x04, /**< Z axis medium performance mode */
LIS3MDL_OMZ_HIGH = 0x08, /**< Z axis high performance mode */
LIS3MDL_OMZ_ULTRA = 0x0C /**< Z axis ultra performance mode */
}lis3mdl_omz_t;
/**
* @brief LIS3MDL temperature sensor enabling
*/
typedef enum {
LIS3MDL_TEMP_DISABLED = 0x00, /**< Temperature sensor disabled. */
LIS3MDL_TEMP_ENABLED = 0x80 /**< Temperature sensor enabled. */
}lis3mdl_temp_t;
/**
* @brief LIS3MDL block data update
*/
typedef enum {
LIS3MDL_BDU_CONTINUOUS = 0x00, /**< Continuous Update */
LIS3MDL_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */
}lis3mdl_bdu_t;
/**
* @brief LIS3MDL endianness
*/
typedef enum {
LIS3MDL_END_LITTLE = 0x00, /**< Little endian. */
LIS3MDL_END_BIG = 0x02 /**< Big endian. */
}lis3mdl_end_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LIS3MDL_UNINIT = 0, /**< Not initialized. */
LIS3MDL_STOP = 1, /**< Stopped. */
LIS3MDL_READY = 2, /**< Ready. */
} lis3mdl_state_t;
/**
* @brief LIS3MDL configuration structure.
*/
typedef struct {
#if (LIS3MDL_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LIS3MDL.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LIS3MDL.
*/
const SPIConfig *spicfg;
#endif /* LIS3MDL_USE_SPI */
#if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LIS3MDL.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LIS3MDL.
*/
const I2CConfig *i2ccfg;
#endif /* LIS3MDL_USE_I2C */
/**
* @brief LIS3MDL slave address
*/
lis3mdl_sad_t slaveaddress;
/**
* @brief LIS3MDL full scale
*/
lis3mdl_fs_t fullscale;
/**
* @brief LIS3MDL output data rate
*/
lis3mdl_odr_t outputdatarate;
/**
* @brief LIS3MDL low power mode configuration
*/
lis3mdl_lp_t lowpowermode;
/**
* @brief LIS3MDL conversion mode
*/
lis3mdl_md_t conversionmode;
/**
* @brief LIS3MDL operation mode for X and Y axes
*/
lis3mdl_omxy_t operationmodexy;
/**
* @brief LIS3MDL operation mode for Z axis
*/
lis3mdl_omz_t operationmodez;
/**
* @brief LIS3MDL temperature sensor enabling
*/
lis3mdl_temp_t temperature;
/**
* @brief LIS3MDL block data update
*/
lis3mdl_bdu_t blockdataupdate;
/**
* @brief LIS3MDL endianness
*/
lis3mdl_end_t endianness;
} LIS3MDLConfig;
/**
* @brief Structure representing a LIS3MDL driver.
*/
typedef struct LIS3MDLDriver LIS3MDLDriver;
/**
* @brief @p LIS3MDL specific methods.
*/
#define _lis3mdl_methods \
_base_compass_methods \
/* Retrieve the temperature of LIS3MDL chip.*/ \
msg_t (*get_temperature)(void *instance, float* temperature);
/**
* @extends BaseCompassVMT
*
* @brief @p LIS3MDL virtual methods table.
*/
struct LIS3MDLVMT {
_lis3mdl_methods
};
/**
* @brief @p LIS3MDLDriver specific data.
*/
#define _lis3mdl_data \
_base_compass_data \
/* Driver state.*/ \
lis3mdl_state_t state; \
/* Current configuration data.*/ \
const LIS3MDLConfig *config; \
/* Current sensitivity.*/ \
float sensitivity[LIS3MDL_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[LIS3MDL_NUMBER_OF_AXES];
/**
* @extends BaseCompass
*
* @brief LIS3MDL 3-axis compass class.
* @details This class extends @p BaseCompass by adding physical
* driver implementation.
*/
struct LIS3MDLDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseCompass Virtual Methods Table. */
const struct BaseCompassVMT *vmt_basecompass;
/** @brief LIS3MDL Virtual Methods Table. */
const struct LIS3MDLVMT *vmt_lis3mdl;
_lis3mdl_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU.
* @note Temperature sensor must be enabled using a proper configuration.
*
* @param[in] ip pointer to a @p BaseCompass class.
* @param[out] temp the MEMS temperature as single precision floating.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define compassGetTemp(ip, tpp) \
(ip)->vmt_lis3mdl->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lis3mdlObjectInit(LIS3MDLDriver *devp);
void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config);
void lis3mdlStop(LIS3MDLDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LIS3MDL_H_ */
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lis3mdl.h
* @brief LIS3MDL MEMS interface module header.
*
* @{
*/
#ifndef _LIS3MDL_H_
#define _LIS3MDL_H_
#include "hal_compass.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LIS3MDL number of axes.
*/
#define LIS3MDL_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief LIS3MDL SPI interface switch.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p FALSE.
*/
#if !defined(LIS3MDL_USE_SPI) || defined(__DOXYGEN__)
#define LIS3MDL_USE_SPI FALSE
#endif
/**
* @brief LIS3MDL I2C interface switch.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p TRUE.
*/
#if !defined(LIS3MDL_USE_I2C) || defined(__DOXYGEN__)
#define LIS3MDL_USE_I2C TRUE
#endif
/**
* @brief LIS3MDL shared I2C switch.
* @details If set to @p TRUE the device acquires I2C bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION
*/
#if !defined(LIS3MDL_SHARED_I2C) || defined(__DOXYGEN__)
#define LIS3MDL_SHARED_I2C FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !(LIS3MDL_USE_SPI ^ LIS3MDL_USE_I2C)
#error "LIS3MDL_USE_SPI and LIS3MDL_USE_I2C cannot be both true or both false"
#endif
#if LIS3MDL_USE_SPI && !HAL_USE_SPI
#error "LIS3MDL_USE_SPI requires HAL_USE_SPI"
#endif
#if LIS3MDL_USE_I2C && !HAL_USE_I2C
#error "LIS3MDL_USE_I2C requires HAL_USE_I2C"
#endif
#if LIS3MDL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
#error "LIS3MDL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LIS3MDL data structures and types
* @{
*/
/**
* @brief LIS3MDL slave address
*/
typedef enum {
LIS3MDL_SAD_GND = 0x1C, /**< Slave Address when SA1 is to GND */
LIS3MDL_SAD_VCC = 0x1E /**< Slave Address when SA1 is to VCC */
}lis3mdl_sad_t;
/**
* @brief LIS3MDL full scale
*/
typedef enum {
LIS3MDL_FS_4GA = 0x00, /**< ±4 Gauss */
LIS3MDL_FS_8GA = 0x02, /**< ±8 Gauss */
LIS3MDL_FS_12GA = 0x04, /**< ±12 Gauss */
LIS3MDL_FS_16GA = 0x0C /**< ±16 Gauss */
}lis3mdl_fs_t;
/**
* @brief LIS3MDL output data rate
*/
typedef enum {
LIS3MDL_ODR_0_625HZ = 0x00, /**< Output Data Rate = 0.625 Hz */
LIS3MDL_ODR_1_25HZ = 0x04, /**< Output Data Rate = 1.25 Hz */
LIS3MDL_ODR_2_5HZ = 0x08, /**< Output Data Rate = 2.5 Hz */
LIS3MDL_ODR_5HZ = 0x0C, /**< Output Data Rate = 5 Hz */
LIS3MDL_ODR_10HZ = 0x10, /**< Output Data Rate = 10 Hz */
LIS3MDL_ODR_20HZ = 0x14, /**< Output Data Rate = 20 Hz */
LIS3MDL_ODR_40HZ = 0x18, /**< Output Data Rate = 40 Hz */
LIS3MDL_ODR_80HZ = 0x1C /**< Output Data Rate = 80 Hz */
}lis3mdl_odr_t;
/**
* @brief LIS3MDL low power mode configuration
*/
typedef enum {
LIS3MDL_LP_DISABLED = 0x00, /**< Low Power mode disabled */
LIS3MDL_LP_ENABLED = 0x20 /**< Low Power mode enabled */
}lis3mdl_lp_t;
/**
* @brief LIS3MDL conversion mode
*/
typedef enum {
LIS3MDL_MD_CONTINUOUS = 0x00, /**< Continuous conversion mode */
LIS3MDL_MD_SINGLE = 0x01, /**< Single conversion mode */
LIS3MDL_MD_POWER_DOWN = 0x02 /**< Power down mode */
}lis3mdl_md_t;
/**
* @brief LIS3MDL operation mode for X and Y axes
*/
typedef enum {
LIS3MDL_OMXY_LOW_POWER = 0x00, /**< X-Y axes low power mode */
LIS3MDL_OMXY_MEDIUM = 0x20, /**< X-Y axes medium performance mode */
LIS3MDL_OMXY_HIGH = 0x40, /**< X-Y axes high performance mode */
LIS3MDL_OMXY_ULTRA = 0x60 /**< X-Y axes ultra performance mode */
}lis3mdl_omxy_t;
/**
* @brief LIS3MDL operation mode for Z axis
*/
typedef enum {
LIS3MDL_OMZ_LOW_POWER = 0x00, /**< Z axis low power mode */
LIS3MDL_OMZ_MEDIUM = 0x04, /**< Z axis medium performance mode */
LIS3MDL_OMZ_HIGH = 0x08, /**< Z axis high performance mode */
LIS3MDL_OMZ_ULTRA = 0x0C /**< Z axis ultra performance mode */
}lis3mdl_omz_t;
/**
* @brief LIS3MDL temperature sensor enabling
*/
typedef enum {
LIS3MDL_TEMP_DISABLED = 0x00, /**< Temperature sensor disabled. */
LIS3MDL_TEMP_ENABLED = 0x80 /**< Temperature sensor enabled. */
}lis3mdl_temp_t;
/**
* @brief LIS3MDL block data update
*/
typedef enum {
LIS3MDL_BDU_CONTINUOUS = 0x00, /**< Continuous Update */
LIS3MDL_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */
}lis3mdl_bdu_t;
/**
* @brief LIS3MDL endianness
*/
typedef enum {
LIS3MDL_END_LITTLE = 0x00, /**< Little endian. */
LIS3MDL_END_BIG = 0x02 /**< Big endian. */
}lis3mdl_end_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LIS3MDL_UNINIT = 0, /**< Not initialized. */
LIS3MDL_STOP = 1, /**< Stopped. */
LIS3MDL_READY = 2, /**< Ready. */
} lis3mdl_state_t;
/**
* @brief LIS3MDL configuration structure.
*/
typedef struct {
#if (LIS3MDL_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LIS3MDL.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LIS3MDL.
*/
const SPIConfig *spicfg;
#endif /* LIS3MDL_USE_SPI */
#if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LIS3MDL.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LIS3MDL.
*/
const I2CConfig *i2ccfg;
#endif /* LIS3MDL_USE_I2C */
/**
* @brief LIS3MDL slave address
*/
lis3mdl_sad_t slaveaddress;
/**
* @brief LIS3MDL full scale
*/
lis3mdl_fs_t fullscale;
/**
* @brief LIS3MDL output data rate
*/
lis3mdl_odr_t outputdatarate;
/**
* @brief LIS3MDL low power mode configuration
*/
lis3mdl_lp_t lowpowermode;
/**
* @brief LIS3MDL conversion mode
*/
lis3mdl_md_t conversionmode;
/**
* @brief LIS3MDL operation mode for X and Y axes
*/
lis3mdl_omxy_t operationmodexy;
/**
* @brief LIS3MDL operation mode for Z axis
*/
lis3mdl_omz_t operationmodez;
/**
* @brief LIS3MDL temperature sensor enabling
*/
lis3mdl_temp_t temperature;
/**
* @brief LIS3MDL block data update
*/
lis3mdl_bdu_t blockdataupdate;
/**
* @brief LIS3MDL endianness
*/
lis3mdl_end_t endianness;
} LIS3MDLConfig;
/**
* @brief Structure representing a LIS3MDL driver.
*/
typedef struct LIS3MDLDriver LIS3MDLDriver;
/**
* @brief @p LIS3MDL specific methods.
*/
#define _lis3mdl_methods \
_base_compass_methods \
/* Retrieve the temperature of LIS3MDL chip.*/ \
msg_t (*get_temperature)(void *instance, float* temperature);
/**
* @extends BaseCompassVMT
*
* @brief @p LIS3MDL virtual methods table.
*/
struct LIS3MDLVMT {
_lis3mdl_methods
};
/**
* @brief @p LIS3MDLDriver specific data.
*/
#define _lis3mdl_data \
_base_compass_data \
/* Driver state.*/ \
lis3mdl_state_t state; \
/* Current configuration data.*/ \
const LIS3MDLConfig *config; \
/* Current sensitivity.*/ \
float sensitivity[LIS3MDL_NUMBER_OF_AXES]; \
/* Bias data.*/ \
int32_t bias[LIS3MDL_NUMBER_OF_AXES];
/**
* @extends BaseCompass
*
* @brief LIS3MDL 3-axis compass class.
* @details This class extends @p BaseCompass by adding physical
* driver implementation.
*/
struct LIS3MDLDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseCompass Virtual Methods Table. */
const struct BaseCompassVMT *vmt_basecompass;
/** @brief LIS3MDL Virtual Methods Table. */
const struct LIS3MDLVMT *vmt_lis3mdl;
_lis3mdl_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get current MEMS temperature.
* @detail This information is very useful especially for high accuracy IMU.
* @note Temperature sensor must be enabled using a proper configuration.
*
* @param[in] ip pointer to a @p BaseCompass class.
* @param[out] temp the MEMS temperature as single precision floating.
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more errors occurred.
* @api
*/
#define compassGetTemp(ip, tpp) \
(ip)->vmt_lis3mdl->get_temperature(ip, tpp)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lis3mdlObjectInit(LIS3MDLDriver *devp);
void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config);
void lis3mdlStop(LIS3MDLDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LIS3MDL_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,441 +1,441 @@
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lsm303dlhc.h
* @brief LSM303DLHC MEMS interface module header.
*
* @{
*/
#ifndef _LSM303DLHC_H_
#define _LSM303DLHC_H_
#include "hal_accelerometer.h"
#include "hal_compass.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LSM303DLHC accelerometer subsystem number of axes.
*/
#define LSM303DLHC_ACC_NUMBER_OF_AXES ((size_t) 3U)
/**
* @brief LSM303DLHC compass subsystem number of axes.
*/
#define LSM303DLHC_COMP_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief LSM303DLHC SPI interface selector.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p FALSE.
*/
#if !defined(LSM303DLHC_USE_SPI) || defined(__DOXYGEN__)
#define LSM303DLHC_USE_SPI FALSE
#endif
/**
* @brief LSM303DLHC I2C interface selector.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p TRUE.
*/
#if !defined(LSM303DLHC_USE_I2C) || defined(__DOXYGEN__)
#define LSM303DLHC_USE_I2C TRUE
#endif
/**
* @brief LSM303DLHC shared I2C switch.
* @details If set to @p TRUE the device acquires I2C bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION.
*/
#if !defined(LSM303DLHC_SHARED_I2C) || defined(__DOXYGEN__)
#define LSM303DLHC_SHARED_I2C FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if LSM303DLHC_USE_SPI && LSM303DLHC_USE_I2C
#error "LSM303DLHC_USE_SPI and LSM303DLHC_USE_I2C cannot be both true"
#endif
#if LSM303DLHC_USE_SPI && !HAL_USE_SPI
#error "LSM303DLHC_USE_SPI requires HAL_USE_SPI"
#endif
#if LSM303DLHC_USE_I2C && !HAL_USE_I2C
#error "LSM303DLHC_USE_I2C requires HAL_USE_I2C"
#endif
#if LSM303DLHC_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
#error "LSM303DLHC_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LSM303DLHC accelerometer subsystem data structures and types.
* @{
*/
/**
* @brief LSM303DLHC accelerometer subsystem full scale.
*/
typedef enum {
LSM303DLHC_ACC_FS_2G = 0x00, /**< Full scale ±2g. */
LSM303DLHC_ACC_FS_4G = 0x10, /**< Full scale ±4g. */
LSM303DLHC_ACC_FS_8G = 0x20, /**< Full scale ±8g. */
LSM303DLHC_ACC_FS_16G = 0x30 /**< Full scale ±16g. */
} lsm303dlhc_acc_fs_t;
/**
* @brief LSM303DLHC accelerometer subsystem output data rate.
*/
typedef enum {
LSM303DLHC_ACC_ODR_PD = 0x00, /**< Power down */
LSM303DLHC_ACC_ODR_1Hz = 0x10, /**< ODR 1 Hz */
LSM303DLHC_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */
LSM303DLHC_ACC_ODR_25Hz = 0x30, /**< ODR 25 Hz */
LSM303DLHC_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */
LSM303DLHC_ACC_ODR_100Hz = 0x50, /**< ODR 100 Hz */
LSM303DLHC_ACC_ODR_200Hz = 0x60, /**< ODR 200 Hz */
LSM303DLHC_ACC_ODR_400Hz = 0x70, /**< ODR 400 Hz */
LSM303DLHC_ACC_ODR_1620Hz = 0x80, /**< ODR 1620 Hz (LP only) */
LSM303DLHC_ACC_ODR_1344Hz = 0x90 /**< ODR 1344 Hz or 5376 Hz in LP */
} lsm303dlhc_acc_odr_t;
/**
* @brief LSM303DLHC accelerometer subsystem axes enabling.
*/
typedef enum {
LSM303DLHC_ACC_AE_DISABLED = 0x00,/**< All axes disabled. */
LSM303DLHC_ACC_AE_X = 0x01, /**< Only X-axis enabled. */
LSM303DLHC_ACC_AE_Y = 0x02, /**< Only Y-axis enabled. */
LSM303DLHC_ACC_AE_XY = 0x03, /**< X and Y axes enabled. */
LSM303DLHC_ACC_AE_Z = 0x04, /**< Only Z-axis enabled. */
LSM303DLHC_ACC_AE_XZ = 0x05, /**< X and Z axes enabled. */
LSM303DLHC_ACC_AE_YZ = 0x06, /**< Y and Z axes enabled. */
LSM303DLHC_ACC_AE_XYZ = 0x07 /**< All axes enabled. */
} lsm303dlhc_acc_ae_t;
/**
* @brief LSM303DLHC accelerometer subsystem low power mode.
*/
typedef enum {
LSM303DLHC_ACC_LP_DISABLED = 0x00,/**< Low power mode disabled. */
LSM303DLHC_ACC_LP_ENABLED = 0x40 /**< Low power mode enabled. */
} lsm303dlhc_acc_lp_t;
/**
* @brief LSM303DLHC accelerometer subsystem high resolution mode.
*/
typedef enum {
LSM303DLHC_ACC_HR_DISABLED = 0x00,/**< High resolution mode disabled. */
LSM303DLHC_ACC_HR_ENABLED = 0x08 /**< High resolution mode enabled. */
} lsm303dlhc_acc_hr_t;
/**
* @brief LSM303DLHC accelerometer subsystem block data update.
*/
typedef enum {
LSM303DLHC_ACC_BDU_CONT = 0x00, /**< Continuous update */
LSM303DLHC_ACC_BDU_BLOCK = 0x80 /**< Update blocked */
} lsm303dlhc_acc_bdu_t;
/**
* @brief LSM303DLHC accelerometer endianness.
*/
typedef enum {
LSM303DLHC_ACC_END_LITTLE = 0x00, /**< Little Endian */
LSM303DLHC_ACC_END_BIG = 0x40 /**< Big Endian */
} lsm303dlhc_acc_end_t;
/**
* @brief LSM303DLHC accelerometer subsystem unit.
*/
typedef enum {
LSM303DLHC_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
LSM303DLHC_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
LSM303DLHC_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
} lsm303dlhc_acc_unit_t;
/**
* @brief LSM303DLHC accelerometer subsystem configuration structure.
*/
typedef struct {
/**
* @brief LSM303DLHC accelerometer subsystem full scale.
*/
lsm303dlhc_acc_fs_t fullscale;
/**
* @brief LSM303DLHC accelerometer subsystem output data rate.
*/
lsm303dlhc_acc_odr_t outdatarate;
/**
* @brief LSM303DLHC accelerometer subsystem axes enabling.
*/
lsm303dlhc_acc_ae_t axesenabling;
/**
* @brief LSM303DLHC accelerometer subsystem low power mode.
*/
lsm303dlhc_acc_lp_t lowpower;
/**
* @brief LSM303DLHC accelerometer subsystem high resolution mode.
*/
lsm303dlhc_acc_hr_t highresmode;
/**
* @brief LSM303DLHC accelerometer subsystem block data update.
*/
lsm303dlhc_acc_bdu_t blockdataupdate;
/**
* @brief LSM303DLHC accelerometer endianness.
*/
lsm303dlhc_acc_end_t endianess;
/**
* @brief LSM303DLHC accelerometer subsystem unit.
*/
lsm303dlhc_acc_unit_t unit;
} LSM303DLHCAccConfig;
/** @} */
/**
* @name LSM303DLHC compass subsystem data structures and types.
* @{
*/
/**
* @brief LSM303DLHC compass subsystem full scale.
*/
typedef enum {
LSM303DLHC_COMP_FS_1_3_GA = 0x20, /**< Full scale ±1.3 Gauss */
LSM303DLHC_COMP_FS_1_9_GA = 0x40, /**< Full scale ±1.9 Gauss */
LSM303DLHC_COMP_FS_2_5_GA = 0x60, /**< Full scale ±2.5 Gauss */
LSM303DLHC_COMP_FS_4_0_GA = 0x80, /**< Full scale ±4.0 Gauss */
LSM303DLHC_COMP_FS_4_7_GA = 0xA0, /**< Full scale ±4.7 Gauss */
LSM303DLHC_COMP_FS_5_6_GA = 0xC0, /**< Full scale ±5.6 Gauss */
LSM303DLHC_COMP_FS_8_1_GA = 0xE0 /**< Full scale ±8.1 Gauss */
} lsm303dlhc_comp_fs_t;
/**
* @brief LSM303DLHC compass subsystem output data rate.
*/
typedef enum {
LSM303DLHC_COMP_ODR_0_75HZ = 0x00,/**< ODR 0.75 Hz */
LSM303DLHC_COMP_ODR_1_5HZ = 0x04, /**< ODR 1.5 Hz */
LSM303DLHC_COMP_ODR_3_0HZ = 0x08, /**< ODR 3 Hz */
LSM303DLHC_COMP_ODR_7_5HZ = 0x0C, /**< ODR 7.5 Hz */
LSM303DLHC_COMP_ODR_15HZ = 0x10, /**< ODR 15 Hz */
LSM303DLHC_COMP_ODR_30HZ = 0x14, /**< ODR 30 Hz */
LSM303DLHC_COMP_ODR_75HZ = 0x18, /**< ODR 75 Hz */
LSM303DLHC_COMP_ODR_220HZ = 0x1C /**< ODR 220 Hz */
} lsm303dlhc_comp_odr_t;
/**
* @brief LSM303DLHC compass subsystem working mode.
*/
typedef enum {
LSM303DLHC_COMP_MD_CONT = 0x00, /**< Continuous-Conversion Mode */
LSM303DLHC_COMP_MD_BLOCK = 0x01, /**< Single-Conversion Mode */
LSM303DLHC_COMP_MD_SLEEP = 0x02 /**< Sleep Mode */
} lsm303dlhc_comp_md_t;
/**
* @brief LSM303DLHC compass subsystem configuration structure.
*/
typedef struct {
/**
* @brief LSM303DLHC compass subsystem full scale.
*/
lsm303dlhc_comp_fs_t fullscale;
/**
* @brief LSM303DLHC compass subsystem output data rate.
*/
lsm303dlhc_comp_odr_t outputdatarate;
/**
* @brief LSM303DLHC compass subsystem working mode.
*/
lsm303dlhc_comp_md_t mode;
} LSM303DLHCCompConfig;
/** @} */
/**
* @name LSM303DLHC main system data structures and types.
* @{
*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LSM303DLHC_UNINIT = 0, /**< Not initialized. */
LSM303DLHC_STOP = 1, /**< Stopped. */
LSM303DLHC_READY = 2, /**< Ready. */
} lsm303dlhc_state_t;
/**
* @brief LSM303DLHC configuration structure.
*/
typedef struct {
#if (LSM303DLHC_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LSM303DLHC.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LSM303DLHC accelerometer
* subsystem.
*/
const SPIConfig *accspicfg;
/**
* @brief SPI configuration associated to this LSM303DLHC compass
* subsystem.
*/
const SPIConfig *compspicfg;
#endif /* LSM303DLHC_USE_SPI */
#if (LSM303DLHC_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LSM303DLHC.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LSM303DLHC accelerometer
* subsystem.
*/
const I2CConfig *i2ccfg;
#endif /* LSM303DLHC_USE_I2C */
/**
* @brief LSM303DLHC accelerometer subsystem configuration structure
*/
const LSM303DLHCAccConfig *acccfg;
/**
* @brief LSM303DLHC compass subsystem configuration structure
*/
const LSM303DLHCCompConfig *compcfg;
} LSM303DLHCConfig;
/**
* @brief Structure representing a LSM303DLHC driver.
*/
typedef struct LSM303DLHCDriver LSM303DLHCDriver;
/**
* @brief @p LSM303DLHC accelerometer subsystem specific methods.
*/
#define _lsm303dlhc_acc_methods \
_base_accelerometer_methods
/**
* @brief @p LSM303DLHC compass subsystem specific methods.
*/
#define _lsm303dlhc_comp_methods \
_base_compass_methods
/**
* @extends BaseAccelerometerVMT
*
* @brief @p LSM303DLHC accelerometer virtual methods table.
*/
struct LSM303DLHCACCVMT {
_lsm303dlhc_acc_methods
};
/**
* @extends BaseCompassVMT
*
* @brief @p LSM303DLHC compass virtual methods table.
*/
struct LSM303DLHCCOMPVMT {
_lsm303dlhc_comp_methods
};
/**
* @brief @p LSM303DLHCDriver specific data.
*/
#define _lsm303dlhc_data \
_base_accelerometer_data \
_base_compass_data \
/* Driver state.*/ \
lsm303dlhc_state_t state; \
/* Current configuration data.*/ \
const LSM303DLHCConfig *config; \
/* Current accelerometer sensitivity.*/ \
float accsensitivity[LSM303DLHC_ACC_NUMBER_OF_AXES]; \
/* Accelerometer bias data.*/ \
int32_t accbias[LSM303DLHC_ACC_NUMBER_OF_AXES]; \
/* Current compass sensitivity.*/ \
float compsensitivity[LSM303DLHC_COMP_NUMBER_OF_AXES];\
/* Bias data.*/ \
int32_t compbias[LSM303DLHC_COMP_NUMBER_OF_AXES];
/**
* @brief LSM303DLHC 6-axis accelerometer/compass class.
*/
struct LSM303DLHCDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseAccelerometer Virtual Methods Table. */
const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
/** @brief BaseCompass Virtual Methods Table. */
const struct BaseCompassVMT *vmt_basecompass;
/** @brief LSM303DLHC Accelerometer Virtual Methods Table. */
const struct LSM303DLHCACCVMT *vmt_lsm303dlhcacc;
/** @brief LSM303DLHC Compass Virtual Methods Table. */
const struct LSM303DLHCCOMPVMT *vmt_lsm303dlhccomp;
_lsm303dlhc_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lsm303dlhcObjectInit(LSM303DLHCDriver *devp);
void lsm303dlhcStart(LSM303DLHCDriver *devp, const LSM303DLHCConfig *config);
void lsm303dlhcStop(LSM303DLHCDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LSM303DLHC_H_ */
/** @} */
/*
ChibiOS - Copyright (C) 2016 Rocco Marco Guglielmi
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lsm303dlhc.h
* @brief LSM303DLHC MEMS interface module header.
*
* @{
*/
#ifndef _LSM303DLHC_H_
#define _LSM303DLHC_H_
#include "hal_accelerometer.h"
#include "hal_compass.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief LSM303DLHC accelerometer subsystem number of axes.
*/
#define LSM303DLHC_ACC_NUMBER_OF_AXES ((size_t) 3U)
/**
* @brief LSM303DLHC compass subsystem number of axes.
*/
#define LSM303DLHC_COMP_NUMBER_OF_AXES ((size_t) 3U)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief LSM303DLHC SPI interface selector.
* @details If set to @p TRUE the support for SPI is included.
* @note The default is @p FALSE.
*/
#if !defined(LSM303DLHC_USE_SPI) || defined(__DOXYGEN__)
#define LSM303DLHC_USE_SPI FALSE
#endif
/**
* @brief LSM303DLHC I2C interface selector.
* @details If set to @p TRUE the support for I2C is included.
* @note The default is @p TRUE.
*/
#if !defined(LSM303DLHC_USE_I2C) || defined(__DOXYGEN__)
#define LSM303DLHC_USE_I2C TRUE
#endif
/**
* @brief LSM303DLHC shared I2C switch.
* @details If set to @p TRUE the device acquires I2C bus ownership
* on each transaction.
* @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION.
*/
#if !defined(LSM303DLHC_SHARED_I2C) || defined(__DOXYGEN__)
#define LSM303DLHC_SHARED_I2C FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if LSM303DLHC_USE_SPI && LSM303DLHC_USE_I2C
#error "LSM303DLHC_USE_SPI and LSM303DLHC_USE_I2C cannot be both true"
#endif
#if LSM303DLHC_USE_SPI && !HAL_USE_SPI
#error "LSM303DLHC_USE_SPI requires HAL_USE_SPI"
#endif
#if LSM303DLHC_USE_I2C && !HAL_USE_I2C
#error "LSM303DLHC_USE_I2C requires HAL_USE_I2C"
#endif
#if LSM303DLHC_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
#error "LSM303DLHC_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @name LSM303DLHC accelerometer subsystem data structures and types.
* @{
*/
/**
* @brief LSM303DLHC accelerometer subsystem full scale.
*/
typedef enum {
LSM303DLHC_ACC_FS_2G = 0x00, /**< Full scale ±2g. */
LSM303DLHC_ACC_FS_4G = 0x10, /**< Full scale ±4g. */
LSM303DLHC_ACC_FS_8G = 0x20, /**< Full scale ±8g. */
LSM303DLHC_ACC_FS_16G = 0x30 /**< Full scale ±16g. */
} lsm303dlhc_acc_fs_t;
/**
* @brief LSM303DLHC accelerometer subsystem output data rate.
*/
typedef enum {
LSM303DLHC_ACC_ODR_PD = 0x00, /**< Power down */
LSM303DLHC_ACC_ODR_1Hz = 0x10, /**< ODR 1 Hz */
LSM303DLHC_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */
LSM303DLHC_ACC_ODR_25Hz = 0x30, /**< ODR 25 Hz */
LSM303DLHC_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */
LSM303DLHC_ACC_ODR_100Hz = 0x50, /**< ODR 100 Hz */
LSM303DLHC_ACC_ODR_200Hz = 0x60, /**< ODR 200 Hz */
LSM303DLHC_ACC_ODR_400Hz = 0x70, /**< ODR 400 Hz */
LSM303DLHC_ACC_ODR_1620Hz = 0x80, /**< ODR 1620 Hz (LP only) */
LSM303DLHC_ACC_ODR_1344Hz = 0x90 /**< ODR 1344 Hz or 5376 Hz in LP */
} lsm303dlhc_acc_odr_t;
/**
* @brief LSM303DLHC accelerometer subsystem axes enabling.
*/
typedef enum {
LSM303DLHC_ACC_AE_DISABLED = 0x00,/**< All axes disabled. */
LSM303DLHC_ACC_AE_X = 0x01, /**< Only X-axis enabled. */
LSM303DLHC_ACC_AE_Y = 0x02, /**< Only Y-axis enabled. */
LSM303DLHC_ACC_AE_XY = 0x03, /**< X and Y axes enabled. */
LSM303DLHC_ACC_AE_Z = 0x04, /**< Only Z-axis enabled. */
LSM303DLHC_ACC_AE_XZ = 0x05, /**< X and Z axes enabled. */
LSM303DLHC_ACC_AE_YZ = 0x06, /**< Y and Z axes enabled. */
LSM303DLHC_ACC_AE_XYZ = 0x07 /**< All axes enabled. */
} lsm303dlhc_acc_ae_t;
/**
* @brief LSM303DLHC accelerometer subsystem low power mode.
*/
typedef enum {
LSM303DLHC_ACC_LP_DISABLED = 0x00,/**< Low power mode disabled. */
LSM303DLHC_ACC_LP_ENABLED = 0x40 /**< Low power mode enabled. */
} lsm303dlhc_acc_lp_t;
/**
* @brief LSM303DLHC accelerometer subsystem high resolution mode.
*/
typedef enum {
LSM303DLHC_ACC_HR_DISABLED = 0x00,/**< High resolution mode disabled. */
LSM303DLHC_ACC_HR_ENABLED = 0x08 /**< High resolution mode enabled. */
} lsm303dlhc_acc_hr_t;
/**
* @brief LSM303DLHC accelerometer subsystem block data update.
*/
typedef enum {
LSM303DLHC_ACC_BDU_CONT = 0x00, /**< Continuous update */
LSM303DLHC_ACC_BDU_BLOCK = 0x80 /**< Update blocked */
} lsm303dlhc_acc_bdu_t;
/**
* @brief LSM303DLHC accelerometer endianness.
*/
typedef enum {
LSM303DLHC_ACC_END_LITTLE = 0x00, /**< Little Endian */
LSM303DLHC_ACC_END_BIG = 0x40 /**< Big Endian */
} lsm303dlhc_acc_end_t;
/**
* @brief LSM303DLHC accelerometer subsystem unit.
*/
typedef enum {
LSM303DLHC_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
LSM303DLHC_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
LSM303DLHC_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
} lsm303dlhc_acc_unit_t;
/**
* @brief LSM303DLHC accelerometer subsystem configuration structure.
*/
typedef struct {
/**
* @brief LSM303DLHC accelerometer subsystem full scale.
*/
lsm303dlhc_acc_fs_t fullscale;
/**
* @brief LSM303DLHC accelerometer subsystem output data rate.
*/
lsm303dlhc_acc_odr_t outdatarate;
/**
* @brief LSM303DLHC accelerometer subsystem axes enabling.
*/
lsm303dlhc_acc_ae_t axesenabling;
/**
* @brief LSM303DLHC accelerometer subsystem low power mode.
*/
lsm303dlhc_acc_lp_t lowpower;
/**
* @brief LSM303DLHC accelerometer subsystem high resolution mode.
*/
lsm303dlhc_acc_hr_t highresmode;
/**
* @brief LSM303DLHC accelerometer subsystem block data update.
*/
lsm303dlhc_acc_bdu_t blockdataupdate;
/**
* @brief LSM303DLHC accelerometer endianness.
*/
lsm303dlhc_acc_end_t endianess;
/**
* @brief LSM303DLHC accelerometer subsystem unit.
*/
lsm303dlhc_acc_unit_t unit;
} LSM303DLHCAccConfig;
/** @} */
/**
* @name LSM303DLHC compass subsystem data structures and types.
* @{
*/
/**
* @brief LSM303DLHC compass subsystem full scale.
*/
typedef enum {
LSM303DLHC_COMP_FS_1_3_GA = 0x20, /**< Full scale ±1.3 Gauss */
LSM303DLHC_COMP_FS_1_9_GA = 0x40, /**< Full scale ±1.9 Gauss */
LSM303DLHC_COMP_FS_2_5_GA = 0x60, /**< Full scale ±2.5 Gauss */
LSM303DLHC_COMP_FS_4_0_GA = 0x80, /**< Full scale ±4.0 Gauss */
LSM303DLHC_COMP_FS_4_7_GA = 0xA0, /**< Full scale ±4.7 Gauss */
LSM303DLHC_COMP_FS_5_6_GA = 0xC0, /**< Full scale ±5.6 Gauss */
LSM303DLHC_COMP_FS_8_1_GA = 0xE0 /**< Full scale ±8.1 Gauss */
} lsm303dlhc_comp_fs_t;
/**
* @brief LSM303DLHC compass subsystem output data rate.
*/
typedef enum {
LSM303DLHC_COMP_ODR_0_75HZ = 0x00,/**< ODR 0.75 Hz */
LSM303DLHC_COMP_ODR_1_5HZ = 0x04, /**< ODR 1.5 Hz */
LSM303DLHC_COMP_ODR_3_0HZ = 0x08, /**< ODR 3 Hz */
LSM303DLHC_COMP_ODR_7_5HZ = 0x0C, /**< ODR 7.5 Hz */
LSM303DLHC_COMP_ODR_15HZ = 0x10, /**< ODR 15 Hz */
LSM303DLHC_COMP_ODR_30HZ = 0x14, /**< ODR 30 Hz */
LSM303DLHC_COMP_ODR_75HZ = 0x18, /**< ODR 75 Hz */
LSM303DLHC_COMP_ODR_220HZ = 0x1C /**< ODR 220 Hz */
} lsm303dlhc_comp_odr_t;
/**
* @brief LSM303DLHC compass subsystem working mode.
*/
typedef enum {
LSM303DLHC_COMP_MD_CONT = 0x00, /**< Continuous-Conversion Mode */
LSM303DLHC_COMP_MD_BLOCK = 0x01, /**< Single-Conversion Mode */
LSM303DLHC_COMP_MD_SLEEP = 0x02 /**< Sleep Mode */
} lsm303dlhc_comp_md_t;
/**
* @brief LSM303DLHC compass subsystem configuration structure.
*/
typedef struct {
/**
* @brief LSM303DLHC compass subsystem full scale.
*/
lsm303dlhc_comp_fs_t fullscale;
/**
* @brief LSM303DLHC compass subsystem output data rate.
*/
lsm303dlhc_comp_odr_t outputdatarate;
/**
* @brief LSM303DLHC compass subsystem working mode.
*/
lsm303dlhc_comp_md_t mode;
} LSM303DLHCCompConfig;
/** @} */
/**
* @name LSM303DLHC main system data structures and types.
* @{
*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
LSM303DLHC_UNINIT = 0, /**< Not initialized. */
LSM303DLHC_STOP = 1, /**< Stopped. */
LSM303DLHC_READY = 2, /**< Ready. */
} lsm303dlhc_state_t;
/**
* @brief LSM303DLHC configuration structure.
*/
typedef struct {
#if (LSM303DLHC_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LSM303DLHC.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LSM303DLHC accelerometer
* subsystem.
*/
const SPIConfig *accspicfg;
/**
* @brief SPI configuration associated to this LSM303DLHC compass
* subsystem.
*/
const SPIConfig *compspicfg;
#endif /* LSM303DLHC_USE_SPI */
#if (LSM303DLHC_USE_I2C) || defined(__DOXYGEN__)
/**
* @brief I2C driver associated to this LSM303DLHC.
*/
I2CDriver *i2cp;
/**
* @brief I2C configuration associated to this LSM303DLHC accelerometer
* subsystem.
*/
const I2CConfig *i2ccfg;
#endif /* LSM303DLHC_USE_I2C */
/**
* @brief LSM303DLHC accelerometer subsystem configuration structure
*/
const LSM303DLHCAccConfig *acccfg;
/**
* @brief LSM303DLHC compass subsystem configuration structure
*/
const LSM303DLHCCompConfig *compcfg;
} LSM303DLHCConfig;
/**
* @brief Structure representing a LSM303DLHC driver.
*/
typedef struct LSM303DLHCDriver LSM303DLHCDriver;
/**
* @brief @p LSM303DLHC accelerometer subsystem specific methods.
*/
#define _lsm303dlhc_acc_methods \
_base_accelerometer_methods
/**
* @brief @p LSM303DLHC compass subsystem specific methods.
*/
#define _lsm303dlhc_comp_methods \
_base_compass_methods
/**
* @extends BaseAccelerometerVMT
*
* @brief @p LSM303DLHC accelerometer virtual methods table.
*/
struct LSM303DLHCACCVMT {
_lsm303dlhc_acc_methods
};
/**
* @extends BaseCompassVMT
*
* @brief @p LSM303DLHC compass virtual methods table.
*/
struct LSM303DLHCCOMPVMT {
_lsm303dlhc_comp_methods
};
/**
* @brief @p LSM303DLHCDriver specific data.
*/
#define _lsm303dlhc_data \
_base_accelerometer_data \
_base_compass_data \
/* Driver state.*/ \
lsm303dlhc_state_t state; \
/* Current configuration data.*/ \
const LSM303DLHCConfig *config; \
/* Current accelerometer sensitivity.*/ \
float accsensitivity[LSM303DLHC_ACC_NUMBER_OF_AXES]; \
/* Accelerometer bias data.*/ \
int32_t accbias[LSM303DLHC_ACC_NUMBER_OF_AXES]; \
/* Current compass sensitivity.*/ \
float compsensitivity[LSM303DLHC_COMP_NUMBER_OF_AXES];\
/* Bias data.*/ \
int32_t compbias[LSM303DLHC_COMP_NUMBER_OF_AXES];
/**
* @brief LSM303DLHC 6-axis accelerometer/compass class.
*/
struct LSM303DLHCDriver {
/** @brief BaseSensor Virtual Methods Table. */
const struct BaseSensorVMT *vmt_basesensor;
/** @brief BaseAccelerometer Virtual Methods Table. */
const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
/** @brief BaseCompass Virtual Methods Table. */
const struct BaseCompassVMT *vmt_basecompass;
/** @brief LSM303DLHC Accelerometer Virtual Methods Table. */
const struct LSM303DLHCACCVMT *vmt_lsm303dlhcacc;
/** @brief LSM303DLHC Compass Virtual Methods Table. */
const struct LSM303DLHCCOMPVMT *vmt_lsm303dlhccomp;
_lsm303dlhc_data
};
/** @} */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void lsm303dlhcObjectInit(LSM303DLHCDriver *devp);
void lsm303dlhcStart(LSM303DLHCDriver *devp, const LSM303DLHCConfig *config);
void lsm303dlhcStop(LSM303DLHCDriver *devp);
#ifdef __cplusplus
}
#endif
#endif /* _LSM303DLHC_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,339 +1,339 @@
/*
Managed Flash Storage - Copyright (C) 2016 Giovanni Di Sirio
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file mfs.h
* @brief Managed Flash Storage module header.
*
* @{
*/
#ifndef MFS_H
#define MFS_H
#include "hal_flash.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define MFS_BANK_MAGIC_1 0xEC705ADEU
#define MFS_BANK_MAGIC_2 0xF0339CC5U
#define MFS_HEADER_MAGIC 0x5FAEU
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief Record identifiers cache size.
* @details Cache trades RAM for a faster access to stored records. If zero
* then the cache is disabled.
*/
#if !defined(MFS_CFG_ID_CACHE_SIZE) || defined(__DOXIGEN__)
#define MFS_CFG_ID_CACHE_SIZE 16
#endif
/**
* @brief Maximum number of repair attempts on partition mount.
*/
#if !defined(MFS_CFG_MAX_REPAIR_ATTEMPTS) || defined(__DOXIGEN__)
#define MFS_CFG_MAX_REPAIR_ATTEMPTS 3
#endif
/**
* @brief Verify written data.
*/
#if !defined(MFS_CFG_WRITE_VERIFY) || defined(__DOXIGEN__)
#define MFS_CFG_WRITE_VERIFY TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if MFS_CFG_ID_CACHE_SIZE < 0
#error "invalid MFS_CFG_ID_CACHE_SIZE value"
#endif
#if (MFS_CFG_MAX_REPAIR_ATTEMPTS < 1) || (MFS_CFG_MAX_REPAIR_ATTEMPTS > 10)
#error "invalid MFS_MAX_REPAIR_ATTEMPTS value"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a flash bank.
*/
typedef enum {
MFS_BANK_0 = 0,
MFS_BANK_1 = 1
} mfs_bank_t;
/**
* @brief Type of driver state machine states.
*/
typedef enum {
MFS_UNINIT = 0,
MFS_STOP = 1,
MFS_READY = 2,
MFS_MOUNTED = 3,
MFS_ACTIVE = 4
} mfs_state_t;
/**
* @brief Type of an MFS error code.
* @note Errors are negative integers, informative warnings are positive
* integers.
*/
typedef enum {
MFS_NO_ERROR = 0,
MFS_REPAIR_WARNING = 1,
MFS_GC_WARNING = 2,
MFS_ID_NOT_FOUND = -1,
MFS_CRC_ERROR = -2,
MFS_FLASH_FAILURE = -3,
MFS_INTERNAL_ERROR = -4
} mfs_error_t;
/**
* @brief Type of a bank state assessment.
*/
typedef enum {
MFS_BANK_ERASED = 0,
MFS_BANK_OK = 1,
MFS_BANK_PARTIAL = 2,
MFS_BANK_GARBAGE = 3
} mfs_bank_state_t;
/**
* @brief Type of a bank header.
* @note The header resides in the first 16 bytes of a bank extending
* to the next page boundary.
*/
typedef struct {
/**
* @brief Bank magic 1.
*/
uint32_t magic1;
/**
* @brief Bank magic 2.
*/
uint32_t magic2;
/**
* @brief Usage counter of the bank.
* @details This value is increased each time a bank swap is performed. It
* indicates how much wearing the flash has already endured.
*/
uint32_t counter;
/**
* @brief First data element.
*/
flash_offset_t next;
/**
* @brief Header CRC.
*/
uint16_t crc;
} mfs_bank_header_t;
/**
* @brief Type of a data block header.
* @details This structure is placed before each written data block.
*/
typedef struct {
/**
* @brief Data header magic.
*/
uint16_t magic;
/**
* @brief Data CRC.
*/
uint16_t crc;
/**
* @brief Data identifier.
*/
uint32_t id;
/**
* @brief Data size for forward scan.
*/
uint32_t size;
/**
* @brief Address of the previous header or zero if none.
*/
flash_offset_t prev_header;
} mfs_data_header_t;
#if (MFS_CFG_ID_CACHE_SIZE > 0) || defined(__DOXYGEN__)
/**
* @brief Type of an element of the record identifiers cache.
*/
typedef struct mfs_cached_id {
/**
* @brief Pointer to the next element in the list.
*/
struct mfs_cached_id *lru_next;
/**
* @brief Pointer to the previous element in the list.
*/
struct mfs_cached_id *lru_prev;
/**
* @brief Identifier of the cached element.
*/
uint32_t id;
/**
* @brief Data address of the cached element.
*/
flash_offset_t offset;
/**
* @brief Data size of the cached element.
*/
uint32_t size;
} mfs_cached_id_t;
/**
* @brief Type of an element of the record identifiers cache.
*/
typedef struct mfs_cache_header {
/**
* @brief Pointer to the first element in the list.
*/
struct mfs_cached_id *lru_next;
/**
* @brief Pointer to the last element in the list.
*/
struct mfs_cached_id *lru_prev;
} mfs_cache_header_t;
#endif /* MFS_CFG_ID_CACHE_SIZE > 0 */
/**
* @brief Type of a MFS configuration structure.
*/
typedef struct {
/**
* @brief Flash driver associated to this MFS instance.
*/
BaseFlash *flashp;
/**
* @brief Base sector index for bank 0.
*/
flash_sector_t bank0_start;
/**
* #brief Number of sectors for bank 0.
*/
flash_sector_t bank0_sectors;
/**
* @brief Base sector index for bank 1.
*/
flash_sector_t bank1_start;
/**
* #brief Number of sectors for bank 1.
*/
flash_sector_t bank1_sectors;
} MFSConfig;
/**
* @extends BaseFlash
*
* @brief Type of an MFS instance.
*/
typedef struct {
/**
* @brief Driver state.
*/
mfs_state_t state;
/**
* @brief Current configuration data.
*/
const MFSConfig *config;
/**
* @brief Bank currently in use.
*/
mfs_bank_t current_bank;
/**
* @brief Size in bytes of banks.
*/
uint32_t banks_size;
/**
* @brief Pointer to the next free position in the current bank.
*/
flash_offset_t next_offset;
/**
* @brief Pointer to the last header in the list or zero.
*/
flash_offset_t last_offset;
/**
* @brief Used space in the current bank without considering erased records.
*/
uint32_t used_space;
#if (MFS_CFG_ID_CACHE_SIZE > 0) || defined(__DOXYGEN__)
/**
* @brief Header of the cache LRU list.
*/
mfs_cache_header_t cache_header;
/**
* @brief Array of the cached identifiers.
*/
mfs_cached_id_t cache_buffer[MFS_CFG_ID_CACHE_SIZE];
#endif /* MFS_CFG_ID_CACHE_SIZE > 0 */
} MFSDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Error codes handling macros
* @{
*/
#define MFS_IS_ERROR(err) ((err) < MFS_NO_ERROR)
#define MFS_IS_WARNING(err) ((err) > MFS_NO_ERROR)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void mfsObjectInit(MFSDriver *devp);
void mfsStart(MFSDriver *devp, const MFSConfig *config);
void mfsStop(MFSDriver *devp);
mfs_error_t mfsMount(MFSDriver *devp);
mfs_error_t mfsUnmount(MFSDriver *devp);
mfs_error_t mfsReadRecord(MFSDriver *devp, uint32_t id,
uint32_t *np, uint8_t *buffer);
mfs_error_t mfsUpdateRecord(MFSDriver *devp, uint32_t id,
uint32_t n, const uint8_t *buffer);
mfs_error_t mfsEraseRecord(MFSDriver *devp, uint32_t id);
#ifdef __cplusplus
}
#endif
#endif /* MFS_H */
/** @} */
/*
Managed Flash Storage - Copyright (C) 2016 Giovanni Di Sirio
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file mfs.h
* @brief Managed Flash Storage module header.
*
* @{
*/
#ifndef MFS_H
#define MFS_H
#include "hal_flash.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define MFS_BANK_MAGIC_1 0xEC705ADEU
#define MFS_BANK_MAGIC_2 0xF0339CC5U
#define MFS_HEADER_MAGIC 0x5FAEU
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief Record identifiers cache size.
* @details Cache trades RAM for a faster access to stored records. If zero
* then the cache is disabled.
*/
#if !defined(MFS_CFG_ID_CACHE_SIZE) || defined(__DOXIGEN__)
#define MFS_CFG_ID_CACHE_SIZE 16
#endif
/**
* @brief Maximum number of repair attempts on partition mount.
*/
#if !defined(MFS_CFG_MAX_REPAIR_ATTEMPTS) || defined(__DOXIGEN__)
#define MFS_CFG_MAX_REPAIR_ATTEMPTS 3
#endif
/**
* @brief Verify written data.
*/
#if !defined(MFS_CFG_WRITE_VERIFY) || defined(__DOXIGEN__)
#define MFS_CFG_WRITE_VERIFY TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if MFS_CFG_ID_CACHE_SIZE < 0
#error "invalid MFS_CFG_ID_CACHE_SIZE value"
#endif
#if (MFS_CFG_MAX_REPAIR_ATTEMPTS < 1) || (MFS_CFG_MAX_REPAIR_ATTEMPTS > 10)
#error "invalid MFS_MAX_REPAIR_ATTEMPTS value"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a flash bank.
*/
typedef enum {
MFS_BANK_0 = 0,
MFS_BANK_1 = 1
} mfs_bank_t;
/**
* @brief Type of driver state machine states.
*/
typedef enum {
MFS_UNINIT = 0,
MFS_STOP = 1,
MFS_READY = 2,
MFS_MOUNTED = 3,
MFS_ACTIVE = 4
} mfs_state_t;
/**
* @brief Type of an MFS error code.
* @note Errors are negative integers, informative warnings are positive
* integers.
*/
typedef enum {
MFS_NO_ERROR = 0,
MFS_REPAIR_WARNING = 1,
MFS_GC_WARNING = 2,
MFS_ID_NOT_FOUND = -1,
MFS_CRC_ERROR = -2,
MFS_FLASH_FAILURE = -3,
MFS_INTERNAL_ERROR = -4
} mfs_error_t;
/**
* @brief Type of a bank state assessment.
*/
typedef enum {
MFS_BANK_ERASED = 0,
MFS_BANK_OK = 1,
MFS_BANK_PARTIAL = 2,
MFS_BANK_GARBAGE = 3
} mfs_bank_state_t;
/**
* @brief Type of a bank header.
* @note The header resides in the first 16 bytes of a bank extending
* to the next page boundary.
*/
typedef struct {
/**
* @brief Bank magic 1.
*/
uint32_t magic1;
/**
* @brief Bank magic 2.
*/
uint32_t magic2;
/**
* @brief Usage counter of the bank.
* @details This value is increased each time a bank swap is performed. It
* indicates how much wearing the flash has already endured.
*/
uint32_t counter;
/**
* @brief First data element.
*/
flash_offset_t next;
/**
* @brief Header CRC.
*/
uint16_t crc;
} mfs_bank_header_t;
/**
* @brief Type of a data block header.
* @details This structure is placed before each written data block.
*/
typedef struct {
/**
* @brief Data header magic.
*/
uint16_t magic;
/**
* @brief Data CRC.
*/
uint16_t crc;
/**
* @brief Data identifier.
*/
uint32_t id;
/**
* @brief Data size for forward scan.
*/
uint32_t size;
/**
* @brief Address of the previous header or zero if none.
*/
flash_offset_t prev_header;
} mfs_data_header_t;
#if (MFS_CFG_ID_CACHE_SIZE > 0) || defined(__DOXYGEN__)
/**
* @brief Type of an element of the record identifiers cache.
*/
typedef struct mfs_cached_id {
/**
* @brief Pointer to the next element in the list.
*/
struct mfs_cached_id *lru_next;
/**
* @brief Pointer to the previous element in the list.
*/
struct mfs_cached_id *lru_prev;
/**
* @brief Identifier of the cached element.
*/
uint32_t id;
/**
* @brief Data address of the cached element.
*/
flash_offset_t offset;
/**
* @brief Data size of the cached element.
*/
uint32_t size;
} mfs_cached_id_t;
/**
* @brief Type of an element of the record identifiers cache.
*/
typedef struct mfs_cache_header {
/**
* @brief Pointer to the first element in the list.
*/
struct mfs_cached_id *lru_next;
/**
* @brief Pointer to the last element in the list.
*/
struct mfs_cached_id *lru_prev;
} mfs_cache_header_t;
#endif /* MFS_CFG_ID_CACHE_SIZE > 0 */
/**
* @brief Type of a MFS configuration structure.
*/
typedef struct {
/**
* @brief Flash driver associated to this MFS instance.
*/
BaseFlash *flashp;
/**
* @brief Base sector index for bank 0.
*/
flash_sector_t bank0_start;
/**
* #brief Number of sectors for bank 0.
*/
flash_sector_t bank0_sectors;
/**
* @brief Base sector index for bank 1.
*/
flash_sector_t bank1_start;
/**
* #brief Number of sectors for bank 1.
*/
flash_sector_t bank1_sectors;
} MFSConfig;
/**
* @extends BaseFlash
*
* @brief Type of an MFS instance.
*/
typedef struct {
/**
* @brief Driver state.
*/
mfs_state_t state;
/**
* @brief Current configuration data.
*/
const MFSConfig *config;
/**
* @brief Bank currently in use.
*/
mfs_bank_t current_bank;
/**
* @brief Size in bytes of banks.
*/
uint32_t banks_size;
/**
* @brief Pointer to the next free position in the current bank.
*/
flash_offset_t next_offset;
/**
* @brief Pointer to the last header in the list or zero.
*/
flash_offset_t last_offset;
/**
* @brief Used space in the current bank without considering erased records.
*/
uint32_t used_space;
#if (MFS_CFG_ID_CACHE_SIZE > 0) || defined(__DOXYGEN__)
/**
* @brief Header of the cache LRU list.
*/
mfs_cache_header_t cache_header;
/**
* @brief Array of the cached identifiers.
*/
mfs_cached_id_t cache_buffer[MFS_CFG_ID_CACHE_SIZE];
#endif /* MFS_CFG_ID_CACHE_SIZE > 0 */
} MFSDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Error codes handling macros
* @{
*/
#define MFS_IS_ERROR(err) ((err) < MFS_NO_ERROR)
#define MFS_IS_WARNING(err) ((err) > MFS_NO_ERROR)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void mfsObjectInit(MFSDriver *devp);
void mfsStart(MFSDriver *devp, const MFSConfig *config);
void mfsStop(MFSDriver *devp);
mfs_error_t mfsMount(MFSDriver *devp);
mfs_error_t mfsUnmount(MFSDriver *devp);
mfs_error_t mfsReadRecord(MFSDriver *devp, uint32_t id,
uint32_t *np, uint8_t *buffer);
mfs_error_t mfsUpdateRecord(MFSDriver *devp, uint32_t id,
uint32_t n, const uint8_t *buffer);
mfs_error_t mfsEraseRecord(MFSDriver *devp, uint32_t id);
#ifdef __cplusplus
}
#endif
#endif /* MFS_H */
/** @} */