aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiovanni Di Sirio <gdisirio@gmail.com>2016-06-16 07:44:08 +0000
committerGiovanni Di Sirio <gdisirio@gmail.com>2016-06-16 07:44:08 +0000
commit77a63206e770cb4a73abf3063ce381fa8de4705b (patch)
treec6c33fbd512f6989c5f318e945b4a394502071b8
parentc4995095eec2018618a9f96a09797ce84e470af9 (diff)
downloadChibiOS-77a63206e770cb4a73abf3063ce381fa8de4705b.tar.gz
ChibiOS-77a63206e770cb4a73abf3063ce381fa8de4705b.tar.bz2
ChibiOS-77a63206e770cb4a73abf3063ce381fa8de4705b.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9627 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--os/ex/Micron/m25q.c1668
-rw-r--r--os/ex/Micron/m25q.h546
-rw-r--r--os/ex/ST/l3gd20.c964
-rw-r--r--os/ex/ST/l3gd20.h660
-rw-r--r--os/ex/ST/lis302dl.c858
-rw-r--r--os/ex/ST/lis302dl.h604
-rw-r--r--os/ex/ST/lis3dsh.c1228
-rw-r--r--os/ex/ST/lis3dsh.h652
-rw-r--r--os/ex/ST/lis3mdl.c966
-rw-r--r--os/ex/ST/lis3mdl.h736
-rw-r--r--os/ex/ST/lsm303dlhc.c1808
-rw-r--r--os/ex/ST/lsm303dlhc.h882
-rw-r--r--os/ex/ST/lsm6ds0.c1692
-rw-r--r--os/ex/ST/lsm6ds0.h1208
-rw-r--r--os/ex/subsystems/mfs/mfs.c1366
-rw-r--r--os/ex/subsystems/mfs/mfs.h678
16 files changed, 8258 insertions, 8258 deletions
diff --git a/os/ex/Micron/m25q.c b/os/ex/Micron/m25q.c
index 3dbb3df62..3d6de626d 100644
--- a/os/ex/Micron/m25q.c
+++ b/os/ex/Micron/m25q.c
@@ -1,834 +1,834 @@
-/*
- 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.c
- * @brief Micron serial flash driver code.
- *
- * @addtogroup m25q
- * @{
- */
-
-#include <string.h>
-
-#include "hal.h"
-#include "m25q.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#define PAGE_SIZE 256U
-#define PAGE_MASK (PAGE_SIZE - 1U)
-
-#if M25Q_USE_SUB_SECTORS == TRUE
-#define SECTOR_SIZE 0x00001000U
-#define CMD_SECTOR_ERASE M25Q_CMD_SUBSECTOR_ERASE
-#else
-#define SECTOR_SIZE 0x00010000U
-#define CMD_SECTOR_ERASE M25Q_CMD_SECTOR_ERASE
-#endif
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-static const flash_descriptor_t *m25q_get_descriptor(void *instance);
-static flash_error_t m25q_read(void *instance, flash_offset_t offset,
- size_t n, uint8_t *rp);
-static flash_error_t m25q_program(void *instance, flash_offset_t offset,
- size_t n, const uint8_t *pp);
-static flash_error_t m25q_start_erase_all(void *instance);
-static flash_error_t m25q_start_erase_sector(void *instance,
- flash_sector_t sector);
-static flash_error_t m25q_query_erase(void *instance, uint32_t *msec);
-static flash_error_t m25q_verify_erase(void *instance, flash_sector_t sector);
-static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
- size_t n, uint8_t *rp);
-
-/**
- * @brief Virtual methods table.
- */
-static const struct M25QDriverVMT m25q_vmt = {
- m25q_get_descriptor, m25q_read, m25q_program,
- m25q_start_erase_all, m25q_start_erase_sector,
- m25q_query_erase, m25q_verify_erase,
- m25q_read_sfdp
-};
-
-/**
- * @brief N25Q128 descriptor.
- */
-static flash_descriptor_t m25q_descriptor = {
- .attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |
- FLASH_ATTR_SUSPEND_ERASE_CAPABLE,
- .page_size = 256U,
- .sectors_count = 0U, /* It is overwritten.*/
- .sectors = NULL,
- .sectors_size = SECTOR_SIZE,
- .address = 0U
-};
-
-#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
-/* Initial M25Q_CMD_READ_ID command.*/
-static const qspi_command_t m25q_cmd_read_id = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_READ_ID) |
-#if M25Q_SWITCH_WIDTH == TRUE
- QSPI_CFG_CMD_MODE_ONE_LINE |
- QSPI_CFG_DATA_MODE_ONE_LINE,
-#else
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
- QSPI_CFG_CMD_MODE_ONE_LINE |
- QSPI_CFG_DATA_MODE_ONE_LINE,
-#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
- QSPI_CFG_CMD_MODE_TWO_LINES |
- QSPI_CFG_DATA_MODE_TWO_LINES,
-#else
- QSPI_CFG_CMD_MODE_FOUR_LINES |
- QSPI_CFG_DATA_MODE_FOUR_LINES,
-#endif
-#endif
- .addr = 0,
- .alt = 0
-};
-
-/* Initial M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER command.*/
-static const qspi_command_t m25q_cmd_write_evconf = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER) |
-#if M25Q_SWITCH_WIDTH == TRUE
- QSPI_CFG_CMD_MODE_ONE_LINE |
- QSPI_CFG_DATA_MODE_ONE_LINE,
-#else
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
- QSPI_CFG_CMD_MODE_ONE_LINE |
- QSPI_CFG_DATA_MODE_ONE_LINE,
-#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
- QSPI_CFG_CMD_MODE_TWO_LINES |
- QSPI_CFG_DATA_MODE_TWO_LINES,
-#else
- QSPI_CFG_CMD_MODE_FOUR_LINES |
- QSPI_CFG_DATA_MODE_FOUR_LINES,
-#endif
-#endif
- .addr = 0,
- .alt = 0
-};
-
-/* Initial M25Q_CMD_WRITE_ENABLE command.*/
-static const qspi_command_t m25q_cmd_write_enable = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENABLE) |
-#if M25Q_SWITCH_WIDTH == TRUE
- QSPI_CFG_CMD_MODE_ONE_LINE,
-#else
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
- QSPI_CFG_CMD_MODE_ONE_LINE,
-#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
- QSPI_CFG_CMD_MODE_TWO_LINES,
-#else
- QSPI_CFG_CMD_MODE_FOUR_LINES,
-#endif
-#endif
- .addr = 0,
- .alt = 0
-};
-
-/* Bus width initialization.*/
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
-static const uint8_t m25q_evconf_value[1] = {0xCF};
-#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
-static const uint8_t m25q_evconf_value[1] = {0x8F};
-#else
-static const uint8_t m25q_evconf_value[1] = {0x4F};
-#endif
-#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
-
-static const uint8_t m25q_manufacturer_ids[] = M25Q_SUPPORTED_MANUFACTURE_IDS;
-static const uint8_t m25q_memory_type_ids[] = M25Q_SUPPORTED_MEMORY_TYPE_IDS;
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-static bool m25q_find_id(const uint8_t *set, size_t size, uint8_t element) {
- size_t i;
-
- for (i = 0; i < size; i++) {
- if (set[i] == element) {
- return true;
- }
- }
- return false;
-}
-
-#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
-void m25q_reset_xip(M25QDriver *devp) {
- static const uint8_t flash_conf[1] = {
- (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
- };
- qspi_command_t cmd;
- uint8_t buf[1];
-
- /* Resetting XIP mode by reading one byte without XIP confirmation bit.*/
- cmd.alt = 0xFF;
- cmd.addr = 0;
- cmd.cfg = QSPI_CFG_CMD_MODE_NONE |
- QSPI_CFG_ADDR_SIZE_24 |
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
- QSPI_CFG_ADDR_MODE_ONE_LINE |
- QSPI_CFG_DATA_MODE_ONE_LINE |
-#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
- QSPI_CFG_ADDR_MODE_TWO_LINES |
- QSPI_CFG_DATA_MODE_TWO_LINES |
-#else
- QSPI_CFG_ADDR_MODE_FOUR_LINES |
- QSPI_CFG_DATA_MODE_FOUR_LINES |
-#endif
- QSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/
- QSPI_CFG_ALT_SIZE_8 |
- QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
- qspiReceive(devp->config->busp, &cmd, 1, buf);
-
- /* Enabling write operation.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
-
- /* Rewriting volatile configuration register.*/
- jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
- 1, flash_conf);
-}
-
-void m25q_reset_memory(M25QDriver *devp) {
-
- /* 1x M25Q_CMD_RESET_ENABLE command.*/
- static const qspi_command_t cmd_reset_enable_1 = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
- QSPI_CFG_CMD_MODE_ONE_LINE,
- .addr = 0,
- .alt = 0
- };
-
- /* 1x M25Q_CMD_RESET_MEMORY command.*/
- static const qspi_command_t cmd_reset_memory_1 = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
- QSPI_CFG_CMD_MODE_ONE_LINE,
- .addr = 0,
- .alt = 0
- };
-
- /* If the device is in one bit mode then the following commands are
- rejected because shorter than 8 bits. If the device is in multiple
- bits mode then the commands are accepted and the device is reset to
- one bit mode.*/
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI4L
- /* 4x M25Q_CMD_RESET_ENABLE command.*/
- static const qspi_command_t cmd_reset_enable_4 = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
- QSPI_CFG_CMD_MODE_FOUR_LINES,
- .addr = 0,
- .alt = 0
- };
-
- /* 4x M25Q_CMD_RESET_MEMORY command.*/
- static const qspi_command_t cmd_reset_memory_4 = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
- QSPI_CFG_CMD_MODE_FOUR_LINES,
- .addr = 0,
- .alt = 0
- };
-
- qspiCommand(devp->config->busp, &cmd_reset_enable_4);
- qspiCommand(devp->config->busp, &cmd_reset_memory_4);
-#else
- /* 2x M25Q_CMD_RESET_ENABLE command.*/
- static const qspi_command_t cmd_reset_enable_2 = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
- QSPI_CFG_CMD_MODE_TWO_LINES,
- .addr = 0,
- .alt = 0
- };
-
- /* 2x M25Q_CMD_RESET_MEMORY command.*/
- static const qspi_command_t cmd_reset_memory_2 = {
- .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
- QSPI_CFG_CMD_MODE_TWO_LINES,
- .addr = 0,
- .alt = 0
- };
-
- qspiCommand(devp->config->busp, &cmd_reset_enable_2);
- qspiCommand(devp->config->busp, &cmd_reset_memory_2);
-#endif
-
- /* Now the device should be in one bit mode for sure and we perform a
- device reset.*/
- qspiCommand(devp->config->busp, &cmd_reset_enable_1);
- qspiCommand(devp->config->busp, &cmd_reset_memory_1);
-}
-#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
-
-static flash_error_t m25q_poll_status(M25QDriver *devp) {
- uint8_t sts;
-
- do {
-#if M25Q_NICE_WAITING == TRUE
- osalThreadSleepMilliseconds(1);
-#endif
- /* Read status command.*/
- jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
- 1, &sts);
- } while ((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U);
-
- /* Checking for errors.*/
- if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
- /* Clearing status register.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
-
- /* Program operation failed.*/
- return FLASH_ERROR_PROGRAM;
- }
-
- return FLASH_NO_ERROR;
-}
-
-static const flash_descriptor_t *m25q_get_descriptor(void *instance) {
- M25QDriver *devp = (M25QDriver *)instance;
-
- osalDbgCheck(instance != NULL);
- osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP),
- "invalid state");
-
- return &m25q_descriptor;
-}
-
-static flash_error_t m25q_read(void *instance, flash_offset_t offset,
- size_t n, uint8_t *rp) {
- M25QDriver *devp = (M25QDriver *)instance;
-
- osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
- osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
- (size_t)m25q_descriptor.sectors_size);
- osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
- "invalid state");
-
- if (devp->state == FLASH_ERASE) {
- return FLASH_BUSY_ERASING;
- }
-
- /* Bus acquired.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* FLASH_READY state while the operation is performed.*/
- devp->state = FLASH_READ;
-
-#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
- /* Fast read command in QSPI mode.*/
- jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
- offset, M25Q_READ_DUMMY_CYCLES, n, rp);
-#else
- /* Normal read command in SPI mode.*/
- jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
- offset, n, rp);
-#endif
-
- /* Ready state again.*/
- devp->state = FLASH_READY;
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return FLASH_NO_ERROR;
-}
-
-static flash_error_t m25q_program(void *instance, flash_offset_t offset,
- size_t n, const uint8_t *pp) {
- M25QDriver *devp = (M25QDriver *)instance;
-
- osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
- osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
- (size_t)m25q_descriptor.sectors_size);
- osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
- "invalid state");
-
- if (devp->state == FLASH_ERASE) {
- return FLASH_BUSY_ERASING;
- }
-
- /* Bus acquired.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* FLASH_PGM state while the operation is performed.*/
- devp->state = FLASH_PGM;
-
- /* Data is programmed page by page.*/
- while (n > 0U) {
- flash_error_t err;
-
- /* Data size that can be written in a single program page operation.*/
- size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset);
- if (chunk > n) {
- chunk = n;
- }
-
- /* Enabling write operation.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
-
- /* Page program command.*/
- jesd216_cmd_addr_send(devp->config->busp, M25Q_CMD_PAGE_PROGRAM, offset,
- chunk, pp);
-
- /* Wait for status and check errors.*/
- err = m25q_poll_status(devp);
- if (err != FLASH_NO_ERROR) {
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return err;
- }
-
- /* Next page.*/
- offset += chunk;
- pp += chunk;
- n -= chunk;
- }
-
- /* Ready state again.*/
- devp->state = FLASH_READY;
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return FLASH_NO_ERROR;
-}
-
-static flash_error_t m25q_start_erase_all(void *instance) {
- M25QDriver *devp = (M25QDriver *)instance;
-
- osalDbgCheck(instance != NULL);
- osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
- "invalid state");
-
- if (devp->state == FLASH_ERASE) {
- return FLASH_BUSY_ERASING;
- }
-
- /* Bus acquired.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* FLASH_ERASE state while the operation is performed.*/
- devp->state = FLASH_ERASE;
-
- /* Enabling write operation.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
-
- /* Bulk erase command.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_BULK_ERASE);
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return FLASH_NO_ERROR;
-}
-
-static flash_error_t m25q_start_erase_sector(void *instance,
- flash_sector_t sector) {
- M25QDriver *devp = (M25QDriver *)instance;
- flash_offset_t offset = (flash_offset_t)(sector * SECTOR_SIZE);
-
- osalDbgCheck(instance != NULL);
- osalDbgCheck(sector < m25q_descriptor.sectors_count);
- osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
- "invalid state");
-
- if (devp->state == FLASH_ERASE) {
- return FLASH_BUSY_ERASING;
- }
-
- /* Bus acquired.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* FLASH_ERASE state while the operation is performed.*/
- devp->state = FLASH_ERASE;
-
- /* Enabling write operation.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
-
- /* Sector erase command.*/
- jesd216_cmd_addr(devp->config->busp, M25Q_CMD_SECTOR_ERASE, offset);
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return FLASH_NO_ERROR;
-}
-
-static flash_error_t m25q_verify_erase(void *instance,
- flash_sector_t sector) {
- M25QDriver *devp = (M25QDriver *)instance;
- uint8_t cmpbuf[M25Q_COMPARE_BUFFER_SIZE];
- flash_offset_t offset;
- size_t n;
-
- osalDbgCheck(instance != NULL);
- osalDbgCheck(sector < m25q_descriptor.sectors_count);
- osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
- "invalid state");
-
- if (devp->state == FLASH_ERASE) {
- return FLASH_BUSY_ERASING;
- }
-
- /* Bus acquired.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* FLASH_READY state while the operation is performed.*/
- devp->state = FLASH_READ;
-
- /* Read command.*/
- offset = (flash_offset_t)(sector * SECTOR_SIZE);
- n = SECTOR_SIZE;
- while (n > 0U) {
- uint8_t *p;
-
-#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
- jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
- offset, M25Q_READ_DUMMY_CYCLES,
- sizeof cmpbuf, cmpbuf);
-#else
- /* Normal read command in SPI mode.*/
- jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
- offset, sizeof cmpbuf, cmpbuf);
-#endif
-
- /* Checking for erased state of current buffer.*/
- for (p = cmpbuf; p < &cmpbuf[M25Q_COMPARE_BUFFER_SIZE]; p++) {
- if (*p != 0xFFU) {
- /* Ready state again.*/
- devp->state = FLASH_READY;
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return FLASH_ERROR_VERIFY;
- }
- }
-
- offset += sizeof cmpbuf;
- n -= sizeof cmpbuf;
- }
-
- /* Ready state again.*/
- devp->state = FLASH_READY;
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- return FLASH_NO_ERROR;
-}
-
-static flash_error_t m25q_query_erase(void *instance, uint32_t *msec) {
- M25QDriver *devp = (M25QDriver *)instance;
- uint8_t sts;
-
- osalDbgCheck(instance != NULL);
- osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
- "invalid state");
-
- /* If there is an erase in progress then the device must be checked.*/
- if (devp->state == FLASH_ERASE) {
-
- /* Bus acquired.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* Read status command.*/
- jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
- 1, &sts);
-
- /* If the P/E bit is zero (busy) or the flash in a suspended state then
- report that the operation is still in progress.*/
- if (((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U) ||
- ((sts & M25Q_FLAGS_ERASE_SUSPEND) != 0U)) {
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
-
- /* Recommended time before polling again, this is a simplified
- implementation.*/
- if (msec != NULL) {
- *msec = 1U;
- }
-
- return FLASH_BUSY_ERASING;
- }
-
- /* The device is ready to accept commands.*/
- devp->state = FLASH_READY;
-
- /* Checking for errors.*/
- if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
-
- /* Clearing status register.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
-
- /* Erase operation failed.*/
- return FLASH_ERROR_ERASE;
- }
-
- /* Bus released.*/
- jesd216_bus_release(devp->config->busp);
- }
-
- return FLASH_NO_ERROR;
-}
-
-static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
- size_t n, uint8_t *rp) {
-
- (void)instance;
- (void)rp;
- (void)offset;
- (void)n;
-
- return FLASH_NO_ERROR;
-}
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Initializes an instance.
- *
- * @param[out] devp pointer to the @p M25QDriver object
- *
- * @init
- */
-void m25qObjectInit(M25QDriver *devp) {
-
- osalDbgCheck(devp != NULL);
-
- devp->vmt = &m25q_vmt;
- devp->state = FLASH_STOP;
- devp->config = NULL;
-}
-
-/**
- * @brief Configures and activates N25Q128 driver.
- *
- * @param[in] devp pointer to the @p M25QDriver object
- * @param[in] config pointer to the configuration
- *
- * @api
- */
-void m25qStart(M25QDriver *devp, const M25QConfig *config) {
-
- osalDbgCheck((devp != NULL) && (config != NULL));
- osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
-
- devp->config = config;
-
- if (devp->state == FLASH_STOP) {
-
- /* Bus acquisition.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_SPI
- /* Reading device ID.*/
- jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_ID,
- sizeof devp->device_id, devp->device_id);
-
-#else /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
- /* Attempting a reset of the XIP mode, it could be in an unexpected state
- because a CPU reset does not reset the memory too.*/
- m25q_reset_xip(devp);
-
- /* Attempting a eeset of the device, it could be in an unexpected state
- because a CPU reset does not reset the memory too.*/
- m25q_reset_memory(devp);
-
- /* Reading device ID and unique ID.*/
- qspiReceive(devp->config->busp, &m25q_cmd_read_id,
- sizeof devp->device_id, devp->device_id);
-#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
-
- /* Checking if the device is white listed.*/
- osalDbgAssert(m25q_find_id(m25q_manufacturer_ids,
- sizeof m25q_manufacturer_ids,
- devp->device_id[0]),
- "invalid manufacturer id");
- osalDbgAssert(m25q_find_id(m25q_memory_type_ids,
- sizeof m25q_memory_type_ids,
- devp->device_id[1]),
- "invalid memory type id");
-
-#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)
- /* Setting up final bus width.*/
- qspiCommand(devp->config->busp, &m25q_cmd_write_enable);
- qspiSend(devp->config->busp, &m25q_cmd_write_evconf, 1, m25q_evconf_value);
-
- {
- uint8_t id[3];
-
- /* Reading ID again for confirmation.*/
- jesd216_cmd_receive(devp->config->busp, M25Q_CMD_MULTIPLE_IO_READ_ID,
- 3, id);
-
- /* Checking if the device is white listed.*/
- osalDbgAssert(memcmp(id, devp->device_id, 3) == 0,
- "id confirmation failed");
- }
-#endif
-
- /* Setting up the device size.*/
- m25q_descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) /
- SECTOR_SIZE;
-
-#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI)
- {
- static const uint8_t flash_conf[1] = {
- (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
- };
-
- /* Setting up the dummy cycles to be used for fast read operations.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
- jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
- 1, flash_conf);
- }
-#endif
-
- /* Driver in ready state.*/
- devp->state = FLASH_READY;
-
- /* Bus release.*/
- jesd216_bus_release(devp->config->busp);
- }
-}
-
-/**
- * @brief Deactivates the N25Q128 driver.
- *
- * @param[in] devp pointer to the @p M25QDriver object
- *
- * @api
- */
-void m25qStop(M25QDriver *devp) {
-
- osalDbgCheck(devp != NULL);
- osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
-
- if (devp->state != FLASH_STOP) {
-
- /* Bus acquisition.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* Stopping bus device.*/
- jesd216_stop(devp->config->busp);
-
- /* Deleting current configuration.*/
- devp->config = NULL;
-
- /* Driver stopped.*/
- devp->state = FLASH_STOP;
-
- /* Bus release.*/
- jesd216_bus_release(devp->config->busp);
- }
-}
-
-#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
-#if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
-/**
- * @brief Enters the memory Mapping mode.
- * @details The memory mapping mode is only available when the QSPI mode
- * is selected and the underlying QSPI controller supports the
- * feature.
- *
- * @param[in] devp pointer to the @p M25QDriver object
- * @param[out] addrp pointer to the memory start address of the mapped
- * flash or @p NULL
- *
- * @api
- */
-void m25qMemoryMap(M25QDriver *devp, uint8_t **addrp) {
- static const uint8_t flash_status_xip[1] = {
- (M25Q_READ_DUMMY_CYCLES << 4U) | 0x07U
- };
- qspi_command_t cmd;
-
- /* Bus acquisition.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- /* Activating XIP mode in the device.*/
- jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
- jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
- 1, flash_status_xip);
-
- /* Putting the QSPI driver in memory mapped mode.*/
- cmd.cfg = QSPI_CFG_CMD(M25Q_CMD_FAST_READ) |
- QSPI_CFG_ADDR_SIZE_24 |
-#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
- QSPI_CFG_CMD_MODE_ONE_LINE |
- QSPI_CFG_ADDR_MODE_ONE_LINE |
- QSPI_CFG_DATA_MODE_ONE_LINE |
-#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
- QSPI_CFG_CMD_MODE_TWO_LINES |
- QSPI_CFG_ADDR_MODE_TWO_LINES |
- QSPI_CFG_DATA_MODE_TWO_LINES |
-#else
- QSPI_CFG_CMD_MODE_FOUR_LINES |
- QSPI_CFG_ADDR_MODE_FOUR_LINES |
- QSPI_CFG_DATA_MODE_FOUR_LINES |
-#endif
- QSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/
- QSPI_CFG_ALT_SIZE_8 |
- QSPI_CFG_SIOO |
- QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
-
- qspiMapFlash(devp->config->busp, &cmd, addrp);
-
- /* Bus release.*/
- jesd216_bus_release(devp->config->busp);
-}
-
-/**
- * @brief Leaves the memory Mapping mode.
- *
- * @param[in] devp pointer to the @p M25QDriver object
- *
- * @api
- */
-void m25qMemoryUnmap(M25QDriver *devp) {
-
- /* Bus acquisition.*/
- jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
-
- qspiUnmapFlash(devp->config->busp);
-
- m25q_reset_xip(devp);
-
- /* Bus release.*/
- jesd216_bus_release(devp->config->busp);
-}
-#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
-#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
-
-/** @} */
+/*
+ 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.c
+ * @brief Micron serial flash driver code.
+ *
+ * @addtogroup m25q
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+#include "m25q.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define PAGE_SIZE 256U
+#define PAGE_MASK (PAGE_SIZE - 1U)
+
+#if M25Q_USE_SUB_SECTORS == TRUE
+#define SECTOR_SIZE 0x00001000U
+#define CMD_SECTOR_ERASE M25Q_CMD_SUBSECTOR_ERASE
+#else
+#define SECTOR_SIZE 0x00010000U
+#define CMD_SECTOR_ERASE M25Q_CMD_SECTOR_ERASE
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const flash_descriptor_t *m25q_get_descriptor(void *instance);
+static flash_error_t m25q_read(void *instance, flash_offset_t offset,
+ size_t n, uint8_t *rp);
+static flash_error_t m25q_program(void *instance, flash_offset_t offset,
+ size_t n, const uint8_t *pp);
+static flash_error_t m25q_start_erase_all(void *instance);
+static flash_error_t m25q_start_erase_sector(void *instance,
+ flash_sector_t sector);
+static flash_error_t m25q_query_erase(void *instance, uint32_t *msec);
+static flash_error_t m25q_verify_erase(void *instance, flash_sector_t sector);
+static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
+ size_t n, uint8_t *rp);
+
+/**
+ * @brief Virtual methods table.
+ */
+static const struct M25QDriverVMT m25q_vmt = {
+ m25q_get_descriptor, m25q_read, m25q_program,
+ m25q_start_erase_all, m25q_start_erase_sector,
+ m25q_query_erase, m25q_verify_erase,
+ m25q_read_sfdp
+};
+
+/**
+ * @brief N25Q128 descriptor.
+ */
+static flash_descriptor_t m25q_descriptor = {
+ .attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |
+ FLASH_ATTR_SUSPEND_ERASE_CAPABLE,
+ .page_size = 256U,
+ .sectors_count = 0U, /* It is overwritten.*/
+ .sectors = NULL,
+ .sectors_size = SECTOR_SIZE,
+ .address = 0U
+};
+
+#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
+/* Initial M25Q_CMD_READ_ID command.*/
+static const qspi_command_t m25q_cmd_read_id = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_READ_ID) |
+#if M25Q_SWITCH_WIDTH == TRUE
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE,
+#else
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE,
+#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
+ QSPI_CFG_CMD_MODE_TWO_LINES |
+ QSPI_CFG_DATA_MODE_TWO_LINES,
+#else
+ QSPI_CFG_CMD_MODE_FOUR_LINES |
+ QSPI_CFG_DATA_MODE_FOUR_LINES,
+#endif
+#endif
+ .addr = 0,
+ .alt = 0
+};
+
+/* Initial M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER command.*/
+static const qspi_command_t m25q_cmd_write_evconf = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER) |
+#if M25Q_SWITCH_WIDTH == TRUE
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE,
+#else
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE,
+#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
+ QSPI_CFG_CMD_MODE_TWO_LINES |
+ QSPI_CFG_DATA_MODE_TWO_LINES,
+#else
+ QSPI_CFG_CMD_MODE_FOUR_LINES |
+ QSPI_CFG_DATA_MODE_FOUR_LINES,
+#endif
+#endif
+ .addr = 0,
+ .alt = 0
+};
+
+/* Initial M25Q_CMD_WRITE_ENABLE command.*/
+static const qspi_command_t m25q_cmd_write_enable = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENABLE) |
+#if M25Q_SWITCH_WIDTH == TRUE
+ QSPI_CFG_CMD_MODE_ONE_LINE,
+#else
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
+ QSPI_CFG_CMD_MODE_ONE_LINE,
+#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
+ QSPI_CFG_CMD_MODE_TWO_LINES,
+#else
+ QSPI_CFG_CMD_MODE_FOUR_LINES,
+#endif
+#endif
+ .addr = 0,
+ .alt = 0
+};
+
+/* Bus width initialization.*/
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
+static const uint8_t m25q_evconf_value[1] = {0xCF};
+#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
+static const uint8_t m25q_evconf_value[1] = {0x8F};
+#else
+static const uint8_t m25q_evconf_value[1] = {0x4F};
+#endif
+#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
+
+static const uint8_t m25q_manufacturer_ids[] = M25Q_SUPPORTED_MANUFACTURE_IDS;
+static const uint8_t m25q_memory_type_ids[] = M25Q_SUPPORTED_MEMORY_TYPE_IDS;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static bool m25q_find_id(const uint8_t *set, size_t size, uint8_t element) {
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (set[i] == element) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
+void m25q_reset_xip(M25QDriver *devp) {
+ static const uint8_t flash_conf[1] = {
+ (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
+ };
+ qspi_command_t cmd;
+ uint8_t buf[1];
+
+ /* Resetting XIP mode by reading one byte without XIP confirmation bit.*/
+ cmd.alt = 0xFF;
+ cmd.addr = 0;
+ cmd.cfg = QSPI_CFG_CMD_MODE_NONE |
+ QSPI_CFG_ADDR_SIZE_24 |
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
+ QSPI_CFG_ADDR_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE |
+#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
+ QSPI_CFG_ADDR_MODE_TWO_LINES |
+ QSPI_CFG_DATA_MODE_TWO_LINES |
+#else
+ QSPI_CFG_ADDR_MODE_FOUR_LINES |
+ QSPI_CFG_DATA_MODE_FOUR_LINES |
+#endif
+ QSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/
+ QSPI_CFG_ALT_SIZE_8 |
+ QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
+ qspiReceive(devp->config->busp, &cmd, 1, buf);
+
+ /* Enabling write operation.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
+
+ /* Rewriting volatile configuration register.*/
+ jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
+ 1, flash_conf);
+}
+
+void m25q_reset_memory(M25QDriver *devp) {
+
+ /* 1x M25Q_CMD_RESET_ENABLE command.*/
+ static const qspi_command_t cmd_reset_enable_1 = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
+ QSPI_CFG_CMD_MODE_ONE_LINE,
+ .addr = 0,
+ .alt = 0
+ };
+
+ /* 1x M25Q_CMD_RESET_MEMORY command.*/
+ static const qspi_command_t cmd_reset_memory_1 = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
+ QSPI_CFG_CMD_MODE_ONE_LINE,
+ .addr = 0,
+ .alt = 0
+ };
+
+ /* If the device is in one bit mode then the following commands are
+ rejected because shorter than 8 bits. If the device is in multiple
+ bits mode then the commands are accepted and the device is reset to
+ one bit mode.*/
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI4L
+ /* 4x M25Q_CMD_RESET_ENABLE command.*/
+ static const qspi_command_t cmd_reset_enable_4 = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
+ QSPI_CFG_CMD_MODE_FOUR_LINES,
+ .addr = 0,
+ .alt = 0
+ };
+
+ /* 4x M25Q_CMD_RESET_MEMORY command.*/
+ static const qspi_command_t cmd_reset_memory_4 = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
+ QSPI_CFG_CMD_MODE_FOUR_LINES,
+ .addr = 0,
+ .alt = 0
+ };
+
+ qspiCommand(devp->config->busp, &cmd_reset_enable_4);
+ qspiCommand(devp->config->busp, &cmd_reset_memory_4);
+#else
+ /* 2x M25Q_CMD_RESET_ENABLE command.*/
+ static const qspi_command_t cmd_reset_enable_2 = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
+ QSPI_CFG_CMD_MODE_TWO_LINES,
+ .addr = 0,
+ .alt = 0
+ };
+
+ /* 2x M25Q_CMD_RESET_MEMORY command.*/
+ static const qspi_command_t cmd_reset_memory_2 = {
+ .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
+ QSPI_CFG_CMD_MODE_TWO_LINES,
+ .addr = 0,
+ .alt = 0
+ };
+
+ qspiCommand(devp->config->busp, &cmd_reset_enable_2);
+ qspiCommand(devp->config->busp, &cmd_reset_memory_2);
+#endif
+
+ /* Now the device should be in one bit mode for sure and we perform a
+ device reset.*/
+ qspiCommand(devp->config->busp, &cmd_reset_enable_1);
+ qspiCommand(devp->config->busp, &cmd_reset_memory_1);
+}
+#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
+
+static flash_error_t m25q_poll_status(M25QDriver *devp) {
+ uint8_t sts;
+
+ do {
+#if M25Q_NICE_WAITING == TRUE
+ osalThreadSleepMilliseconds(1);
+#endif
+ /* Read status command.*/
+ jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
+ 1, &sts);
+ } while ((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U);
+
+ /* Checking for errors.*/
+ if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
+ /* Clearing status register.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
+
+ /* Program operation failed.*/
+ return FLASH_ERROR_PROGRAM;
+ }
+
+ return FLASH_NO_ERROR;
+}
+
+static const flash_descriptor_t *m25q_get_descriptor(void *instance) {
+ M25QDriver *devp = (M25QDriver *)instance;
+
+ osalDbgCheck(instance != NULL);
+ osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP),
+ "invalid state");
+
+ return &m25q_descriptor;
+}
+
+static flash_error_t m25q_read(void *instance, flash_offset_t offset,
+ size_t n, uint8_t *rp) {
+ M25QDriver *devp = (M25QDriver *)instance;
+
+ osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
+ osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
+ (size_t)m25q_descriptor.sectors_size);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ if (devp->state == FLASH_ERASE) {
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* Bus acquired.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* FLASH_READY state while the operation is performed.*/
+ devp->state = FLASH_READ;
+
+#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
+ /* Fast read command in QSPI mode.*/
+ jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
+ offset, M25Q_READ_DUMMY_CYCLES, n, rp);
+#else
+ /* Normal read command in SPI mode.*/
+ jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
+ offset, n, rp);
+#endif
+
+ /* Ready state again.*/
+ devp->state = FLASH_READY;
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return FLASH_NO_ERROR;
+}
+
+static flash_error_t m25q_program(void *instance, flash_offset_t offset,
+ size_t n, const uint8_t *pp) {
+ M25QDriver *devp = (M25QDriver *)instance;
+
+ osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
+ osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
+ (size_t)m25q_descriptor.sectors_size);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ if (devp->state == FLASH_ERASE) {
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* Bus acquired.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* FLASH_PGM state while the operation is performed.*/
+ devp->state = FLASH_PGM;
+
+ /* Data is programmed page by page.*/
+ while (n > 0U) {
+ flash_error_t err;
+
+ /* Data size that can be written in a single program page operation.*/
+ size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset);
+ if (chunk > n) {
+ chunk = n;
+ }
+
+ /* Enabling write operation.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
+
+ /* Page program command.*/
+ jesd216_cmd_addr_send(devp->config->busp, M25Q_CMD_PAGE_PROGRAM, offset,
+ chunk, pp);
+
+ /* Wait for status and check errors.*/
+ err = m25q_poll_status(devp);
+ if (err != FLASH_NO_ERROR) {
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return err;
+ }
+
+ /* Next page.*/
+ offset += chunk;
+ pp += chunk;
+ n -= chunk;
+ }
+
+ /* Ready state again.*/
+ devp->state = FLASH_READY;
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return FLASH_NO_ERROR;
+}
+
+static flash_error_t m25q_start_erase_all(void *instance) {
+ M25QDriver *devp = (M25QDriver *)instance;
+
+ osalDbgCheck(instance != NULL);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ if (devp->state == FLASH_ERASE) {
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* Bus acquired.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* FLASH_ERASE state while the operation is performed.*/
+ devp->state = FLASH_ERASE;
+
+ /* Enabling write operation.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
+
+ /* Bulk erase command.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_BULK_ERASE);
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return FLASH_NO_ERROR;
+}
+
+static flash_error_t m25q_start_erase_sector(void *instance,
+ flash_sector_t sector) {
+ M25QDriver *devp = (M25QDriver *)instance;
+ flash_offset_t offset = (flash_offset_t)(sector * SECTOR_SIZE);
+
+ osalDbgCheck(instance != NULL);
+ osalDbgCheck(sector < m25q_descriptor.sectors_count);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ if (devp->state == FLASH_ERASE) {
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* Bus acquired.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* FLASH_ERASE state while the operation is performed.*/
+ devp->state = FLASH_ERASE;
+
+ /* Enabling write operation.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
+
+ /* Sector erase command.*/
+ jesd216_cmd_addr(devp->config->busp, M25Q_CMD_SECTOR_ERASE, offset);
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return FLASH_NO_ERROR;
+}
+
+static flash_error_t m25q_verify_erase(void *instance,
+ flash_sector_t sector) {
+ M25QDriver *devp = (M25QDriver *)instance;
+ uint8_t cmpbuf[M25Q_COMPARE_BUFFER_SIZE];
+ flash_offset_t offset;
+ size_t n;
+
+ osalDbgCheck(instance != NULL);
+ osalDbgCheck(sector < m25q_descriptor.sectors_count);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ if (devp->state == FLASH_ERASE) {
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* Bus acquired.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* FLASH_READY state while the operation is performed.*/
+ devp->state = FLASH_READ;
+
+ /* Read command.*/
+ offset = (flash_offset_t)(sector * SECTOR_SIZE);
+ n = SECTOR_SIZE;
+ while (n > 0U) {
+ uint8_t *p;
+
+#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
+ jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
+ offset, M25Q_READ_DUMMY_CYCLES,
+ sizeof cmpbuf, cmpbuf);
+#else
+ /* Normal read command in SPI mode.*/
+ jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
+ offset, sizeof cmpbuf, cmpbuf);
+#endif
+
+ /* Checking for erased state of current buffer.*/
+ for (p = cmpbuf; p < &cmpbuf[M25Q_COMPARE_BUFFER_SIZE]; p++) {
+ if (*p != 0xFFU) {
+ /* Ready state again.*/
+ devp->state = FLASH_READY;
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return FLASH_ERROR_VERIFY;
+ }
+ }
+
+ offset += sizeof cmpbuf;
+ n -= sizeof cmpbuf;
+ }
+
+ /* Ready state again.*/
+ devp->state = FLASH_READY;
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ return FLASH_NO_ERROR;
+}
+
+static flash_error_t m25q_query_erase(void *instance, uint32_t *msec) {
+ M25QDriver *devp = (M25QDriver *)instance;
+ uint8_t sts;
+
+ osalDbgCheck(instance != NULL);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ /* If there is an erase in progress then the device must be checked.*/
+ if (devp->state == FLASH_ERASE) {
+
+ /* Bus acquired.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* Read status command.*/
+ jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
+ 1, &sts);
+
+ /* If the P/E bit is zero (busy) or the flash in a suspended state then
+ report that the operation is still in progress.*/
+ if (((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U) ||
+ ((sts & M25Q_FLAGS_ERASE_SUSPEND) != 0U)) {
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+
+ /* Recommended time before polling again, this is a simplified
+ implementation.*/
+ if (msec != NULL) {
+ *msec = 1U;
+ }
+
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* The device is ready to accept commands.*/
+ devp->state = FLASH_READY;
+
+ /* Checking for errors.*/
+ if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
+
+ /* Clearing status register.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
+
+ /* Erase operation failed.*/
+ return FLASH_ERROR_ERASE;
+ }
+
+ /* Bus released.*/
+ jesd216_bus_release(devp->config->busp);
+ }
+
+ return FLASH_NO_ERROR;
+}
+
+static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
+ size_t n, uint8_t *rp) {
+
+ (void)instance;
+ (void)rp;
+ (void)offset;
+ (void)n;
+
+ return FLASH_NO_ERROR;
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initializes an instance.
+ *
+ * @param[out] devp pointer to the @p M25QDriver object
+ *
+ * @init
+ */
+void m25qObjectInit(M25QDriver *devp) {
+
+ osalDbgCheck(devp != NULL);
+
+ devp->vmt = &m25q_vmt;
+ devp->state = FLASH_STOP;
+ devp->config = NULL;
+}
+
+/**
+ * @brief Configures and activates N25Q128 driver.
+ *
+ * @param[in] devp pointer to the @p M25QDriver object
+ * @param[in] config pointer to the configuration
+ *
+ * @api
+ */
+void m25qStart(M25QDriver *devp, const M25QConfig *config) {
+
+ osalDbgCheck((devp != NULL) && (config != NULL));
+ osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
+
+ devp->config = config;
+
+ if (devp->state == FLASH_STOP) {
+
+ /* Bus acquisition.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_SPI
+ /* Reading device ID.*/
+ jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_ID,
+ sizeof devp->device_id, devp->device_id);
+
+#else /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
+ /* Attempting a reset of the XIP mode, it could be in an unexpected state
+ because a CPU reset does not reset the memory too.*/
+ m25q_reset_xip(devp);
+
+ /* Attempting a eeset of the device, it could be in an unexpected state
+ because a CPU reset does not reset the memory too.*/
+ m25q_reset_memory(devp);
+
+ /* Reading device ID and unique ID.*/
+ qspiReceive(devp->config->busp, &m25q_cmd_read_id,
+ sizeof devp->device_id, devp->device_id);
+#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
+
+ /* Checking if the device is white listed.*/
+ osalDbgAssert(m25q_find_id(m25q_manufacturer_ids,
+ sizeof m25q_manufacturer_ids,
+ devp->device_id[0]),
+ "invalid manufacturer id");
+ osalDbgAssert(m25q_find_id(m25q_memory_type_ids,
+ sizeof m25q_memory_type_ids,
+ devp->device_id[1]),
+ "invalid memory type id");
+
+#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)
+ /* Setting up final bus width.*/
+ qspiCommand(devp->config->busp, &m25q_cmd_write_enable);
+ qspiSend(devp->config->busp, &m25q_cmd_write_evconf, 1, m25q_evconf_value);
+
+ {
+ uint8_t id[3];
+
+ /* Reading ID again for confirmation.*/
+ jesd216_cmd_receive(devp->config->busp, M25Q_CMD_MULTIPLE_IO_READ_ID,
+ 3, id);
+
+ /* Checking if the device is white listed.*/
+ osalDbgAssert(memcmp(id, devp->device_id, 3) == 0,
+ "id confirmation failed");
+ }
+#endif
+
+ /* Setting up the device size.*/
+ m25q_descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) /
+ SECTOR_SIZE;
+
+#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI)
+ {
+ static const uint8_t flash_conf[1] = {
+ (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
+ };
+
+ /* Setting up the dummy cycles to be used for fast read operations.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
+ jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
+ 1, flash_conf);
+ }
+#endif
+
+ /* Driver in ready state.*/
+ devp->state = FLASH_READY;
+
+ /* Bus release.*/
+ jesd216_bus_release(devp->config->busp);
+ }
+}
+
+/**
+ * @brief Deactivates the N25Q128 driver.
+ *
+ * @param[in] devp pointer to the @p M25QDriver object
+ *
+ * @api
+ */
+void m25qStop(M25QDriver *devp) {
+
+ osalDbgCheck(devp != NULL);
+ osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
+
+ if (devp->state != FLASH_STOP) {
+
+ /* Bus acquisition.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* Stopping bus device.*/
+ jesd216_stop(devp->config->busp);
+
+ /* Deleting current configuration.*/
+ devp->config = NULL;
+
+ /* Driver stopped.*/
+ devp->state = FLASH_STOP;
+
+ /* Bus release.*/
+ jesd216_bus_release(devp->config->busp);
+ }
+}
+
+#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
+#if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Enters the memory Mapping mode.
+ * @details The memory mapping mode is only available when the QSPI mode
+ * is selected and the underlying QSPI controller supports the
+ * feature.
+ *
+ * @param[in] devp pointer to the @p M25QDriver object
+ * @param[out] addrp pointer to the memory start address of the mapped
+ * flash or @p NULL
+ *
+ * @api
+ */
+void m25qMemoryMap(M25QDriver *devp, uint8_t **addrp) {
+ static const uint8_t flash_status_xip[1] = {
+ (M25Q_READ_DUMMY_CYCLES << 4U) | 0x07U
+ };
+ qspi_command_t cmd;
+
+ /* Bus acquisition.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ /* Activating XIP mode in the device.*/
+ jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
+ jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
+ 1, flash_status_xip);
+
+ /* Putting the QSPI driver in memory mapped mode.*/
+ cmd.cfg = QSPI_CFG_CMD(M25Q_CMD_FAST_READ) |
+ QSPI_CFG_ADDR_SIZE_24 |
+#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_ADDR_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE |
+#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
+ QSPI_CFG_CMD_MODE_TWO_LINES |
+ QSPI_CFG_ADDR_MODE_TWO_LINES |
+ QSPI_CFG_DATA_MODE_TWO_LINES |
+#else
+ QSPI_CFG_CMD_MODE_FOUR_LINES |
+ QSPI_CFG_ADDR_MODE_FOUR_LINES |
+ QSPI_CFG_DATA_MODE_FOUR_LINES |
+#endif
+ QSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/
+ QSPI_CFG_ALT_SIZE_8 |
+ QSPI_CFG_SIOO |
+ QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
+
+ qspiMapFlash(devp->config->busp, &cmd, addrp);
+
+ /* Bus release.*/
+ jesd216_bus_release(devp->config->busp);
+}
+
+/**
+ * @brief Leaves the memory Mapping mode.
+ *
+ * @param[in] devp pointer to the @p M25QDriver object
+ *
+ * @api
+ */
+void m25qMemoryUnmap(M25QDriver *devp) {
+
+ /* Bus acquisition.*/
+ jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
+
+ qspiUnmapFlash(devp->config->busp);
+
+ m25q_reset_xip(devp);
+
+ /* Bus release.*/
+ jesd216_bus_release(devp->config->busp);
+}
+#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
+#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
+
+/** @} */
diff --git a/os/ex/Micron/m25q.h b/os/ex/Micron/m25q.h
index 230df9814..0a5a6f31b 100644
--- a/os/ex/Micron/m25q.h
+++ b/os/ex/Micron/m25q.h
@@ -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 */
+
+/** @} */
+
diff --git a/os/ex/ST/l3gd20.c b/os/ex/ST/l3gd20.c
index d36399d91..3e9c93640 100644
--- a/os/ex/ST/l3gd20.c
+++ b/os/ex/ST/l3gd20.c
@@ -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;
+}
+/** @} */
diff --git a/os/ex/ST/l3gd20.h b/os/ex/ST/l3gd20.h
index f798d0c25..5e7011a76 100644
--- a/os/ex/ST/l3gd20.h
+++ b/os/ex/ST/l3gd20.h
@@ -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_ */
+
+/** @} */
+
diff --git a/os/ex/ST/lis302dl.c b/os/ex/ST/lis302dl.c
index 0a76a39db..32b347929 100644
--- a/os/ex/ST/lis302dl.c
+++ b/os/ex/ST/lis302dl.c
@@ -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;
+}
+/** @} */
diff --git a/os/ex/ST/lis302dl.h b/os/ex/ST/lis302dl.h
index baa513205..e4c175029 100644
--- a/os/ex/ST/lis302dl.h
+++ b/os/ex/ST/lis302dl.h
@@ -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_ */
+
+/** @} */
+
diff --git a/os/ex/ST/lis3dsh.c b/os/ex/ST/lis3dsh.c
index c28f60304..cdf4d9754 100644
--- a/os/ex/ST/lis3dsh.c
+++ b/os/ex/ST/lis3dsh.c
@@ -1,614 +1,614 @@
-/*
- 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.c
- * @brief LIS3DSH MEMS interface module code.
- *
- * @addtogroup lis3dsh
- * @{
- */
-
-#include "hal.h"
-#include "lis3dsh.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#define LIS3DSH_SENS_2G ((float)0.06f)
-#define LIS3DSH_SENS_4G ((float)0.12f)
-#define LIS3DSH_SENS_6G ((float)0.18f)
-#define LIS3DSH_SENS_8G ((float)0.24f)
-#define LIS3DSH_SENS_16G ((float)0.73f)
-
-#define LIS3DSH_DI ((uint8_t)0xFF)
-#define LIS3DSH_DI_0 ((uint8_t)0x01)
-#define LIS3DSH_DI_1 ((uint8_t)0x02)
-#define LIS3DSH_DI_2 ((uint8_t)0x04)
-#define LIS3DSH_DI_3 ((uint8_t)0x08)
-#define LIS3DSH_DI_4 ((uint8_t)0x10)
-#define LIS3DSH_DI_5 ((uint8_t)0x20)
-#define LIS3DSH_DI_6 ((uint8_t)0x40)
-#define LIS3DSH_DI_7 ((uint8_t)0x80)
-
-#define LIS3DSH_AD ((uint8_t)0x3F)
-#define LIS3DSH_AD_0 ((uint8_t)0x01)
-#define LIS3DSH_AD_1 ((uint8_t)0x02)
-#define LIS3DSH_AD_2 ((uint8_t)0x04)
-#define LIS3DSH_AD_3 ((uint8_t)0x08)
-#define LIS3DSH_AD_4 ((uint8_t)0x10)
-#define LIS3DSH_AD_5 ((uint8_t)0x20)
-
-#define LIS3DSH_MS ((uint8_t)0x40)
-#define LIS3DSH_RW ((uint8_t)0x80)
-
-#define LIS3DSH_AD_INFO1 ((uint8_t)0x0D)
-#define LIS3DSH_AD_INFO2 ((uint8_t)0x0E)
-#define LIS3DSH_AD_WHO_AM_I ((uint8_t)0x0F)
-#define LIS3DSH_AD_CTRL_REG3 ((uint8_t)0x23)
-#define LIS3DSH_AD_CTRL_REG4 ((uint8_t)0x20)
-#define LIS3DSH_AD_CTRL_REG5 ((uint8_t)0x24)
-#define LIS3DSH_AD_CTRL_REG6 ((uint8_t)0x25)
-#define LIS3DSH_AD_STATUS ((uint8_t)0x27)
-#define LIS3DSH_AD_OUT_T ((uint8_t)0x0C)
-#define LIS3DSH_AD_OFF_X ((uint8_t)0x10)
-#define LIS3DSH_AD_OFF_Y ((uint8_t)0x11)
-#define LIS3DSH_AD_OFF_Z ((uint8_t)0x12)
-#define LIS3DSH_AD_CS_X ((uint8_t)0x13)
-#define LIS3DSH_AD_CS_Y ((uint8_t)0x14)
-#define LIS3DSH_AD_CS_Z ((uint8_t)0x15)
-#define LIS3DSH_AD_LC_L ((uint8_t)0x16)
-#define LIS3DSH_AD_LC_H ((uint8_t)0x17)
-#define LIS3DSH_AD_STAT ((uint8_t)0x18)
-#define LIS3DSH_AD_VFC_1 ((uint8_t)0x1B)
-#define LIS3DSH_AD_VFC_2 ((uint8_t)0x1C)
-#define LIS3DSH_AD_VFC_3 ((uint8_t)0x1D)
-#define LIS3DSH_AD_VFC_4 ((uint8_t)0x1E)
-#define LIS3DSH_AD_THRS3 ((uint8_t)0x1F)
-#define LIS3DSH_AD_OUT_X_L ((uint8_t)0x28)
-#define LIS3DSH_AD_OUT_X_H ((uint8_t)0x29)
-#define LIS3DSH_AD_OUT_Y_L ((uint8_t)0x2A)
-#define LIS3DSH_AD_OUT_Y_H ((uint8_t)0x2B)
-#define LIS3DSH_AD_OUT_Z_L ((uint8_t)0x2C)
-#define LIS3DSH_AD_OUT_Z_H ((uint8_t)0x2D)
-#define LIS3DSH_AD_FIFO_CTRL ((uint8_t)0x2E)
-#define LIS3DSH_AD_FIFO_SRC ((uint8_t)0x2F)
-#define LIS3DSH_AD_CTRL_REG1 ((uint8_t)0x21)
-#define LIS3DSH_AD_ST1_0 ((uint8_t)0x40)
-#define LIS3DSH_AD_ST1_1 ((uint8_t)0x41)
-#define LIS3DSH_AD_ST1_2 ((uint8_t)0x42)
-#define LIS3DSH_AD_ST1_3 ((uint8_t)0x43)
-#define LIS3DSH_AD_ST1_4 ((uint8_t)0x44)
-#define LIS3DSH_AD_ST1_5 ((uint8_t)0x45)
-#define LIS3DSH_AD_ST1_6 ((uint8_t)0x46)
-#define LIS3DSH_AD_ST1_7 ((uint8_t)0x47)
-#define LIS3DSH_AD_ST1_8 ((uint8_t)0x48)
-#define LIS3DSH_AD_ST1_9 ((uint8_t)0x49)
-#define LIS3DSH_AD_ST1_A ((uint8_t)0x4A)
-#define LIS3DSH_AD_ST1_B ((uint8_t)0x4B)
-#define LIS3DSH_AD_ST1_C ((uint8_t)0x4C)
-#define LIS3DSH_AD_ST1_D ((uint8_t)0x4D)
-#define LIS3DSH_AD_ST1_E ((uint8_t)0x4E)
-#define LIS3DSH_AD_ST1_F ((uint8_t)0x4F)
-#define LIS3DSH_AD_TIM4_1 ((uint8_t)0x50)
-#define LIS3DSH_AD_TIM3_1 ((uint8_t)0x51)
-#define LIS3DSH_AD_TIM2_1_L ((uint8_t)0x52)
-#define LIS3DSH_AD_TIM2_1_H ((uint8_t)0x53)
-#define LIS3DSH_AD_TIM1_1_L ((uint8_t)0x54)
-#define LIS3DSH_AD_TIM1_1_H ((uint8_t)0x55)
-#define LIS3DSH_AD_THRS2_1 ((uint8_t)0x56)
-#define LIS3DSH_AD_THRS1_1 ((uint8_t)0x57)
-#define LIS3DSH_AD_MASK1_B ((uint8_t)0x59)
-#define LIS3DSH_AD_MASK1_A ((uint8_t)0x5A)
-#define LIS3DSH_AD_SETT1 ((uint8_t)0x5B)
-#define LIS3DSH_AD_PR1 ((uint8_t)0x5C)
-#define LIS3DSH_AD_TC1_L ((uint8_t)0x5D)
-#define LIS3DSH_AD_TC1_H ((uint8_t)0x5E)
-#define LIS3DSH_AD_OUTS1 ((uint8_t)0x5F)
-#define LIS3DSH_AD_PEAK1 ((uint8_t)0x19)
-#define LIS3DSH_AD_CTRL_REG2 ((uint8_t)0x22)
-#define LIS3DSH_AD_ST2_0 ((uint8_t)0x60)
-#define LIS3DSH_AD_ST2_1 ((uint8_t)0x61)
-#define LIS3DSH_AD_ST2_2 ((uint8_t)0x62)
-#define LIS3DSH_AD_ST2_3 ((uint8_t)0x63)
-#define LIS3DSH_AD_ST2_4 ((uint8_t)0x64)
-#define LIS3DSH_AD_ST2_5 ((uint8_t)0x65)
-#define LIS3DSH_AD_ST2_6 ((uint8_t)0x66)
-#define LIS3DSH_AD_ST2_7 ((uint8_t)0x67)
-#define LIS3DSH_AD_ST2_8 ((uint8_t)0x68)
-#define LIS3DSH_AD_ST2_9 ((uint8_t)0x69)
-#define LIS3DSH_AD_ST2_A ((uint8_t)0x6A)
-#define LIS3DSH_AD_ST2_B ((uint8_t)0x6B)
-#define LIS3DSH_AD_ST2_C ((uint8_t)0x6C)
-#define LIS3DSH_AD_ST2_D ((uint8_t)0x6D)
-#define LIS3DSH_AD_ST2_E ((uint8_t)0x6E)
-#define LIS3DSH_AD_ST2_F ((uint8_t)0x6F)
-#define LIS3DSH_AD_TIM4_2 ((uint8_t)0x70)
-#define LIS3DSH_AD_TIM3_2 ((uint8_t)0x71)
-#define LIS3DSH_AD_TIM2_2_L ((uint8_t)0x72)
-#define LIS3DSH_AD_TIM2_2_H ((uint8_t)0x73)
-#define LIS3DSH_AD_TIM1_2_L ((uint8_t)0x74)
-#define LIS3DSH_AD_TIM1_2_H ((uint8_t)0x75)
-#define LIS3DSH_AD_THRS2_2 ((uint8_t)0x76)
-#define LIS3DSH_AD_THRS1_2 ((uint8_t)0x77)
-#define LIS3DSH_AD_MASK2_B ((uint8_t)0x79)
-#define LIS3DSH_AD_MASK2_A ((uint8_t)0x7A)
-#define LIS3DSH_AD_SETT2 ((uint8_t)0x7B)
-#define LIS3DSH_AD_PR2 ((uint8_t)0x7C)
-#define LIS3DSH_AD_TC2_L ((uint8_t)0x7D)
-#define LIS3DSH_AD_TC2_H ((uint8_t)0x7E)
-#define LIS3DSH_AD_OUTS2 ((uint8_t)0x7F)
-#define LIS3DSH_AD_PEAK2 ((uint8_t)0x1A)
-#define LIS3DSH_AD_DES2 ((uint8_t)0x78)
-
-#define LIS3DSH_CTRL_REG5_FS_MASK ((uint8_t)0x38)
-#define TO_G ((float)0.001f)
-#define TO_SI ((float)0.00981f)
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if (LIS3DSH_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 lis3dshSPIReadRegister(SPIDriver *spip, uint8_t reg) {
- uint8_t txbuf[2] = {LIS3DSH_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 lis3dshSPIWriteRegister(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, "lis3dshSPIWriteRegister(), reserved register");
- case LIS3DSH_AD_INFO1:
- case LIS3DSH_AD_INFO2:
- case LIS3DSH_AD_WHO_AM_I:
- case LIS3DSH_AD_STATUS:
- case LIS3DSH_AD_OUT_T:
- case LIS3DSH_AD_STAT:
- case LIS3DSH_AD_OUT_X_L:
- case LIS3DSH_AD_OUT_X_H:
- case LIS3DSH_AD_OUT_Y_L:
- case LIS3DSH_AD_OUT_Y_H:
- case LIS3DSH_AD_OUT_Z_L:
- case LIS3DSH_AD_OUT_Z_H:
- case LIS3DSH_AD_FIFO_SRC:
- case LIS3DSH_AD_FIFO_CTRL:
- case LIS3DSH_AD_PR1:
- case LIS3DSH_AD_TC1_L:
- case LIS3DSH_AD_TC1_H:
- case LIS3DSH_AD_OUTS1:
- case LIS3DSH_AD_PEAK1:
- case LIS3DSH_AD_PR2:
- case LIS3DSH_AD_TC2_L:
- case LIS3DSH_AD_TC2_H:
- case LIS3DSH_AD_OUTS2:
- case LIS3DSH_AD_PEAK2:
- /* Read only registers cannot be written, the command is ignored.*/
- return;
- case LIS3DSH_AD_CTRL_REG3:
- case LIS3DSH_AD_CTRL_REG4:
- case LIS3DSH_AD_CTRL_REG5:
- case LIS3DSH_AD_CTRL_REG6:
- case LIS3DSH_AD_OFF_X:
- case LIS3DSH_AD_OFF_Y:
- case LIS3DSH_AD_OFF_Z:
- case LIS3DSH_AD_CS_X:
- case LIS3DSH_AD_CS_Y:
- case LIS3DSH_AD_CS_Z:
- case LIS3DSH_AD_LC_L:
- case LIS3DSH_AD_LC_H:
- case LIS3DSH_AD_VFC_1:
- case LIS3DSH_AD_VFC_2:
- case LIS3DSH_AD_VFC_3:
- case LIS3DSH_AD_VFC_4:
- case LIS3DSH_AD_THRS3:
- case LIS3DSH_AD_CTRL_REG1:
- case LIS3DSH_AD_ST1_0:
- case LIS3DSH_AD_ST1_1:
- case LIS3DSH_AD_ST1_2:
- case LIS3DSH_AD_ST1_3:
- case LIS3DSH_AD_ST1_4:
- case LIS3DSH_AD_ST1_5:
- case LIS3DSH_AD_ST1_6:
- case LIS3DSH_AD_ST1_7:
- case LIS3DSH_AD_ST1_8:
- case LIS3DSH_AD_ST1_9:
- case LIS3DSH_AD_ST1_A:
- case LIS3DSH_AD_ST1_B:
- case LIS3DSH_AD_ST1_C:
- case LIS3DSH_AD_ST1_D:
- case LIS3DSH_AD_ST1_E:
- case LIS3DSH_AD_ST1_F:
- case LIS3DSH_AD_TIM4_1:
- case LIS3DSH_AD_TIM3_1:
- case LIS3DSH_AD_TIM2_1_L:
- case LIS3DSH_AD_TIM2_1_H:
- case LIS3DSH_AD_TIM1_1_L:
- case LIS3DSH_AD_TIM1_1_H:
- case LIS3DSH_AD_THRS2_1:
- case LIS3DSH_AD_THRS1_1:
- case LIS3DSH_AD_MASK1_B:
- case LIS3DSH_AD_MASK1_A:
- case LIS3DSH_AD_SETT1:
- case LIS3DSH_AD_CTRL_REG2:
- case LIS3DSH_AD_ST2_0:
- case LIS3DSH_AD_ST2_1:
- case LIS3DSH_AD_ST2_2:
- case LIS3DSH_AD_ST2_3:
- case LIS3DSH_AD_ST2_4:
- case LIS3DSH_AD_ST2_5:
- case LIS3DSH_AD_ST2_6:
- case LIS3DSH_AD_ST2_7:
- case LIS3DSH_AD_ST2_8:
- case LIS3DSH_AD_ST2_9:
- case LIS3DSH_AD_ST2_A:
- case LIS3DSH_AD_ST2_B:
- case LIS3DSH_AD_ST2_C:
- case LIS3DSH_AD_ST2_D:
- case LIS3DSH_AD_ST2_E:
- case LIS3DSH_AD_ST2_F:
- case LIS3DSH_AD_TIM4_2:
- case LIS3DSH_AD_TIM3_2:
- case LIS3DSH_AD_TIM2_2_L:
- case LIS3DSH_AD_TIM2_2_H:
- case LIS3DSH_AD_TIM1_2_L:
- case LIS3DSH_AD_TIM1_2_H:
- case LIS3DSH_AD_THRS2_2:
- case LIS3DSH_AD_THRS1_2:
- case LIS3DSH_AD_MASK2_B:
- case LIS3DSH_AD_MASK2_A:
- case LIS3DSH_AD_SETT2:
- case LIS3DSH_AD_DES2:
- spiSelect(spip);
- uint8_t txbuf[2] = {reg, value};
- spiSend(spip, 2, txbuf);
- spiUnselect(spip);
- }
-}
-#endif /* LIS3DSH_USE_SPI */
-
-/*
- * Interface implementation.
- */
-static size_t get_axes_number(void *ip) {
-
- osalDbgCheck(ip != NULL);
- return LIS3DSH_NUMBER_OF_AXES;
-}
-
-static msg_t read_raw(void *ip, int32_t axes[LIS3DSH_NUMBER_OF_AXES]) {
- int16_t tmp;
- osalDbgCheck((ip != NULL) && (axes != NULL));
-
- osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
- "read_raw(), invalid state");
-
-#if LIS3DSH_USE_SPI
- osalDbgAssert((((LIS3DSHDriver *)ip)->config->spip->state == SPI_READY),
- "read_raw(), channel not ready");
-#if LIS3DSH_SHARED_SPI
- spiAcquireBus(((LIS3DSHDriver *)ip)->config->spip);
- spiStart(((LIS3DSHDriver *)ip)->config->spip,
- ((LIS3DSHDriver *)ip)->config->spicfg);
-#endif /* LIS3DSH_SHARED_SPI */
- if(((LIS3DSHDriver *)ip)->config->axesenabling & LIS3DSH_AE_X){
- tmp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_X_L);
- tmp += lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_X_H) << 8;
- axes[0] = (int32_t)tmp + ((LIS3DSHDriver *)ip)->bias[0];
- }
- if(((LIS3DSHDriver *)ip)->config->axesenabling & LIS3DSH_AE_Y){
- tmp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_Y_L);
- tmp += lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_Y_H) << 8;
- axes[1] = (int32_t)tmp + ((LIS3DSHDriver *)ip)->bias[1];
- }
- if(((LIS3DSHDriver *)ip)->config->axesenabling & LIS3DSH_AE_Z){
- tmp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_Z_L);
- tmp += lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_Z_H) << 8;
- axes[2] = (int32_t)tmp + ((LIS3DSHDriver *)ip)->bias[2];
- }
-#if LIS3DSH_SHARED_SPI
- spiReleaseBus(((LIS3DSHDriver *)ip)->config->spip);
-#endif /* LIS3DSH_SHARED_SPI */
-#endif /* LIS3DSH_USE_SPI */
- return MSG_OK;
-}
-
-static msg_t read_cooked(void *ip, float axes[]) {
- uint32_t i;
- int32_t raw[LIS3DSH_NUMBER_OF_AXES];
- msg_t msg;
-
- osalDbgCheck((ip != NULL) && (axes != NULL));
-
- osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
- "read_cooked(), invalid state");
-
- msg = read_raw(ip, raw);
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES ; i++){
- axes[i] = raw[i] * ((LIS3DSHDriver *)ip)->sensitivity[i];
- if(((LIS3DSHDriver *)ip)->config->unit == LIS3DSH_ACC_UNIT_G){
- axes[i] *= TO_G;
- }
- else if(((LIS3DSHDriver *)ip)->config->unit == LIS3DSH_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((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY) ||
- (((LIS3DSHDriver *)ip)->state == LIS3DSH_STOP),
- "set_bias(), invalid state");
-
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++) {
- ((LIS3DSHDriver *)ip)->bias[i] = bp[i];
- }
- return MSG_OK;
-}
-
-static msg_t reset_bias(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY) ||
- (((LIS3DSHDriver *)ip)->state == LIS3DSH_STOP),
- "reset_bias(), invalid state");
-
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- ((LIS3DSHDriver *)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((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
- "set_sensivity(), invalid state");
-
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++) {
- ((LIS3DSHDriver *)ip)->sensitivity[i] = sp[i];
- }
- return MSG_OK;
-}
-
-static msg_t reset_sensivity(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
- "reset_sensivity(), invalid state");
-
- if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_2G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_2G;
- else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_4G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_4G;
- else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_6G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_6G;
- else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_8G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_8G;
- else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_16G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_16G;
- else {
- osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
- return MSG_RESET;
- }
- return MSG_OK;
-}
-
-static msg_t get_temperature(void *ip, int8_t* tempp) {
-#if LIS3DSH_USE_SPI
- osalDbgAssert((((LIS3DSHDriver *)ip)->config->spip->state == SPI_READY),
- "read_raw(), channel not ready");
-#if LIS3DSH_SHARED_SPI
- spiAcquireBus(((LIS3DSHDriver *)ip)->config->spip);
- spiStart(((LIS3DSHDriver *)ip)->config->spip,
- ((LIS3DSHDriver *)ip)->config->spicfg);
-#endif /* LIS3DSH_SHARED_SPI */
- *tempp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
- LIS3DSH_AD_OUT_T);
-#if LIS3DSH_SHARED_SPI
- spiReleaseBus(((LIS3DSHDriver *)ip)->config->spip);
-#endif /* LIS3DSH_SHARED_SPI */
-#endif /* LIS3DSH_USE_SPI */
- 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 LIS3DSHVMT vmt_lis3dsh = {
- 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 LIS3DSHDriver object
- *
- * @init
- */
-void lis3dshObjectInit(LIS3DSHDriver *devp) {
- uint32_t i;
- devp->vmt_basesensor = &vmt_basesensor;
- devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
- devp->vmt_lis3dsh = &vmt_lis3dsh;
- devp->config = NULL;
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- devp->bias[i] = 0;
- devp->state = LIS3DSH_STOP;
-}
-
-/**
- * @brief Configures and activates LIS3DSH Complex Driver peripheral.
- *
- * @param[in] devp pointer to the @p LIS3DSHDriver object
- * @param[in] config pointer to the @p LIS3DSHConfig object
- *
- * @api
- */
-void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config) {
- uint32_t i;
- osalDbgCheck((devp != NULL) && (config != NULL));
-
- osalDbgAssert((devp->state == LIS3DSH_STOP) || (devp->state == LIS3DSH_READY),
- "lis3dshStart(), invalid state");
-
- devp->config = config;
-
-#if LIS3DSH_USE_SPI
-#if LIS3DSH_SHARED_SPI
- spiAcquireBus((devp)->config->spip);
-#endif /* LIS3DSH_SHARED_SPI */
- spiStart((devp)->config->spip,
- (devp)->config->spicfg);
- lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4,
- devp->config->axesenabling |
- devp->config->blockdataupdate |
- devp->config->outputdatarate);
- lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5,
- devp->config->fullscale |
- devp->config->antialiasing );
-#if LIS3DSH_SHARED_SPI
- spiReleaseBus((devp)->config->spip);
-#endif /* LIS3DSH_SHARED_SPI */
-#endif /* LIS3DSH_USE_SPI */
-
- /* Storing sensitivity information according to full scale value */
- if(devp->config->fullscale == LIS3DSH_FS_2G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- devp->sensitivity[i] = LIS3DSH_SENS_2G;
- else if(devp->config->fullscale == LIS3DSH_FS_4G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- devp->sensitivity[i] = LIS3DSH_SENS_4G;
- else if(devp->config->fullscale == LIS3DSH_FS_6G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- devp->sensitivity[i] = LIS3DSH_SENS_6G;
- else if(devp->config->fullscale == LIS3DSH_FS_8G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- devp->sensitivity[i] = LIS3DSH_SENS_8G;
- else if(devp->config->fullscale == LIS3DSH_FS_16G)
- for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
- devp->sensitivity[i] = LIS3DSH_SENS_16G;
- else {
- osalDbgAssert(FALSE, "lis3dshStart(), accelerometer full scale issue");
- }
- /* This is the Accelerometer transient recovery time */
- osalThreadSleepMilliseconds(10);
-
- devp->state = LIS3DSH_READY;
-}
-
-/**
- * @brief Deactivates the LIS3DSH Complex Driver peripheral.
- *
- * @param[in] devp pointer to the @p LIS3DSHDriver object
- *
- * @api
- */
-void lis3dshStop(LIS3DSHDriver *devp) {
-
- osalDbgCheck(devp != NULL);
-
- osalDbgAssert((devp->state == LIS3DSH_STOP) || (devp->state == LIS3DSH_READY),
- "lis3dshStop(), invalid state");
-
-#if (LIS3DSH_USE_SPI)
- if (devp->state == LIS3DSH_STOP) {
-#if LIS3DSH_SHARED_SPI
- spiAcquireBus((devp)->config->spip);
- spiStart((devp)->config->spip,
- (devp)->config->spicfg);
-#endif /* LIS3DSH_SHARED_SPI */
- lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4,
- LIS3DSH_ODR_PD | LIS3DSH_AE_DISABLED);
- spiStop((devp)->config->spip);
-#if LIS3DSH_SHARED_SPI
- spiReleaseBus((devp)->config->spip);
-#endif /* LIS3DSH_SHARED_SPI */
- }
-#endif /* LIS3DSH_USE_SPI */
- devp->state = LIS3DSH_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 lis3dsh.c
+ * @brief LIS3DSH MEMS interface module code.
+ *
+ * @addtogroup lis3dsh
+ * @{
+ */
+
+#include "hal.h"
+#include "lis3dsh.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define LIS3DSH_SENS_2G ((float)0.06f)
+#define LIS3DSH_SENS_4G ((float)0.12f)
+#define LIS3DSH_SENS_6G ((float)0.18f)
+#define LIS3DSH_SENS_8G ((float)0.24f)
+#define LIS3DSH_SENS_16G ((float)0.73f)
+
+#define LIS3DSH_DI ((uint8_t)0xFF)
+#define LIS3DSH_DI_0 ((uint8_t)0x01)
+#define LIS3DSH_DI_1 ((uint8_t)0x02)
+#define LIS3DSH_DI_2 ((uint8_t)0x04)
+#define LIS3DSH_DI_3 ((uint8_t)0x08)
+#define LIS3DSH_DI_4 ((uint8_t)0x10)
+#define LIS3DSH_DI_5 ((uint8_t)0x20)
+#define LIS3DSH_DI_6 ((uint8_t)0x40)
+#define LIS3DSH_DI_7 ((uint8_t)0x80)
+
+#define LIS3DSH_AD ((uint8_t)0x3F)
+#define LIS3DSH_AD_0 ((uint8_t)0x01)
+#define LIS3DSH_AD_1 ((uint8_t)0x02)
+#define LIS3DSH_AD_2 ((uint8_t)0x04)
+#define LIS3DSH_AD_3 ((uint8_t)0x08)
+#define LIS3DSH_AD_4 ((uint8_t)0x10)
+#define LIS3DSH_AD_5 ((uint8_t)0x20)
+
+#define LIS3DSH_MS ((uint8_t)0x40)
+#define LIS3DSH_RW ((uint8_t)0x80)
+
+#define LIS3DSH_AD_INFO1 ((uint8_t)0x0D)
+#define LIS3DSH_AD_INFO2 ((uint8_t)0x0E)
+#define LIS3DSH_AD_WHO_AM_I ((uint8_t)0x0F)
+#define LIS3DSH_AD_CTRL_REG3 ((uint8_t)0x23)
+#define LIS3DSH_AD_CTRL_REG4 ((uint8_t)0x20)
+#define LIS3DSH_AD_CTRL_REG5 ((uint8_t)0x24)
+#define LIS3DSH_AD_CTRL_REG6 ((uint8_t)0x25)
+#define LIS3DSH_AD_STATUS ((uint8_t)0x27)
+#define LIS3DSH_AD_OUT_T ((uint8_t)0x0C)
+#define LIS3DSH_AD_OFF_X ((uint8_t)0x10)
+#define LIS3DSH_AD_OFF_Y ((uint8_t)0x11)
+#define LIS3DSH_AD_OFF_Z ((uint8_t)0x12)
+#define LIS3DSH_AD_CS_X ((uint8_t)0x13)
+#define LIS3DSH_AD_CS_Y ((uint8_t)0x14)
+#define LIS3DSH_AD_CS_Z ((uint8_t)0x15)
+#define LIS3DSH_AD_LC_L ((uint8_t)0x16)
+#define LIS3DSH_AD_LC_H ((uint8_t)0x17)
+#define LIS3DSH_AD_STAT ((uint8_t)0x18)
+#define LIS3DSH_AD_VFC_1 ((uint8_t)0x1B)
+#define LIS3DSH_AD_VFC_2 ((uint8_t)0x1C)
+#define LIS3DSH_AD_VFC_3 ((uint8_t)0x1D)
+#define LIS3DSH_AD_VFC_4 ((uint8_t)0x1E)
+#define LIS3DSH_AD_THRS3 ((uint8_t)0x1F)
+#define LIS3DSH_AD_OUT_X_L ((uint8_t)0x28)
+#define LIS3DSH_AD_OUT_X_H ((uint8_t)0x29)
+#define LIS3DSH_AD_OUT_Y_L ((uint8_t)0x2A)
+#define LIS3DSH_AD_OUT_Y_H ((uint8_t)0x2B)
+#define LIS3DSH_AD_OUT_Z_L ((uint8_t)0x2C)
+#define LIS3DSH_AD_OUT_Z_H ((uint8_t)0x2D)
+#define LIS3DSH_AD_FIFO_CTRL ((uint8_t)0x2E)
+#define LIS3DSH_AD_FIFO_SRC ((uint8_t)0x2F)
+#define LIS3DSH_AD_CTRL_REG1 ((uint8_t)0x21)
+#define LIS3DSH_AD_ST1_0 ((uint8_t)0x40)
+#define LIS3DSH_AD_ST1_1 ((uint8_t)0x41)
+#define LIS3DSH_AD_ST1_2 ((uint8_t)0x42)
+#define LIS3DSH_AD_ST1_3 ((uint8_t)0x43)
+#define LIS3DSH_AD_ST1_4 ((uint8_t)0x44)
+#define LIS3DSH_AD_ST1_5 ((uint8_t)0x45)
+#define LIS3DSH_AD_ST1_6 ((uint8_t)0x46)
+#define LIS3DSH_AD_ST1_7 ((uint8_t)0x47)
+#define LIS3DSH_AD_ST1_8 ((uint8_t)0x48)
+#define LIS3DSH_AD_ST1_9 ((uint8_t)0x49)
+#define LIS3DSH_AD_ST1_A ((uint8_t)0x4A)
+#define LIS3DSH_AD_ST1_B ((uint8_t)0x4B)
+#define LIS3DSH_AD_ST1_C ((uint8_t)0x4C)
+#define LIS3DSH_AD_ST1_D ((uint8_t)0x4D)
+#define LIS3DSH_AD_ST1_E ((uint8_t)0x4E)
+#define LIS3DSH_AD_ST1_F ((uint8_t)0x4F)
+#define LIS3DSH_AD_TIM4_1 ((uint8_t)0x50)
+#define LIS3DSH_AD_TIM3_1 ((uint8_t)0x51)
+#define LIS3DSH_AD_TIM2_1_L ((uint8_t)0x52)
+#define LIS3DSH_AD_TIM2_1_H ((uint8_t)0x53)
+#define LIS3DSH_AD_TIM1_1_L ((uint8_t)0x54)
+#define LIS3DSH_AD_TIM1_1_H ((uint8_t)0x55)
+#define LIS3DSH_AD_THRS2_1 ((uint8_t)0x56)
+#define LIS3DSH_AD_THRS1_1 ((uint8_t)0x57)
+#define LIS3DSH_AD_MASK1_B ((uint8_t)0x59)
+#define LIS3DSH_AD_MASK1_A ((uint8_t)0x5A)
+#define LIS3DSH_AD_SETT1 ((uint8_t)0x5B)
+#define LIS3DSH_AD_PR1 ((uint8_t)0x5C)
+#define LIS3DSH_AD_TC1_L ((uint8_t)0x5D)
+#define LIS3DSH_AD_TC1_H ((uint8_t)0x5E)
+#define LIS3DSH_AD_OUTS1 ((uint8_t)0x5F)
+#define LIS3DSH_AD_PEAK1 ((uint8_t)0x19)
+#define LIS3DSH_AD_CTRL_REG2 ((uint8_t)0x22)
+#define LIS3DSH_AD_ST2_0 ((uint8_t)0x60)
+#define LIS3DSH_AD_ST2_1 ((uint8_t)0x61)
+#define LIS3DSH_AD_ST2_2 ((uint8_t)0x62)
+#define LIS3DSH_AD_ST2_3 ((uint8_t)0x63)
+#define LIS3DSH_AD_ST2_4 ((uint8_t)0x64)
+#define LIS3DSH_AD_ST2_5 ((uint8_t)0x65)
+#define LIS3DSH_AD_ST2_6 ((uint8_t)0x66)
+#define LIS3DSH_AD_ST2_7 ((uint8_t)0x67)
+#define LIS3DSH_AD_ST2_8 ((uint8_t)0x68)
+#define LIS3DSH_AD_ST2_9 ((uint8_t)0x69)
+#define LIS3DSH_AD_ST2_A ((uint8_t)0x6A)
+#define LIS3DSH_AD_ST2_B ((uint8_t)0x6B)
+#define LIS3DSH_AD_ST2_C ((uint8_t)0x6C)
+#define LIS3DSH_AD_ST2_D ((uint8_t)0x6D)
+#define LIS3DSH_AD_ST2_E ((uint8_t)0x6E)
+#define LIS3DSH_AD_ST2_F ((uint8_t)0x6F)
+#define LIS3DSH_AD_TIM4_2 ((uint8_t)0x70)
+#define LIS3DSH_AD_TIM3_2 ((uint8_t)0x71)
+#define LIS3DSH_AD_TIM2_2_L ((uint8_t)0x72)
+#define LIS3DSH_AD_TIM2_2_H ((uint8_t)0x73)
+#define LIS3DSH_AD_TIM1_2_L ((uint8_t)0x74)
+#define LIS3DSH_AD_TIM1_2_H ((uint8_t)0x75)
+#define LIS3DSH_AD_THRS2_2 ((uint8_t)0x76)
+#define LIS3DSH_AD_THRS1_2 ((uint8_t)0x77)
+#define LIS3DSH_AD_MASK2_B ((uint8_t)0x79)
+#define LIS3DSH_AD_MASK2_A ((uint8_t)0x7A)
+#define LIS3DSH_AD_SETT2 ((uint8_t)0x7B)
+#define LIS3DSH_AD_PR2 ((uint8_t)0x7C)
+#define LIS3DSH_AD_TC2_L ((uint8_t)0x7D)
+#define LIS3DSH_AD_TC2_H ((uint8_t)0x7E)
+#define LIS3DSH_AD_OUTS2 ((uint8_t)0x7F)
+#define LIS3DSH_AD_PEAK2 ((uint8_t)0x1A)
+#define LIS3DSH_AD_DES2 ((uint8_t)0x78)
+
+#define LIS3DSH_CTRL_REG5_FS_MASK ((uint8_t)0x38)
+#define TO_G ((float)0.001f)
+#define TO_SI ((float)0.00981f)
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if (LIS3DSH_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 lis3dshSPIReadRegister(SPIDriver *spip, uint8_t reg) {
+ uint8_t txbuf[2] = {LIS3DSH_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 lis3dshSPIWriteRegister(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, "lis3dshSPIWriteRegister(), reserved register");
+ case LIS3DSH_AD_INFO1:
+ case LIS3DSH_AD_INFO2:
+ case LIS3DSH_AD_WHO_AM_I:
+ case LIS3DSH_AD_STATUS:
+ case LIS3DSH_AD_OUT_T:
+ case LIS3DSH_AD_STAT:
+ case LIS3DSH_AD_OUT_X_L:
+ case LIS3DSH_AD_OUT_X_H:
+ case LIS3DSH_AD_OUT_Y_L:
+ case LIS3DSH_AD_OUT_Y_H:
+ case LIS3DSH_AD_OUT_Z_L:
+ case LIS3DSH_AD_OUT_Z_H:
+ case LIS3DSH_AD_FIFO_SRC:
+ case LIS3DSH_AD_FIFO_CTRL:
+ case LIS3DSH_AD_PR1:
+ case LIS3DSH_AD_TC1_L:
+ case LIS3DSH_AD_TC1_H:
+ case LIS3DSH_AD_OUTS1:
+ case LIS3DSH_AD_PEAK1:
+ case LIS3DSH_AD_PR2:
+ case LIS3DSH_AD_TC2_L:
+ case LIS3DSH_AD_TC2_H:
+ case LIS3DSH_AD_OUTS2:
+ case LIS3DSH_AD_PEAK2:
+ /* Read only registers cannot be written, the command is ignored.*/
+ return;
+ case LIS3DSH_AD_CTRL_REG3:
+ case LIS3DSH_AD_CTRL_REG4:
+ case LIS3DSH_AD_CTRL_REG5:
+ case LIS3DSH_AD_CTRL_REG6:
+ case LIS3DSH_AD_OFF_X:
+ case LIS3DSH_AD_OFF_Y:
+ case LIS3DSH_AD_OFF_Z:
+ case LIS3DSH_AD_CS_X:
+ case LIS3DSH_AD_CS_Y:
+ case LIS3DSH_AD_CS_Z:
+ case LIS3DSH_AD_LC_L:
+ case LIS3DSH_AD_LC_H:
+ case LIS3DSH_AD_VFC_1:
+ case LIS3DSH_AD_VFC_2:
+ case LIS3DSH_AD_VFC_3:
+ case LIS3DSH_AD_VFC_4:
+ case LIS3DSH_AD_THRS3:
+ case LIS3DSH_AD_CTRL_REG1:
+ case LIS3DSH_AD_ST1_0:
+ case LIS3DSH_AD_ST1_1:
+ case LIS3DSH_AD_ST1_2:
+ case LIS3DSH_AD_ST1_3:
+ case LIS3DSH_AD_ST1_4:
+ case LIS3DSH_AD_ST1_5:
+ case LIS3DSH_AD_ST1_6:
+ case LIS3DSH_AD_ST1_7:
+ case LIS3DSH_AD_ST1_8:
+ case LIS3DSH_AD_ST1_9:
+ case LIS3DSH_AD_ST1_A:
+ case LIS3DSH_AD_ST1_B:
+ case LIS3DSH_AD_ST1_C:
+ case LIS3DSH_AD_ST1_D:
+ case LIS3DSH_AD_ST1_E:
+ case LIS3DSH_AD_ST1_F:
+ case LIS3DSH_AD_TIM4_1:
+ case LIS3DSH_AD_TIM3_1:
+ case LIS3DSH_AD_TIM2_1_L:
+ case LIS3DSH_AD_TIM2_1_H:
+ case LIS3DSH_AD_TIM1_1_L:
+ case LIS3DSH_AD_TIM1_1_H:
+ case LIS3DSH_AD_THRS2_1:
+ case LIS3DSH_AD_THRS1_1:
+ case LIS3DSH_AD_MASK1_B:
+ case LIS3DSH_AD_MASK1_A:
+ case LIS3DSH_AD_SETT1:
+ case LIS3DSH_AD_CTRL_REG2:
+ case LIS3DSH_AD_ST2_0:
+ case LIS3DSH_AD_ST2_1:
+ case LIS3DSH_AD_ST2_2:
+ case LIS3DSH_AD_ST2_3:
+ case LIS3DSH_AD_ST2_4:
+ case LIS3DSH_AD_ST2_5:
+ case LIS3DSH_AD_ST2_6:
+ case LIS3DSH_AD_ST2_7:
+ case LIS3DSH_AD_ST2_8:
+ case LIS3DSH_AD_ST2_9:
+ case LIS3DSH_AD_ST2_A:
+ case LIS3DSH_AD_ST2_B:
+ case LIS3DSH_AD_ST2_C:
+ case LIS3DSH_AD_ST2_D:
+ case LIS3DSH_AD_ST2_E:
+ case LIS3DSH_AD_ST2_F:
+ case LIS3DSH_AD_TIM4_2:
+ case LIS3DSH_AD_TIM3_2:
+ case LIS3DSH_AD_TIM2_2_L:
+ case LIS3DSH_AD_TIM2_2_H:
+ case LIS3DSH_AD_TIM1_2_L:
+ case LIS3DSH_AD_TIM1_2_H:
+ case LIS3DSH_AD_THRS2_2:
+ case LIS3DSH_AD_THRS1_2:
+ case LIS3DSH_AD_MASK2_B:
+ case LIS3DSH_AD_MASK2_A:
+ case LIS3DSH_AD_SETT2:
+ case LIS3DSH_AD_DES2:
+ spiSelect(spip);
+ uint8_t txbuf[2] = {reg, value};
+ spiSend(spip, 2, txbuf);
+ spiUnselect(spip);
+ }
+}
+#endif /* LIS3DSH_USE_SPI */
+
+/*
+ * Interface implementation.
+ */
+static size_t get_axes_number(void *ip) {
+
+ osalDbgCheck(ip != NULL);
+ return LIS3DSH_NUMBER_OF_AXES;
+}
+
+static msg_t read_raw(void *ip, int32_t axes[LIS3DSH_NUMBER_OF_AXES]) {
+ int16_t tmp;
+ osalDbgCheck((ip != NULL) && (axes != NULL));
+
+ osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
+ "read_raw(), invalid state");
+
+#if LIS3DSH_USE_SPI
+ osalDbgAssert((((LIS3DSHDriver *)ip)->config->spip->state == SPI_READY),
+ "read_raw(), channel not ready");
+#if LIS3DSH_SHARED_SPI
+ spiAcquireBus(((LIS3DSHDriver *)ip)->config->spip);
+ spiStart(((LIS3DSHDriver *)ip)->config->spip,
+ ((LIS3DSHDriver *)ip)->config->spicfg);
+#endif /* LIS3DSH_SHARED_SPI */
+ if(((LIS3DSHDriver *)ip)->config->axesenabling & LIS3DSH_AE_X){
+ tmp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_X_L);
+ tmp += lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_X_H) << 8;
+ axes[0] = (int32_t)tmp + ((LIS3DSHDriver *)ip)->bias[0];
+ }
+ if(((LIS3DSHDriver *)ip)->config->axesenabling & LIS3DSH_AE_Y){
+ tmp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_Y_L);
+ tmp += lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_Y_H) << 8;
+ axes[1] = (int32_t)tmp + ((LIS3DSHDriver *)ip)->bias[1];
+ }
+ if(((LIS3DSHDriver *)ip)->config->axesenabling & LIS3DSH_AE_Z){
+ tmp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_Z_L);
+ tmp += lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_Z_H) << 8;
+ axes[2] = (int32_t)tmp + ((LIS3DSHDriver *)ip)->bias[2];
+ }
+#if LIS3DSH_SHARED_SPI
+ spiReleaseBus(((LIS3DSHDriver *)ip)->config->spip);
+#endif /* LIS3DSH_SHARED_SPI */
+#endif /* LIS3DSH_USE_SPI */
+ return MSG_OK;
+}
+
+static msg_t read_cooked(void *ip, float axes[]) {
+ uint32_t i;
+ int32_t raw[LIS3DSH_NUMBER_OF_AXES];
+ msg_t msg;
+
+ osalDbgCheck((ip != NULL) && (axes != NULL));
+
+ osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
+ "read_cooked(), invalid state");
+
+ msg = read_raw(ip, raw);
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES ; i++){
+ axes[i] = raw[i] * ((LIS3DSHDriver *)ip)->sensitivity[i];
+ if(((LIS3DSHDriver *)ip)->config->unit == LIS3DSH_ACC_UNIT_G){
+ axes[i] *= TO_G;
+ }
+ else if(((LIS3DSHDriver *)ip)->config->unit == LIS3DSH_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((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY) ||
+ (((LIS3DSHDriver *)ip)->state == LIS3DSH_STOP),
+ "set_bias(), invalid state");
+
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++) {
+ ((LIS3DSHDriver *)ip)->bias[i] = bp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t reset_bias(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY) ||
+ (((LIS3DSHDriver *)ip)->state == LIS3DSH_STOP),
+ "reset_bias(), invalid state");
+
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ ((LIS3DSHDriver *)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((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
+ "set_sensivity(), invalid state");
+
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++) {
+ ((LIS3DSHDriver *)ip)->sensitivity[i] = sp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t reset_sensivity(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LIS3DSHDriver *)ip)->state == LIS3DSH_READY),
+ "reset_sensivity(), invalid state");
+
+ if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_2G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_2G;
+ else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_4G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_4G;
+ else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_6G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_6G;
+ else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_8G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_8G;
+ else if(((LIS3DSHDriver *)ip)->config->fullscale == LIS3DSH_FS_16G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ ((LIS3DSHDriver *)ip)->sensitivity[i] = LIS3DSH_SENS_16G;
+ else {
+ osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
+ return MSG_RESET;
+ }
+ return MSG_OK;
+}
+
+static msg_t get_temperature(void *ip, int8_t* tempp) {
+#if LIS3DSH_USE_SPI
+ osalDbgAssert((((LIS3DSHDriver *)ip)->config->spip->state == SPI_READY),
+ "read_raw(), channel not ready");
+#if LIS3DSH_SHARED_SPI
+ spiAcquireBus(((LIS3DSHDriver *)ip)->config->spip);
+ spiStart(((LIS3DSHDriver *)ip)->config->spip,
+ ((LIS3DSHDriver *)ip)->config->spicfg);
+#endif /* LIS3DSH_SHARED_SPI */
+ *tempp = lis3dshSPIReadRegister(((LIS3DSHDriver *)ip)->config->spip,
+ LIS3DSH_AD_OUT_T);
+#if LIS3DSH_SHARED_SPI
+ spiReleaseBus(((LIS3DSHDriver *)ip)->config->spip);
+#endif /* LIS3DSH_SHARED_SPI */
+#endif /* LIS3DSH_USE_SPI */
+ 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 LIS3DSHVMT vmt_lis3dsh = {
+ 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 LIS3DSHDriver object
+ *
+ * @init
+ */
+void lis3dshObjectInit(LIS3DSHDriver *devp) {
+ uint32_t i;
+ devp->vmt_basesensor = &vmt_basesensor;
+ devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
+ devp->vmt_lis3dsh = &vmt_lis3dsh;
+ devp->config = NULL;
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ devp->bias[i] = 0;
+ devp->state = LIS3DSH_STOP;
+}
+
+/**
+ * @brief Configures and activates LIS3DSH Complex Driver peripheral.
+ *
+ * @param[in] devp pointer to the @p LIS3DSHDriver object
+ * @param[in] config pointer to the @p LIS3DSHConfig object
+ *
+ * @api
+ */
+void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config) {
+ uint32_t i;
+ osalDbgCheck((devp != NULL) && (config != NULL));
+
+ osalDbgAssert((devp->state == LIS3DSH_STOP) || (devp->state == LIS3DSH_READY),
+ "lis3dshStart(), invalid state");
+
+ devp->config = config;
+
+#if LIS3DSH_USE_SPI
+#if LIS3DSH_SHARED_SPI
+ spiAcquireBus((devp)->config->spip);
+#endif /* LIS3DSH_SHARED_SPI */
+ spiStart((devp)->config->spip,
+ (devp)->config->spicfg);
+ lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4,
+ devp->config->axesenabling |
+ devp->config->blockdataupdate |
+ devp->config->outputdatarate);
+ lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5,
+ devp->config->fullscale |
+ devp->config->antialiasing );
+#if LIS3DSH_SHARED_SPI
+ spiReleaseBus((devp)->config->spip);
+#endif /* LIS3DSH_SHARED_SPI */
+#endif /* LIS3DSH_USE_SPI */
+
+ /* Storing sensitivity information according to full scale value */
+ if(devp->config->fullscale == LIS3DSH_FS_2G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ devp->sensitivity[i] = LIS3DSH_SENS_2G;
+ else if(devp->config->fullscale == LIS3DSH_FS_4G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ devp->sensitivity[i] = LIS3DSH_SENS_4G;
+ else if(devp->config->fullscale == LIS3DSH_FS_6G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ devp->sensitivity[i] = LIS3DSH_SENS_6G;
+ else if(devp->config->fullscale == LIS3DSH_FS_8G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ devp->sensitivity[i] = LIS3DSH_SENS_8G;
+ else if(devp->config->fullscale == LIS3DSH_FS_16G)
+ for(i = 0; i < LIS3DSH_NUMBER_OF_AXES; i++)
+ devp->sensitivity[i] = LIS3DSH_SENS_16G;
+ else {
+ osalDbgAssert(FALSE, "lis3dshStart(), accelerometer full scale issue");
+ }
+ /* This is the Accelerometer transient recovery time */
+ osalThreadSleepMilliseconds(10);
+
+ devp->state = LIS3DSH_READY;
+}
+
+/**
+ * @brief Deactivates the LIS3DSH Complex Driver peripheral.
+ *
+ * @param[in] devp pointer to the @p LIS3DSHDriver object
+ *
+ * @api
+ */
+void lis3dshStop(LIS3DSHDriver *devp) {
+
+ osalDbgCheck(devp != NULL);
+
+ osalDbgAssert((devp->state == LIS3DSH_STOP) || (devp->state == LIS3DSH_READY),
+ "lis3dshStop(), invalid state");
+
+#if (LIS3DSH_USE_SPI)
+ if (devp->state == LIS3DSH_STOP) {
+#if LIS3DSH_SHARED_SPI
+ spiAcquireBus((devp)->config->spip);
+ spiStart((devp)->config->spip,
+ (devp)->config->spicfg);
+#endif /* LIS3DSH_SHARED_SPI */
+ lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4,
+ LIS3DSH_ODR_PD | LIS3DSH_AE_DISABLED);
+ spiStop((devp)->config->spip);
+#if LIS3DSH_SHARED_SPI
+ spiReleaseBus((devp)->config->spip);
+#endif /* LIS3DSH_SHARED_SPI */
+ }
+#endif /* LIS3DSH_USE_SPI */
+ devp->state = LIS3DSH_STOP;
+}
+/** @} */
diff --git a/os/ex/ST/lis3dsh.h b/os/ex/ST/lis3dsh.h
index 1f0ebcd17..9cc202039 100644
--- a/os/ex/ST/lis3dsh.h
+++ b/os/ex/ST/lis3dsh.h
@@ -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_ */
+
+/** @} */
+
diff --git a/os/ex/ST/lis3mdl.c b/os/ex/ST/lis3mdl.c
index 7abcd41e2..659cc29e0 100644
--- a/os/ex/ST/lis3mdl.c
+++ b/os/ex/ST/lis3mdl.c
@@ -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;
+}
+/** @} */
diff --git a/os/ex/ST/lis3mdl.h b/os/ex/ST/lis3mdl.h
index e80579984..3a641b575 100644
--- a/os/ex/ST/lis3mdl.h
+++ b/os/ex/ST/lis3mdl.h
@@ -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_ */
+
+/** @} */
+
diff --git a/os/ex/ST/lsm303dlhc.c b/os/ex/ST/lsm303dlhc.c
index 74cde4caf..ab57cb5d9 100644
--- a/os/ex/ST/lsm303dlhc.c
+++ b/os/ex/ST/lsm303dlhc.c
@@ -1,904 +1,904 @@
-/*
- 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.c
- * @brief LSM303DLHC MEMS interface module code.
- *
- * @addtogroup lsm303dlhc
- * @{
- */
-
-#include "hal.h"
-#include "lsm303dlhc.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#define LSM303DLHC_ACC_SENS_2G ((float)0.0610f)
-#define LSM303DLHC_ACC_SENS_4G ((float)0.1221f)
-#define LSM303DLHC_ACC_SENS_8G ((float)0.2442f)
-#define LSM303DLHC_ACC_SENS_16G ((float)0.4884f)
-
-#define LSM303DLHC_COMP_SENS_XY_1_3GA ((float)1100.0f)
-#define LSM303DLHC_COMP_SENS_XY_1_9GA ((float)855.0f)
-#define LSM303DLHC_COMP_SENS_XY_2_5GA ((float)670.0f)
-#define LSM303DLHC_COMP_SENS_XY_4_0GA ((float)450.0f)
-#define LSM303DLHC_COMP_SENS_XY_4_7GA ((float)400.0f)
-#define LSM303DLHC_COMP_SENS_XY_5_6GA ((float)330.0f)
-#define LSM303DLHC_COMP_SENS_XY_8_1GA ((float)230.0f)
-
-#define LSM303DLHC_COMP_SENS_Z_1_3GA ((float)980.0f)
-#define LSM303DLHC_COMP_SENS_Z_1_9GA ((float)765.0f)
-#define LSM303DLHC_COMP_SENS_Z_2_5GA ((float)600.0f)
-#define LSM303DLHC_COMP_SENS_Z_4_0GA ((float)400.0f)
-#define LSM303DLHC_COMP_SENS_Z_4_7GA ((float)355.0f)
-#define LSM303DLHC_COMP_SENS_Z_5_6GA ((float)295.0f)
-#define LSM303DLHC_COMP_SENS_Z_8_1GA ((float)205.0f)
-
-#define LSM303DLHC_DI ((uint8_t)0xFF)
-#define LSM303DLHC_DI_0 ((uint8_t)0x01)
-#define LSM303DLHC_DI_1 ((uint8_t)0x02)
-#define LSM303DLHC_DI_2 ((uint8_t)0x04)
-#define LSM303DLHC_DI_3 ((uint8_t)0x08)
-#define LSM303DLHC_DI_4 ((uint8_t)0x10)
-#define LSM303DLHC_DI_5 ((uint8_t)0x20)
-#define LSM303DLHC_DI_6 ((uint8_t)0x40)
-#define LSM303DLHC_DI_7 ((uint8_t)0x80)
-
-#define LSM303DLHC_AD_0 ((uint8_t)0x01)
-#define LSM303DLHC_AD_1 ((uint8_t)0x02)
-#define LSM303DLHC_AD_2 ((uint8_t)0x04)
-#define LSM303DLHC_AD_3 ((uint8_t)0x08)
-#define LSM303DLHC_AD_4 ((uint8_t)0x10)
-#define LSM303DLHC_AD_5 ((uint8_t)0x20)
-#define LSM303DLHC_AD_6 ((uint8_t)0x40)
-#define LSM303DLHC_RW ((uint8_t)0x80)
-
-#define LSM303DLHC_AD_ACC_CTRL_REG1 ((uint8_t)0x20)
-#define LSM303DLHC_AD_ACC_CTRL_REG2 ((uint8_t)0x21)
-#define LSM303DLHC_AD_ACC_CTRL_REG3 ((uint8_t)0x22)
-#define LSM303DLHC_AD_ACC_CTRL_REG4 ((uint8_t)0x23)
-#define LSM303DLHC_AD_ACC_CTRL_REG5 ((uint8_t)0x24)
-#define LSM303DLHC_AD_ACC_CTRL_REG6 ((uint8_t)0x25)
-#define LSM303DLHC_AD_ACC_REFERENCE ((uint8_t)0x26)
-#define LSM303DLHC_AD_ACC_STATUS_REG ((uint8_t)0x27)
-#define LSM303DLHC_AD_ACC_OUT_X_L ((uint8_t)0x28)
-#define LSM303DLHC_AD_ACC_OUT_X_H ((uint8_t)0x29)
-#define LSM303DLHC_AD_ACC_OUT_Y_L ((uint8_t)0x2A)
-#define LSM303DLHC_AD_ACC_OUT_Y_H ((uint8_t)0x2B)
-#define LSM303DLHC_AD_ACC_OUT_Z_L ((uint8_t)0x2C)
-#define LSM303DLHC_AD_ACC_OUT_Z_H ((uint8_t)0x2D)
-#define LSM303DLHC_AD_ACC_FIFO_CTRL_REG ((uint8_t)0x2E)
-#define LSM303DLHC_AD_ACC_FIFO_SRC_REG ((uint8_t)0x2F)
-#define LSM303DLHC_AD_ACC_INT1_CFG ((uint8_t)0x30)
-#define LSM303DLHC_AD_ACC_INT1_SRC ((uint8_t)0x31)
-#define LSM303DLHC_AD_ACC_INT1_THS ((uint8_t)0x32)
-#define LSM303DLHC_AD_ACC_INT1_DURATION ((uint8_t)0x33)
-#define LSM303DLHC_AD_ACC_INT2_CFG ((uint8_t)0x34)
-#define LSM303DLHC_AD_ACC_INT2_SRC ((uint8_t)0x35)
-#define LSM303DLHC_AD_ACC_INT2_THS ((uint8_t)0x36)
-#define LSM303DLHC_AD_ACC_INT2_DURATION ((uint8_t)0x37)
-#define LSM303DLHC_AD_ACC_CLICK_CFG ((uint8_t)0x38)
-#define LSM303DLHC_AD_ACC_CLICK_SRC ((uint8_t)0x39)
-#define LSM303DLHC_AD_ACC_CLICK_THS ((uint8_t)0x3A)
-#define LSM303DLHC_AD_ACC_TIME_LIMIT ((uint8_t)0x3B)
-#define LSM303DLHC_AD_ACC_TIME_LATENCY ((uint8_t)0x3C)
-#define LSM303DLHC_AD_ACC_TIME_WINDOW ((uint8_t)0x3D)
-#define LSM303DLHC_AD_COMP_CRA_REG ((uint8_t)0x00)
-#define LSM303DLHC_AD_COMP_CRB_REG ((uint8_t)0x01)
-#define LSM303DLHC_AD_COMP_MR_REG ((uint8_t)0x02)
-#define LSM303DLHC_AD_COMP_OUT_X_H ((uint8_t)0x03)
-#define LSM303DLHC_AD_COMP_OUT_X_L ((uint8_t)0x04)
-#define LSM303DLHC_AD_COMP_OUT_Z_H ((uint8_t)0x05)
-#define LSM303DLHC_AD_COMP_OUT_Z_L ((uint8_t)0x06)
-#define LSM303DLHC_AD_COMP_OUT_Y_H ((uint8_t)0x07)
-#define LSM303DLHC_AD_COMP_OUT_Y_L ((uint8_t)0x08)
-#define LSM303DLHC_AD_COMP_SR_REG ((uint8_t)0x09)
-#define LSM303DLHC_AD_COMP_IRA_REG ((uint8_t)0x0A)
-#define LSM303DLHC_AD_COMP_IRB_REG ((uint8_t)0x0B)
-#define LSM303DLHC_AD_COMP_IRC_REG ((uint8_t)0x0C)
-#define LSM303DLHC_AD_COMP_TEMP_OUT_H ((uint8_t)0x31)
-#define LSM303DLHC_AD_COMP_TEMP_OUT_L ((uint8_t)0x32)
-
-#define LSM303DLHC_ACC_CTRL_REG4_FS_MASK ((uint8_t)0x30)
-#define LSM303DLHC_COMP_CTRL_REGB_FS_MASK ((uint8_t)0xE0)
-
-#define TO_G ((float)0.001f)
-#define TO_SI ((float)0.00981f)
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief Accelerometer Power Mode
- */
-typedef enum {
- LSM303DLHC_ACC_PM_NORMAL = 0x00, /**< Normal mode enabled */
- LSM303DLHC_ACC_PM_LP = 0x08 /**< Low Power mode enabled */
-} lsm303dlhc_acc_pm_t;
-
-/**
- * @brief Accelerometer and Compass Slave Address.
- */
-typedef enum {
- LSM303DLHC_SAD_ACC = 0x19, /**< SAD for accelerometer. */
- LSM303DLHC_SAD_COMP = 0x1E /**< SAD for compass. */
-} lsm303dlhc_sad_t;
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if (LSM303DLHC_USE_I2C) || defined(__DOXYGEN__)
-/**
- * @brief Reads registers value using I2C.
- * @pre The I2C interface must be initialized and the driver started.
- * @note IF_ADD_INC bit must be 1 in CTRL_REG8
- *
- * @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 lsm303dlhcI2CReadRegister(I2CDriver *i2cp, lsm303dlhc_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 lsm303dlhcI2CWriteRegister(I2CDriver *i2cp, lsm303dlhc_sad_t sad, uint8_t reg,
- uint8_t value) {
- uint8_t rxbuf;
- uint8_t txbuf[2];
- if(sad == LSM303DLHC_SAD_ACC) {
- switch (reg) {
- default:
- /* Reserved register must not be written, according to the datasheet
- * this could permanently damage the device.
- */
- osalDbgAssert(FALSE, "lsm303dlhcWriteRegisterI2C(), reserved register");
- case LSM303DLHC_AD_ACC_STATUS_REG:
- case LSM303DLHC_AD_ACC_OUT_X_L:
- case LSM303DLHC_AD_ACC_OUT_X_H:
- case LSM303DLHC_AD_ACC_OUT_Y_L:
- case LSM303DLHC_AD_ACC_OUT_Y_H:
- case LSM303DLHC_AD_ACC_OUT_Z_L:
- case LSM303DLHC_AD_ACC_OUT_Z_H:
- case LSM303DLHC_AD_ACC_FIFO_SRC_REG:
- case LSM303DLHC_AD_ACC_INT1_SRC:
- case LSM303DLHC_AD_ACC_INT2_SRC:
- /* Read only registers cannot be written, the command is ignored.*/
- return MSG_RESET;
- case LSM303DLHC_AD_ACC_CTRL_REG1:
- case LSM303DLHC_AD_ACC_CTRL_REG2:
- case LSM303DLHC_AD_ACC_CTRL_REG3:
- case LSM303DLHC_AD_ACC_CTRL_REG4:
- case LSM303DLHC_AD_ACC_CTRL_REG5:
- case LSM303DLHC_AD_ACC_CTRL_REG6:
- case LSM303DLHC_AD_ACC_REFERENCE:
- case LSM303DLHC_AD_ACC_FIFO_CTRL_REG:
- case LSM303DLHC_AD_ACC_INT1_CFG:
- case LSM303DLHC_AD_ACC_INT1_THS:
- case LSM303DLHC_AD_ACC_INT1_DURATION:
- case LSM303DLHC_AD_ACC_INT2_CFG:
- case LSM303DLHC_AD_ACC_INT2_THS:
- case LSM303DLHC_AD_ACC_INT2_DURATION:
- case LSM303DLHC_AD_ACC_CLICK_CFG:
- case LSM303DLHC_AD_ACC_CLICK_SRC:
- case LSM303DLHC_AD_ACC_CLICK_THS:
- case LSM303DLHC_AD_ACC_TIME_LIMIT:
- case LSM303DLHC_AD_ACC_TIME_LATENCY:
- case LSM303DLHC_AD_ACC_TIME_WINDOW:
- txbuf[0] = reg;
- txbuf[1] = value;
- return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
- break;
- }
- }
- if(sad == LSM303DLHC_SAD_COMP) {
- switch (reg) {
- default:
- /* Reserved register must not be written, according to the datasheet
- * this could permanently damage the device.
- */
- osalDbgAssert(FALSE, "lsm303dlhcWriteRegisterI2C(), reserved register");
- case LSM303DLHC_AD_COMP_OUT_X_H:
- case LSM303DLHC_AD_COMP_OUT_X_L:
- case LSM303DLHC_AD_COMP_OUT_Z_H:
- case LSM303DLHC_AD_COMP_OUT_Z_L:
- case LSM303DLHC_AD_COMP_OUT_Y_H:
- case LSM303DLHC_AD_COMP_OUT_Y_L:
- case LSM303DLHC_AD_COMP_SR_REG:
- case LSM303DLHC_AD_COMP_IRA_REG:
- case LSM303DLHC_AD_COMP_IRB_REG:
- case LSM303DLHC_AD_COMP_IRC_REG:
- case LSM303DLHC_AD_COMP_TEMP_OUT_H:
- case LSM303DLHC_AD_COMP_TEMP_OUT_L:
- /* Read only registers cannot be written, the command is ignored.*/
- return MSG_RESET;
- case LSM303DLHC_AD_COMP_CRA_REG:
- case LSM303DLHC_AD_COMP_CRB_REG:
- case LSM303DLHC_AD_COMP_MR_REG:
- txbuf[0] = reg;
- txbuf[1] = value;
- return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
- break;
- }
- }
- osalDbgAssert(FALSE, "lsm303dlhcWriteRegisterI2C(), wrong SAD");
- return MSG_RESET;
-}
-#endif /* LSM303DLHC_USE_I2C */
-
-/*
- * Interface implementation.
- */
-static size_t acc_get_axes_number(void *ip) {
-
- osalDbgCheck(ip != NULL);
- return LSM303DLHC_ACC_NUMBER_OF_AXES;
-}
-
-static size_t comp_get_axes_number(void *ip) {
-
- osalDbgCheck(ip != NULL);
- return LSM303DLHC_COMP_NUMBER_OF_AXES;
-}
-
-static size_t sens_get_axes_number(void *ip) {
- size_t size = 0;
-
- osalDbgCheck(ip != NULL);
- if (((LSM303DLHCDriver *)ip)->config->acccfg != NULL)
- size += acc_get_axes_number(ip);
- if (((LSM303DLHCDriver *)ip)->config->compcfg != NULL)
- size += comp_get_axes_number(ip);
- return size;
-}
-
-static msg_t acc_read_raw(void *ip, int32_t axes[]) {
- int16_t tmp;
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM303DLHCDriver *)ip)->config->acccfg != NULL));
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "acc_read_raw(), invalid state");
-
-#if LSM303DLHC_USE_I2C
- osalDbgAssert((((LSM303DLHCDriver *)ip)->config->i2cp->state == I2C_READY),
- "acc_read_raw(), channel not ready");
-#if LSM303DLHC_SHARED_I2C
- i2cAcquireBus(((LSM303DLHCDriver *)ip)->config->i2cp);
- i2cStart(((LSM303DLHCDriver *)ip)->config->i2cp,
- ((LSM303DLHCDriver *)ip)->config->i2ccfg);
-#endif /* LSM303DLHC_SHARED_I2C */
- if(((LSM303DLHCDriver *)ip)->config->acccfg->axesenabling & LSM303DLHC_ACC_AE_X){
- tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_OUT_X_L, NULL);
- tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_OUT_X_H, NULL) << 8;
- axes[0] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->accbias[0];
- }
- if(((LSM303DLHCDriver *)ip)->config->acccfg->axesenabling & LSM303DLHC_ACC_AE_Y){
- tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_OUT_Y_L, NULL);
- tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_OUT_Y_H, NULL) << 8;
- axes[1] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->accbias[1];
- }
- if(((LSM303DLHCDriver *)ip)->config->acccfg->axesenabling & LSM303DLHC_ACC_AE_Z){
- tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_OUT_Z_L, NULL);
- tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_OUT_Z_H, NULL) << 8;
- axes[2] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->accbias[2];
- }
-#if LSM303DLHC_SHARED_I2C
- i2cReleaseBus(((LSM303DLHCDriver *)ip)->config->i2cp);
-#endif /* LSM303DLHC_SHARED_I2C */
-#endif /* LSM303DLHC_USE_I2C */
- return MSG_OK;
-}
-
-static msg_t comp_read_raw(void *ip, int32_t axes[]) {
- int16_t tmp;
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM303DLHCDriver *)ip)->config->compcfg != NULL));
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "comp_read_raw(), invalid state");
-
-#if LSM303DLHC_USE_I2C
- osalDbgAssert((((LSM303DLHCDriver *)ip)->config->i2cp->state == I2C_READY),
- "comp_read_raw(), channel not ready");
-#if LSM303DLHC_SHARED_I2C
- i2cAcquireBus(((LSM303DLHCDriver *)ip)->config->i2cp);
- i2cStart(((LSM303DLHCDriver *)ip)->config->i2cp,
- ((LSM303DLHCDriver *)ip)->config->i2ccfg);
-#endif /* LSM303DLHC_SHARED_I2C */
- tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_OUT_X_L, NULL);
- tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_OUT_X_H, NULL) << 8;
- axes[0] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->compbias[0];
-
- tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_OUT_Y_L, NULL);
- tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_OUT_Y_H, NULL) << 8;
- axes[1] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->compbias[1];
-
- tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_OUT_Z_L, NULL);
- tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_OUT_Z_H, NULL) << 8;
- axes[2] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->compbias[2];
-#if LSM303DLHC_SHARED_I2C
- i2cReleaseBus(((LSM303DLHCDriver *)ip)->config->i2cp);
-#endif /* LSM303DLHC_SHARED_I2C */
-#endif /* LSM303DLHC_USE_I2C */
- return MSG_OK;
-}
-
-static msg_t sens_read_raw(void *ip, int32_t axes[]) {
- int32_t* bp = axes;
- msg_t msg;
- if (((LSM303DLHCDriver *)ip)->config->acccfg != NULL) {
- msg = acc_read_raw(ip, bp);
- if(msg != MSG_OK)
- return msg;
- bp += LSM303DLHC_ACC_NUMBER_OF_AXES;
- }
- if (((LSM303DLHCDriver *)ip)->config->compcfg != NULL) {
- msg = comp_read_raw(ip, bp);
- }
- return msg;
-}
-
-static msg_t acc_read_cooked(void *ip, float axes[]) {
- uint32_t i;
- int32_t raw[LSM303DLHC_ACC_NUMBER_OF_AXES];
- msg_t msg;
-
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM303DLHCDriver *)ip)->config->acccfg != NULL));
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "acc_read_cooked(), invalid state");
-
- msg = acc_read_raw(ip, raw);
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES ; i++){
- axes[i] = raw[i] * ((LSM303DLHCDriver *)ip)->accsensitivity[i];
- if(((LSM303DLHCDriver *)ip)->config->acccfg->unit == LSM303DLHC_ACC_UNIT_G){
- axes[i] *= TO_G;
- }
- else if(((LSM303DLHCDriver *)ip)->config->acccfg->unit == LSM303DLHC_ACC_UNIT_SI){
- axes[i] *= TO_SI;
- }
- }
- return msg;
-}
-
-static msg_t comp_read_cooked(void *ip, float axes[]) {
- uint32_t i;
- int32_t raw[LSM303DLHC_COMP_NUMBER_OF_AXES];
- msg_t msg;
-
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM303DLHCDriver *)ip)->config->compcfg != NULL));
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "comp_read_cooked(), invalid state");
-
- msg = comp_read_raw(ip, raw);
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES ; i++){
- axes[i] = raw[i] / ((LSM303DLHCDriver *)ip)->compsensitivity[i];
- }
- return msg;
-}
-
-static msg_t sens_read_cooked(void *ip, float axes[]) {
- float* bp = axes;
- msg_t msg;
- if (((LSM303DLHCDriver *)ip)->config->acccfg != NULL) {
- msg = acc_read_cooked(ip, bp);
- if(msg != MSG_OK)
- return msg;
- bp += LSM303DLHC_ACC_NUMBER_OF_AXES;
- }
- if (((LSM303DLHCDriver *)ip)->config->compcfg != NULL) {
- msg = comp_read_cooked(ip, bp);
- }
- return msg;
-}
-
-static msg_t acc_set_bias(void *ip, int32_t *bp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (bp !=NULL));
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
- (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
- "acc_set_bias(), invalid state");
-
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) {
- ((LSM303DLHCDriver *)ip)->accbias[i] = bp[i];
- }
- return MSG_OK;
-}
-
-static msg_t comp_set_bias(void *ip, int32_t *bp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (bp !=NULL));
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
- (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
- "comp_set_bias(), invalid state");
-
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- ((LSM303DLHCDriver *)ip)->compbias[i] = bp[i];
- }
- return MSG_OK;
-}
-
-static msg_t acc_reset_bias(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
- (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
- "acc_reset_bias(), invalid state");
-
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- ((LSM303DLHCDriver *)ip)->accbias[i] = 0;
- return MSG_OK;
-}
-
-static msg_t comp_reset_bias(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
- (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
- "comp_reset_bias(), invalid state");
-
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++)
- ((LSM303DLHCDriver *)ip)->compbias[i] = 0;
- return MSG_OK;
-}
-
-static msg_t acc_set_sensivity(void *ip, float *sp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (sp !=NULL));
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "acc_set_sensivity(), invalid state");
-
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) {
- ((LSM303DLHCDriver *)ip)->accsensitivity[i] = sp[i];
- }
- return MSG_OK;
-}
-
-static msg_t comp_set_sensivity(void *ip, float *sp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (sp !=NULL));
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "comp_set_sensivity(), invalid state");
-
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = sp[i];
- }
- return MSG_OK;
-}
-
-static msg_t acc_reset_sensivity(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "acc_reset_sensivity(), invalid state");
-
- if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_2G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_2G;
- else if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_4G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_4G;
- else if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_8G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_8G;
- else if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_16G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_16G;
- else {
- osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
- return MSG_RESET;
- }
- return MSG_OK;
-}
-
-static msg_t comp_reset_sensivity(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
- "comp_reset_sensivity(), invalid state");
-
- if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_3_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_3GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_3GA;
- }
- }
- else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_9_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_9GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_9GA;
- }
- }
- else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_2_5_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_2_5GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_2_5GA;
- }
- }
- else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_0_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_0GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_0GA;
- }
- }
- else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_7_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_7GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_7GA;
- }
- }
- else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_5_6_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_5_6GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_5_6GA;
- }
- }
- else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_8_1_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_8_1GA;
- }
- else {
- ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_8_1GA;
- }
- }
- else {
- osalDbgAssert(FALSE, "reset_sensivity(), compass full scale issue");
- return MSG_RESET;
- }
- return MSG_OK;
-}
-
-static const struct BaseSensorVMT vmt_basesensor = {
- sens_get_axes_number, sens_read_raw, sens_read_cooked
-};
-
-static const struct BaseCompassVMT vmt_basecompass = {
- comp_get_axes_number, comp_read_raw, comp_read_cooked,
- comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity
-};
-
-static const struct BaseAccelerometerVMT vmt_baseaccelerometer = {
- acc_get_axes_number, acc_read_raw, acc_read_cooked,
- acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
-};
-
-static const struct LSM303DLHCACCVMT vmt_lsm303dlhcacc = {
- acc_get_axes_number, acc_read_raw, acc_read_cooked,
- acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
-};
-
-static const struct LSM303DLHCCOMPVMT vmt_lsm303dlhccomp = {
- comp_get_axes_number, comp_read_raw, comp_read_cooked,
- comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity
-};
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Initializes an instance.
- *
- * @param[out] devp pointer to the @p LSM303DLHCDriver object
- *
- * @init
- */
-void lsm303dlhcObjectInit(LSM303DLHCDriver *devp) {
- uint32_t i;
- devp->vmt_basesensor = &vmt_basesensor;
- devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
- devp->vmt_basecompass = &vmt_basecompass;
- devp->vmt_lsm303dlhcacc = &vmt_lsm303dlhcacc;
- devp->vmt_lsm303dlhccomp = &vmt_lsm303dlhccomp;
- devp->config = NULL;
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- devp->accbias[i] = 0;
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++)
- devp->compbias[i] = 0;
- devp->state = LSM303DLHC_STOP;
-}
-
-/**
- * @brief Configures and activates LSM303DLHC Complex Driver peripheral.
- *
- * @param[in] devp pointer to the @p LSM303DLHCDriver object
- * @param[in] config pointer to the @p LSM303DLHCConfig object
- *
- * @api
- */
-void lsm303dlhcStart(LSM303DLHCDriver *devp, const LSM303DLHCConfig *config) {
- uint32_t i;
- osalDbgCheck((devp != NULL) && (config != NULL));
-
- osalDbgAssert((devp->state == LSM303DLHC_STOP) || (devp->state == LSM303DLHC_READY),
- "lsm303dlhcStart(), invalid state");
-
- devp->config = config;
-
-#if LSM303DLHC_USE_I2C
-#if LSM303DLHC_SHARED_I2C
- i2cAcquireBus((devp)->config->i2cp);
-#endif /* LSM303DLHC_SHARED_I2C */
- i2cStart((devp)->config->i2cp,
- (devp)->config->i2ccfg);
- if((devp)->config->acccfg != NULL) {
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_CTRL_REG1,
- devp->config->acccfg->axesenabling |
- devp->config->acccfg->outdatarate |
- devp->config->acccfg->lowpower);
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_CTRL_REG4,
- devp->config->acccfg->endianess |
- devp->config->acccfg->fullscale |
- devp->config->acccfg->blockdataupdate |
- devp->config->acccfg->highresmode);
- }
- if((devp)->config->compcfg != NULL) {
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_CRA_REG,
- devp->config->compcfg->outputdatarate);
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_CRB_REG,
- devp->config->compcfg->fullscale);
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_MR_REG,
- devp->config->compcfg->mode);
- }
-#if LSM303DLHC_SHARED_I2C
- i2cReleaseBus((devp)->config->i2cp);
-#endif /* LSM303DLHC_SHARED_I2C */
-#endif /* LSM303DLHC_USE_I2C */
- /* Storing sensitivity information according to full scale value */
- if((devp)->config->acccfg != NULL) {
- if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_2G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_2G;
- else if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_4G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_4G;
- else if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_8G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_8G;
- else if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_16G)
- for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_16G;
- else
- osalDbgAssert(FALSE, "lsm303dlhcStart(), accelerometer full scale issue");
- }
- if((devp)->config->compcfg != NULL) {
- if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_3_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_3GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_3GA;
- }
- }
- else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_9_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_9GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_9GA;
- }
- }
- else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_2_5_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_2_5GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_2_5GA;
- }
- }
- else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_0_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_0GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_0GA;
- }
- }
- else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_7_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_7GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_7GA;
- }
- }
- else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_5_6_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_5_6GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_5_6GA;
- }
- }
- else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_8_1_GA)
- for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
- if(i != 2) {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_8_1GA;
- }
- else {
- devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_8_1GA;
- }
- }
- else
- osalDbgAssert(FALSE, "lsm303dlhcStart(), compass full scale issue");
- }
- /* This is the Compass transient recovery time */
- osalThreadSleepMilliseconds(5);
-
- devp->state = LSM303DLHC_READY;
-}
-
-/**
- * @brief Deactivates the LSM303DLHC Complex Driver peripheral.
- *
- * @param[in] devp pointer to the @p LSM303DLHCDriver object
- *
- * @api
- */
-void lsm303dlhcStop(LSM303DLHCDriver *devp) {
-
- osalDbgCheck(devp != NULL);
-
- osalDbgAssert((devp->state == LSM303DLHC_STOP) || (devp->state == LSM303DLHC_READY),
- "lsm303dlhcStop(), invalid state");
-
-#if (LSM303DLHC_USE_I2C)
- if (devp->state == LSM303DLHC_STOP) {
-#if LSM303DLHC_SHARED_I2C
- i2cAcquireBus((devp)->config->i2cp);
- i2cStart((devp)->config->i2cp,
- (devp)->config->i2ccfg);
-#endif /* LSM303DLHC_SHARED_I2C */
- if((devp)->config->acccfg != NULL) {
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_ACC,
- LSM303DLHC_AD_ACC_CTRL_REG1,
- LSM303DLHC_ACC_AE_DISABLED |
- LSM303DLHC_ACC_ODR_PD);
- }
- if((devp)->config->compcfg != NULL) {
- lsm303dlhcI2CWriteRegister(devp->config->i2cp,
- LSM303DLHC_SAD_COMP,
- LSM303DLHC_AD_COMP_MR_REG,
- LSM303DLHC_COMP_MD_SLEEP);
- }
- i2cStop((devp)->config->i2cp);
-#if LSM303DLHC_SHARED_I2C
- i2cReleaseBus((devp)->config->i2cp);
-#endif /* LSM303DLHC_SHARED_I2C */
- }
-#endif /* LSM303DLHC_USE_I2C */
- devp->state = LSM303DLHC_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 lsm303dlhc.c
+ * @brief LSM303DLHC MEMS interface module code.
+ *
+ * @addtogroup lsm303dlhc
+ * @{
+ */
+
+#include "hal.h"
+#include "lsm303dlhc.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define LSM303DLHC_ACC_SENS_2G ((float)0.0610f)
+#define LSM303DLHC_ACC_SENS_4G ((float)0.1221f)
+#define LSM303DLHC_ACC_SENS_8G ((float)0.2442f)
+#define LSM303DLHC_ACC_SENS_16G ((float)0.4884f)
+
+#define LSM303DLHC_COMP_SENS_XY_1_3GA ((float)1100.0f)
+#define LSM303DLHC_COMP_SENS_XY_1_9GA ((float)855.0f)
+#define LSM303DLHC_COMP_SENS_XY_2_5GA ((float)670.0f)
+#define LSM303DLHC_COMP_SENS_XY_4_0GA ((float)450.0f)
+#define LSM303DLHC_COMP_SENS_XY_4_7GA ((float)400.0f)
+#define LSM303DLHC_COMP_SENS_XY_5_6GA ((float)330.0f)
+#define LSM303DLHC_COMP_SENS_XY_8_1GA ((float)230.0f)
+
+#define LSM303DLHC_COMP_SENS_Z_1_3GA ((float)980.0f)
+#define LSM303DLHC_COMP_SENS_Z_1_9GA ((float)765.0f)
+#define LSM303DLHC_COMP_SENS_Z_2_5GA ((float)600.0f)
+#define LSM303DLHC_COMP_SENS_Z_4_0GA ((float)400.0f)
+#define LSM303DLHC_COMP_SENS_Z_4_7GA ((float)355.0f)
+#define LSM303DLHC_COMP_SENS_Z_5_6GA ((float)295.0f)
+#define LSM303DLHC_COMP_SENS_Z_8_1GA ((float)205.0f)
+
+#define LSM303DLHC_DI ((uint8_t)0xFF)
+#define LSM303DLHC_DI_0 ((uint8_t)0x01)
+#define LSM303DLHC_DI_1 ((uint8_t)0x02)
+#define LSM303DLHC_DI_2 ((uint8_t)0x04)
+#define LSM303DLHC_DI_3 ((uint8_t)0x08)
+#define LSM303DLHC_DI_4 ((uint8_t)0x10)
+#define LSM303DLHC_DI_5 ((uint8_t)0x20)
+#define LSM303DLHC_DI_6 ((uint8_t)0x40)
+#define LSM303DLHC_DI_7 ((uint8_t)0x80)
+
+#define LSM303DLHC_AD_0 ((uint8_t)0x01)
+#define LSM303DLHC_AD_1 ((uint8_t)0x02)
+#define LSM303DLHC_AD_2 ((uint8_t)0x04)
+#define LSM303DLHC_AD_3 ((uint8_t)0x08)
+#define LSM303DLHC_AD_4 ((uint8_t)0x10)
+#define LSM303DLHC_AD_5 ((uint8_t)0x20)
+#define LSM303DLHC_AD_6 ((uint8_t)0x40)
+#define LSM303DLHC_RW ((uint8_t)0x80)
+
+#define LSM303DLHC_AD_ACC_CTRL_REG1 ((uint8_t)0x20)
+#define LSM303DLHC_AD_ACC_CTRL_REG2 ((uint8_t)0x21)
+#define LSM303DLHC_AD_ACC_CTRL_REG3 ((uint8_t)0x22)
+#define LSM303DLHC_AD_ACC_CTRL_REG4 ((uint8_t)0x23)
+#define LSM303DLHC_AD_ACC_CTRL_REG5 ((uint8_t)0x24)
+#define LSM303DLHC_AD_ACC_CTRL_REG6 ((uint8_t)0x25)
+#define LSM303DLHC_AD_ACC_REFERENCE ((uint8_t)0x26)
+#define LSM303DLHC_AD_ACC_STATUS_REG ((uint8_t)0x27)
+#define LSM303DLHC_AD_ACC_OUT_X_L ((uint8_t)0x28)
+#define LSM303DLHC_AD_ACC_OUT_X_H ((uint8_t)0x29)
+#define LSM303DLHC_AD_ACC_OUT_Y_L ((uint8_t)0x2A)
+#define LSM303DLHC_AD_ACC_OUT_Y_H ((uint8_t)0x2B)
+#define LSM303DLHC_AD_ACC_OUT_Z_L ((uint8_t)0x2C)
+#define LSM303DLHC_AD_ACC_OUT_Z_H ((uint8_t)0x2D)
+#define LSM303DLHC_AD_ACC_FIFO_CTRL_REG ((uint8_t)0x2E)
+#define LSM303DLHC_AD_ACC_FIFO_SRC_REG ((uint8_t)0x2F)
+#define LSM303DLHC_AD_ACC_INT1_CFG ((uint8_t)0x30)
+#define LSM303DLHC_AD_ACC_INT1_SRC ((uint8_t)0x31)
+#define LSM303DLHC_AD_ACC_INT1_THS ((uint8_t)0x32)
+#define LSM303DLHC_AD_ACC_INT1_DURATION ((uint8_t)0x33)
+#define LSM303DLHC_AD_ACC_INT2_CFG ((uint8_t)0x34)
+#define LSM303DLHC_AD_ACC_INT2_SRC ((uint8_t)0x35)
+#define LSM303DLHC_AD_ACC_INT2_THS ((uint8_t)0x36)
+#define LSM303DLHC_AD_ACC_INT2_DURATION ((uint8_t)0x37)
+#define LSM303DLHC_AD_ACC_CLICK_CFG ((uint8_t)0x38)
+#define LSM303DLHC_AD_ACC_CLICK_SRC ((uint8_t)0x39)
+#define LSM303DLHC_AD_ACC_CLICK_THS ((uint8_t)0x3A)
+#define LSM303DLHC_AD_ACC_TIME_LIMIT ((uint8_t)0x3B)
+#define LSM303DLHC_AD_ACC_TIME_LATENCY ((uint8_t)0x3C)
+#define LSM303DLHC_AD_ACC_TIME_WINDOW ((uint8_t)0x3D)
+#define LSM303DLHC_AD_COMP_CRA_REG ((uint8_t)0x00)
+#define LSM303DLHC_AD_COMP_CRB_REG ((uint8_t)0x01)
+#define LSM303DLHC_AD_COMP_MR_REG ((uint8_t)0x02)
+#define LSM303DLHC_AD_COMP_OUT_X_H ((uint8_t)0x03)
+#define LSM303DLHC_AD_COMP_OUT_X_L ((uint8_t)0x04)
+#define LSM303DLHC_AD_COMP_OUT_Z_H ((uint8_t)0x05)
+#define LSM303DLHC_AD_COMP_OUT_Z_L ((uint8_t)0x06)
+#define LSM303DLHC_AD_COMP_OUT_Y_H ((uint8_t)0x07)
+#define LSM303DLHC_AD_COMP_OUT_Y_L ((uint8_t)0x08)
+#define LSM303DLHC_AD_COMP_SR_REG ((uint8_t)0x09)
+#define LSM303DLHC_AD_COMP_IRA_REG ((uint8_t)0x0A)
+#define LSM303DLHC_AD_COMP_IRB_REG ((uint8_t)0x0B)
+#define LSM303DLHC_AD_COMP_IRC_REG ((uint8_t)0x0C)
+#define LSM303DLHC_AD_COMP_TEMP_OUT_H ((uint8_t)0x31)
+#define LSM303DLHC_AD_COMP_TEMP_OUT_L ((uint8_t)0x32)
+
+#define LSM303DLHC_ACC_CTRL_REG4_FS_MASK ((uint8_t)0x30)
+#define LSM303DLHC_COMP_CTRL_REGB_FS_MASK ((uint8_t)0xE0)
+
+#define TO_G ((float)0.001f)
+#define TO_SI ((float)0.00981f)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Accelerometer Power Mode
+ */
+typedef enum {
+ LSM303DLHC_ACC_PM_NORMAL = 0x00, /**< Normal mode enabled */
+ LSM303DLHC_ACC_PM_LP = 0x08 /**< Low Power mode enabled */
+} lsm303dlhc_acc_pm_t;
+
+/**
+ * @brief Accelerometer and Compass Slave Address.
+ */
+typedef enum {
+ LSM303DLHC_SAD_ACC = 0x19, /**< SAD for accelerometer. */
+ LSM303DLHC_SAD_COMP = 0x1E /**< SAD for compass. */
+} lsm303dlhc_sad_t;
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if (LSM303DLHC_USE_I2C) || defined(__DOXYGEN__)
+/**
+ * @brief Reads registers value using I2C.
+ * @pre The I2C interface must be initialized and the driver started.
+ * @note IF_ADD_INC bit must be 1 in CTRL_REG8
+ *
+ * @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 lsm303dlhcI2CReadRegister(I2CDriver *i2cp, lsm303dlhc_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 lsm303dlhcI2CWriteRegister(I2CDriver *i2cp, lsm303dlhc_sad_t sad, uint8_t reg,
+ uint8_t value) {
+ uint8_t rxbuf;
+ uint8_t txbuf[2];
+ if(sad == LSM303DLHC_SAD_ACC) {
+ switch (reg) {
+ default:
+ /* Reserved register must not be written, according to the datasheet
+ * this could permanently damage the device.
+ */
+ osalDbgAssert(FALSE, "lsm303dlhcWriteRegisterI2C(), reserved register");
+ case LSM303DLHC_AD_ACC_STATUS_REG:
+ case LSM303DLHC_AD_ACC_OUT_X_L:
+ case LSM303DLHC_AD_ACC_OUT_X_H:
+ case LSM303DLHC_AD_ACC_OUT_Y_L:
+ case LSM303DLHC_AD_ACC_OUT_Y_H:
+ case LSM303DLHC_AD_ACC_OUT_Z_L:
+ case LSM303DLHC_AD_ACC_OUT_Z_H:
+ case LSM303DLHC_AD_ACC_FIFO_SRC_REG:
+ case LSM303DLHC_AD_ACC_INT1_SRC:
+ case LSM303DLHC_AD_ACC_INT2_SRC:
+ /* Read only registers cannot be written, the command is ignored.*/
+ return MSG_RESET;
+ case LSM303DLHC_AD_ACC_CTRL_REG1:
+ case LSM303DLHC_AD_ACC_CTRL_REG2:
+ case LSM303DLHC_AD_ACC_CTRL_REG3:
+ case LSM303DLHC_AD_ACC_CTRL_REG4:
+ case LSM303DLHC_AD_ACC_CTRL_REG5:
+ case LSM303DLHC_AD_ACC_CTRL_REG6:
+ case LSM303DLHC_AD_ACC_REFERENCE:
+ case LSM303DLHC_AD_ACC_FIFO_CTRL_REG:
+ case LSM303DLHC_AD_ACC_INT1_CFG:
+ case LSM303DLHC_AD_ACC_INT1_THS:
+ case LSM303DLHC_AD_ACC_INT1_DURATION:
+ case LSM303DLHC_AD_ACC_INT2_CFG:
+ case LSM303DLHC_AD_ACC_INT2_THS:
+ case LSM303DLHC_AD_ACC_INT2_DURATION:
+ case LSM303DLHC_AD_ACC_CLICK_CFG:
+ case LSM303DLHC_AD_ACC_CLICK_SRC:
+ case LSM303DLHC_AD_ACC_CLICK_THS:
+ case LSM303DLHC_AD_ACC_TIME_LIMIT:
+ case LSM303DLHC_AD_ACC_TIME_LATENCY:
+ case LSM303DLHC_AD_ACC_TIME_WINDOW:
+ txbuf[0] = reg;
+ txbuf[1] = value;
+ return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
+ break;
+ }
+ }
+ if(sad == LSM303DLHC_SAD_COMP) {
+ switch (reg) {
+ default:
+ /* Reserved register must not be written, according to the datasheet
+ * this could permanently damage the device.
+ */
+ osalDbgAssert(FALSE, "lsm303dlhcWriteRegisterI2C(), reserved register");
+ case LSM303DLHC_AD_COMP_OUT_X_H:
+ case LSM303DLHC_AD_COMP_OUT_X_L:
+ case LSM303DLHC_AD_COMP_OUT_Z_H:
+ case LSM303DLHC_AD_COMP_OUT_Z_L:
+ case LSM303DLHC_AD_COMP_OUT_Y_H:
+ case LSM303DLHC_AD_COMP_OUT_Y_L:
+ case LSM303DLHC_AD_COMP_SR_REG:
+ case LSM303DLHC_AD_COMP_IRA_REG:
+ case LSM303DLHC_AD_COMP_IRB_REG:
+ case LSM303DLHC_AD_COMP_IRC_REG:
+ case LSM303DLHC_AD_COMP_TEMP_OUT_H:
+ case LSM303DLHC_AD_COMP_TEMP_OUT_L:
+ /* Read only registers cannot be written, the command is ignored.*/
+ return MSG_RESET;
+ case LSM303DLHC_AD_COMP_CRA_REG:
+ case LSM303DLHC_AD_COMP_CRB_REG:
+ case LSM303DLHC_AD_COMP_MR_REG:
+ txbuf[0] = reg;
+ txbuf[1] = value;
+ return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
+ break;
+ }
+ }
+ osalDbgAssert(FALSE, "lsm303dlhcWriteRegisterI2C(), wrong SAD");
+ return MSG_RESET;
+}
+#endif /* LSM303DLHC_USE_I2C */
+
+/*
+ * Interface implementation.
+ */
+static size_t acc_get_axes_number(void *ip) {
+
+ osalDbgCheck(ip != NULL);
+ return LSM303DLHC_ACC_NUMBER_OF_AXES;
+}
+
+static size_t comp_get_axes_number(void *ip) {
+
+ osalDbgCheck(ip != NULL);
+ return LSM303DLHC_COMP_NUMBER_OF_AXES;
+}
+
+static size_t sens_get_axes_number(void *ip) {
+ size_t size = 0;
+
+ osalDbgCheck(ip != NULL);
+ if (((LSM303DLHCDriver *)ip)->config->acccfg != NULL)
+ size += acc_get_axes_number(ip);
+ if (((LSM303DLHCDriver *)ip)->config->compcfg != NULL)
+ size += comp_get_axes_number(ip);
+ return size;
+}
+
+static msg_t acc_read_raw(void *ip, int32_t axes[]) {
+ int16_t tmp;
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM303DLHCDriver *)ip)->config->acccfg != NULL));
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "acc_read_raw(), invalid state");
+
+#if LSM303DLHC_USE_I2C
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->config->i2cp->state == I2C_READY),
+ "acc_read_raw(), channel not ready");
+#if LSM303DLHC_SHARED_I2C
+ i2cAcquireBus(((LSM303DLHCDriver *)ip)->config->i2cp);
+ i2cStart(((LSM303DLHCDriver *)ip)->config->i2cp,
+ ((LSM303DLHCDriver *)ip)->config->i2ccfg);
+#endif /* LSM303DLHC_SHARED_I2C */
+ if(((LSM303DLHCDriver *)ip)->config->acccfg->axesenabling & LSM303DLHC_ACC_AE_X){
+ tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_OUT_X_L, NULL);
+ tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_OUT_X_H, NULL) << 8;
+ axes[0] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->accbias[0];
+ }
+ if(((LSM303DLHCDriver *)ip)->config->acccfg->axesenabling & LSM303DLHC_ACC_AE_Y){
+ tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_OUT_Y_L, NULL);
+ tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_OUT_Y_H, NULL) << 8;
+ axes[1] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->accbias[1];
+ }
+ if(((LSM303DLHCDriver *)ip)->config->acccfg->axesenabling & LSM303DLHC_ACC_AE_Z){
+ tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_OUT_Z_L, NULL);
+ tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_OUT_Z_H, NULL) << 8;
+ axes[2] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->accbias[2];
+ }
+#if LSM303DLHC_SHARED_I2C
+ i2cReleaseBus(((LSM303DLHCDriver *)ip)->config->i2cp);
+#endif /* LSM303DLHC_SHARED_I2C */
+#endif /* LSM303DLHC_USE_I2C */
+ return MSG_OK;
+}
+
+static msg_t comp_read_raw(void *ip, int32_t axes[]) {
+ int16_t tmp;
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM303DLHCDriver *)ip)->config->compcfg != NULL));
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "comp_read_raw(), invalid state");
+
+#if LSM303DLHC_USE_I2C
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->config->i2cp->state == I2C_READY),
+ "comp_read_raw(), channel not ready");
+#if LSM303DLHC_SHARED_I2C
+ i2cAcquireBus(((LSM303DLHCDriver *)ip)->config->i2cp);
+ i2cStart(((LSM303DLHCDriver *)ip)->config->i2cp,
+ ((LSM303DLHCDriver *)ip)->config->i2ccfg);
+#endif /* LSM303DLHC_SHARED_I2C */
+ tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_OUT_X_L, NULL);
+ tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_OUT_X_H, NULL) << 8;
+ axes[0] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->compbias[0];
+
+ tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_OUT_Y_L, NULL);
+ tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_OUT_Y_H, NULL) << 8;
+ axes[1] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->compbias[1];
+
+ tmp = lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_OUT_Z_L, NULL);
+ tmp += lsm303dlhcI2CReadRegister(((LSM303DLHCDriver *)ip)->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_OUT_Z_H, NULL) << 8;
+ axes[2] = (int32_t)tmp - ((LSM303DLHCDriver *)ip)->compbias[2];
+#if LSM303DLHC_SHARED_I2C
+ i2cReleaseBus(((LSM303DLHCDriver *)ip)->config->i2cp);
+#endif /* LSM303DLHC_SHARED_I2C */
+#endif /* LSM303DLHC_USE_I2C */
+ return MSG_OK;
+}
+
+static msg_t sens_read_raw(void *ip, int32_t axes[]) {
+ int32_t* bp = axes;
+ msg_t msg;
+ if (((LSM303DLHCDriver *)ip)->config->acccfg != NULL) {
+ msg = acc_read_raw(ip, bp);
+ if(msg != MSG_OK)
+ return msg;
+ bp += LSM303DLHC_ACC_NUMBER_OF_AXES;
+ }
+ if (((LSM303DLHCDriver *)ip)->config->compcfg != NULL) {
+ msg = comp_read_raw(ip, bp);
+ }
+ return msg;
+}
+
+static msg_t acc_read_cooked(void *ip, float axes[]) {
+ uint32_t i;
+ int32_t raw[LSM303DLHC_ACC_NUMBER_OF_AXES];
+ msg_t msg;
+
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM303DLHCDriver *)ip)->config->acccfg != NULL));
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "acc_read_cooked(), invalid state");
+
+ msg = acc_read_raw(ip, raw);
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES ; i++){
+ axes[i] = raw[i] * ((LSM303DLHCDriver *)ip)->accsensitivity[i];
+ if(((LSM303DLHCDriver *)ip)->config->acccfg->unit == LSM303DLHC_ACC_UNIT_G){
+ axes[i] *= TO_G;
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->acccfg->unit == LSM303DLHC_ACC_UNIT_SI){
+ axes[i] *= TO_SI;
+ }
+ }
+ return msg;
+}
+
+static msg_t comp_read_cooked(void *ip, float axes[]) {
+ uint32_t i;
+ int32_t raw[LSM303DLHC_COMP_NUMBER_OF_AXES];
+ msg_t msg;
+
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM303DLHCDriver *)ip)->config->compcfg != NULL));
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "comp_read_cooked(), invalid state");
+
+ msg = comp_read_raw(ip, raw);
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES ; i++){
+ axes[i] = raw[i] / ((LSM303DLHCDriver *)ip)->compsensitivity[i];
+ }
+ return msg;
+}
+
+static msg_t sens_read_cooked(void *ip, float axes[]) {
+ float* bp = axes;
+ msg_t msg;
+ if (((LSM303DLHCDriver *)ip)->config->acccfg != NULL) {
+ msg = acc_read_cooked(ip, bp);
+ if(msg != MSG_OK)
+ return msg;
+ bp += LSM303DLHC_ACC_NUMBER_OF_AXES;
+ }
+ if (((LSM303DLHCDriver *)ip)->config->compcfg != NULL) {
+ msg = comp_read_cooked(ip, bp);
+ }
+ return msg;
+}
+
+static msg_t acc_set_bias(void *ip, int32_t *bp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (bp !=NULL));
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
+ (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
+ "acc_set_bias(), invalid state");
+
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) {
+ ((LSM303DLHCDriver *)ip)->accbias[i] = bp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t comp_set_bias(void *ip, int32_t *bp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (bp !=NULL));
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
+ (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
+ "comp_set_bias(), invalid state");
+
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ ((LSM303DLHCDriver *)ip)->compbias[i] = bp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t acc_reset_bias(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
+ (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
+ "acc_reset_bias(), invalid state");
+
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ ((LSM303DLHCDriver *)ip)->accbias[i] = 0;
+ return MSG_OK;
+}
+
+static msg_t comp_reset_bias(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY) ||
+ (((LSM303DLHCDriver *)ip)->state == LSM303DLHC_STOP),
+ "comp_reset_bias(), invalid state");
+
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++)
+ ((LSM303DLHCDriver *)ip)->compbias[i] = 0;
+ return MSG_OK;
+}
+
+static msg_t acc_set_sensivity(void *ip, float *sp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (sp !=NULL));
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "acc_set_sensivity(), invalid state");
+
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) {
+ ((LSM303DLHCDriver *)ip)->accsensitivity[i] = sp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t comp_set_sensivity(void *ip, float *sp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (sp !=NULL));
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "comp_set_sensivity(), invalid state");
+
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = sp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t acc_reset_sensivity(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "acc_reset_sensivity(), invalid state");
+
+ if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_2G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_2G;
+ else if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_4G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_4G;
+ else if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_8G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_8G;
+ else if(((LSM303DLHCDriver *)ip)->config->acccfg->fullscale == LSM303DLHC_ACC_FS_16G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ ((LSM303DLHCDriver *)ip)->accsensitivity[i] = LSM303DLHC_ACC_SENS_16G;
+ else {
+ osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
+ return MSG_RESET;
+ }
+ return MSG_OK;
+}
+
+static msg_t comp_reset_sensivity(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM303DLHCDriver *)ip)->state == LSM303DLHC_READY),
+ "comp_reset_sensivity(), invalid state");
+
+ if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_3_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_3GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_3GA;
+ }
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_9_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_9GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_9GA;
+ }
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_2_5_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_2_5GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_2_5GA;
+ }
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_0_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_0GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_0GA;
+ }
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_7_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_7GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_7GA;
+ }
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_5_6_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_5_6GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_5_6GA;
+ }
+ }
+ else if(((LSM303DLHCDriver *)ip)->config->compcfg->fullscale == LSM303DLHC_COMP_FS_8_1_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_8_1GA;
+ }
+ else {
+ ((LSM303DLHCDriver *)ip)->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_8_1GA;
+ }
+ }
+ else {
+ osalDbgAssert(FALSE, "reset_sensivity(), compass full scale issue");
+ return MSG_RESET;
+ }
+ return MSG_OK;
+}
+
+static const struct BaseSensorVMT vmt_basesensor = {
+ sens_get_axes_number, sens_read_raw, sens_read_cooked
+};
+
+static const struct BaseCompassVMT vmt_basecompass = {
+ comp_get_axes_number, comp_read_raw, comp_read_cooked,
+ comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity
+};
+
+static const struct BaseAccelerometerVMT vmt_baseaccelerometer = {
+ acc_get_axes_number, acc_read_raw, acc_read_cooked,
+ acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
+};
+
+static const struct LSM303DLHCACCVMT vmt_lsm303dlhcacc = {
+ acc_get_axes_number, acc_read_raw, acc_read_cooked,
+ acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
+};
+
+static const struct LSM303DLHCCOMPVMT vmt_lsm303dlhccomp = {
+ comp_get_axes_number, comp_read_raw, comp_read_cooked,
+ comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity
+};
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initializes an instance.
+ *
+ * @param[out] devp pointer to the @p LSM303DLHCDriver object
+ *
+ * @init
+ */
+void lsm303dlhcObjectInit(LSM303DLHCDriver *devp) {
+ uint32_t i;
+ devp->vmt_basesensor = &vmt_basesensor;
+ devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
+ devp->vmt_basecompass = &vmt_basecompass;
+ devp->vmt_lsm303dlhcacc = &vmt_lsm303dlhcacc;
+ devp->vmt_lsm303dlhccomp = &vmt_lsm303dlhccomp;
+ devp->config = NULL;
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ devp->accbias[i] = 0;
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++)
+ devp->compbias[i] = 0;
+ devp->state = LSM303DLHC_STOP;
+}
+
+/**
+ * @brief Configures and activates LSM303DLHC Complex Driver peripheral.
+ *
+ * @param[in] devp pointer to the @p LSM303DLHCDriver object
+ * @param[in] config pointer to the @p LSM303DLHCConfig object
+ *
+ * @api
+ */
+void lsm303dlhcStart(LSM303DLHCDriver *devp, const LSM303DLHCConfig *config) {
+ uint32_t i;
+ osalDbgCheck((devp != NULL) && (config != NULL));
+
+ osalDbgAssert((devp->state == LSM303DLHC_STOP) || (devp->state == LSM303DLHC_READY),
+ "lsm303dlhcStart(), invalid state");
+
+ devp->config = config;
+
+#if LSM303DLHC_USE_I2C
+#if LSM303DLHC_SHARED_I2C
+ i2cAcquireBus((devp)->config->i2cp);
+#endif /* LSM303DLHC_SHARED_I2C */
+ i2cStart((devp)->config->i2cp,
+ (devp)->config->i2ccfg);
+ if((devp)->config->acccfg != NULL) {
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_CTRL_REG1,
+ devp->config->acccfg->axesenabling |
+ devp->config->acccfg->outdatarate |
+ devp->config->acccfg->lowpower);
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_CTRL_REG4,
+ devp->config->acccfg->endianess |
+ devp->config->acccfg->fullscale |
+ devp->config->acccfg->blockdataupdate |
+ devp->config->acccfg->highresmode);
+ }
+ if((devp)->config->compcfg != NULL) {
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_CRA_REG,
+ devp->config->compcfg->outputdatarate);
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_CRB_REG,
+ devp->config->compcfg->fullscale);
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_MR_REG,
+ devp->config->compcfg->mode);
+ }
+#if LSM303DLHC_SHARED_I2C
+ i2cReleaseBus((devp)->config->i2cp);
+#endif /* LSM303DLHC_SHARED_I2C */
+#endif /* LSM303DLHC_USE_I2C */
+ /* Storing sensitivity information according to full scale value */
+ if((devp)->config->acccfg != NULL) {
+ if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_2G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_2G;
+ else if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_4G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_4G;
+ else if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_8G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_8G;
+ else if(devp->config->acccfg->fullscale == LSM303DLHC_ACC_FS_16G)
+ for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_16G;
+ else
+ osalDbgAssert(FALSE, "lsm303dlhcStart(), accelerometer full scale issue");
+ }
+ if((devp)->config->compcfg != NULL) {
+ if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_3_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_3GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_3GA;
+ }
+ }
+ else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_1_9_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1_9GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1_9GA;
+ }
+ }
+ else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_2_5_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_2_5GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_2_5GA;
+ }
+ }
+ else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_0_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_0GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_0GA;
+ }
+ }
+ else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_4_7_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4_7GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4_7GA;
+ }
+ }
+ else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_5_6_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_5_6GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_5_6GA;
+ }
+ }
+ else if(devp->config->compcfg->fullscale == LSM303DLHC_COMP_FS_8_1_GA)
+ for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) {
+ if(i != 2) {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_8_1GA;
+ }
+ else {
+ devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_8_1GA;
+ }
+ }
+ else
+ osalDbgAssert(FALSE, "lsm303dlhcStart(), compass full scale issue");
+ }
+ /* This is the Compass transient recovery time */
+ osalThreadSleepMilliseconds(5);
+
+ devp->state = LSM303DLHC_READY;
+}
+
+/**
+ * @brief Deactivates the LSM303DLHC Complex Driver peripheral.
+ *
+ * @param[in] devp pointer to the @p LSM303DLHCDriver object
+ *
+ * @api
+ */
+void lsm303dlhcStop(LSM303DLHCDriver *devp) {
+
+ osalDbgCheck(devp != NULL);
+
+ osalDbgAssert((devp->state == LSM303DLHC_STOP) || (devp->state == LSM303DLHC_READY),
+ "lsm303dlhcStop(), invalid state");
+
+#if (LSM303DLHC_USE_I2C)
+ if (devp->state == LSM303DLHC_STOP) {
+#if LSM303DLHC_SHARED_I2C
+ i2cAcquireBus((devp)->config->i2cp);
+ i2cStart((devp)->config->i2cp,
+ (devp)->config->i2ccfg);
+#endif /* LSM303DLHC_SHARED_I2C */
+ if((devp)->config->acccfg != NULL) {
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_ACC,
+ LSM303DLHC_AD_ACC_CTRL_REG1,
+ LSM303DLHC_ACC_AE_DISABLED |
+ LSM303DLHC_ACC_ODR_PD);
+ }
+ if((devp)->config->compcfg != NULL) {
+ lsm303dlhcI2CWriteRegister(devp->config->i2cp,
+ LSM303DLHC_SAD_COMP,
+ LSM303DLHC_AD_COMP_MR_REG,
+ LSM303DLHC_COMP_MD_SLEEP);
+ }
+ i2cStop((devp)->config->i2cp);
+#if LSM303DLHC_SHARED_I2C
+ i2cReleaseBus((devp)->config->i2cp);
+#endif /* LSM303DLHC_SHARED_I2C */
+ }
+#endif /* LSM303DLHC_USE_I2C */
+ devp->state = LSM303DLHC_STOP;
+}
+/** @} */
diff --git a/os/ex/ST/lsm303dlhc.h b/os/ex/ST/lsm303dlhc.h
index 2fe8d70b3..17fd55ec2 100644
--- a/os/ex/ST/lsm303dlhc.h
+++ b/os/ex/ST/lsm303dlhc.h
@@ -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_ */
+
+/** @} */
diff --git a/os/ex/ST/lsm6ds0.c b/os/ex/ST/lsm6ds0.c
index caa0d875d..054cca679 100644
--- a/os/ex/ST/lsm6ds0.c
+++ b/os/ex/ST/lsm6ds0.c
@@ -1,846 +1,846 @@
-/*
- 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 lsm6ds0.c
- * @brief LSM6DS0 MEMS interface module code.
- *
- * @addtogroup lsm6ds0
- * @{
- */
-
-#include "hal.h"
-#include "lsm6ds0.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#define LSM6DS0_ACC_SENS_2G ((float)0.061f)
-#define LSM6DS0_ACC_SENS_4G ((float)0.122f)
-#define LSM6DS0_ACC_SENS_8G ((float)0.244f)
-#define LSM6DS0_ACC_SENS_16G ((float)0.732f)
-
-#define LSM6DS0_GYRO_SENS_245DPS ((float)0.00875f)
-#define LSM6DS0_GYRO_SENS_500DPS ((float)0.01750f)
-#define LSM6DS0_GYRO_SENS_2000DPS ((float)0.07000f)
-
-#define LSM6DS0_TEMP_SENS ((float)16.0f)
-#define LSM6DS0_TEMP_SENS_OFF ((float)25.0f)
-
-#define LSM6DS0_DI ((uint8_t)0xFF)
-#define LSM6DS0_DI_0 ((uint8_t)0x01)
-#define LSM6DS0_DI_1 ((uint8_t)0x02)
-#define LSM6DS0_DI_2 ((uint8_t)0x04)
-#define LSM6DS0_DI_3 ((uint8_t)0x08)
-#define LSM6DS0_DI_4 ((uint8_t)0x10)
-#define LSM6DS0_DI_5 ((uint8_t)0x20)
-#define LSM6DS0_DI_6 ((uint8_t)0x40)
-#define LSM6DS0_DI_7 ((uint8_t)0x80)
-
-#define LSM6DS0_AD_0 ((uint8_t)0x01)
-#define LSM6DS0_AD_1 ((uint8_t)0x02)
-#define LSM6DS0_AD_2 ((uint8_t)0x04)
-#define LSM6DS0_AD_3 ((uint8_t)0x08)
-#define LSM6DS0_AD_4 ((uint8_t)0x10)
-#define LSM6DS0_AD_5 ((uint8_t)0x20)
-#define LSM6DS0_AD_6 ((uint8_t)0x40)
-
-#define LSM6DS0_RW ((uint8_t)0x80)
-
-#define LSM6DS0_AD_ACT_THS ((uint8_t)0x04)
-#define LSM6DS0_AD_ACT_DUR ((uint8_t)0x05)
-#define LSM6DS0_AD_INT_GEN_CFG_XL ((uint8_t)0x06)
-#define LSM6DS0_AD_INT_GEN_THS_X_XL ((uint8_t)0x07)
-#define LSM6DS0_AD_INT_GEN_THS_Y_XL ((uint8_t)0x08)
-#define LSM6DS0_AD_INT_GEN_THS_Z_XL ((uint8_t)0x09)
-#define LSM6DS0_AD_INT_GEN_DUR_XL ((uint8_t)0x0A)
-#define LSM6DS0_AD_REFERENCE_G ((uint8_t)0x0B)
-#define LSM6DS0_AD_INT_CTRL ((uint8_t)0x0C)
-#define LSM6DS0_AD_WHO_AM_I ((uint8_t)0x0F)
-#define LSM6DS0_AD_CTRL_REG1_G ((uint8_t)0x10)
-#define LSM6DS0_AD_CTRL_REG2_G ((uint8_t)0x11)
-#define LSM6DS0_AD_CTRL_REG3_G ((uint8_t)0x12)
-#define LSM6DS0_AD_ORIENT_CFG_G ((uint8_t)0x13)
-#define LSM6DS0_AD_INT_GEN_SRC_G ((uint8_t)0x14)
-#define LSM6DS0_AD_OUT_TEMP_L ((uint8_t)0x15)
-#define LSM6DS0_AD_OUT_TEMP_H ((uint8_t)0x16)
-#define LSM6DS0_AD_STATUS_REG1 ((uint8_t)0x17)
-#define LSM6DS0_AD_OUT_X_L_G ((uint8_t)0x18)
-#define LSM6DS0_AD_OUT_X_H_G ((uint8_t)0x19)
-#define LSM6DS0_AD_OUT_Y_L_G ((uint8_t)0x1A)
-#define LSM6DS0_AD_OUT_Y_H_G ((uint8_t)0x1B)
-#define LSM6DS0_AD_OUT_Z_L_G ((uint8_t)0x1C)
-#define LSM6DS0_AD_OUT_Z_H_G ((uint8_t)0x1D)
-#define LSM6DS0_AD_CTRL_REG4 ((uint8_t)0x1E)
-#define LSM6DS0_AD_CTRL_REG5_XL ((uint8_t)0x1F)
-#define LSM6DS0_AD_CTRL_REG6_XL ((uint8_t)0x20)
-#define LSM6DS0_AD_CTRL_REG7_XL ((uint8_t)0x21)
-#define LSM6DS0_AD_CTRL_REG8 ((uint8_t)0x22)
-#define LSM6DS0_AD_CTRL_REG9 ((uint8_t)0x23)
-#define LSM6DS0_AD_CTRL_REG10 ((uint8_t)0x24)
-#define LSM6DS0_AD_INT_GEN_SRC_XL ((uint8_t)0x26)
-#define LSM6DS0_AD_STATUS_REG2 ((uint8_t)0x27)
-#define LSM6DS0_AD_OUT_X_L_XL ((uint8_t)0x28)
-#define LSM6DS0_AD_OUT_X_H_XL ((uint8_t)0x29)
-#define LSM6DS0_AD_OUT_Y_L_XL ((uint8_t)0x2A)
-#define LSM6DS0_AD_OUT_Y_H_XL ((uint8_t)0x2B)
-#define LSM6DS0_AD_OUT_Z_L_XL ((uint8_t)0x2C)
-#define LSM6DS0_AD_OUT_Z_H_XL ((uint8_t)0x2D)
-#define LSM6DS0_AD_FIFO_CTRL ((uint8_t)0x2E)
-#define LSM6DS0_AD_FIFO_SRC ((uint8_t)0x2F)
-#define LSM6DS0_AD_INT_GEN_CFG_G ((uint8_t)0x30)
-#define LSM6DS0_AD_INT_GEN_THS_XH_G ((uint8_t)0x31)
-#define LSM6DS0_AD_INT_GEN_THS_XL_G ((uint8_t)0x32)
-#define LSM6DS0_AD_INT_GEN_THS_YH_G ((uint8_t)0x33)
-#define LSM6DS0_AD_INT_GEN_THS_YL_G ((uint8_t)0x34)
-#define LSM6DS0_AD_INT_GEN_THS_ZH_G ((uint8_t)0x35)
-#define LSM6DS0_AD_INT_GEN_THS_ZL_G ((uint8_t)0x36)
-#define LSM6DS0_AD_INT_GEN_DUR_G ((uint8_t)0x37)
-
-#define LSM6DS0_CTRL_REG1_G_FS_MASK ((uint8_t)0x18)
-#define LSM6DS0_CTRL_REG6_XL_FS_MASK ((uint8_t)0x18)
-
-#define TO_G ((float)0.001f)
-#define TO_SI ((float)0.00981f)
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief LSM6DS0 address increment mode.
- */
-typedef enum {
- LSM6DS0_IF_ADD_INC_DIS = 0x00, /**< Address increment disabled. */
- LSM6DS0_IF_ADD_INC_EN = 0x04 /**< Address increment disabled. */
-}lsm6ds0_id_add_inc_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem sleep mode.
- */
-typedef enum {
- LSM6DS0_GYRO_SLP_DISABLED = 0x00, /**< Gyroscope in normal mode. */
- LSM6DS0_GYRO_SLP_ENABLED = 0x40 /**< Gyroscope in sleep mode. */
-}lsm6ds0_gyro_slp_t;
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if (LSM6DS0_USE_I2C) || defined(__DOXYGEN__)
-/**
- * @brief Reads registers value using I2C.
- * @pre The I2C interface must be initialized and the driver started.
- * @note IF_ADD_INC bit must be 1 in CTRL_REG8
- *
- * @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 lsm6ds0I2CReadRegister(I2CDriver *i2cp, lsm6ds0_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 lsm6ds0I2CWriteRegister(I2CDriver *i2cp, lsm6ds0_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.
- */
- osalDbgAssert(FALSE, "lsm6ds0WriteRegisterI2C(), reserved register");
- case LSM6DS0_AD_WHO_AM_I:
- case LSM6DS0_AD_INT_GEN_SRC_G:
- case LSM6DS0_AD_OUT_TEMP_L:
- case LSM6DS0_AD_OUT_TEMP_H:
- case LSM6DS0_AD_STATUS_REG1:
- case LSM6DS0_AD_OUT_X_L_G:
- case LSM6DS0_AD_OUT_X_H_G:
- case LSM6DS0_AD_OUT_Y_L_G:
- case LSM6DS0_AD_OUT_Y_H_G:
- case LSM6DS0_AD_OUT_Z_L_G:
- case LSM6DS0_AD_OUT_Z_H_G:
- case LSM6DS0_AD_INT_GEN_SRC_XL:
- case LSM6DS0_AD_STATUS_REG2:
- case LSM6DS0_AD_OUT_X_L_XL:
- case LSM6DS0_AD_OUT_X_H_XL:
- case LSM6DS0_AD_OUT_Y_L_XL:
- case LSM6DS0_AD_OUT_Y_H_XL:
- case LSM6DS0_AD_OUT_Z_L_XL:
- case LSM6DS0_AD_OUT_Z_H_XL:
- case LSM6DS0_AD_FIFO_SRC:
- /* Read only registers cannot be written, the command is ignored.*/
- return MSG_RESET;
- case LSM6DS0_AD_ACT_THS:
- case LSM6DS0_AD_ACT_DUR:
- case LSM6DS0_AD_INT_GEN_CFG_XL:
- case LSM6DS0_AD_INT_GEN_THS_X_XL:
- case LSM6DS0_AD_INT_GEN_THS_Y_XL:
- case LSM6DS0_AD_INT_GEN_THS_Z_XL:
- case LSM6DS0_AD_INT_GEN_DUR_XL:
- case LSM6DS0_AD_REFERENCE_G:
- case LSM6DS0_AD_INT_CTRL:
- case LSM6DS0_AD_CTRL_REG1_G:
- case LSM6DS0_AD_CTRL_REG2_G:
- case LSM6DS0_AD_CTRL_REG3_G:
- case LSM6DS0_AD_ORIENT_CFG_G:
- case LSM6DS0_AD_CTRL_REG4:
- case LSM6DS0_AD_CTRL_REG5_XL:
- case LSM6DS0_AD_CTRL_REG6_XL:
- case LSM6DS0_AD_CTRL_REG7_XL:
- case LSM6DS0_AD_CTRL_REG8:
- case LSM6DS0_AD_CTRL_REG9:
- case LSM6DS0_AD_CTRL_REG10:
- case LSM6DS0_AD_FIFO_CTRL:
- case LSM6DS0_AD_INT_GEN_CFG_G:
- case LSM6DS0_AD_INT_GEN_THS_XH_G:
- case LSM6DS0_AD_INT_GEN_THS_XL_G:
- case LSM6DS0_AD_INT_GEN_THS_YH_G:
- case LSM6DS0_AD_INT_GEN_THS_YL_G:
- case LSM6DS0_AD_INT_GEN_THS_ZH_G:
- case LSM6DS0_AD_INT_GEN_THS_ZL_G:
- case LSM6DS0_AD_INT_GEN_DUR_G:
- txbuf[0] = reg;
- txbuf[1] = value;
- return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
- break;
- }
-}
-#endif /* LSM6DS0_USE_I2C */
-
-/*
- * Interface implementation.
- */
-static size_t acc_get_axes_number(void *ip) {
-
- osalDbgCheck(ip != NULL);
- return LSM6DS0_ACC_NUMBER_OF_AXES;
-}
-
-static size_t gyro_get_axes_number(void *ip) {
-
- osalDbgCheck(ip != NULL);
- return LSM6DS0_GYRO_NUMBER_OF_AXES;
-}
-
-static size_t sens_get_axes_number(void *ip) {
- size_t size = 0;
-
- osalDbgCheck(ip != NULL);
- if (((LSM6DS0Driver *)ip)->config->acccfg != NULL)
- size += acc_get_axes_number(ip);
- if (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL)
- size += gyro_get_axes_number(ip);
- return size;
-}
-
-static msg_t acc_read_raw(void *ip, int32_t axes[]) {
- int16_t tmp;
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM6DS0Driver *)ip)->config->acccfg != NULL));
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "acc_read_raw(), invalid state");
-
-#if LSM6DS0_USE_I2C
- osalDbgAssert((((LSM6DS0Driver *)ip)->config->i2cp->state == I2C_READY),
- "acc_read_raw(), channel not ready");
-#if LSM6DS0_SHARED_I2C
- i2cAcquireBus(((LSM6DS0Driver *)ip)->config->i2cp);
- i2cStart(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->i2ccfg);
-#endif /* LSM6DS0_SHARED_I2C */
- if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_ACC_AE_X){
- tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_X_L_XL, NULL);
- tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_X_H_XL, NULL) << 8;
- axes[0] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->accbias[0];
- }
- if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_ACC_AE_Y){
- tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Y_L_XL, NULL);
- tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Y_H_XL, NULL) << 8;
- axes[1] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->accbias[1];
- }
- if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_ACC_AE_Z){
- tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Z_L_XL, NULL);
- tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Z_H_XL, NULL) << 8;
- axes[2] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->accbias[2];
- }
-#if LSM6DS0_SHARED_I2C
- i2cReleaseBus(((LSM6DS0Driver *)ip)->config->i2cp);
-#endif /* LSM6DS0_SHARED_I2C */
-#endif /* LSM6DS0_USE_I2C */
- return MSG_OK;
-}
-
-static msg_t gyro_read_raw(void *ip, int32_t axes[]) {
- int16_t tmp;
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL));
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "gyro_read_raw(), invalid state");
-
-#if LSM6DS0_USE_I2C
- osalDbgAssert((((LSM6DS0Driver *)ip)->config->i2cp->state == I2C_READY),
- "gyro_read_raw(), channel not ready");
-#if LSM6DS0_SHARED_I2C
- i2cAcquireBus(((LSM6DS0Driver *)ip)->config->i2cp);
- i2cStart(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->i2ccfg);
-#endif /* LSM6DS0_SHARED_I2C */
- if(((LSM6DS0Driver *)ip)->config->gyrocfg->axesenabling & LSM6DS0_GYRO_AE_X){
- tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_X_L_G, NULL);
- tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_X_H_G, NULL) << 8;
- axes[0] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->gyrobias[0];
- }
- if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_GYRO_AE_Y){
- tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Y_L_G, NULL);
- tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Y_H_G, NULL) << 8;
- axes[1] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->gyrobias[1];
- }
- if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_GYRO_AE_Z){
- tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Z_L_G, NULL);
- tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_Z_H_G, NULL) << 8;
- axes[2] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->gyrobias[2];
- }
-#if LSM6DS0_SHARED_I2C
- i2cReleaseBus(((LSM6DS0Driver *)ip)->config->i2cp);
-#endif /* LSM6DS0_SHARED_I2C */
-#endif /* LSM6DS0_USE_I2C */
- return MSG_OK;
-}
-
-static msg_t sens_read_raw(void *ip, int32_t axes[]) {
- int32_t* bp = axes;
- msg_t msg;
- if (((LSM6DS0Driver *)ip)->config->acccfg != NULL) {
- msg = acc_read_raw(ip, bp);
- if(msg != MSG_OK)
- return msg;
- bp += LSM6DS0_ACC_NUMBER_OF_AXES;
- }
- if (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL) {
- msg = gyro_read_raw(ip, bp);
- }
- return msg;
-}
-
-static msg_t acc_read_cooked(void *ip, float axes[]) {
- uint32_t i;
- int32_t raw[LSM6DS0_ACC_NUMBER_OF_AXES];
- msg_t msg;
-
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM6DS0Driver *)ip)->config->acccfg != NULL));
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "acc_read_cooked(), invalid state");
-
- msg = acc_read_raw(ip, raw);
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES ; i++){
- axes[i] = raw[i] * ((LSM6DS0Driver *)ip)->accsensitivity[i];
- if(((LSM6DS0Driver *)ip)->config->acccfg->unit == LSM6DS0_ACC_UNIT_G){
- axes[i] *= TO_G;
- }
- else if(((LSM6DS0Driver *)ip)->config->acccfg->unit == LSM6DS0_ACC_UNIT_SI){
- axes[i] *= TO_SI;
- }
- }
- return msg;
-}
-
-static msg_t gyro_read_cooked(void *ip, float axes[]) {
- uint32_t i;
- int32_t raw[LSM6DS0_GYRO_NUMBER_OF_AXES];
- msg_t msg;
-
- osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
- (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL));
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "gyro_read_cooked(), invalid state");
-
- msg = gyro_read_raw(ip, raw);
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES ; i++){
- axes[i] = raw[i] * ((LSM6DS0Driver *)ip)->gyrosensitivity[i];
- }
- return msg;
-}
-
-static msg_t sens_read_cooked(void *ip, float axes[]) {
- float* bp = axes;
- msg_t msg;
- if (((LSM6DS0Driver *)ip)->config->acccfg != NULL) {
- msg = acc_read_cooked(ip, bp);
- if(msg != MSG_OK)
- return msg;
- bp += LSM6DS0_ACC_NUMBER_OF_AXES;
- }
- if (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL) {
- msg = gyro_read_cooked(ip, bp);
- }
- return msg;
-}
-
-static msg_t gyro_sample_bias(void *ip) {
- uint32_t i, j;
- int32_t raw[LSM6DS0_GYRO_NUMBER_OF_AXES];
- int32_t buff[LSM6DS0_GYRO_NUMBER_OF_AXES] = {0, 0, 0};
- msg_t msg;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "sample_bias(), invalid state");
-
- for(i = 0; i < LSM6DS0_GYRO_BIAS_ACQ_TIMES; i++){
- msg = gyro_read_raw(ip, raw);
- if(msg != MSG_OK)
- return msg;
- for(j = 0; j < LSM6DS0_GYRO_NUMBER_OF_AXES; j++){
- buff[j] += raw[j];
- }
- osalThreadSleepMicroseconds(LSM6DS0_GYRO_BIAS_SETTLING_uS);
- }
-
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++){
- ((LSM6DS0Driver *)ip)->gyrobias[i] = buff[i] / LSM6DS0_GYRO_BIAS_ACQ_TIMES;
- }
- return msg;
-}
-
-static msg_t acc_set_bias(void *ip, int32_t *bp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (bp !=NULL));
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
- (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
- "acc_set_bias(), invalid state");
-
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) {
- ((LSM6DS0Driver *)ip)->accbias[i] = bp[i];
- }
- return MSG_OK;
-}
-
-static msg_t gyro_set_bias(void *ip, int32_t *bp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (bp !=NULL));
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
- (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
- "gyro_set_bias(), invalid state");
-
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) {
- ((LSM6DS0Driver *)ip)->gyrobias[i] = bp[i];
- }
- return MSG_OK;
-}
-
-static msg_t acc_reset_bias(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
- (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
- "acc_reset_bias(), invalid state");
-
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->accbias[i] = 0;
- return MSG_OK;
-}
-
-static msg_t gyro_reset_bias(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
- (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
- "gyro_reset_bias(), invalid state");
-
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->gyrobias[i] = 0;
- return MSG_OK;
-}
-
-static msg_t acc_set_sensivity(void *ip, float *sp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (sp !=NULL));
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "acc_set_sensivity(), invalid state");
-
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) {
- ((LSM6DS0Driver *)ip)->accsensitivity[i] = sp[i];
- }
- return MSG_OK;
-}
-
-static msg_t gyro_set_sensivity(void *ip, float *sp) {
- uint32_t i;
-
- osalDbgCheck((ip != NULL) && (sp !=NULL));
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "gyro_set_sensivity(), invalid state");
-
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) {
- ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = sp[i];
- }
- return MSG_OK;
-}
-
-static msg_t acc_reset_sensivity(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "acc_reset_sensivity(), invalid state");
-
- if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_2G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_2G;
- else if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_4G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_4G;
- else if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_8G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_8G;
- else if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_16G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_16G;
- else {
- osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
- return MSG_RESET;
- }
- return MSG_OK;
-}
-
-static msg_t gyro_reset_sensivity(void *ip) {
- uint32_t i;
-
- osalDbgCheck(ip != NULL);
-
- osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
- "gyro_reset_sensivity(), invalid state");
-
- if(((LSM6DS0Driver *)ip)->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_245DSP)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_245DPS;
- else if(((LSM6DS0Driver *)ip)->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_500DSP)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_500DPS;
- else if(((LSM6DS0Driver *)ip)->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_2000DSP)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_2000DPS;
- else {
- osalDbgAssert(FALSE, "reset_sensivity(), gyroscope full scale issue");
- return MSG_RESET;
- }
- return MSG_OK;
-}
-
-static msg_t sens_get_temperature(void *ip, float* tempp) {
- int16_t temp;
-#if LSM6DS0_USE_I2C
- osalDbgAssert((((LSM6DS0Driver *)ip)->config->i2cp->state == I2C_READY),
- "gyro_read_raw(), channel not ready");
-#if LSM6DS0_SHARED_I2C
- i2cAcquireBus(((LSM6DS0Driver *)ip)->config->i2cp);
- i2cStart(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->i2ccfg);
-#endif /* LSM6DS0_SHARED_I2C */
- temp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_TEMP_L, NULL);
- temp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
- ((LSM6DS0Driver *)ip)->config->slaveaddress,
- LSM6DS0_AD_OUT_TEMP_H, NULL) << 8;
-#if LSM6DS0_SHARED_I2C
- i2cReleaseBus(((LSM6DS0Driver *)ip)->config->i2cp);
-#endif /* LSM6DS0_SHARED_I2C */
-#endif /* LSM6DS0_USE_I2C */
- *tempp = ((float)temp / LSM6DS0_TEMP_SENS) + LSM6DS0_TEMP_SENS_OFF;
- return MSG_OK;
-}
-
-static const struct BaseSensorVMT vmt_basesensor = {
- sens_get_axes_number, sens_read_raw, sens_read_cooked
-};
-
-static const struct BaseGyroscopeVMT vmt_basegyroscope = {
- gyro_get_axes_number, gyro_read_raw, gyro_read_cooked,
- gyro_sample_bias, gyro_set_bias, gyro_reset_bias,
- gyro_set_sensivity, gyro_reset_sensivity
-};
-
-static const struct BaseAccelerometerVMT vmt_baseaccelerometer = {
- acc_get_axes_number, acc_read_raw, acc_read_cooked,
- acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
-};
-
-static const struct LSM6DS0ACCVMT vmt_lsm6ds0acc = {
- acc_get_axes_number, acc_read_raw, acc_read_cooked,
- acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
-};
-
-static const struct LSM6DS0GYROVMT vmt_lsm6ds0gyro = {
- gyro_get_axes_number, gyro_read_raw, gyro_read_cooked,
- gyro_sample_bias, gyro_set_bias, gyro_reset_bias,
- gyro_set_sensivity, gyro_reset_sensivity, sens_get_temperature
-};
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Initializes an instance.
- *
- * @param[out] devp pointer to the @p LSM6DS0Driver object
- *
- * @init
- */
-void lsm6ds0ObjectInit(LSM6DS0Driver *devp) {
- uint32_t i;
- devp->vmt_basesensor = &vmt_basesensor;
- devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
- devp->vmt_basegyroscope = &vmt_basegyroscope;
- devp->vmt_lsm6ds0acc = &vmt_lsm6ds0acc;
- devp->vmt_lsm6ds0gyro = &vmt_lsm6ds0gyro;
- devp->config = NULL;
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- devp->accbias[i] = 0;
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
- devp->gyrobias[i] = 0;
- devp->state = LSM6DS0_STOP;
-}
-
-/**
- * @brief Configures and activates LSM6DS0 Complex Driver peripheral.
- *
- * @param[in] devp pointer to the @p LSM6DS0Driver object
- * @param[in] config pointer to the @p LSM6DS0Config object
- *
- * @api
- */
-void lsm6ds0Start(LSM6DS0Driver *devp, const LSM6DS0Config *config) {
- uint32_t i;
- osalDbgCheck((devp != NULL) && (config != NULL));
-
- osalDbgAssert((devp->state == LSM6DS0_STOP) || (devp->state == LSM6DS0_READY),
- "lsm6ds0Start(), invalid state");
-
- devp->config = config;
-
-#if LSM6DS0_USE_I2C
-#if LSM6DS0_SHARED_I2C
- i2cAcquireBus((devp)->config->i2cp);
-#endif /* LSM6DS0_SHARED_I2C */
- i2cStart((devp)->config->i2cp,
- (devp)->config->i2ccfg);
- if((devp)->config->acccfg != NULL) {
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG5_XL,
- devp->config->acccfg->decmode |
- devp->config->acccfg->axesenabling);
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG6_XL,
- devp->config->acccfg->outdatarate |
- devp->config->acccfg->fullscale );
- }
- if((devp)->config->gyrocfg != NULL) {
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG1_G,
- devp->config->gyrocfg->fullscale |
- devp->config->gyrocfg->outdatarate);
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG2_G,
- devp->config->gyrocfg->outsel);
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG3_G,
- devp->config->gyrocfg->hpfenable |
- devp->config->gyrocfg->lowmodecfg |
- devp->config->gyrocfg->hpcfg);
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG4,
- devp->config->gyrocfg->axesenabling);
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG9,
- LSM6DS0_GYRO_SLP_DISABLED);
- }
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG8,
- devp->config->endianness |
- devp->config->blockdataupdate);
-#if LSM6DS0_SHARED_I2C
- i2cReleaseBus((devp)->config->i2cp);
-#endif /* LSM6DS0_SHARED_I2C */
-#endif /* LSM6DS0_USE_I2C */
- /* Storing sensitivity information according to full scale value */
- if((devp)->config->acccfg != NULL) {
- if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_2G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM6DS0_ACC_SENS_2G;
- else if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_4G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM6DS0_ACC_SENS_4G;
- else if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_8G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM6DS0_ACC_SENS_8G;
- else if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_16G)
- for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
- devp->accsensitivity[i] = LSM6DS0_ACC_SENS_16G;
- else
- osalDbgAssert(FALSE, "lsm6ds0Start(), accelerometer full scale issue");
- }
- if((devp)->config->gyrocfg != NULL) {
- if(devp->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_245DSP)
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
- devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_245DPS;
- else if(devp->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_500DSP)
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
- devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_500DPS;
- else if(devp->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_2000DSP)
- for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
- devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_2000DPS;
- else
- osalDbgAssert(FALSE, "lsm6ds0Start(), gyroscope full scale issue");
- }
- /* This is the Gyroscope transient recovery time */
- osalThreadSleepMilliseconds(5);
-
- devp->state = LSM6DS0_READY;
-}
-
-/**
- * @brief Deactivates the LSM6DS0 Complex Driver peripheral.
- *
- * @param[in] devp pointer to the @p LSM6DS0Driver object
- *
- * @api
- */
-void lsm6ds0Stop(LSM6DS0Driver *devp) {
-
- osalDbgCheck(devp != NULL);
-
- osalDbgAssert((devp->state == LSM6DS0_STOP) || (devp->state == LSM6DS0_READY),
- "lsm6ds0Stop(), invalid state");
-
-#if (LSM6DS0_USE_I2C)
- if (devp->state == LSM6DS0_STOP) {
-#if LSM6DS0_SHARED_I2C
- i2cAcquireBus((devp)->config->i2cp);
- i2cStart((devp)->config->i2cp,
- (devp)->config->i2ccfg);
-#endif /* LSM6DS0_SHARED_I2C */
- if((devp)->config->acccfg != NULL) {
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG6_XL,
- LSM6DS0_ACC_ODR_PD);
- }
- if((devp)->config->gyrocfg != NULL) {
- lsm6ds0I2CWriteRegister(devp->config->i2cp,
- devp->config->slaveaddress,
- LSM6DS0_AD_CTRL_REG9,
- LSM6DS0_GYRO_SLP_ENABLED);
- }
- i2cStop((devp)->config->i2cp);
-#if LSM6DS0_SHARED_I2C
- i2cReleaseBus((devp)->config->i2cp);
-#endif /* LSM6DS0_SHARED_I2C */
- }
-#endif /* LSM6DS0_USE_I2C */
- devp->state = LSM6DS0_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 lsm6ds0.c
+ * @brief LSM6DS0 MEMS interface module code.
+ *
+ * @addtogroup lsm6ds0
+ * @{
+ */
+
+#include "hal.h"
+#include "lsm6ds0.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define LSM6DS0_ACC_SENS_2G ((float)0.061f)
+#define LSM6DS0_ACC_SENS_4G ((float)0.122f)
+#define LSM6DS0_ACC_SENS_8G ((float)0.244f)
+#define LSM6DS0_ACC_SENS_16G ((float)0.732f)
+
+#define LSM6DS0_GYRO_SENS_245DPS ((float)0.00875f)
+#define LSM6DS0_GYRO_SENS_500DPS ((float)0.01750f)
+#define LSM6DS0_GYRO_SENS_2000DPS ((float)0.07000f)
+
+#define LSM6DS0_TEMP_SENS ((float)16.0f)
+#define LSM6DS0_TEMP_SENS_OFF ((float)25.0f)
+
+#define LSM6DS0_DI ((uint8_t)0xFF)
+#define LSM6DS0_DI_0 ((uint8_t)0x01)
+#define LSM6DS0_DI_1 ((uint8_t)0x02)
+#define LSM6DS0_DI_2 ((uint8_t)0x04)
+#define LSM6DS0_DI_3 ((uint8_t)0x08)
+#define LSM6DS0_DI_4 ((uint8_t)0x10)
+#define LSM6DS0_DI_5 ((uint8_t)0x20)
+#define LSM6DS0_DI_6 ((uint8_t)0x40)
+#define LSM6DS0_DI_7 ((uint8_t)0x80)
+
+#define LSM6DS0_AD_0 ((uint8_t)0x01)
+#define LSM6DS0_AD_1 ((uint8_t)0x02)
+#define LSM6DS0_AD_2 ((uint8_t)0x04)
+#define LSM6DS0_AD_3 ((uint8_t)0x08)
+#define LSM6DS0_AD_4 ((uint8_t)0x10)
+#define LSM6DS0_AD_5 ((uint8_t)0x20)
+#define LSM6DS0_AD_6 ((uint8_t)0x40)
+
+#define LSM6DS0_RW ((uint8_t)0x80)
+
+#define LSM6DS0_AD_ACT_THS ((uint8_t)0x04)
+#define LSM6DS0_AD_ACT_DUR ((uint8_t)0x05)
+#define LSM6DS0_AD_INT_GEN_CFG_XL ((uint8_t)0x06)
+#define LSM6DS0_AD_INT_GEN_THS_X_XL ((uint8_t)0x07)
+#define LSM6DS0_AD_INT_GEN_THS_Y_XL ((uint8_t)0x08)
+#define LSM6DS0_AD_INT_GEN_THS_Z_XL ((uint8_t)0x09)
+#define LSM6DS0_AD_INT_GEN_DUR_XL ((uint8_t)0x0A)
+#define LSM6DS0_AD_REFERENCE_G ((uint8_t)0x0B)
+#define LSM6DS0_AD_INT_CTRL ((uint8_t)0x0C)
+#define LSM6DS0_AD_WHO_AM_I ((uint8_t)0x0F)
+#define LSM6DS0_AD_CTRL_REG1_G ((uint8_t)0x10)
+#define LSM6DS0_AD_CTRL_REG2_G ((uint8_t)0x11)
+#define LSM6DS0_AD_CTRL_REG3_G ((uint8_t)0x12)
+#define LSM6DS0_AD_ORIENT_CFG_G ((uint8_t)0x13)
+#define LSM6DS0_AD_INT_GEN_SRC_G ((uint8_t)0x14)
+#define LSM6DS0_AD_OUT_TEMP_L ((uint8_t)0x15)
+#define LSM6DS0_AD_OUT_TEMP_H ((uint8_t)0x16)
+#define LSM6DS0_AD_STATUS_REG1 ((uint8_t)0x17)
+#define LSM6DS0_AD_OUT_X_L_G ((uint8_t)0x18)
+#define LSM6DS0_AD_OUT_X_H_G ((uint8_t)0x19)
+#define LSM6DS0_AD_OUT_Y_L_G ((uint8_t)0x1A)
+#define LSM6DS0_AD_OUT_Y_H_G ((uint8_t)0x1B)
+#define LSM6DS0_AD_OUT_Z_L_G ((uint8_t)0x1C)
+#define LSM6DS0_AD_OUT_Z_H_G ((uint8_t)0x1D)
+#define LSM6DS0_AD_CTRL_REG4 ((uint8_t)0x1E)
+#define LSM6DS0_AD_CTRL_REG5_XL ((uint8_t)0x1F)
+#define LSM6DS0_AD_CTRL_REG6_XL ((uint8_t)0x20)
+#define LSM6DS0_AD_CTRL_REG7_XL ((uint8_t)0x21)
+#define LSM6DS0_AD_CTRL_REG8 ((uint8_t)0x22)
+#define LSM6DS0_AD_CTRL_REG9 ((uint8_t)0x23)
+#define LSM6DS0_AD_CTRL_REG10 ((uint8_t)0x24)
+#define LSM6DS0_AD_INT_GEN_SRC_XL ((uint8_t)0x26)
+#define LSM6DS0_AD_STATUS_REG2 ((uint8_t)0x27)
+#define LSM6DS0_AD_OUT_X_L_XL ((uint8_t)0x28)
+#define LSM6DS0_AD_OUT_X_H_XL ((uint8_t)0x29)
+#define LSM6DS0_AD_OUT_Y_L_XL ((uint8_t)0x2A)
+#define LSM6DS0_AD_OUT_Y_H_XL ((uint8_t)0x2B)
+#define LSM6DS0_AD_OUT_Z_L_XL ((uint8_t)0x2C)
+#define LSM6DS0_AD_OUT_Z_H_XL ((uint8_t)0x2D)
+#define LSM6DS0_AD_FIFO_CTRL ((uint8_t)0x2E)
+#define LSM6DS0_AD_FIFO_SRC ((uint8_t)0x2F)
+#define LSM6DS0_AD_INT_GEN_CFG_G ((uint8_t)0x30)
+#define LSM6DS0_AD_INT_GEN_THS_XH_G ((uint8_t)0x31)
+#define LSM6DS0_AD_INT_GEN_THS_XL_G ((uint8_t)0x32)
+#define LSM6DS0_AD_INT_GEN_THS_YH_G ((uint8_t)0x33)
+#define LSM6DS0_AD_INT_GEN_THS_YL_G ((uint8_t)0x34)
+#define LSM6DS0_AD_INT_GEN_THS_ZH_G ((uint8_t)0x35)
+#define LSM6DS0_AD_INT_GEN_THS_ZL_G ((uint8_t)0x36)
+#define LSM6DS0_AD_INT_GEN_DUR_G ((uint8_t)0x37)
+
+#define LSM6DS0_CTRL_REG1_G_FS_MASK ((uint8_t)0x18)
+#define LSM6DS0_CTRL_REG6_XL_FS_MASK ((uint8_t)0x18)
+
+#define TO_G ((float)0.001f)
+#define TO_SI ((float)0.00981f)
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief LSM6DS0 address increment mode.
+ */
+typedef enum {
+ LSM6DS0_IF_ADD_INC_DIS = 0x00, /**< Address increment disabled. */
+ LSM6DS0_IF_ADD_INC_EN = 0x04 /**< Address increment disabled. */
+}lsm6ds0_id_add_inc_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem sleep mode.
+ */
+typedef enum {
+ LSM6DS0_GYRO_SLP_DISABLED = 0x00, /**< Gyroscope in normal mode. */
+ LSM6DS0_GYRO_SLP_ENABLED = 0x40 /**< Gyroscope in sleep mode. */
+}lsm6ds0_gyro_slp_t;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if (LSM6DS0_USE_I2C) || defined(__DOXYGEN__)
+/**
+ * @brief Reads registers value using I2C.
+ * @pre The I2C interface must be initialized and the driver started.
+ * @note IF_ADD_INC bit must be 1 in CTRL_REG8
+ *
+ * @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 lsm6ds0I2CReadRegister(I2CDriver *i2cp, lsm6ds0_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 lsm6ds0I2CWriteRegister(I2CDriver *i2cp, lsm6ds0_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.
+ */
+ osalDbgAssert(FALSE, "lsm6ds0WriteRegisterI2C(), reserved register");
+ case LSM6DS0_AD_WHO_AM_I:
+ case LSM6DS0_AD_INT_GEN_SRC_G:
+ case LSM6DS0_AD_OUT_TEMP_L:
+ case LSM6DS0_AD_OUT_TEMP_H:
+ case LSM6DS0_AD_STATUS_REG1:
+ case LSM6DS0_AD_OUT_X_L_G:
+ case LSM6DS0_AD_OUT_X_H_G:
+ case LSM6DS0_AD_OUT_Y_L_G:
+ case LSM6DS0_AD_OUT_Y_H_G:
+ case LSM6DS0_AD_OUT_Z_L_G:
+ case LSM6DS0_AD_OUT_Z_H_G:
+ case LSM6DS0_AD_INT_GEN_SRC_XL:
+ case LSM6DS0_AD_STATUS_REG2:
+ case LSM6DS0_AD_OUT_X_L_XL:
+ case LSM6DS0_AD_OUT_X_H_XL:
+ case LSM6DS0_AD_OUT_Y_L_XL:
+ case LSM6DS0_AD_OUT_Y_H_XL:
+ case LSM6DS0_AD_OUT_Z_L_XL:
+ case LSM6DS0_AD_OUT_Z_H_XL:
+ case LSM6DS0_AD_FIFO_SRC:
+ /* Read only registers cannot be written, the command is ignored.*/
+ return MSG_RESET;
+ case LSM6DS0_AD_ACT_THS:
+ case LSM6DS0_AD_ACT_DUR:
+ case LSM6DS0_AD_INT_GEN_CFG_XL:
+ case LSM6DS0_AD_INT_GEN_THS_X_XL:
+ case LSM6DS0_AD_INT_GEN_THS_Y_XL:
+ case LSM6DS0_AD_INT_GEN_THS_Z_XL:
+ case LSM6DS0_AD_INT_GEN_DUR_XL:
+ case LSM6DS0_AD_REFERENCE_G:
+ case LSM6DS0_AD_INT_CTRL:
+ case LSM6DS0_AD_CTRL_REG1_G:
+ case LSM6DS0_AD_CTRL_REG2_G:
+ case LSM6DS0_AD_CTRL_REG3_G:
+ case LSM6DS0_AD_ORIENT_CFG_G:
+ case LSM6DS0_AD_CTRL_REG4:
+ case LSM6DS0_AD_CTRL_REG5_XL:
+ case LSM6DS0_AD_CTRL_REG6_XL:
+ case LSM6DS0_AD_CTRL_REG7_XL:
+ case LSM6DS0_AD_CTRL_REG8:
+ case LSM6DS0_AD_CTRL_REG9:
+ case LSM6DS0_AD_CTRL_REG10:
+ case LSM6DS0_AD_FIFO_CTRL:
+ case LSM6DS0_AD_INT_GEN_CFG_G:
+ case LSM6DS0_AD_INT_GEN_THS_XH_G:
+ case LSM6DS0_AD_INT_GEN_THS_XL_G:
+ case LSM6DS0_AD_INT_GEN_THS_YH_G:
+ case LSM6DS0_AD_INT_GEN_THS_YL_G:
+ case LSM6DS0_AD_INT_GEN_THS_ZH_G:
+ case LSM6DS0_AD_INT_GEN_THS_ZL_G:
+ case LSM6DS0_AD_INT_GEN_DUR_G:
+ txbuf[0] = reg;
+ txbuf[1] = value;
+ return i2cMasterTransmitTimeout(i2cp, sad, txbuf, 2, &rxbuf, 0, TIME_INFINITE);
+ break;
+ }
+}
+#endif /* LSM6DS0_USE_I2C */
+
+/*
+ * Interface implementation.
+ */
+static size_t acc_get_axes_number(void *ip) {
+
+ osalDbgCheck(ip != NULL);
+ return LSM6DS0_ACC_NUMBER_OF_AXES;
+}
+
+static size_t gyro_get_axes_number(void *ip) {
+
+ osalDbgCheck(ip != NULL);
+ return LSM6DS0_GYRO_NUMBER_OF_AXES;
+}
+
+static size_t sens_get_axes_number(void *ip) {
+ size_t size = 0;
+
+ osalDbgCheck(ip != NULL);
+ if (((LSM6DS0Driver *)ip)->config->acccfg != NULL)
+ size += acc_get_axes_number(ip);
+ if (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL)
+ size += gyro_get_axes_number(ip);
+ return size;
+}
+
+static msg_t acc_read_raw(void *ip, int32_t axes[]) {
+ int16_t tmp;
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM6DS0Driver *)ip)->config->acccfg != NULL));
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "acc_read_raw(), invalid state");
+
+#if LSM6DS0_USE_I2C
+ osalDbgAssert((((LSM6DS0Driver *)ip)->config->i2cp->state == I2C_READY),
+ "acc_read_raw(), channel not ready");
+#if LSM6DS0_SHARED_I2C
+ i2cAcquireBus(((LSM6DS0Driver *)ip)->config->i2cp);
+ i2cStart(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->i2ccfg);
+#endif /* LSM6DS0_SHARED_I2C */
+ if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_ACC_AE_X){
+ tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_X_L_XL, NULL);
+ tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_X_H_XL, NULL) << 8;
+ axes[0] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->accbias[0];
+ }
+ if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_ACC_AE_Y){
+ tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Y_L_XL, NULL);
+ tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Y_H_XL, NULL) << 8;
+ axes[1] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->accbias[1];
+ }
+ if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_ACC_AE_Z){
+ tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Z_L_XL, NULL);
+ tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Z_H_XL, NULL) << 8;
+ axes[2] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->accbias[2];
+ }
+#if LSM6DS0_SHARED_I2C
+ i2cReleaseBus(((LSM6DS0Driver *)ip)->config->i2cp);
+#endif /* LSM6DS0_SHARED_I2C */
+#endif /* LSM6DS0_USE_I2C */
+ return MSG_OK;
+}
+
+static msg_t gyro_read_raw(void *ip, int32_t axes[]) {
+ int16_t tmp;
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL));
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "gyro_read_raw(), invalid state");
+
+#if LSM6DS0_USE_I2C
+ osalDbgAssert((((LSM6DS0Driver *)ip)->config->i2cp->state == I2C_READY),
+ "gyro_read_raw(), channel not ready");
+#if LSM6DS0_SHARED_I2C
+ i2cAcquireBus(((LSM6DS0Driver *)ip)->config->i2cp);
+ i2cStart(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->i2ccfg);
+#endif /* LSM6DS0_SHARED_I2C */
+ if(((LSM6DS0Driver *)ip)->config->gyrocfg->axesenabling & LSM6DS0_GYRO_AE_X){
+ tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_X_L_G, NULL);
+ tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_X_H_G, NULL) << 8;
+ axes[0] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->gyrobias[0];
+ }
+ if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_GYRO_AE_Y){
+ tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Y_L_G, NULL);
+ tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Y_H_G, NULL) << 8;
+ axes[1] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->gyrobias[1];
+ }
+ if(((LSM6DS0Driver *)ip)->config->acccfg->axesenabling & LSM6DS0_GYRO_AE_Z){
+ tmp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Z_L_G, NULL);
+ tmp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_Z_H_G, NULL) << 8;
+ axes[2] = (int32_t)tmp - ((LSM6DS0Driver *)ip)->gyrobias[2];
+ }
+#if LSM6DS0_SHARED_I2C
+ i2cReleaseBus(((LSM6DS0Driver *)ip)->config->i2cp);
+#endif /* LSM6DS0_SHARED_I2C */
+#endif /* LSM6DS0_USE_I2C */
+ return MSG_OK;
+}
+
+static msg_t sens_read_raw(void *ip, int32_t axes[]) {
+ int32_t* bp = axes;
+ msg_t msg;
+ if (((LSM6DS0Driver *)ip)->config->acccfg != NULL) {
+ msg = acc_read_raw(ip, bp);
+ if(msg != MSG_OK)
+ return msg;
+ bp += LSM6DS0_ACC_NUMBER_OF_AXES;
+ }
+ if (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL) {
+ msg = gyro_read_raw(ip, bp);
+ }
+ return msg;
+}
+
+static msg_t acc_read_cooked(void *ip, float axes[]) {
+ uint32_t i;
+ int32_t raw[LSM6DS0_ACC_NUMBER_OF_AXES];
+ msg_t msg;
+
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM6DS0Driver *)ip)->config->acccfg != NULL));
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "acc_read_cooked(), invalid state");
+
+ msg = acc_read_raw(ip, raw);
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES ; i++){
+ axes[i] = raw[i] * ((LSM6DS0Driver *)ip)->accsensitivity[i];
+ if(((LSM6DS0Driver *)ip)->config->acccfg->unit == LSM6DS0_ACC_UNIT_G){
+ axes[i] *= TO_G;
+ }
+ else if(((LSM6DS0Driver *)ip)->config->acccfg->unit == LSM6DS0_ACC_UNIT_SI){
+ axes[i] *= TO_SI;
+ }
+ }
+ return msg;
+}
+
+static msg_t gyro_read_cooked(void *ip, float axes[]) {
+ uint32_t i;
+ int32_t raw[LSM6DS0_GYRO_NUMBER_OF_AXES];
+ msg_t msg;
+
+ osalDbgCheck(((ip != NULL) && (axes != NULL)) &&
+ (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL));
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "gyro_read_cooked(), invalid state");
+
+ msg = gyro_read_raw(ip, raw);
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES ; i++){
+ axes[i] = raw[i] * ((LSM6DS0Driver *)ip)->gyrosensitivity[i];
+ }
+ return msg;
+}
+
+static msg_t sens_read_cooked(void *ip, float axes[]) {
+ float* bp = axes;
+ msg_t msg;
+ if (((LSM6DS0Driver *)ip)->config->acccfg != NULL) {
+ msg = acc_read_cooked(ip, bp);
+ if(msg != MSG_OK)
+ return msg;
+ bp += LSM6DS0_ACC_NUMBER_OF_AXES;
+ }
+ if (((LSM6DS0Driver *)ip)->config->gyrocfg != NULL) {
+ msg = gyro_read_cooked(ip, bp);
+ }
+ return msg;
+}
+
+static msg_t gyro_sample_bias(void *ip) {
+ uint32_t i, j;
+ int32_t raw[LSM6DS0_GYRO_NUMBER_OF_AXES];
+ int32_t buff[LSM6DS0_GYRO_NUMBER_OF_AXES] = {0, 0, 0};
+ msg_t msg;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "sample_bias(), invalid state");
+
+ for(i = 0; i < LSM6DS0_GYRO_BIAS_ACQ_TIMES; i++){
+ msg = gyro_read_raw(ip, raw);
+ if(msg != MSG_OK)
+ return msg;
+ for(j = 0; j < LSM6DS0_GYRO_NUMBER_OF_AXES; j++){
+ buff[j] += raw[j];
+ }
+ osalThreadSleepMicroseconds(LSM6DS0_GYRO_BIAS_SETTLING_uS);
+ }
+
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++){
+ ((LSM6DS0Driver *)ip)->gyrobias[i] = buff[i] / LSM6DS0_GYRO_BIAS_ACQ_TIMES;
+ }
+ return msg;
+}
+
+static msg_t acc_set_bias(void *ip, int32_t *bp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (bp !=NULL));
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
+ (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
+ "acc_set_bias(), invalid state");
+
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) {
+ ((LSM6DS0Driver *)ip)->accbias[i] = bp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t gyro_set_bias(void *ip, int32_t *bp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (bp !=NULL));
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
+ (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
+ "gyro_set_bias(), invalid state");
+
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) {
+ ((LSM6DS0Driver *)ip)->gyrobias[i] = bp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t acc_reset_bias(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
+ (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
+ "acc_reset_bias(), invalid state");
+
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->accbias[i] = 0;
+ return MSG_OK;
+}
+
+static msg_t gyro_reset_bias(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY) ||
+ (((LSM6DS0Driver *)ip)->state == LSM6DS0_STOP),
+ "gyro_reset_bias(), invalid state");
+
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->gyrobias[i] = 0;
+ return MSG_OK;
+}
+
+static msg_t acc_set_sensivity(void *ip, float *sp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (sp !=NULL));
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "acc_set_sensivity(), invalid state");
+
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) {
+ ((LSM6DS0Driver *)ip)->accsensitivity[i] = sp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t gyro_set_sensivity(void *ip, float *sp) {
+ uint32_t i;
+
+ osalDbgCheck((ip != NULL) && (sp !=NULL));
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "gyro_set_sensivity(), invalid state");
+
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) {
+ ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = sp[i];
+ }
+ return MSG_OK;
+}
+
+static msg_t acc_reset_sensivity(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "acc_reset_sensivity(), invalid state");
+
+ if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_2G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_2G;
+ else if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_4G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_4G;
+ else if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_8G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_8G;
+ else if(((LSM6DS0Driver *)ip)->config->acccfg->fullscale == LSM6DS0_ACC_FS_16G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->accsensitivity[i] = LSM6DS0_ACC_SENS_16G;
+ else {
+ osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue");
+ return MSG_RESET;
+ }
+ return MSG_OK;
+}
+
+static msg_t gyro_reset_sensivity(void *ip) {
+ uint32_t i;
+
+ osalDbgCheck(ip != NULL);
+
+ osalDbgAssert((((LSM6DS0Driver *)ip)->state == LSM6DS0_READY),
+ "gyro_reset_sensivity(), invalid state");
+
+ if(((LSM6DS0Driver *)ip)->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_245DSP)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_245DPS;
+ else if(((LSM6DS0Driver *)ip)->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_500DSP)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_500DPS;
+ else if(((LSM6DS0Driver *)ip)->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_2000DSP)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ ((LSM6DS0Driver *)ip)->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_2000DPS;
+ else {
+ osalDbgAssert(FALSE, "reset_sensivity(), gyroscope full scale issue");
+ return MSG_RESET;
+ }
+ return MSG_OK;
+}
+
+static msg_t sens_get_temperature(void *ip, float* tempp) {
+ int16_t temp;
+#if LSM6DS0_USE_I2C
+ osalDbgAssert((((LSM6DS0Driver *)ip)->config->i2cp->state == I2C_READY),
+ "gyro_read_raw(), channel not ready");
+#if LSM6DS0_SHARED_I2C
+ i2cAcquireBus(((LSM6DS0Driver *)ip)->config->i2cp);
+ i2cStart(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->i2ccfg);
+#endif /* LSM6DS0_SHARED_I2C */
+ temp = lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_TEMP_L, NULL);
+ temp += lsm6ds0I2CReadRegister(((LSM6DS0Driver *)ip)->config->i2cp,
+ ((LSM6DS0Driver *)ip)->config->slaveaddress,
+ LSM6DS0_AD_OUT_TEMP_H, NULL) << 8;
+#if LSM6DS0_SHARED_I2C
+ i2cReleaseBus(((LSM6DS0Driver *)ip)->config->i2cp);
+#endif /* LSM6DS0_SHARED_I2C */
+#endif /* LSM6DS0_USE_I2C */
+ *tempp = ((float)temp / LSM6DS0_TEMP_SENS) + LSM6DS0_TEMP_SENS_OFF;
+ return MSG_OK;
+}
+
+static const struct BaseSensorVMT vmt_basesensor = {
+ sens_get_axes_number, sens_read_raw, sens_read_cooked
+};
+
+static const struct BaseGyroscopeVMT vmt_basegyroscope = {
+ gyro_get_axes_number, gyro_read_raw, gyro_read_cooked,
+ gyro_sample_bias, gyro_set_bias, gyro_reset_bias,
+ gyro_set_sensivity, gyro_reset_sensivity
+};
+
+static const struct BaseAccelerometerVMT vmt_baseaccelerometer = {
+ acc_get_axes_number, acc_read_raw, acc_read_cooked,
+ acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
+};
+
+static const struct LSM6DS0ACCVMT vmt_lsm6ds0acc = {
+ acc_get_axes_number, acc_read_raw, acc_read_cooked,
+ acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity
+};
+
+static const struct LSM6DS0GYROVMT vmt_lsm6ds0gyro = {
+ gyro_get_axes_number, gyro_read_raw, gyro_read_cooked,
+ gyro_sample_bias, gyro_set_bias, gyro_reset_bias,
+ gyro_set_sensivity, gyro_reset_sensivity, sens_get_temperature
+};
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initializes an instance.
+ *
+ * @param[out] devp pointer to the @p LSM6DS0Driver object
+ *
+ * @init
+ */
+void lsm6ds0ObjectInit(LSM6DS0Driver *devp) {
+ uint32_t i;
+ devp->vmt_basesensor = &vmt_basesensor;
+ devp->vmt_baseaccelerometer = &vmt_baseaccelerometer;
+ devp->vmt_basegyroscope = &vmt_basegyroscope;
+ devp->vmt_lsm6ds0acc = &vmt_lsm6ds0acc;
+ devp->vmt_lsm6ds0gyro = &vmt_lsm6ds0gyro;
+ devp->config = NULL;
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ devp->accbias[i] = 0;
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
+ devp->gyrobias[i] = 0;
+ devp->state = LSM6DS0_STOP;
+}
+
+/**
+ * @brief Configures and activates LSM6DS0 Complex Driver peripheral.
+ *
+ * @param[in] devp pointer to the @p LSM6DS0Driver object
+ * @param[in] config pointer to the @p LSM6DS0Config object
+ *
+ * @api
+ */
+void lsm6ds0Start(LSM6DS0Driver *devp, const LSM6DS0Config *config) {
+ uint32_t i;
+ osalDbgCheck((devp != NULL) && (config != NULL));
+
+ osalDbgAssert((devp->state == LSM6DS0_STOP) || (devp->state == LSM6DS0_READY),
+ "lsm6ds0Start(), invalid state");
+
+ devp->config = config;
+
+#if LSM6DS0_USE_I2C
+#if LSM6DS0_SHARED_I2C
+ i2cAcquireBus((devp)->config->i2cp);
+#endif /* LSM6DS0_SHARED_I2C */
+ i2cStart((devp)->config->i2cp,
+ (devp)->config->i2ccfg);
+ if((devp)->config->acccfg != NULL) {
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG5_XL,
+ devp->config->acccfg->decmode |
+ devp->config->acccfg->axesenabling);
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG6_XL,
+ devp->config->acccfg->outdatarate |
+ devp->config->acccfg->fullscale );
+ }
+ if((devp)->config->gyrocfg != NULL) {
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG1_G,
+ devp->config->gyrocfg->fullscale |
+ devp->config->gyrocfg->outdatarate);
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG2_G,
+ devp->config->gyrocfg->outsel);
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG3_G,
+ devp->config->gyrocfg->hpfenable |
+ devp->config->gyrocfg->lowmodecfg |
+ devp->config->gyrocfg->hpcfg);
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG4,
+ devp->config->gyrocfg->axesenabling);
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG9,
+ LSM6DS0_GYRO_SLP_DISABLED);
+ }
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG8,
+ devp->config->endianness |
+ devp->config->blockdataupdate);
+#if LSM6DS0_SHARED_I2C
+ i2cReleaseBus((devp)->config->i2cp);
+#endif /* LSM6DS0_SHARED_I2C */
+#endif /* LSM6DS0_USE_I2C */
+ /* Storing sensitivity information according to full scale value */
+ if((devp)->config->acccfg != NULL) {
+ if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_2G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM6DS0_ACC_SENS_2G;
+ else if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_4G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM6DS0_ACC_SENS_4G;
+ else if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_8G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM6DS0_ACC_SENS_8G;
+ else if(devp->config->acccfg->fullscale == LSM6DS0_ACC_FS_16G)
+ for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++)
+ devp->accsensitivity[i] = LSM6DS0_ACC_SENS_16G;
+ else
+ osalDbgAssert(FALSE, "lsm6ds0Start(), accelerometer full scale issue");
+ }
+ if((devp)->config->gyrocfg != NULL) {
+ if(devp->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_245DSP)
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
+ devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_245DPS;
+ else if(devp->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_500DSP)
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
+ devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_500DPS;
+ else if(devp->config->gyrocfg->fullscale == LSM6DS0_GYRO_FS_2000DSP)
+ for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++)
+ devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_2000DPS;
+ else
+ osalDbgAssert(FALSE, "lsm6ds0Start(), gyroscope full scale issue");
+ }
+ /* This is the Gyroscope transient recovery time */
+ osalThreadSleepMilliseconds(5);
+
+ devp->state = LSM6DS0_READY;
+}
+
+/**
+ * @brief Deactivates the LSM6DS0 Complex Driver peripheral.
+ *
+ * @param[in] devp pointer to the @p LSM6DS0Driver object
+ *
+ * @api
+ */
+void lsm6ds0Stop(LSM6DS0Driver *devp) {
+
+ osalDbgCheck(devp != NULL);
+
+ osalDbgAssert((devp->state == LSM6DS0_STOP) || (devp->state == LSM6DS0_READY),
+ "lsm6ds0Stop(), invalid state");
+
+#if (LSM6DS0_USE_I2C)
+ if (devp->state == LSM6DS0_STOP) {
+#if LSM6DS0_SHARED_I2C
+ i2cAcquireBus((devp)->config->i2cp);
+ i2cStart((devp)->config->i2cp,
+ (devp)->config->i2ccfg);
+#endif /* LSM6DS0_SHARED_I2C */
+ if((devp)->config->acccfg != NULL) {
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG6_XL,
+ LSM6DS0_ACC_ODR_PD);
+ }
+ if((devp)->config->gyrocfg != NULL) {
+ lsm6ds0I2CWriteRegister(devp->config->i2cp,
+ devp->config->slaveaddress,
+ LSM6DS0_AD_CTRL_REG9,
+ LSM6DS0_GYRO_SLP_ENABLED);
+ }
+ i2cStop((devp)->config->i2cp);
+#if LSM6DS0_SHARED_I2C
+ i2cReleaseBus((devp)->config->i2cp);
+#endif /* LSM6DS0_SHARED_I2C */
+ }
+#endif /* LSM6DS0_USE_I2C */
+ devp->state = LSM6DS0_STOP;
+}
+/** @} */
diff --git a/os/ex/ST/lsm6ds0.h b/os/ex/ST/lsm6ds0.h
index a43bf7ad9..a2cee28ec 100644
--- a/os/ex/ST/lsm6ds0.h
+++ b/os/ex/ST/lsm6ds0.h
@@ -1,604 +1,604 @@
-/*
- 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 lsm6ds0.h
- * @brief LSM6DS0 MEMS interface module header.
- *
- * @{
- */
-#ifndef _LSM6DS0_H_
-#define _LSM6DS0_H_
-
-#include "hal_accelerometer.h"
-#include "hal_gyroscope.h"
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/**
- * @brief LSM6DS0 accelerometer subsystem number of axes.
- */
-#define LSM6DS0_ACC_NUMBER_OF_AXES ((size_t) 3U)
-
-/**
- * @brief LSM6DS0 gyroscope subsystem number of axes.
- */
-#define LSM6DS0_GYRO_NUMBER_OF_AXES ((size_t) 3U)
-
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
-
-/**
- * @name Configuration options
- * @{
- */
-/**
- * @brief LSM6DS0 SPI interface selector.
- * @details If set to @p TRUE the support for SPI is included.
- * @note The default is @p FALSE.
- */
-#if !defined(LSM6DS0_USE_SPI) || defined(__DOXYGEN__)
-#define LSM6DS0_USE_SPI FALSE
-#endif
-
-/**
- * @brief LSM6DS0 I2C interface selector.
- * @details If set to @p TRUE the support for I2C is included.
- * @note The default is @p TRUE.
- */
-#if !defined(LSM6DS0_USE_I2C) || defined(__DOXYGEN__)
-#define LSM6DS0_USE_I2C TRUE
-#endif
-
-/**
- * @brief LSM6DS0 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(LSM6DS0_SHARED_I2C) || defined(__DOXYGEN__)
-#define LSM6DS0_SHARED_I2C FALSE
-#endif
-
-/**
- * @brief Number of acquisitions for gyroscope 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(LSM6DS0_GYRO_BIAS_ACQ_TIMES) || defined(__DOXYGEN__)
-#define LSM6DS0_GYRO_BIAS_ACQ_TIMES 50
-#endif
-
-/**
- * @brief Settling time for gyroscope bias removal.
- * @details This is the time between each bias acquisition.
- */
-#if !defined(LSM6DS0_GYRO_BIAS_SETTLING_uS) || defined(__DOXYGEN__)
-#define LSM6DS0_GYRO_BIAS_SETTLING_uS 5000
-#endif
-/** @} */
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-#if LSM6DS0_USE_SPI && LSM6DS0_USE_I2C
-#error "LSM6DS0_USE_SPI and LSM6DS0_USE_I2C cannot be both true"
-#endif
-
-#if LSM6DS0_USE_SPI && !HAL_USE_SPI
-#error "LSM6DS0_USE_SPI requires HAL_USE_SPI"
-#endif
-
-#if LSM6DS0_USE_I2C && !HAL_USE_I2C
-#error "LSM6DS0_USE_I2C requires HAL_USE_I2C"
-#endif
-
-#if LSM6DS0_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
-#error "LSM6DS0_SHARED_SPI requires I2C_USE_MUTUAL_EXCLUSION"
-#endif
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/**
- * @name LSM6DS0 accelerometer subsystem data structures and types.
- * @{
- */
-
-/**
- * @brief LSM6DS0 accelerometer subsystem full scale.
- */
-typedef enum {
- LSM6DS0_ACC_FS_2G = 0x00, /**< Full scale ±2g. */
- LSM6DS0_ACC_FS_4G = 0x10, /**< Full scale ±4g. */
- LSM6DS0_ACC_FS_8G = 0x18, /**< Full scale ±8g. */
- LSM6DS0_ACC_FS_16G = 0x08 /**< Full scale ±16g. */
-} lsm6ds0_acc_fs_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem output data rate.
- */
-typedef enum {
- LSM6DS0_ACC_ODR_PD = 0x00, /**< Power down */
- LSM6DS0_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */
- LSM6DS0_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */
- LSM6DS0_ACC_ODR_119Hz = 0x60, /**< ODR 119 Hz */
- LSM6DS0_ACC_ODR_238Hz = 0x80, /**< ODR 238 Hz */
- LSM6DS0_ACC_ODR_476Hz = 0xA0, /**< ODR 476 Hz */
- LSM6DS0_ACC_ODR_952Hz = 0xC0 /**< ODR 952 Hz */
-} lsm6ds0_acc_odr_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem axes enabling.
- */
-typedef enum {
- LSM6DS0_ACC_AE_DISABLED = 0x00, /**< All axes disabled. */
- LSM6DS0_ACC_AE_X = 0x08, /**< Only X-axis enabled. */
- LSM6DS0_ACC_AE_Y = 0x10, /**< Only Y-axis enabled. */
- LSM6DS0_ACC_AE_XY = 0x18, /**< X and Y axes enabled. */
- LSM6DS0_ACC_AE_Z = 0x20, /**< Only Z-axis enabled. */
- LSM6DS0_ACC_AE_XZ = 0x28, /**< X and Z axes enabled. */
- LSM6DS0_ACC_AE_YZ = 0x30, /**< Y and Z axes enabled. */
- LSM6DS0_ACC_AE_XYZ = 0x38 /**< All axes enabled. */
-} lsm6ds0_acc_ae_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem anti aliasing filter bandwidth.
- */
-typedef enum {
- LSM6DS0_ACC_OBW_ODR = 0x00, /**< Depending on ODR. */
- LSM6DS0_ACC_OBW_AA = 0x04 /**< Same of the Anti aliasing. */
-} lsm6ds0_acc_obw_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem high resolution mode.
- */
-typedef enum {
- LSM6DS0_ACC_HR_DISABLED = 0x00, /**< High resolution mode disabled. */
- LSM6DS0_ACC_HR_ENABLED = 0x80 /**< High resolution mode enabled. */
-} lsm6ds0_acc_hr_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem filtered data selection.
- */
-typedef enum {
- LSM6DS0_ACC_FDS_ENABLED = 0x00, /**< Internal filter bypassed. */
- LSM6DS0_ACC_FDS_DISABLED = 0x04 /**< Internal filter not bypassed. */
-} lsm6ds0_acc_fds_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem digital filter.
- */
-typedef enum {
- LSM6DS0_ACC_DCF_400 = 0x00, /**< Low pass cutoff freq. ODR/400 Hz. */
- LSM6DS0_ACC_DCF_100 = 0x20, /**< Low pass cutoff freq. ODR/100 Hz. */
- LSM6DS0_ACC_DCF_50 = 0x60, /**< Low pass cutoff freq. ODR/50 Hz. */
- LSM6DS0_ACC_DCF_9 = 0x40 /**< Low pass cutoff freq. ODR/9 Hz. */
-} lsm6ds0_acc_dcf_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem anti aliasing filter bandwidth.
- */
-typedef enum {
- LSM6DS0_ACC_AABW_408Hz = 0x00, /**< Anti Aliasing filter BW 408Hz. */
- LSM6DS0_ACC_AABW_211Hz = 0x01, /**< Anti Aliasing filter BW 211Hz. */
- LSM6DS0_ACC_AABW_105Hz = 0x02, /**< Anti Aliasing filter BW 105Hz. */
- LSM6DS0_ACC_AABW_50Hz = 0x03, /**< Anti Aliasing filter BW 50Hz. */
- LSM6DS0_ACC_AABW_AUTO = 0x04 /**< Anti Aliasing filter BW auto. */
-} lsm6ds0_acc_aabw_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem decimation mode.
- */
-typedef enum {
- LSM6DS0_ACC_DEC_DISABLED = 0x00, /**< Decimation disabled. */
- LSM6DS0_ACC_DEC_X2 = 0x40, /**< Output updated every 2 samples. */
- LSM6DS0_ACC_DEC_X4 = 0x80, /**< Output updated every 4 samples. */
- LSM6DS0_ACC_DEC_X8 = 0xC0 /**< Output updated every 8 samples. */
-} lsm6ds0_acc_dec_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem unit.
- */
-typedef enum {
- LSM6DS0_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
- LSM6DS0_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
- LSM6DS0_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
-} lsm6ds0_acc_unit_t;
-
-/**
- * @brief LSM6DS0 accelerometer subsystem configuration structure.
- */
-typedef struct {
- /**
- * @brief LSM6DS0 accelerometer subsystem full scale.
- */
- lsm6ds0_acc_fs_t fullscale;
- /**
- * @brief LSM6DS0 accelerometer subsystem output data rate.
- */
- lsm6ds0_acc_odr_t outdatarate;
- /**
- * @brief LSM6DS0 accelerometer subsystem axes enabling.
- */
- lsm6ds0_acc_ae_t axesenabling;
- /**
- * @brief LSM6DS0 accelerometer subsystem output bandwidth.
- */
- lsm6ds0_acc_obw_t outbandwidth;
- /**
- * @brief LSM6DS0 accelerometer subsystem high resolution mode.
- */
- lsm6ds0_acc_hr_t highresmode;
- /**
- * @brief LSM6DS0 accelerometer subsystem filtered data selection.
- */
- lsm6ds0_acc_fds_t filtdatasel;
- /**
- * @brief LSM6DS0 accelerometer subsystem digital filter.
- */
- lsm6ds0_acc_dcf_t digifilter;
- /**
- * @brief LSM6DS0 accelerometer subsystem anti aliasing filter bandwidth.
- */
- lsm6ds0_acc_aabw_t aabandwidth;
- /**
- * @brief LSM6DS0 accelerometer subsystem decimation mode.
- */
- lsm6ds0_acc_dec_t decmode;
- /**
- * @brief LSM6DS0 accelerometer subsystem unit.
- */
- lsm6ds0_acc_unit_t unit;
-} LSM6DS0AccConfig;
-/** @} */
-
-/**
- * @name LSM6DS0 gyroscope subsystem data structures and types.
- * @{
- */
-/**
- * @brief LSM6DS0 gyroscope subsystem full scale.
- */
-typedef enum {
- LSM6DS0_GYRO_FS_245DSP = 0x00, /**< Full scale ±245 degree per second */
- LSM6DS0_GYRO_FS_500DSP = 0x08, /**< Full scale ±500 degree per second */
- LSM6DS0_GYRO_FS_2000DSP = 0x18 /**< Full scale ±2000 degree per second */
-} lsm6ds0_gyro_fs_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem output data rate.
- */
-typedef enum {
- LSM6DS0_GYRO_ODR_PD = 0x00,
- LSM6DS0_GYRO_ODR_95HZ_FC_25 = 0x10,
- LSM6DS0_GYRO_ODR_14_9HZ_FC_5 = 0X20,
- LSM6DS0_GYRO_ODR_59_5HZ_FC_16 = 0X40,
- LSM6DS0_GYRO_ODR_119HZ_FC_14 = 0X60,
- LSM6DS0_GYRO_ODR_119HZ_FC_31 = 0X61,
- LSM6DS0_GYRO_ODR_238HZ_FC_14 = 0X80,
- LSM6DS0_GYRO_ODR_238HZ_FC_29 = 0X81,
- LSM6DS0_GYRO_ODR_238HZ_FC_63 = 0X82,
- LSM6DS0_GYRO_ODR_238HZ_FC_78 = 0X83,
- LSM6DS0_GYRO_ODR_476HZ_FC_21 = 0XA0,
- LSM6DS0_GYRO_ODR_476HZ_FC_28 = 0XA1,
- LSM6DS0_GYRO_ODR_476HZ_FC_57 = 0XA2,
- LSM6DS0_GYRO_ODR_476HZ_FC_100 = 0XA3,
- LSM6DS0_GYRO_ODR_952HZ_FC_33 = 0XC0,
- LSM6DS0_GYRO_ODR_952HZ_FC_40 = 0XC1,
- LSM6DS0_GYRO_ODR_952HZ_FC_58 = 0XC2,
- LSM6DS0_GYRO_ODR_952HZ_FC_100 = 0XC3
-} lsm6ds0_gyro_odr_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem axes enabling.
- */
-typedef enum {
- LSM6DS0_GYRO_AE_DISABLED = 0x00, /**< All axes disabled. */
- LSM6DS0_GYRO_AE_X = 0x08, /**< Only X-axis enabled. */
- LSM6DS0_GYRO_AE_Y = 0x10, /**< Only Y-axis enabled. */
- LSM6DS0_GYRO_AE_XY = 0x18, /**< X and Y axes enabled. */
- LSM6DS0_GYRO_AE_Z = 0x20, /**< Only Z-axis enabled. */
- LSM6DS0_GYRO_AE_XZ = 0x28, /**< X and Z axes enabled. */
- LSM6DS0_GYRO_AE_YZ = 0x30, /**< Y and Z axes enabled. */
- LSM6DS0_GYRO_AE_XYZ = 0x38 /**< All axes enabled. */
-} lsm6ds0_gyro_ae_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem low mode configuration.
- */
-typedef enum {
- LSM6DS0_GYRO_LP_DISABLED = 0x00, /**< Low power mode disabled. */
- LSM6DS0_GYRO_LP_ENABLED = 0x80 /**< Low power mode enabled. */
-} lsm6ds0_gyro_lp_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem output selection.
- */
-typedef enum {
- LSM6DS0_GYRO_OUT_SEL_0 = 0x00, /**< Low pass filter 1. */
- LSM6DS0_GYRO_OUT_SEL_1 = 0x01, /**< High pass filter 1 if enabled. */
- LSM6DS0_GYRO_OUT_SEL_2 = 0x02 /**< Low pass filter 2. */
-} lsm6ds0_gyro_out_sel_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem high pass filter.
- */
-typedef enum {
- LSM6DS0_GYRO_HP_DISABLED = 0x00, /**< High pass filter disabled. */
- LSM6DS0_GYRO_HP_ENABLED = 0x40 /**< High pass filter enabled. */
-} lsm6ds0_gyro_hp_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem high pass filter configuration.
- */
-typedef enum {
- LSM6DS0_GYRO_HPCF_0 = 0x00, /**< Refer to table 48 of RM */
- LSM6DS0_GYRO_HPCF_1 = 0x01,
- LSM6DS0_GYRO_HPCF_2 = 0x02,
- LSM6DS0_GYRO_HPCF_3 = 0x03,
- LSM6DS0_GYRO_HPCF_4 = 0x04,
- LSM6DS0_GYRO_HPCF_5 = 0x05,
- LSM6DS0_GYRO_HPCF_6 = 0x06,
- LSM6DS0_GYRO_HPCF_7 = 0x07,
- LSM6DS0_GYRO_HPCF_8 = 0x08,
- LSM6DS0_GYRO_HPCF_9 = 0x09
-} lsm6ds0_gyro_hpcf_t;
-
-/**
- * @brief LSM6DS0 gyroscope subsystem configuration structure.
- */
-typedef struct {
- /**
- * @brief LSM6DS0 gyroscope subsystem full scale.
- */
- lsm6ds0_gyro_fs_t fullscale;
- /**
- * @brief LSM6DS0 gyroscope subsystem output data rate.
- */
- lsm6ds0_gyro_odr_t outdatarate;
- /**
- * @brief LSM6DS0 gyroscope subsystem axes enabling.
- */
- lsm6ds0_gyro_ae_t axesenabling;
- /**
- * @brief LSM6DS0 gyroscope subsystem low mode configuration.
- */
- lsm6ds0_gyro_lp_t lowmodecfg;
- /**
- * @brief LSM6DS0 gyroscope subsystem output selection.
- */
- lsm6ds0_gyro_out_sel_t outsel;
- /**
- * @brief LSM6DS0 gyroscope subsystem high pass filter.
- */
- lsm6ds0_gyro_hp_t hpfenable;
- /**
- * @brief LSM6DS0 gyroscope subsystem high pass filter configuration.
- */
- lsm6ds0_gyro_hpcf_t hpcfg;
-} LSM6DS0GyroConfig;
-/** @} */
-
-/**
- * @name LSM6DS0 main system data structures and types.
- * @{
- */
-/**
- * @brief Accelerometer and Gyroscope Slave Address.
- */
-typedef enum {
- LSM6DS0_SAD_GND = 0x6A, /**< SAD pin connected to GND. */
- LSM6DS0_SAD_VCC = 0x6B /**< SAD pin connected to VCC. */
-} lsm6ds0_sad_t;
-
-/**
- * @brief LSM6DS0 block data update.
- */
-typedef enum {
- LSM6DS0_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
- LSM6DS0_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */
-} lsm6ds0_bdu_t;
-
-/**
- * @brief LSM6DS0 endianness.
- */
-typedef enum {
- LSM6DS0_END_LITTLE = 0x00, /**< Little endian. */
- LSM6DS0_END_BIG = 0x20 /**< Big endian. */
-} lsm6ds0_end_t;
-
-/**
- * @brief Driver state machine possible states.
- */
-typedef enum {
- LSM6DS0_UNINIT = 0, /**< Not initialized. */
- LSM6DS0_STOP = 1, /**< Stopped. */
- LSM6DS0_READY = 2, /**< Ready. */
-} lsm6ds0_state_t;
-
-/**
- * @brief LSM6DS0 configuration structure.
- */
-typedef struct {
-#if (LSM6DS0_USE_SPI) || defined(__DOXYGEN__)
- /**
- * @brief SPI driver associated to this LSM6DS0.
- */
- SPIDriver *spip;
- /**
- * @brief SPI configuration associated to this LSM6DS0 accelerometer
- * subsystem.
- */
- const SPIConfig *accspicfg;
- /**
- * @brief SPI configuration associated to this LSM6DS0 compass
- * subsystem.
- */
- const SPIConfig *gyrospicfg;
-#endif /* LSM6DS0_USE_SPI */
-#if (LSM6DS0_USE_I2C) || defined(__DOXYGEN__)
- /**
- * @brief I2C driver associated to this LSM6DS0.
- */
- I2CDriver *i2cp;
- /**
- * @brief I2C configuration associated to this LSM6DS0 accelerometer
- * subsystem.
- */
- const I2CConfig *i2ccfg;
-#endif /* LSM6DS0_USE_I2C */
- /**
- * @brief LSM6DS0 accelerometer subsystem configuration structure
- */
- const LSM6DS0AccConfig *acccfg;
- /**
- * @brief LSM6DS0 gyroscope subsystem configuration structure
- */
- const LSM6DS0GyroConfig *gyrocfg;
- /**
- * @brief Accelerometer and Gyroscope Slave Address
- */
- lsm6ds0_sad_t slaveaddress;
- /**
- * @brief LSM6DS0 block data update
- */
- lsm6ds0_bdu_t blockdataupdate;
- /**
- * @brief LSM6DS0 endianness
- */
- lsm6ds0_end_t endianness;
-} LSM6DS0Config;
-
-/**
- * @brief Structure representing a LSM6DS0 driver.
- */
-typedef struct LSM6DS0Driver LSM6DS0Driver;
-
-/**
- * @brief @p LSM6DS0 accelerometer subsystem specific methods.
- */
-#define _lsm6ds0_acc_methods \
- _base_accelerometer_methods
-
-/**
- * @brief @p LSM6DS0 gyroscope subsystem specific methods.
- */
-#define _lsm6ds0_gyro_methods \
- _base_gyroscope_methods \
- /* Retrieve the temperature of LSM6DS0 chip.*/ \
- msg_t (*get_temperature)(void *instance, float* temperature);
-
-/**
- * @extends BaseAccelerometerVMT
- *
- * @brief @p LSM6DS0 accelerometer virtual methods table.
- */
-struct LSM6DS0ACCVMT {
- _lsm6ds0_acc_methods
-};
-
-/**
- * @extends BaseCompassVMT
- *
- * @brief @p LSM6DS0 gyroscope virtual methods table.
- */
-struct LSM6DS0GYROVMT {
- _lsm6ds0_gyro_methods
-};
-
-/**
- * @brief @p LSM6DS0Driver specific data.
- */
-#define _lsm6ds0_data \
- _base_accelerometer_data \
- _base_gyroscope_data \
- /* Driver state.*/ \
- lsm6ds0_state_t state; \
- /* Current configuration data.*/ \
- const LSM6DS0Config *config; \
- /* Current accelerometer sensitivity.*/ \
- float accsensitivity[LSM6DS0_ACC_NUMBER_OF_AXES]; \
- /* Accelerometer bias data.*/ \
- int32_t accbias[LSM6DS0_ACC_NUMBER_OF_AXES]; \
- /* Current gyroscope sensitivity.*/ \
- float gyrosensitivity[LSM6DS0_GYRO_NUMBER_OF_AXES]; \
- /* Bias data.*/ \
- int32_t gyrobias[LSM6DS0_GYRO_NUMBER_OF_AXES];
-
-/**
- * @brief LSM6DS0 6-axis accelerometer/gyroscope class.
- */
-struct LSM6DS0Driver {
- /** @brief BaseSensor Virtual Methods Table. */
- const struct BaseSensorVMT *vmt_basesensor;
- /** @brief BaseAccelerometer Virtual Methods Table. */
- const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
- /** @brief BaseGyroscope Virtual Methods Table. */
- const struct BaseGyroscopeVMT *vmt_basegyroscope;
- /** @brief LSM6DS0 Accelerometer Virtual Methods Table. */
- const struct LSM6DS0ACCVMT *vmt_lsm6ds0acc;
- /** @brief LSM6DS0 Gyroscope Virtual Methods Table. */
- const struct LSM6DS0GYROVMT *vmt_lsm6ds0gyro;
- _lsm6ds0_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_lsm6ds0gyro->get_temperature(ip, tpp)
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- void lsm6ds0ObjectInit(LSM6DS0Driver *devp);
- void lsm6ds0Start(LSM6DS0Driver *devp, const LSM6DS0Config *config);
- void lsm6ds0Stop(LSM6DS0Driver *devp);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LSM6DS0_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 lsm6ds0.h
+ * @brief LSM6DS0 MEMS interface module header.
+ *
+ * @{
+ */
+#ifndef _LSM6DS0_H_
+#define _LSM6DS0_H_
+
+#include "hal_accelerometer.h"
+#include "hal_gyroscope.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem number of axes.
+ */
+#define LSM6DS0_ACC_NUMBER_OF_AXES ((size_t) 3U)
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem number of axes.
+ */
+#define LSM6DS0_GYRO_NUMBER_OF_AXES ((size_t) 3U)
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief LSM6DS0 SPI interface selector.
+ * @details If set to @p TRUE the support for SPI is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(LSM6DS0_USE_SPI) || defined(__DOXYGEN__)
+#define LSM6DS0_USE_SPI FALSE
+#endif
+
+/**
+ * @brief LSM6DS0 I2C interface selector.
+ * @details If set to @p TRUE the support for I2C is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(LSM6DS0_USE_I2C) || defined(__DOXYGEN__)
+#define LSM6DS0_USE_I2C TRUE
+#endif
+
+/**
+ * @brief LSM6DS0 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(LSM6DS0_SHARED_I2C) || defined(__DOXYGEN__)
+#define LSM6DS0_SHARED_I2C FALSE
+#endif
+
+/**
+ * @brief Number of acquisitions for gyroscope 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(LSM6DS0_GYRO_BIAS_ACQ_TIMES) || defined(__DOXYGEN__)
+#define LSM6DS0_GYRO_BIAS_ACQ_TIMES 50
+#endif
+
+/**
+ * @brief Settling time for gyroscope bias removal.
+ * @details This is the time between each bias acquisition.
+ */
+#if !defined(LSM6DS0_GYRO_BIAS_SETTLING_uS) || defined(__DOXYGEN__)
+#define LSM6DS0_GYRO_BIAS_SETTLING_uS 5000
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if LSM6DS0_USE_SPI && LSM6DS0_USE_I2C
+#error "LSM6DS0_USE_SPI and LSM6DS0_USE_I2C cannot be both true"
+#endif
+
+#if LSM6DS0_USE_SPI && !HAL_USE_SPI
+#error "LSM6DS0_USE_SPI requires HAL_USE_SPI"
+#endif
+
+#if LSM6DS0_USE_I2C && !HAL_USE_I2C
+#error "LSM6DS0_USE_I2C requires HAL_USE_I2C"
+#endif
+
+#if LSM6DS0_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
+#error "LSM6DS0_SHARED_SPI requires I2C_USE_MUTUAL_EXCLUSION"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @name LSM6DS0 accelerometer subsystem data structures and types.
+ * @{
+ */
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem full scale.
+ */
+typedef enum {
+ LSM6DS0_ACC_FS_2G = 0x00, /**< Full scale ±2g. */
+ LSM6DS0_ACC_FS_4G = 0x10, /**< Full scale ±4g. */
+ LSM6DS0_ACC_FS_8G = 0x18, /**< Full scale ±8g. */
+ LSM6DS0_ACC_FS_16G = 0x08 /**< Full scale ±16g. */
+} lsm6ds0_acc_fs_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem output data rate.
+ */
+typedef enum {
+ LSM6DS0_ACC_ODR_PD = 0x00, /**< Power down */
+ LSM6DS0_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */
+ LSM6DS0_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */
+ LSM6DS0_ACC_ODR_119Hz = 0x60, /**< ODR 119 Hz */
+ LSM6DS0_ACC_ODR_238Hz = 0x80, /**< ODR 238 Hz */
+ LSM6DS0_ACC_ODR_476Hz = 0xA0, /**< ODR 476 Hz */
+ LSM6DS0_ACC_ODR_952Hz = 0xC0 /**< ODR 952 Hz */
+} lsm6ds0_acc_odr_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem axes enabling.
+ */
+typedef enum {
+ LSM6DS0_ACC_AE_DISABLED = 0x00, /**< All axes disabled. */
+ LSM6DS0_ACC_AE_X = 0x08, /**< Only X-axis enabled. */
+ LSM6DS0_ACC_AE_Y = 0x10, /**< Only Y-axis enabled. */
+ LSM6DS0_ACC_AE_XY = 0x18, /**< X and Y axes enabled. */
+ LSM6DS0_ACC_AE_Z = 0x20, /**< Only Z-axis enabled. */
+ LSM6DS0_ACC_AE_XZ = 0x28, /**< X and Z axes enabled. */
+ LSM6DS0_ACC_AE_YZ = 0x30, /**< Y and Z axes enabled. */
+ LSM6DS0_ACC_AE_XYZ = 0x38 /**< All axes enabled. */
+} lsm6ds0_acc_ae_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem anti aliasing filter bandwidth.
+ */
+typedef enum {
+ LSM6DS0_ACC_OBW_ODR = 0x00, /**< Depending on ODR. */
+ LSM6DS0_ACC_OBW_AA = 0x04 /**< Same of the Anti aliasing. */
+} lsm6ds0_acc_obw_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem high resolution mode.
+ */
+typedef enum {
+ LSM6DS0_ACC_HR_DISABLED = 0x00, /**< High resolution mode disabled. */
+ LSM6DS0_ACC_HR_ENABLED = 0x80 /**< High resolution mode enabled. */
+} lsm6ds0_acc_hr_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem filtered data selection.
+ */
+typedef enum {
+ LSM6DS0_ACC_FDS_ENABLED = 0x00, /**< Internal filter bypassed. */
+ LSM6DS0_ACC_FDS_DISABLED = 0x04 /**< Internal filter not bypassed. */
+} lsm6ds0_acc_fds_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem digital filter.
+ */
+typedef enum {
+ LSM6DS0_ACC_DCF_400 = 0x00, /**< Low pass cutoff freq. ODR/400 Hz. */
+ LSM6DS0_ACC_DCF_100 = 0x20, /**< Low pass cutoff freq. ODR/100 Hz. */
+ LSM6DS0_ACC_DCF_50 = 0x60, /**< Low pass cutoff freq. ODR/50 Hz. */
+ LSM6DS0_ACC_DCF_9 = 0x40 /**< Low pass cutoff freq. ODR/9 Hz. */
+} lsm6ds0_acc_dcf_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem anti aliasing filter bandwidth.
+ */
+typedef enum {
+ LSM6DS0_ACC_AABW_408Hz = 0x00, /**< Anti Aliasing filter BW 408Hz. */
+ LSM6DS0_ACC_AABW_211Hz = 0x01, /**< Anti Aliasing filter BW 211Hz. */
+ LSM6DS0_ACC_AABW_105Hz = 0x02, /**< Anti Aliasing filter BW 105Hz. */
+ LSM6DS0_ACC_AABW_50Hz = 0x03, /**< Anti Aliasing filter BW 50Hz. */
+ LSM6DS0_ACC_AABW_AUTO = 0x04 /**< Anti Aliasing filter BW auto. */
+} lsm6ds0_acc_aabw_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem decimation mode.
+ */
+typedef enum {
+ LSM6DS0_ACC_DEC_DISABLED = 0x00, /**< Decimation disabled. */
+ LSM6DS0_ACC_DEC_X2 = 0x40, /**< Output updated every 2 samples. */
+ LSM6DS0_ACC_DEC_X4 = 0x80, /**< Output updated every 4 samples. */
+ LSM6DS0_ACC_DEC_X8 = 0xC0 /**< Output updated every 8 samples. */
+} lsm6ds0_acc_dec_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem unit.
+ */
+typedef enum {
+ LSM6DS0_ACC_UNIT_G = 0x00, /**< Cooked data in g. */
+ LSM6DS0_ACC_UNIT_MG = 0x01, /**< Cooked data in mg. */
+ LSM6DS0_ACC_UNIT_SI = 0x02, /**< Cooked data in m/s^2. */
+} lsm6ds0_acc_unit_t;
+
+/**
+ * @brief LSM6DS0 accelerometer subsystem configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief LSM6DS0 accelerometer subsystem full scale.
+ */
+ lsm6ds0_acc_fs_t fullscale;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem output data rate.
+ */
+ lsm6ds0_acc_odr_t outdatarate;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem axes enabling.
+ */
+ lsm6ds0_acc_ae_t axesenabling;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem output bandwidth.
+ */
+ lsm6ds0_acc_obw_t outbandwidth;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem high resolution mode.
+ */
+ lsm6ds0_acc_hr_t highresmode;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem filtered data selection.
+ */
+ lsm6ds0_acc_fds_t filtdatasel;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem digital filter.
+ */
+ lsm6ds0_acc_dcf_t digifilter;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem anti aliasing filter bandwidth.
+ */
+ lsm6ds0_acc_aabw_t aabandwidth;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem decimation mode.
+ */
+ lsm6ds0_acc_dec_t decmode;
+ /**
+ * @brief LSM6DS0 accelerometer subsystem unit.
+ */
+ lsm6ds0_acc_unit_t unit;
+} LSM6DS0AccConfig;
+/** @} */
+
+/**
+ * @name LSM6DS0 gyroscope subsystem data structures and types.
+ * @{
+ */
+/**
+ * @brief LSM6DS0 gyroscope subsystem full scale.
+ */
+typedef enum {
+ LSM6DS0_GYRO_FS_245DSP = 0x00, /**< Full scale ±245 degree per second */
+ LSM6DS0_GYRO_FS_500DSP = 0x08, /**< Full scale ±500 degree per second */
+ LSM6DS0_GYRO_FS_2000DSP = 0x18 /**< Full scale ±2000 degree per second */
+} lsm6ds0_gyro_fs_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem output data rate.
+ */
+typedef enum {
+ LSM6DS0_GYRO_ODR_PD = 0x00,
+ LSM6DS0_GYRO_ODR_95HZ_FC_25 = 0x10,
+ LSM6DS0_GYRO_ODR_14_9HZ_FC_5 = 0X20,
+ LSM6DS0_GYRO_ODR_59_5HZ_FC_16 = 0X40,
+ LSM6DS0_GYRO_ODR_119HZ_FC_14 = 0X60,
+ LSM6DS0_GYRO_ODR_119HZ_FC_31 = 0X61,
+ LSM6DS0_GYRO_ODR_238HZ_FC_14 = 0X80,
+ LSM6DS0_GYRO_ODR_238HZ_FC_29 = 0X81,
+ LSM6DS0_GYRO_ODR_238HZ_FC_63 = 0X82,
+ LSM6DS0_GYRO_ODR_238HZ_FC_78 = 0X83,
+ LSM6DS0_GYRO_ODR_476HZ_FC_21 = 0XA0,
+ LSM6DS0_GYRO_ODR_476HZ_FC_28 = 0XA1,
+ LSM6DS0_GYRO_ODR_476HZ_FC_57 = 0XA2,
+ LSM6DS0_GYRO_ODR_476HZ_FC_100 = 0XA3,
+ LSM6DS0_GYRO_ODR_952HZ_FC_33 = 0XC0,
+ LSM6DS0_GYRO_ODR_952HZ_FC_40 = 0XC1,
+ LSM6DS0_GYRO_ODR_952HZ_FC_58 = 0XC2,
+ LSM6DS0_GYRO_ODR_952HZ_FC_100 = 0XC3
+} lsm6ds0_gyro_odr_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem axes enabling.
+ */
+typedef enum {
+ LSM6DS0_GYRO_AE_DISABLED = 0x00, /**< All axes disabled. */
+ LSM6DS0_GYRO_AE_X = 0x08, /**< Only X-axis enabled. */
+ LSM6DS0_GYRO_AE_Y = 0x10, /**< Only Y-axis enabled. */
+ LSM6DS0_GYRO_AE_XY = 0x18, /**< X and Y axes enabled. */
+ LSM6DS0_GYRO_AE_Z = 0x20, /**< Only Z-axis enabled. */
+ LSM6DS0_GYRO_AE_XZ = 0x28, /**< X and Z axes enabled. */
+ LSM6DS0_GYRO_AE_YZ = 0x30, /**< Y and Z axes enabled. */
+ LSM6DS0_GYRO_AE_XYZ = 0x38 /**< All axes enabled. */
+} lsm6ds0_gyro_ae_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem low mode configuration.
+ */
+typedef enum {
+ LSM6DS0_GYRO_LP_DISABLED = 0x00, /**< Low power mode disabled. */
+ LSM6DS0_GYRO_LP_ENABLED = 0x80 /**< Low power mode enabled. */
+} lsm6ds0_gyro_lp_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem output selection.
+ */
+typedef enum {
+ LSM6DS0_GYRO_OUT_SEL_0 = 0x00, /**< Low pass filter 1. */
+ LSM6DS0_GYRO_OUT_SEL_1 = 0x01, /**< High pass filter 1 if enabled. */
+ LSM6DS0_GYRO_OUT_SEL_2 = 0x02 /**< Low pass filter 2. */
+} lsm6ds0_gyro_out_sel_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem high pass filter.
+ */
+typedef enum {
+ LSM6DS0_GYRO_HP_DISABLED = 0x00, /**< High pass filter disabled. */
+ LSM6DS0_GYRO_HP_ENABLED = 0x40 /**< High pass filter enabled. */
+} lsm6ds0_gyro_hp_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem high pass filter configuration.
+ */
+typedef enum {
+ LSM6DS0_GYRO_HPCF_0 = 0x00, /**< Refer to table 48 of RM */
+ LSM6DS0_GYRO_HPCF_1 = 0x01,
+ LSM6DS0_GYRO_HPCF_2 = 0x02,
+ LSM6DS0_GYRO_HPCF_3 = 0x03,
+ LSM6DS0_GYRO_HPCF_4 = 0x04,
+ LSM6DS0_GYRO_HPCF_5 = 0x05,
+ LSM6DS0_GYRO_HPCF_6 = 0x06,
+ LSM6DS0_GYRO_HPCF_7 = 0x07,
+ LSM6DS0_GYRO_HPCF_8 = 0x08,
+ LSM6DS0_GYRO_HPCF_9 = 0x09
+} lsm6ds0_gyro_hpcf_t;
+
+/**
+ * @brief LSM6DS0 gyroscope subsystem configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief LSM6DS0 gyroscope subsystem full scale.
+ */
+ lsm6ds0_gyro_fs_t fullscale;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem output data rate.
+ */
+ lsm6ds0_gyro_odr_t outdatarate;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem axes enabling.
+ */
+ lsm6ds0_gyro_ae_t axesenabling;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem low mode configuration.
+ */
+ lsm6ds0_gyro_lp_t lowmodecfg;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem output selection.
+ */
+ lsm6ds0_gyro_out_sel_t outsel;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem high pass filter.
+ */
+ lsm6ds0_gyro_hp_t hpfenable;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem high pass filter configuration.
+ */
+ lsm6ds0_gyro_hpcf_t hpcfg;
+} LSM6DS0GyroConfig;
+/** @} */
+
+/**
+ * @name LSM6DS0 main system data structures and types.
+ * @{
+ */
+/**
+ * @brief Accelerometer and Gyroscope Slave Address.
+ */
+typedef enum {
+ LSM6DS0_SAD_GND = 0x6A, /**< SAD pin connected to GND. */
+ LSM6DS0_SAD_VCC = 0x6B /**< SAD pin connected to VCC. */
+} lsm6ds0_sad_t;
+
+/**
+ * @brief LSM6DS0 block data update.
+ */
+typedef enum {
+ LSM6DS0_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
+ LSM6DS0_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */
+} lsm6ds0_bdu_t;
+
+/**
+ * @brief LSM6DS0 endianness.
+ */
+typedef enum {
+ LSM6DS0_END_LITTLE = 0x00, /**< Little endian. */
+ LSM6DS0_END_BIG = 0x20 /**< Big endian. */
+} lsm6ds0_end_t;
+
+/**
+ * @brief Driver state machine possible states.
+ */
+typedef enum {
+ LSM6DS0_UNINIT = 0, /**< Not initialized. */
+ LSM6DS0_STOP = 1, /**< Stopped. */
+ LSM6DS0_READY = 2, /**< Ready. */
+} lsm6ds0_state_t;
+
+/**
+ * @brief LSM6DS0 configuration structure.
+ */
+typedef struct {
+#if (LSM6DS0_USE_SPI) || defined(__DOXYGEN__)
+ /**
+ * @brief SPI driver associated to this LSM6DS0.
+ */
+ SPIDriver *spip;
+ /**
+ * @brief SPI configuration associated to this LSM6DS0 accelerometer
+ * subsystem.
+ */
+ const SPIConfig *accspicfg;
+ /**
+ * @brief SPI configuration associated to this LSM6DS0 compass
+ * subsystem.
+ */
+ const SPIConfig *gyrospicfg;
+#endif /* LSM6DS0_USE_SPI */
+#if (LSM6DS0_USE_I2C) || defined(__DOXYGEN__)
+ /**
+ * @brief I2C driver associated to this LSM6DS0.
+ */
+ I2CDriver *i2cp;
+ /**
+ * @brief I2C configuration associated to this LSM6DS0 accelerometer
+ * subsystem.
+ */
+ const I2CConfig *i2ccfg;
+#endif /* LSM6DS0_USE_I2C */
+ /**
+ * @brief LSM6DS0 accelerometer subsystem configuration structure
+ */
+ const LSM6DS0AccConfig *acccfg;
+ /**
+ * @brief LSM6DS0 gyroscope subsystem configuration structure
+ */
+ const LSM6DS0GyroConfig *gyrocfg;
+ /**
+ * @brief Accelerometer and Gyroscope Slave Address
+ */
+ lsm6ds0_sad_t slaveaddress;
+ /**
+ * @brief LSM6DS0 block data update
+ */
+ lsm6ds0_bdu_t blockdataupdate;
+ /**
+ * @brief LSM6DS0 endianness
+ */
+ lsm6ds0_end_t endianness;
+} LSM6DS0Config;
+
+/**
+ * @brief Structure representing a LSM6DS0 driver.
+ */
+typedef struct LSM6DS0Driver LSM6DS0Driver;
+
+/**
+ * @brief @p LSM6DS0 accelerometer subsystem specific methods.
+ */
+#define _lsm6ds0_acc_methods \
+ _base_accelerometer_methods
+
+/**
+ * @brief @p LSM6DS0 gyroscope subsystem specific methods.
+ */
+#define _lsm6ds0_gyro_methods \
+ _base_gyroscope_methods \
+ /* Retrieve the temperature of LSM6DS0 chip.*/ \
+ msg_t (*get_temperature)(void *instance, float* temperature);
+
+/**
+ * @extends BaseAccelerometerVMT
+ *
+ * @brief @p LSM6DS0 accelerometer virtual methods table.
+ */
+struct LSM6DS0ACCVMT {
+ _lsm6ds0_acc_methods
+};
+
+/**
+ * @extends BaseCompassVMT
+ *
+ * @brief @p LSM6DS0 gyroscope virtual methods table.
+ */
+struct LSM6DS0GYROVMT {
+ _lsm6ds0_gyro_methods
+};
+
+/**
+ * @brief @p LSM6DS0Driver specific data.
+ */
+#define _lsm6ds0_data \
+ _base_accelerometer_data \
+ _base_gyroscope_data \
+ /* Driver state.*/ \
+ lsm6ds0_state_t state; \
+ /* Current configuration data.*/ \
+ const LSM6DS0Config *config; \
+ /* Current accelerometer sensitivity.*/ \
+ float accsensitivity[LSM6DS0_ACC_NUMBER_OF_AXES]; \
+ /* Accelerometer bias data.*/ \
+ int32_t accbias[LSM6DS0_ACC_NUMBER_OF_AXES]; \
+ /* Current gyroscope sensitivity.*/ \
+ float gyrosensitivity[LSM6DS0_GYRO_NUMBER_OF_AXES]; \
+ /* Bias data.*/ \
+ int32_t gyrobias[LSM6DS0_GYRO_NUMBER_OF_AXES];
+
+/**
+ * @brief LSM6DS0 6-axis accelerometer/gyroscope class.
+ */
+struct LSM6DS0Driver {
+ /** @brief BaseSensor Virtual Methods Table. */
+ const struct BaseSensorVMT *vmt_basesensor;
+ /** @brief BaseAccelerometer Virtual Methods Table. */
+ const struct BaseAccelerometerVMT *vmt_baseaccelerometer;
+ /** @brief BaseGyroscope Virtual Methods Table. */
+ const struct BaseGyroscopeVMT *vmt_basegyroscope;
+ /** @brief LSM6DS0 Accelerometer Virtual Methods Table. */
+ const struct LSM6DS0ACCVMT *vmt_lsm6ds0acc;
+ /** @brief LSM6DS0 Gyroscope Virtual Methods Table. */
+ const struct LSM6DS0GYROVMT *vmt_lsm6ds0gyro;
+ _lsm6ds0_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_lsm6ds0gyro->get_temperature(ip, tpp)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void lsm6ds0ObjectInit(LSM6DS0Driver *devp);
+ void lsm6ds0Start(LSM6DS0Driver *devp, const LSM6DS0Config *config);
+ void lsm6ds0Stop(LSM6DS0Driver *devp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LSM6DS0_H_ */
+
+/** @} */
diff --git a/os/ex/subsystems/mfs/mfs.c b/os/ex/subsystems/mfs/mfs.c
index d232b664d..99a3c0c1b 100644
--- a/os/ex/subsystems/mfs/mfs.c
+++ b/os/ex/subsystems/mfs/mfs.c
@@ -1,683 +1,683 @@
-/*
- 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.c
- * @brief Managed Flash Storage module code.
- * @details This module manages a flash partition as a generic storage where
- * arbitrary data records can be created, updated, deleted and
- * retrieved.<br>
- * A managed partition is composed of two banks of equal size, a
- * bank is composed of one or more erasable sectors, a sector is
- * divided in writable pages.<br>
- * The module handles flash wear leveling and recovery of damaged
- * banks (where possible) caused by power loss during operations.
- * Both operations are transparent to the user.
- *
- * @addtogroup mfs
- * @{
- */
-
-#include "hal.h"
-
-#include "mfs.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#define PAIR(a, b) (((unsigned)(a) << 2U) | (unsigned)(b))
-
-/**
- * @brief Error check helper.
- */
-#define RET_ON_ERROR(err) do { \
- mfs_error_t e = (err); \
- if (e != MFS_NO_ERROR) { \
- return e; \
- } \
-} while (false)
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-const uint16_t crc16_table[256] = {
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
- 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
- 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
- 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
- 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
- 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
- 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
- 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
- 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
- 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
- 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
- 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
- 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
- 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
- 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
- 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
- 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
- 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
- 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
- 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
- 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
- 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
- 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
-};
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-uint16_t crc16(uint16_t crc, const uint8_t *data, size_t n) {
-
- while (n > 0U) {
- crc = (crc << 8U) ^ crc16_table[(crc >> 8U) ^ (uint16_t)*data];
- data++;
- n--;
- }
-
- return crc;
-}
-
-#if (MFS_CFG_ID_CACHE_SIZE > 0) || defined(__DOXYGEN__)
-void mfs_cache_init(MFSDriver *devp) {
-
- (void)devp;
-}
-
-mfs_cached_id_t *mfs_cache_find_id(MFSDriver *devp, uint32_t id) {
-
- (void)devp;
- (void)id;
-
- return NULL;
-}
-
-void mfs_cache_update_id(MFSDriver *devp, uint32_t id) {
-
- (void)devp;
- (void)id;
-}
-
-void mfs_cache_erase_id(MFSDriver *devp, uint32_t id) {
-
- (void)devp;
- (void)id;
-}
-#endif /* MFS_CFG_ID_CACHE_SIZE > 0 */
-
-/**
- * @brief Flash write.
- * @note If the option @p MFS_CFG_WRITE_VERIFY is enabled then the flash
- * is also read back for verification.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] offset flash offset
- * @param[in] n number of bytes to be read
- * @param[out] rp pointer to the data buffer
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @notapi
- */
-static mfs_error_t mfs_flash_write(MFSDriver *devp,
- flash_offset_t offset,
- size_t n, const
- uint8_t *p) {
- flash_error_t ferr;
-
- ferr = flashProgram(devp->config->flashp, offset, n, p);
- if (ferr != FLASH_NO_ERROR) {
- return MFS_FLASH_FAILURE;
- }
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Erases and verifies all sectors belonging to a bank.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] bank bank to be erased
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @notapi
- */
-static mfs_error_t mfs_bank_erase(MFSDriver *devp, mfs_bank_t bank) {
- flash_sector_t sector, end;
-
- if (bank == MFS_BANK_0) {
- sector = devp->config->bank0_start;
- end = devp->config->bank0_start + devp->config->bank0_sectors;
- }
- else {
- sector = devp->config->bank1_start;
- end = devp->config->bank1_start + devp->config->bank1_sectors;
- }
-
- while (sector < end) {
- flash_error_t ferr;
-
- ferr = flashStartEraseSector(devp->config->flashp, sector);
- if (ferr != FLASH_NO_ERROR) {
- return MFS_FLASH_FAILURE;
- }
- ferr = flashWaitErase(devp->config->flashp);
- if (ferr != FLASH_NO_ERROR) {
- return MFS_FLASH_FAILURE;
- }
- ferr = flashVerifyErase(devp->config->flashp, sector);
- if (ferr != FLASH_NO_ERROR) {
- return MFS_FLASH_FAILURE;
- }
-
- sector++;
- }
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Writes the validation header in a bank.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] bank bank to be validated
- * @param[in] cnt value for the flash usage counter
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @notapi
- */
-static mfs_error_t mfs_bank_set_header(MFSDriver *devp,
- mfs_bank_t bank,
- uint32_t cnt) {
- flash_sector_t sector;
- mfs_bank_header_t header;
-
- if (bank == MFS_BANK_0) {
- sector = devp->config->bank0_start;
- }
- else {
- sector = devp->config->bank1_start;
- }
-
- header.magic1 = MFS_BANK_MAGIC_1;
- header.magic1 = MFS_BANK_MAGIC_1;
- header.counter = cnt;
- header.next = sizeof (mfs_bank_header_t);
- header.crc = crc16(0xFFFFU,
- (const uint8_t *)&header,
- sizeof (flash_sector_t) - sizeof (uint16_t));
-
- return mfs_flash_write(devp,
- flashGetSectorOffset(devp->config->flashp, sector),
- sizeof (mfs_bank_header_t),
- (const uint8_t *)&header);
-}
-
-/**
- * @brief Copies all records from a bank to another.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] sbank source bank
- * @param[in] dbank destination bank
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @notapi
- */
-static mfs_error_t mfs_copy_bank(MFSDriver *devp,
- mfs_bank_t sbank,
- mfs_bank_t dbank) {
-
- (void)devp;
- (void)sbank;
- (void)dbank;
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Selects a bank as current.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] bank bank to be erased
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- *
- * @notapi
- */
-static mfs_error_t mfs_mount(MFSDriver *devp, mfs_bank_t bank) {
-
- (void)devp;
- (void)bank;
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Determines the state of a flash bank.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] bank the bank identifier
- * @param[out] cntp bank counter value, only valid if the bank is not
- * in the @p MFS_BANK_GARBAGE or @p MFS_BANK_ERASED
- * states.
- *
- * @return The bank state.
- * @retval MFS_BANK_ERASED if the bank is fully erased.
- * @retval MFS_BANK_OK if the bank contains valid data.
- * @retval MFS_BANK_PARTIAL if the bank contains errors but the data is still
- * readable.
- * @retval MFS_BANK_GARBAGE if the bank contains unreadable garbage.
- */
-static mfs_bank_state_t mfs_get_bank_state(MFSDriver *devp,
- mfs_bank_t bank,
- uint32_t *cntp) {
-
- (void)devp;
- (void)bank;
- (void)cntp;
-
- return MFS_BANK_OK;
-}
-
-/**
- * @brief Performs a flash partition mount attempt.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_REPAIR_WARNING if the operation has been completed but a
- * repair has been performed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @api
- */
-static mfs_error_t mfs_try_mount(MFSDriver *devp) {
- mfs_bank_state_t sts0, sts1;
- uint32_t cnt0 = 0, cnt1 = 0;
-
- /* Assessing the state of the two banks.*/
- sts0 = mfs_get_bank_state(devp, MFS_BANK_0, &cnt0);
- sts1 = mfs_get_bank_state(devp, MFS_BANK_1, &cnt1);
-
- /* Handling all possible scenarios, each one requires its own recovery
- strategy.*/
- switch (PAIR(sts0, sts1)) {
-
- case PAIR(MFS_BANK_ERASED, MFS_BANK_ERASED):
- /* Both banks erased, first initialization.*/
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_NO_ERROR;
-
- case PAIR(MFS_BANK_ERASED, MFS_BANK_OK):
- /* Normal situation, bank one is used.*/
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- return MFS_NO_ERROR;
-
- case PAIR(MFS_BANK_ERASED, MFS_BANK_PARTIAL):
- /* Bank zero is erased, bank one has problems.*/
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_1, MFS_BANK_0));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt1 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_ERASED, MFS_BANK_GARBAGE):
- /* Bank zero is erased, bank one is not readable.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_OK, MFS_BANK_ERASED):
- /* Normal situation, bank zero is used.*/
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_NO_ERROR;
-
- case PAIR(MFS_BANK_OK, MFS_BANK_OK):
- /* Both banks appear to be valid but one must be newer, erasing the
- older one.*/
- if (cnt0 > cnt1) {
- /* Bank 0 is newer.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- }
- else {
- /* Bank 1 is newer.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- }
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_OK, MFS_BANK_PARTIAL):
- /* Bank zero is normal, bank one has problems.*/
- if (cnt0 > cnt1) {
- /* Normal bank zero is more recent than the partial bank one, the
- partial bank needs to be erased.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- }
- else {
- /* Partial bank one is more recent than the normal bank zero.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_1, MFS_BANK_0));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt1 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- }
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_OK, MFS_BANK_GARBAGE):
- /* Bank zero is normal, bank one is unreadable.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_PARTIAL, MFS_BANK_ERASED):
- /* Bank zero has problems, bank one is erased.*/
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_0, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_PARTIAL, MFS_BANK_OK):
- /* Bank zero has problems, bank one is normal.*/
- if (cnt1 > cnt0) {
- /* Normal bank one is more recent than the partial bank zero, the
- partial bank has to be erased.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- }
- else {
- /* Partial bank zero is more recent than the normal bank one.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_0, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- }
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_PARTIAL, MFS_BANK_PARTIAL):
- /* Both banks have problems.*/
- if (cnt0 > cnt1) {
- /* Bank zero is newer, copying in bank one and using it.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_0, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- }
- else {
- /* Bank one is newer, copying in bank zero and using it.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_1, MFS_BANK_0));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt1 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- }
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_PARTIAL, MFS_BANK_GARBAGE):
- /* Bank zero has problems, bank one is unreadable.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_0, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_GARBAGE, MFS_BANK_ERASED):
- /* Bank zero is unreadable, bank one is erased.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_GARBAGE, MFS_BANK_OK):
- /* Bank zero is unreadable, bank one is normal.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_1));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_GARBAGE, MFS_BANK_PARTIAL):
- /* Bank zero is unreadable, bank one has problems.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_copy_bank(devp, MFS_BANK_1, MFS_BANK_0));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt0 + 1));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_REPAIR_WARNING;
-
- case PAIR(MFS_BANK_GARBAGE, MFS_BANK_GARBAGE):
- /* Both banks are unreadable, reinitializing.*/
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
- RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
- RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
- RET_ON_ERROR(mfs_mount(devp, MFS_BANK_0));
- return MFS_REPAIR_WARNING;
-
- default:
- osalSysHalt("internal error");
- }
-
- /* Never reached.*/
- return MFS_INTERNAL_ERROR;
-}
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Initializes an instance.
- *
- * @param[out] devp pointer to the @p MFSDriver object
- *
- * @init
- */
-void mfsObjectInit(MFSDriver *devp) {
-
- osalDbgCheck(devp != NULL);
-
- devp->state = MFS_STOP;
- devp->config = NULL;
-}
-
-/**
- * @brief Configures and activates a MFS driver.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] config pointer to the configuration
- *
- * @api
- */
-void mfsStart(MFSDriver *devp, const MFSConfig *config) {
-
- osalDbgCheck((devp != NULL) && (config != NULL));
- osalDbgAssert(devp->state != MFS_UNINIT, "invalid state");
-
- if (devp->state == MFS_STOP) {
-
- devp->config = config;
- devp->state = MFS_READY;
- }
-}
-
-/**
- * @brief Deactivates a MFS driver.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- *
- * @api
- */
-void mfsStop(MFSDriver *devp) {
-
- osalDbgCheck(devp != NULL);
- osalDbgAssert(devp->state != MFS_UNINIT, "invalid state");
-
- if (devp->state != MFS_STOP) {
-
- devp->state = MFS_STOP;
- }
-}
-
-/**
- * @brief Mounts a managed flash storage.
- * @details This functions checks the storage internal state and eventually
- * performs the required initialization or repair operations.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_REPAIR_WARNING if the operation has been completed but a
- * repair has been performed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @api
- */
-mfs_error_t mfsMount(MFSDriver *devp) {
- unsigned i;
-
- /* Attempting to mount the managed partition.*/
- for (i = 0; i < MFS_CFG_MAX_REPAIR_ATTEMPTS; i++) {
- mfs_error_t err;
-
- err = mfs_try_mount(devp);
- if (!MFS_IS_ERROR(err))
- return err;
- }
-
- return MFS_FLASH_FAILURE;
-}
-
-/**
- * @brief Unmounts a manage flash storage.
- */
-mfs_error_t mfsUnmount(MFSDriver *devp) {
-
- (void)devp;
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Retrieves and reads a data record.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] id record numeric identifier
- * @param[in,out] np on input is the maximum buffer size, on return it is
- * the size of the data copied into the buffer
- * @param[in] buffer pointer to a buffer for record data
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_ID_NOT_FOUND if the specified id does not exists.
- * @retval MFS_CRC_ERROR if retrieved data has a CRC error.
- *
- * @api
- */
-mfs_error_t mfsReadRecord(MFSDriver *devp, uint32_t id,
- uint32_t *np, uint8_t *buffer) {
-
- (void)devp;
- (void)id;
- (void)np;
- (void)buffer;
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Creates or updates a data record.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] id record numeric identifier
- * @param[in] n size of data to be written, it cannot be zero
- * @param[in] buffer pointer to a buffer for record data
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @api
- */
-mfs_error_t mfsUpdateRecord(MFSDriver *devp, uint32_t id,
- uint32_t n, const uint8_t *buffer) {
-
- (void)devp;
- (void)id;
- (void)n;
- (void)buffer;
-
- return MFS_NO_ERROR;
-}
-
-/**
- * @brief Erases a data record.
- *
- * @param[in] devp pointer to the @p MFSDriver object
- * @param[in] id record numeric identifier
- * @return The operation status.
- * @retval MFS_NO_ERROR if the operation has been successfully completed.
- * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
- * failures.
- *
- * @api
- */
-mfs_error_t mfsEraseRecord(MFSDriver *devp, uint32_t id) {
-
- (void)devp;
- (void)id;
-
- return MFS_NO_ERROR;
-}
-
-/** @} */
+/*
+ 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.c
+ * @brief Managed Flash Storage module code.
+ * @details This module manages a flash partition as a generic storage where
+ * arbitrary data records can be created, updated, deleted and
+ * retrieved.<br>
+ * A managed partition is composed of two banks of equal size, a
+ * bank is composed of one or more erasable sectors, a sector is
+ * divided in writable pages.<br>
+ * The module handles flash wear leveling and recovery of damaged
+ * banks (where possible) caused by power loss during operations.
+ * Both operations are transparent to the user.
+ *
+ * @addtogroup mfs
+ * @{
+ */
+
+#include "hal.h"
+
+#include "mfs.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define PAIR(a, b) (((unsigned)(a) << 2U) | (unsigned)(b))
+
+/**
+ * @brief Error check helper.
+ */
+#define RET_ON_ERROR(err) do { \
+ mfs_error_t e = (err); \
+ if (e != MFS_NO_ERROR) { \
+ return e; \
+ } \
+} while (false)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+const uint16_t crc16_table[256] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+uint16_t crc16(uint16_t crc, const uint8_t *data, size_t n) {
+
+ while (n > 0U) {
+ crc = (crc << 8U) ^ crc16_table[(crc >> 8U) ^ (uint16_t)*data];
+ data++;
+ n--;
+ }
+
+ return crc;
+}
+
+#if (MFS_CFG_ID_CACHE_SIZE > 0) || defined(__DOXYGEN__)
+void mfs_cache_init(MFSDriver *devp) {
+
+ (void)devp;
+}
+
+mfs_cached_id_t *mfs_cache_find_id(MFSDriver *devp, uint32_t id) {
+
+ (void)devp;
+ (void)id;
+
+ return NULL;
+}
+
+void mfs_cache_update_id(MFSDriver *devp, uint32_t id) {
+
+ (void)devp;
+ (void)id;
+}
+
+void mfs_cache_erase_id(MFSDriver *devp, uint32_t id) {
+
+ (void)devp;
+ (void)id;
+}
+#endif /* MFS_CFG_ID_CACHE_SIZE > 0 */
+
+/**
+ * @brief Flash write.
+ * @note If the option @p MFS_CFG_WRITE_VERIFY is enabled then the flash
+ * is also read back for verification.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] offset flash offset
+ * @param[in] n number of bytes to be read
+ * @param[out] rp pointer to the data buffer
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @notapi
+ */
+static mfs_error_t mfs_flash_write(MFSDriver *devp,
+ flash_offset_t offset,
+ size_t n, const
+ uint8_t *p) {
+ flash_error_t ferr;
+
+ ferr = flashProgram(devp->config->flashp, offset, n, p);
+ if (ferr != FLASH_NO_ERROR) {
+ return MFS_FLASH_FAILURE;
+ }
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Erases and verifies all sectors belonging to a bank.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] bank bank to be erased
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @notapi
+ */
+static mfs_error_t mfs_bank_erase(MFSDriver *devp, mfs_bank_t bank) {
+ flash_sector_t sector, end;
+
+ if (bank == MFS_BANK_0) {
+ sector = devp->config->bank0_start;
+ end = devp->config->bank0_start + devp->config->bank0_sectors;
+ }
+ else {
+ sector = devp->config->bank1_start;
+ end = devp->config->bank1_start + devp->config->bank1_sectors;
+ }
+
+ while (sector < end) {
+ flash_error_t ferr;
+
+ ferr = flashStartEraseSector(devp->config->flashp, sector);
+ if (ferr != FLASH_NO_ERROR) {
+ return MFS_FLASH_FAILURE;
+ }
+ ferr = flashWaitErase(devp->config->flashp);
+ if (ferr != FLASH_NO_ERROR) {
+ return MFS_FLASH_FAILURE;
+ }
+ ferr = flashVerifyErase(devp->config->flashp, sector);
+ if (ferr != FLASH_NO_ERROR) {
+ return MFS_FLASH_FAILURE;
+ }
+
+ sector++;
+ }
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Writes the validation header in a bank.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] bank bank to be validated
+ * @param[in] cnt value for the flash usage counter
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @notapi
+ */
+static mfs_error_t mfs_bank_set_header(MFSDriver *devp,
+ mfs_bank_t bank,
+ uint32_t cnt) {
+ flash_sector_t sector;
+ mfs_bank_header_t header;
+
+ if (bank == MFS_BANK_0) {
+ sector = devp->config->bank0_start;
+ }
+ else {
+ sector = devp->config->bank1_start;
+ }
+
+ header.magic1 = MFS_BANK_MAGIC_1;
+ header.magic1 = MFS_BANK_MAGIC_1;
+ header.counter = cnt;
+ header.next = sizeof (mfs_bank_header_t);
+ header.crc = crc16(0xFFFFU,
+ (const uint8_t *)&header,
+ sizeof (flash_sector_t) - sizeof (uint16_t));
+
+ return mfs_flash_write(devp,
+ flashGetSectorOffset(devp->config->flashp, sector),
+ sizeof (mfs_bank_header_t),
+ (const uint8_t *)&header);
+}
+
+/**
+ * @brief Copies all records from a bank to another.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] sbank source bank
+ * @param[in] dbank destination bank
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @notapi
+ */
+static mfs_error_t mfs_bank_copy(MFSDriver *devp,
+ mfs_bank_t sbank,
+ mfs_bank_t dbank) {
+
+ (void)devp;
+ (void)sbank;
+ (void)dbank;
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Selects a bank as current.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] bank bank to be erased
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ *
+ * @notapi
+ */
+static mfs_error_t mfs_bank_mount(MFSDriver *devp, mfs_bank_t bank) {
+
+ (void)devp;
+ (void)bank;
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Determines the state of a flash bank.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] bank the bank identifier
+ * @param[out] cntp bank counter value, only valid if the bank is not
+ * in the @p MFS_BANK_GARBAGE or @p MFS_BANK_ERASED
+ * states.
+ *
+ * @return The bank state.
+ * @retval MFS_BANK_ERASED if the bank is fully erased.
+ * @retval MFS_BANK_OK if the bank contains valid data.
+ * @retval MFS_BANK_PARTIAL if the bank contains errors but the data is still
+ * readable.
+ * @retval MFS_BANK_GARBAGE if the bank contains unreadable garbage.
+ */
+static mfs_bank_state_t mfs_get_bank_state(MFSDriver *devp,
+ mfs_bank_t bank,
+ uint32_t *cntp) {
+
+ (void)devp;
+ (void)bank;
+ (void)cntp;
+
+ return MFS_BANK_OK;
+}
+
+/**
+ * @brief Performs a flash partition mount attempt.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_REPAIR_WARNING if the operation has been completed but a
+ * repair has been performed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @api
+ */
+static mfs_error_t mfs_try_mount(MFSDriver *devp) {
+ mfs_bank_state_t sts0, sts1;
+ uint32_t cnt0 = 0, cnt1 = 0;
+
+ /* Assessing the state of the two banks.*/
+ sts0 = mfs_get_bank_state(devp, MFS_BANK_0, &cnt0);
+ sts1 = mfs_get_bank_state(devp, MFS_BANK_1, &cnt1);
+
+ /* Handling all possible scenarios, each one requires its own recovery
+ strategy.*/
+ switch (PAIR(sts0, sts1)) {
+
+ case PAIR(MFS_BANK_ERASED, MFS_BANK_ERASED):
+ /* Both banks erased, first initialization.*/
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_NO_ERROR;
+
+ case PAIR(MFS_BANK_ERASED, MFS_BANK_OK):
+ /* Normal situation, bank one is used.*/
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ return MFS_NO_ERROR;
+
+ case PAIR(MFS_BANK_ERASED, MFS_BANK_PARTIAL):
+ /* Bank zero is erased, bank one has problems.*/
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_1, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt1 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_ERASED, MFS_BANK_GARBAGE):
+ /* Bank zero is erased, bank one is not readable.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_OK, MFS_BANK_ERASED):
+ /* Normal situation, bank zero is used.*/
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_NO_ERROR;
+
+ case PAIR(MFS_BANK_OK, MFS_BANK_OK):
+ /* Both banks appear to be valid but one must be newer, erasing the
+ older one.*/
+ if (cnt0 > cnt1) {
+ /* Bank 0 is newer.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ }
+ else {
+ /* Bank 1 is newer.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ }
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_OK, MFS_BANK_PARTIAL):
+ /* Bank zero is normal, bank one has problems.*/
+ if (cnt0 > cnt1) {
+ /* Normal bank zero is more recent than the partial bank one, the
+ partial bank needs to be erased.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ }
+ else {
+ /* Partial bank one is more recent than the normal bank zero.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_1, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt1 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ }
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_OK, MFS_BANK_GARBAGE):
+ /* Bank zero is normal, bank one is unreadable.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_PARTIAL, MFS_BANK_ERASED):
+ /* Bank zero has problems, bank one is erased.*/
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_0, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_PARTIAL, MFS_BANK_OK):
+ /* Bank zero has problems, bank one is normal.*/
+ if (cnt1 > cnt0) {
+ /* Normal bank one is more recent than the partial bank zero, the
+ partial bank has to be erased.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ }
+ else {
+ /* Partial bank zero is more recent than the normal bank one.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_0, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ }
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_PARTIAL, MFS_BANK_PARTIAL):
+ /* Both banks have problems.*/
+ if (cnt0 > cnt1) {
+ /* Bank zero is newer, copying in bank one and using it.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_0, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ }
+ else {
+ /* Bank one is newer, copying in bank zero and using it.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_1, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt1 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ }
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_PARTIAL, MFS_BANK_GARBAGE):
+ /* Bank zero has problems, bank one is unreadable.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_0, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_1, cnt0 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_GARBAGE, MFS_BANK_ERASED):
+ /* Bank zero is unreadable, bank one is erased.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_GARBAGE, MFS_BANK_OK):
+ /* Bank zero is unreadable, bank one is normal.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_1));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_GARBAGE, MFS_BANK_PARTIAL):
+ /* Bank zero is unreadable, bank one has problems.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_copy(devp, MFS_BANK_1, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, cnt0 + 1));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_REPAIR_WARNING;
+
+ case PAIR(MFS_BANK_GARBAGE, MFS_BANK_GARBAGE):
+ /* Both banks are unreadable, reinitializing.*/
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_0));
+ RET_ON_ERROR(mfs_bank_erase(devp, MFS_BANK_1));
+ RET_ON_ERROR(mfs_bank_set_header(devp, MFS_BANK_0, 1));
+ RET_ON_ERROR(mfs_bank_mount(devp, MFS_BANK_0));
+ return MFS_REPAIR_WARNING;
+
+ default:
+ osalSysHalt("internal error");
+ }
+
+ /* Never reached.*/
+ return MFS_INTERNAL_ERROR;
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initializes an instance.
+ *
+ * @param[out] devp pointer to the @p MFSDriver object
+ *
+ * @init
+ */
+void mfsObjectInit(MFSDriver *devp) {
+
+ osalDbgCheck(devp != NULL);
+
+ devp->state = MFS_STOP;
+ devp->config = NULL;
+}
+
+/**
+ * @brief Configures and activates a MFS driver.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] config pointer to the configuration
+ *
+ * @api
+ */
+void mfsStart(MFSDriver *devp, const MFSConfig *config) {
+
+ osalDbgCheck((devp != NULL) && (config != NULL));
+ osalDbgAssert(devp->state != MFS_UNINIT, "invalid state");
+
+ if (devp->state == MFS_STOP) {
+
+ devp->config = config;
+ devp->state = MFS_READY;
+ }
+}
+
+/**
+ * @brief Deactivates a MFS driver.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ *
+ * @api
+ */
+void mfsStop(MFSDriver *devp) {
+
+ osalDbgCheck(devp != NULL);
+ osalDbgAssert(devp->state != MFS_UNINIT, "invalid state");
+
+ if (devp->state != MFS_STOP) {
+
+ devp->state = MFS_STOP;
+ }
+}
+
+/**
+ * @brief Mounts a managed flash storage.
+ * @details This functions checks the storage internal state and eventually
+ * performs the required initialization or repair operations.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_REPAIR_WARNING if the operation has been completed but a
+ * repair has been performed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @api
+ */
+mfs_error_t mfsMount(MFSDriver *devp) {
+ unsigned i;
+
+ /* Attempting to mount the managed partition.*/
+ for (i = 0; i < MFS_CFG_MAX_REPAIR_ATTEMPTS; i++) {
+ mfs_error_t err;
+
+ err = mfs_try_mount(devp);
+ if (!MFS_IS_ERROR(err))
+ return err;
+ }
+
+ return MFS_FLASH_FAILURE;
+}
+
+/**
+ * @brief Unmounts a manage flash storage.
+ */
+mfs_error_t mfsUnmount(MFSDriver *devp) {
+
+ (void)devp;
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Retrieves and reads a data record.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] id record numeric identifier
+ * @param[in,out] np on input is the maximum buffer size, on return it is
+ * the size of the data copied into the buffer
+ * @param[in] buffer pointer to a buffer for record data
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_ID_NOT_FOUND if the specified id does not exists.
+ * @retval MFS_CRC_ERROR if retrieved data has a CRC error.
+ *
+ * @api
+ */
+mfs_error_t mfsReadRecord(MFSDriver *devp, uint32_t id,
+ uint32_t *np, uint8_t *buffer) {
+
+ (void)devp;
+ (void)id;
+ (void)np;
+ (void)buffer;
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Creates or updates a data record.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] id record numeric identifier
+ * @param[in] n size of data to be written, it cannot be zero
+ * @param[in] buffer pointer to a buffer for record data
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @api
+ */
+mfs_error_t mfsUpdateRecord(MFSDriver *devp, uint32_t id,
+ uint32_t n, const uint8_t *buffer) {
+
+ (void)devp;
+ (void)id;
+ (void)n;
+ (void)buffer;
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Erases a data record.
+ *
+ * @param[in] devp pointer to the @p MFSDriver object
+ * @param[in] id record numeric identifier
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @api
+ */
+mfs_error_t mfsEraseRecord(MFSDriver *devp, uint32_t id) {
+
+ (void)devp;
+ (void)id;
+
+ return MFS_NO_ERROR;
+}
+
+/** @} */
diff --git a/os/ex/subsystems/mfs/mfs.h b/os/ex/subsystems/mfs/mfs.h
index ec5719738..89d6b9958 100644
--- a/os/ex/subsystems/mfs/mfs.h
+++ b/os/ex/subsystems/mfs/mfs.h
@@ -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 */
+
+/** @} */
+