git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9627 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
c4995095ee
commit
77a63206e7
1668
os/ex/Micron/m25q.c
1668
os/ex/Micron/m25q.c
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/** @} */
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/** @} */
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
1228
os/ex/ST/lis3dsh.c
1228
os/ex/ST/lis3dsh.c
File diff suppressed because it is too large
Load Diff
|
@ -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_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/** @} */
|
||||
|
|
|
@ -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
|
@ -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_ */
|
||||
|
||||
/** @} */
|
||||
|
|
1692
os/ex/ST/lsm6ds0.c
1692
os/ex/ST/lsm6ds0.c
File diff suppressed because it is too large
Load Diff
1208
os/ex/ST/lsm6ds0.h
1208
os/ex/ST/lsm6ds0.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
Loading…
Reference in New Issue