From 2759c1bfca0ca8fdd74c766d723a289da49ee8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Sun, 29 Apr 2018 10:47:03 +0200 Subject: [PATCH 1/7] sens0: Simple sensor device interface The sens0 driver provides an easy way to interface with sensors when the application only requires a basic measurement functionality. --- drivers/Makefile.dep | 10 ++ drivers/include/sens0.h | 267 +++++++++++++++++++++++++++++++++ drivers/include/sens0/i2c.h | 101 +++++++++++++ drivers/sens0/Makefile | 3 + drivers/sens0/sens0.c | 62 ++++++++ drivers/sens0/sens0_i2c.c | 227 ++++++++++++++++++++++++++++ drivers/sens0/sens0_i2c_saul.c | 39 +++++ drivers/sens0/specs/Makefile | 2 + makefiles/pseudomodules.inc.mk | 1 + 9 files changed, 712 insertions(+) create mode 100644 drivers/include/sens0.h create mode 100644 drivers/include/sens0/i2c.h create mode 100644 drivers/sens0/Makefile create mode 100644 drivers/sens0/sens0.c create mode 100644 drivers/sens0/sens0_i2c.c create mode 100644 drivers/sens0/sens0_i2c_saul.c create mode 100644 drivers/sens0/specs/Makefile diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 1621e5ec5dd8..705158e98672 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -298,6 +298,16 @@ ifneq (,$(filter sdcard_spi,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter sens0,$(USEMODULE))) + USEMODULE += sens0_specs +endif + +ifneq (,$(filter sens0_i2c,$(USEMODULE))) + USEMODULE += sens0 + FEATURES_REQUIRED += periph_i2c + USEMODULE += xtimer +endif + ifneq (,$(filter sht11,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/drivers/include/sens0.h b/drivers/include/sens0.h new file mode 100644 index 000000000000..484df83e10d6 --- /dev/null +++ b/drivers/include/sens0.h @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_sens0 Sens0 simple sensor driver + * @ingroup drivers_sensors + * @brief Sens0 provides a generic interface for simple digital sensors + * + * The sens0 driver provides an easy way to interface with sensors when the + * application only requires a basic measurement functionality. The sensor + * configuration consists of a hardware specification, @ref sens0_specs_t; + * connection parameters, @ref sens0_i2c_params_t, or TODO sens0_spi_params_t. + * + * The hardware specifications are device specific and describes the + * initialization procedure, as well as the location and format of the sensor + * output registers. All information required for the hardware specification + * should be available in the data sheet for the sensor. + * + * The connection parameters are application or board specific and will be found + * in the electric schematic for the board in combination with the sensor data + * sheet. The connection information contains which bus to use, which CS line + * (SPI connected sensors) or device address (I2C connected sensors) to use for + * accessing the device. + * + * A custom conversion function can be supplied for when the output format is + * not linear, or otherwise incompatible with the default conversion function. + * + * @{ + * + * @file + * @brief Interface definition for the Sens0 driver. + * + * @author Joakim Nohlgård + */ + +/** + * @defgroup drivers_sens0_specs Sens0 supported devices + * @ingroup drivers_sens0 + * @brief Sens0 hardware specifications for interfacing with devices. + */ + +#ifndef SENS0_H +#define SENS0_H + +#include +#include "phydat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sensor output format flags + */ +typedef enum { + /** Set this flag if raw values are in big endian byte order on the device */ + SENS0_BIG_ENDIAN = (1 << 0), + /** This flag ensures that the sign bit is preserved correctly in the default conversion */ + SENS0_SIGNED = (1 << 1), +} sens0_output_flags_t; + +/** + * @brief Register write description + * + * This is used in the initialization procedure to specify where and what to + * write to the device registers. + */ +typedef struct { + uint8_t reg; /**< Register address */ + uint8_t value; /**< Register value */ +} sens0_reg_t; + +/** + * @brief Register bits description + * + * This data type is used to specify only specific bits of an 8 bit register. + */ +typedef struct { + uint8_t reg; /**< Register address */ + uint8_t mask; /**< Bit mask used to select specific bits */ + uint8_t value; /**< Register value */ +} sens0_reg_masked_t; + +/** + * @brief Sensor output specification + * + * This struct describes where to find values in the hardware registers + */ +typedef struct sens0_output { + uint8_t flags; /**< Conversion flags, see @ref sens0_output_flags_t */ + /** + * @brief Number of values + */ + uint8_t nelem; + /** + * @brief Length of each value + * + * It is not defined what happens if the size is > 4 + */ + uint8_t elem_size; + /** + * @brief Hardware register address + */ + uint8_t reg; + /** + * @brief Optional custom function to convert the raw data to @ref phydat_t + * + * @param[in] specs pointer to the specification + * @param[out] data pointer to output buffer + * @param[in] raw pointer to raw input buffer from sensor + * + * @return number of elements converted on success + * @return <0 on failure + */ + int (*conv_func)(const struct sens0_output *specs, phydat_t *data, const uint8_t *raw); + /** + * @brief Scaling fraction numerator + * + * Used by the default conversion function when `conv_func == NULL` + */ + int32_t conv_frac_num; + /** + * @brief Scaling fraction denominator + * + * Used by the default conversion function when `conv_func == NULL` + */ + int32_t conv_frac_den; + /** + * @brief Output value unit, see @ref phydat_t + */ + uint8_t unit; + /** + * @brief Output value scale exponent, see @ref phydat_t + */ + uint8_t scale; +} sens0_output_t; + +/** + * @brief Device hardware specifications + */ +typedef struct { + /** + * @brief Device identification register address + * + * Sometimes also called a WHO_AM_I register. + * During sens0_init, this register at address id.reg will be read and the + * contents will be compared against id.value, to ensure that the driver is + * talking to the correct device. If the value is not the expected value, the + * initialization will abort and an error code will be returned. + * + * The actual value is combined with id.mask to perform a check of only the + * masked bits: + * + * if ((actual_value & id.mask) != id.value) { return error... } + */ + sens0_reg_masked_t id; + /** + * @brief Number of reset registers to write + */ + uint8_t reset_regs_nelem; + /** + * @brief reset write sequence + * + * The register values specified in this vector will be written, in order, + * to the device by @ref sens0_i2c_init + */ + const sens0_reg_t *reset_regs; + /** + * @brief Reset delay + * + * The initialization will sleep after the reset sequence has completed to + * let the hardware complete the operation. + */ + uint32_t reset_delay; + /** + * @brief Number of initialization registers to write + */ + uint8_t init_regs_nelem; + /** + * @brief initialization write sequence + * + * The register values specified in this vector will be written, in order, + * to the device by @ref sens0_i2c_init + */ + const sens0_reg_t *init_regs; + /** + * @brief sensor measurement request register + * + * The masked bits will be written to initiate a measurement. + * + * Set measurement_req.mask = 0x00 if the device does not need explicit + * measurement requests. + */ + sens0_reg_masked_t measurement_req; + /** + * @brief Time in microseconds to wait after a measurement request before + * reading the result register + */ + uint32_t measurement_delay; + /** + * @brief Number of outputs + */ + uint8_t outputs_nelem; + /** + * @brief Output descriptions + */ + const sens0_output_t *outputs; + /** + * @brief Power state register address + */ + uint8_t power_reg; + /** + * @brief Bit mask for standby mode setting in power reg + */ + uint8_t power_mask; + /** + * @brief Value for putting the device in 'active' state + */ + uint8_t power_value_active; + /** + * @brief Value for putting the device in 'standby' state + */ + uint8_t power_value_standby; +} sens0_specs_t; + +/* These functions are prefixed sens0_i2c_, but are located here to avoid + * dependency on periph/i2c.h for specs implementations. The specs must be + * compilable without any particular hardware interface configured or enabled */ + +/** + * @brief Read value from the first output channel on the sensor + * + * This is equivalent to @ref sens0_i2c_read with the @c iout argument bound to 0 + * + * Useful mainly in SAUL driver definitions. + */ +int sens0_i2c_read_output0(const void *dev, phydat_t *res); + +/** + * @brief Read value from the second output channel on the sensor + * + * This is equivalent to @ref sens0_i2c_read with the @c iout argument bound to 1 + * + * Useful mainly in SAUL driver definitions. + */ +int sens0_i2c_read_output1(const void *dev, phydat_t *res); + +/** + * @brief Read value from the third output channel on the sensor + * + * This is equivalent to @ref sens0_i2c_read with the @c iout argument bound to 2 + * + * Useful mainly in SAUL driver definitions. + */ +int sens0_i2c_read_output2(const void *dev, phydat_t *res); + +#ifdef __cplusplus +} +#endif + +#endif /* SENS0_H */ +/** @} */ diff --git a/drivers/include/sens0/i2c.h b/drivers/include/sens0/i2c.h new file mode 100644 index 000000000000..2c8ae2b07cb7 --- /dev/null +++ b/drivers/include/sens0/i2c.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_sens0 + * @brief Sens0 I2C API + * + * Sens0 sensor specifications can be used with multiple interface types, this + * API is for using sensors connected via I2C. + * + * @{ + * + * @file + * @brief Sens0 I2C API declarations + * + * @author Joakim Nohlgård + */ + +#ifndef SENS0_I2C_H +#define SENS0_I2C_H + +#include +#include "periph/i2c.h" +#include "sens0.h" +#include "phydat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief I2C connection parameters + */ +typedef struct { + i2c_t i2c; /**< I2C bus the device is connected to */ + uint8_t addr; /**< I2C bus address of the device */ +} sens0_i2c_params_t; + +/** + * @brief Device descriptor for Sens0 sensors on I2C + */ +typedef struct { + const sens0_specs_t *specs; /**< device hardware specification */ + const sens0_i2c_params_t *params; /**< device configuration parameters */ +} sens0_i2c_t; + +/** + * @brief Initialize an I2C connected Sens0 device + * + * @param[in] dev device descriptor of the device to initialize + * + * @return 0 on success + * @return <0 on failure + * @return -EINVAL if initialization of I2C bus failed + * @return -ENODEV if the hardware identification failed + * @return -EIO if there was a communication problem + */ +int sens0_i2c_init(const sens0_i2c_t *dev); + +/** + * @brief Read sensor data + * + * @param[in] dev device descriptor + * @param[out] data output data + * @param[in] iout output index, must be < `dev->specs->num_outputs` + * + * @return 0 on success + * @return <0 on failure + * @return -EIO if there was a communication problem + */ +int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout); + +/** + * @brief Bring the device out of standby + * + * This will configure the sensor for active measurements + * + * @param[out] dev device descriptor + */ +void sens0_i2c_set_active(const sens0_i2c_t *dev); + +/** + * @brief Put the device in standby + * + * Depending on the sensor, this may reduce power consumption. + * + * @param[in] dev device descriptor + */ +void sens0_i2c_set_standby(const sens0_i2c_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* SENS0_I2C_H */ +/** @} */ diff --git a/drivers/sens0/Makefile b/drivers/sens0/Makefile new file mode 100644 index 000000000000..5e72f3313f01 --- /dev/null +++ b/drivers/sens0/Makefile @@ -0,0 +1,3 @@ +DIRS += specs + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/sens0/sens0.c b/drivers/sens0/sens0.c new file mode 100644 index 000000000000..55121ce86273 --- /dev/null +++ b/drivers/sens0/sens0.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @ingroup drivers_sens0 + * @{ + * + * @file + * @brief Sens0 default parsing function implementation + * + * @author Joakim Nohlgård + * + * @} + */ + +#include +#include "assert.h" +#include "sens0.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +int sens0_parse_raw(const sens0_output_t *out_spec, phydat_t *data, uint8_t *raw) +{ + if (out_spec->conv_func) { + return out_spec->conv_func(out_spec, data, raw); + } + assert(out_spec->nelem <= PHYDAT_DIM); + assert(out_spec->elem_size <= sizeof(int32_t)); + data->scale = out_spec->scale; + data->unit = out_spec->unit; + for (uint8_t k = 0; k < out_spec->nelem; ++k) { + int32_t value = 0; + if (out_spec->flags & SENS0_BIG_ENDIAN) { + /* Big endian byte order */ + for (uint8_t j = 0; j < out_spec->elem_size; ++j) { + value = (value << 8) | raw[j]; + } + } + else { + /* Little endian byte order */ + for (uint8_t j = out_spec->elem_size; j > 0; --j) { + value = (value << 8) | raw[j - 1]; + } + } + raw += out_spec->elem_size; + if (out_spec->flags & SENS0_SIGNED) { + /* sign extend */ + unsigned shift = 8 * (sizeof(value) - out_spec->elem_size); + value = (value << shift) >> shift; + } + value = (value * out_spec->conv_frac_num) / out_spec->conv_frac_den; + data->val[k] = value; + } + return out_spec->nelem; +} diff --git a/drivers/sens0/sens0_i2c.c b/drivers/sens0/sens0_i2c.c new file mode 100644 index 000000000000..134862e5ffcb --- /dev/null +++ b/drivers/sens0/sens0_i2c.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @ingroup drivers_sens0 + * @{ + * + * @file + * @brief Sens0 I2C sensor driver implementation + * + * @author Joakim Nohlgård + * + * @} + */ + +#ifdef MODULE_SENS0_I2C +#include +#include + +#include "assert.h" +#include "xtimer.h" +#include "periph/i2c.h" +#include "log.h" +#include "sens0.h" +#include "sens0/i2c.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define I2C_SPEED I2C_SPEED_FAST + +/* Internal use default parsing function defined in sens0.c */ +int sens0_parse_raw(const sens0_output_t *out_spec, phydat_t *data, uint8_t *raw); + +static int sens0_i2c_write_seq(i2c_t i2c, uint8_t addr, uint8_t nelem, const sens0_reg_t *regs) +{ + DEBUG("sens0: write seq, nelem %u\n", (unsigned)nelem); + for (unsigned k = 0; k < nelem; ++k) { + int res = i2c_write_reg(i2c, addr, regs[k].reg, regs[k].value); + DEBUG("sens0: write i2c %u, addr 0x%02x, reg 0x%02x, value 0x%02x\n", + (unsigned)i2c, (unsigned)addr, (unsigned)regs[k].reg, (unsigned)regs[k].value); + if (res != 1) { + DEBUG("sens0: error writing i2c %u, addr 0x%02x, reg 0x%02x: %d\n", + (unsigned)i2c, (unsigned)addr, (unsigned)regs[k].reg, res); + return -EIO; + } + } + return 0; +} + +int sens0_i2c_init(const sens0_i2c_t *dev) +{ + assert(dev); + const sens0_i2c_params_t *params = dev->params; + assert(params); + const sens0_specs_t *specs = dev->specs; + assert(specs); + + int ret = 0; + /* initialize the I2C bus */ + int res = i2c_acquire(params->i2c); + if (res < 0) { + LOG_ERROR("sens0: i2c_acquire error: %d\n", res); + return -EINVAL; + } + do { + res = i2c_init_master(params->i2c, I2C_SPEED); + if (res < 0) { + LOG_ERROR("sens0: unable to initialize I2C bus %u: %d\n", (unsigned)params->i2c, res); + ret = -EINVAL; + break; + } + + uint8_t reg; + if (specs->id.mask) { + /* Check hardware identification */ + res = i2c_read_reg(params->i2c, params->addr, specs->id.reg, ®); + if (res != 1) { + LOG_ERROR("sens0: error reading hardware ID: %d\n", res); + ret = -EIO; + break; + } + if ((reg & specs->id.mask) != specs->id.value) { + LOG_ERROR("sens0: wrong hardware ID, expected 0x%02x, got 0x%02x\n", + (unsigned)specs->id.value, (unsigned)reg); + ret = -ENODEV; + break; + } + } + /* perform hardware reset sequence */ + res = sens0_i2c_write_seq(params->i2c, params->addr, specs->reset_regs_nelem, specs->reset_regs); + if (res < 0) { + /* Some devices do not ACK the reset command, but instead resets immediately */ + DEBUG("sens0: error writing reset sequence (ignored)\n"); + } + if (specs->reset_delay > 0) { + xtimer_usleep(specs->reset_delay); + } + /* perform initialization sequence */ + res = sens0_i2c_write_seq(params->i2c, params->addr, specs->init_regs_nelem, specs->init_regs); + if (res < 0) { + LOG_ERROR("sens0: error writing init sequence\n"); + ret = -EIO; + break; + } + DEBUG("sens0: init complete\n"); + } while(0); + i2c_release(params->i2c); + return ret; +} + +static void sens0_i2c_set_power(const sens0_i2c_t *dev, uint8_t value) +{ + const sens0_i2c_params_t *params = dev->params; + const sens0_specs_t *specs = dev->specs; + if (specs->power_mask == 0) { + DEBUG("sens0: set_power ignored\n"); + return; + } + int res = i2c_acquire(params->i2c); + if (res < 0) { + LOG_ERROR("sens0: i2c_acquire error: %d\n", res); + return; + } + do { + uint8_t tmp = 0; + res = i2c_read_reg(params->i2c, params->addr, specs->power_reg, &tmp); + if (res != 1) { + LOG_ERROR("sens0: error reading power reg: %d\n", res); + break; + } + tmp = (tmp & ~(specs->power_mask)) | value; + res = i2c_write_reg(params->i2c, params->addr, specs->power_reg, tmp); + if (res != 1) { + LOG_ERROR("sens0: error writing power reg: %d\n", res); + break; + } + } while(0); + i2c_release(params->i2c); +} + +void sens0_i2c_set_active(const sens0_i2c_t *dev) +{ + assert(dev); + DEBUG("sens0: active mode\n"); + sens0_i2c_set_power(dev, dev->specs->power_value_active); +} + +void sens0_i2c_set_standby(const sens0_i2c_t *dev) +{ + assert(dev); + DEBUG("sens0: standby mode\n"); + sens0_i2c_set_power(dev, dev->specs->power_value_standby); +} + +int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) +{ + assert(dev); + const sens0_i2c_params_t *params = dev->params; + const sens0_specs_t *specs = dev->specs; + assert(iout < specs->outputs_nelem); + const sens0_output_t *out_spec = &specs->outputs[iout]; + const uint8_t raw_size = out_spec->nelem * out_spec->elem_size; + uint8_t buf[raw_size]; + + int res = i2c_acquire(params->i2c); + if (res < 0) { + LOG_ERROR("sens0: i2c_acquire error: %d\n", res); + return -EINVAL; + } + int ret = 0; + do { + if (specs->measurement_req.mask == 0) { + /* Skip measurement request if mask is zero */ + break; + } + uint8_t tmp = 0; + if (specs->measurement_req.mask < 0xffu) { + /* Read modify write */ + res = i2c_read_reg(params->i2c, params->addr, specs->measurement_req.reg, &tmp); + if (res != 1) { + LOG_ERROR("sens0: error reading measurement request reg: %d\n", res); + ret = -EIO; + break; + } + tmp &= ~(specs->measurement_req.mask); + } + tmp |= specs->measurement_req.value; + res = i2c_write_reg(params->i2c, params->addr, specs->measurement_req.reg, tmp); + if (res != 1) { + LOG_ERROR("sens0: error writing measurement request: %d\n", res); + ret = -EIO; + break; + } + } while(0); + i2c_release(params->i2c); + if (ret != 0) { + return ret; + } + if (specs->measurement_delay > 0) { + xtimer_usleep(specs->measurement_delay); + } + res = i2c_acquire(params->i2c); + if (res < 0) { + LOG_ERROR("sens0: i2c_acquire error: %d\n", res); + return -EINVAL; + } + res = i2c_read_regs(params->i2c, params->addr, out_spec->reg, buf, raw_size); + i2c_release(params->i2c); + if (res != raw_size) { + LOG_ERROR("sens0: error reading values (i2c=%u, addr=0x%02x, reg=0x%02x, size=%u): %d\n", + params->i2c, params->addr, out_spec->reg, raw_size, res); + return -EIO; + } + + return sens0_parse_raw(out_spec, data, buf); +} + +#else /* MODULE_SENS0_I2C */ +typedef int dont_be_pedantic; +#endif diff --git a/drivers/sens0/sens0_i2c_saul.c b/drivers/sens0/sens0_i2c_saul.c new file mode 100644 index 000000000000..06bf160a02c1 --- /dev/null +++ b/drivers/sens0/sens0_i2c_saul.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup driver_sens0 + * @{ + * + * @file + * @brief SAUL helpers for Sens0 + * + * @author Joakim Nohlgård + * + * @} + */ + +#include "phydat.h" +#include "sens0/i2c.h" + +/* Quick and dirty C alternative to argument binding without lambdas/closures */ + +int sens0_i2c_read_output0(const void *dev, phydat_t *res) +{ + return sens0_i2c_read((const sens0_i2c_t *)dev, res, 0); +} + +int sens0_i2c_read_output1(const void *dev, phydat_t *res) +{ + return sens0_i2c_read((const sens0_i2c_t *)dev, res, 1); +} + +int sens0_i2c_read_output2(const void *dev, phydat_t *res) +{ + return sens0_i2c_read((const sens0_i2c_t *)dev, res, 2); +} diff --git a/drivers/sens0/specs/Makefile b/drivers/sens0/specs/Makefile new file mode 100644 index 000000000000..c9a28aeb1991 --- /dev/null +++ b/drivers/sens0/specs/Makefile @@ -0,0 +1,2 @@ +MODULE = sens0_specs +include $(RIOTBASE)/Makefile.base diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index ebb54ee0a9cf..7e1829353182 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -68,6 +68,7 @@ PSEUDOMODULES += rdcli_simple_standalone PSEUDOMODULES += saul_adc PSEUDOMODULES += saul_default PSEUDOMODULES += saul_gpio +PSEUDOMODULES += sens0_i2c PSEUDOMODULES += schedstatistics PSEUDOMODULES += sock PSEUDOMODULES += sock_ip From 70a560e54014828dc75f8581043648b57e7d7ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Wed, 30 May 2018 07:32:43 +0200 Subject: [PATCH 2/7] squash sens0 new i2c --- drivers/sens0/sens0_i2c.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/drivers/sens0/sens0_i2c.c b/drivers/sens0/sens0_i2c.c index 134862e5ffcb..d1a2b78040f2 100644 --- a/drivers/sens0/sens0_i2c.c +++ b/drivers/sens0/sens0_i2c.c @@ -33,8 +33,6 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#define I2C_SPEED I2C_SPEED_FAST - /* Internal use default parsing function defined in sens0.c */ int sens0_parse_raw(const sens0_output_t *out_spec, phydat_t *data, uint8_t *raw); @@ -42,10 +40,10 @@ static int sens0_i2c_write_seq(i2c_t i2c, uint8_t addr, uint8_t nelem, const sen { DEBUG("sens0: write seq, nelem %u\n", (unsigned)nelem); for (unsigned k = 0; k < nelem; ++k) { - int res = i2c_write_reg(i2c, addr, regs[k].reg, regs[k].value); + int res = i2c_write_reg(i2c, addr, regs[k].reg, regs[k].value, 0); DEBUG("sens0: write i2c %u, addr 0x%02x, reg 0x%02x, value 0x%02x\n", (unsigned)i2c, (unsigned)addr, (unsigned)regs[k].reg, (unsigned)regs[k].value); - if (res != 1) { + if (res != I2C_ACK) { DEBUG("sens0: error writing i2c %u, addr 0x%02x, reg 0x%02x: %d\n", (unsigned)i2c, (unsigned)addr, (unsigned)regs[k].reg, res); return -EIO; @@ -63,25 +61,18 @@ int sens0_i2c_init(const sens0_i2c_t *dev) assert(specs); int ret = 0; - /* initialize the I2C bus */ + /* prepare the I2C bus */ int res = i2c_acquire(params->i2c); if (res < 0) { LOG_ERROR("sens0: i2c_acquire error: %d\n", res); return -EINVAL; } do { - res = i2c_init_master(params->i2c, I2C_SPEED); - if (res < 0) { - LOG_ERROR("sens0: unable to initialize I2C bus %u: %d\n", (unsigned)params->i2c, res); - ret = -EINVAL; - break; - } - uint8_t reg; if (specs->id.mask) { /* Check hardware identification */ - res = i2c_read_reg(params->i2c, params->addr, specs->id.reg, ®); - if (res != 1) { + res = i2c_read_reg(params->i2c, params->addr, specs->id.reg, ®, 0); + if (res != I2C_ACK) { LOG_ERROR("sens0: error reading hardware ID: %d\n", res); ret = -EIO; break; @@ -130,14 +121,14 @@ static void sens0_i2c_set_power(const sens0_i2c_t *dev, uint8_t value) } do { uint8_t tmp = 0; - res = i2c_read_reg(params->i2c, params->addr, specs->power_reg, &tmp); - if (res != 1) { + res = i2c_read_reg(params->i2c, params->addr, specs->power_reg, &tmp, 0); + if (res != I2C_ACK) { LOG_ERROR("sens0: error reading power reg: %d\n", res); break; } tmp = (tmp & ~(specs->power_mask)) | value; - res = i2c_write_reg(params->i2c, params->addr, specs->power_reg, tmp); - if (res != 1) { + res = i2c_write_reg(params->i2c, params->addr, specs->power_reg, tmp, 0); + if (res != I2C_ACK) { LOG_ERROR("sens0: error writing power reg: %d\n", res); break; } @@ -183,8 +174,8 @@ int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) uint8_t tmp = 0; if (specs->measurement_req.mask < 0xffu) { /* Read modify write */ - res = i2c_read_reg(params->i2c, params->addr, specs->measurement_req.reg, &tmp); - if (res != 1) { + res = i2c_read_reg(params->i2c, params->addr, specs->measurement_req.reg, &tmp, 0); + if (res != I2C_ACK) { LOG_ERROR("sens0: error reading measurement request reg: %d\n", res); ret = -EIO; break; @@ -192,8 +183,8 @@ int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) tmp &= ~(specs->measurement_req.mask); } tmp |= specs->measurement_req.value; - res = i2c_write_reg(params->i2c, params->addr, specs->measurement_req.reg, tmp); - if (res != 1) { + res = i2c_write_reg(params->i2c, params->addr, specs->measurement_req.reg, tmp, 0); + if (res != I2C_ACK) { LOG_ERROR("sens0: error writing measurement request: %d\n", res); ret = -EIO; break; @@ -211,9 +202,9 @@ int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) LOG_ERROR("sens0: i2c_acquire error: %d\n", res); return -EINVAL; } - res = i2c_read_regs(params->i2c, params->addr, out_spec->reg, buf, raw_size); + res = i2c_read_regs(params->i2c, params->addr, out_spec->reg, buf, raw_size, 0); i2c_release(params->i2c); - if (res != raw_size) { + if (res != I2C_ACK) { LOG_ERROR("sens0: error reading values (i2c=%u, addr=0x%02x, reg=0x%02x, size=%u): %d\n", params->i2c, params->addr, out_spec->reg, raw_size, res); return -EIO; From 74ada8747f8b2b9c26358025378b858f4b2d1cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Thu, 3 May 2018 12:56:20 +0200 Subject: [PATCH 3/7] sens0: NXP FXAS21002C gyroscope initial support https://www.nxp.com/products/sensors/motion-sensors/gyroscopes/3-axis-digital-gyroscope:FXAS21002C --- drivers/include/sens0/specs/fxas21002c.h | 47 +++++++++++++++ drivers/sens0/specs/sens0_fxas21002c.c | 76 ++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 drivers/include/sens0/specs/fxas21002c.h create mode 100644 drivers/sens0/specs/sens0_fxas21002c.c diff --git a/drivers/include/sens0/specs/fxas21002c.h b/drivers/include/sens0/specs/fxas21002c.h new file mode 100644 index 000000000000..aea968c4f576 --- /dev/null +++ b/drivers/include/sens0/specs/fxas21002c.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_sens0_specs + * @brief NXP FXAS21002C gyroscope + * + * @{ + * @file + * @brief Sens0 specifications for NXP FXAS21002C gyroscope + * + * @see Data sheet https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf + * + * @author Joakim Nohlgård + */ + +#ifndef SENS0_SPECS_FXAS21002C_H +#define SENS0_SPECS_FXAS21002C_H + +#include "sens0.h" +#include "saul.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sens0 specification for NXP FXAS21002C gyroscope + */ +extern const sens0_specs_t sens0_specs_fxas21002c; +/** + * @brief SAUL driver declaration for NXP FXAS21002C gyroscope over I2C + */ +extern const saul_driver_t sens0_saul_drv_fxas21002c_i2c; + +#ifdef __cplusplus +} +#endif + +#endif /* SENS0_SPECS_FXAS21002C_H */ + +/** @} */ diff --git a/drivers/sens0/specs/sens0_fxas21002c.c b/drivers/sens0/specs/sens0_fxas21002c.c new file mode 100644 index 000000000000..89de1e17690a --- /dev/null +++ b/drivers/sens0/specs/sens0_fxas21002c.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_sens0_specs + * @brief NXP FXAS21002C gyroscope + * + * @{ + * @file + * @brief Sens0 specifications for NXP FXAS21002C gyroscope + * + * @see Data sheet https://www.nxp.com/docs/en/data-sheet/FXAS21002.pdf + * + * @author Joakim Nohlgård + * @} + */ + +#include /* for NULL */ +#include "sens0.h" +#include "sens0/specs/fxas21002c.h" +#ifdef MODULE_SAUL +#include "saul.h" +#endif + +static const sens0_reg_t sens0_fxas21002c_reset_regs[] = { + { .reg = 0x13u, .value = 0x40u, /* CTRL_REG1, perform reset, will auto clear */ }, +}; + +static const sens0_reg_t sens0_fxas21002c_init_regs[] = { + { .reg = 0x0du, .value = 0x00u, /* CTRL_REG0, full scale +/- 2000 dps */ }, + { .reg = 0x13u, .value = 0x0cu, /* CTRL_REG1, 100 Hz ODR */ }, +}; + +static const sens0_output_t sens0_fxas21002c_outputs[] = { + { + .flags = SENS0_BIG_ENDIAN | SENS0_SIGNED, + .nelem = 3, + .elem_size = 2, + .reg = 0x01u, + .conv_func = NULL, + .conv_frac_num = 625, /* 0.0625 DPS per LSB */ + .conv_frac_den = 1000, + .unit = UNIT_DPS, + .scale = -1, + }, +}; + +const sens0_specs_t sens0_specs_fxas21002c = { + .id = { .reg = 0x0cu, .mask = 0xffu, .value = 0xd7u, }, + .reset_regs_nelem = sizeof(sens0_fxas21002c_reset_regs) / sizeof(sens0_fxas21002c_reset_regs[0]), + .reset_regs = sens0_fxas21002c_reset_regs, + .reset_delay = 1000u, /* unknown timing, arbitrary delay */ + .init_regs_nelem = sizeof(sens0_fxas21002c_init_regs) / sizeof(sens0_fxas21002c_init_regs[0]), + .init_regs = sens0_fxas21002c_init_regs, + .measurement_req = { .reg = 0, .mask = 0, .value = 0, }, /* No req needed */ + .measurement_delay = 0, /* No delay needed */ + .outputs_nelem = sizeof(sens0_fxas21002c_outputs) / sizeof(sens0_fxas21002c_outputs[0]), + .outputs = sens0_fxas21002c_outputs, + .power_reg = 0x13u, /* CTRL_REG1 */ + .power_mask = 0x03u, /* ACTIVE + READY bit */ + .power_value_active = 0x03u, /* ACTIVE mode */ + .power_value_standby = 0x00u, /* STANDBY mode */ +}; + +#ifdef MODULE_SAUL +const saul_driver_t sens0_saul_drv_fxas21002c_i2c = { + .read = sens0_i2c_read_output0, + .write = saul_notsup, + .type = SAUL_SENSE_GYRO, +}; +#endif /* MODULE_SAUL */ From cb1838c2c4b5399945f82a5a29fc90e76eae890d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Thu, 3 May 2018 12:57:24 +0200 Subject: [PATCH 4/7] sens0: NXP FXOS8700CQ acc + mag 6DOF initial support https://www.nxp.com/products/sensors/motion-sensors/6-axis-sensors/digital-sensor-3d-accelerometer-2g-4g-8g-plus-3d-magnetometer:FXOS8700CQ --- drivers/include/sens0/specs/fxos8700cq.h | 51 +++++++++++++ drivers/sens0/specs/sens0_fxos8700cq.c | 97 ++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 drivers/include/sens0/specs/fxos8700cq.h create mode 100644 drivers/sens0/specs/sens0_fxos8700cq.c diff --git a/drivers/include/sens0/specs/fxos8700cq.h b/drivers/include/sens0/specs/fxos8700cq.h new file mode 100644 index 000000000000..4a9d7b5dd97d --- /dev/null +++ b/drivers/include/sens0/specs/fxos8700cq.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_sens0_specs + * @brief NXP FXOS8700CQ accelerometer + magnetometer 6DOF sensor + * + * @{ + * @file + * @brief Sens0 specifications for NXP FXOS8700CQ + * + * @see Data sheet https://www.nxp.com/docs/en/data-sheet/FXOS8700CQ.pdf + * + * @author Joakim Nohlgård + */ + +#ifndef SENS0_SPECS_FXOS8700CQ_H +#define SENS0_SPECS_FXOS8700CQ_H + +#include "sens0.h" +#include "saul.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sens0 specification for NXP FXOS8700CQ accelerometer + magnetometer 6DOF sensor + */ +extern const sens0_specs_t sens0_specs_fxos8700cq; +/** + * @brief SAUL driver declaration for NXP FXOS8700CQ accelerometer over I2C + */ +extern const saul_driver_t sens0_saul_drv_fxos8700cq_i2c_acc; +/** + * @brief SAUL driver declaration for NXP FXOS8700CQ magnetometer over I2C + */ +extern const saul_driver_t sens0_saul_drv_fxos8700cq_i2c_mag; + +#ifdef __cplusplus +} +#endif + +#endif /* SENS0_SPECS_FXOS8700CQ_H */ + +/** @} */ diff --git a/drivers/sens0/specs/sens0_fxos8700cq.c b/drivers/sens0/specs/sens0_fxos8700cq.c new file mode 100644 index 000000000000..c7fbee669ff6 --- /dev/null +++ b/drivers/sens0/specs/sens0_fxos8700cq.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_sens0_specs + * @brief NXP FXOS8700CQ accelerometer + magnetometer 6DOF sensor + * + * @{ + * @file + * @brief Sens0 specifications for NXP FXOS8700CQ + * + * @see Data sheet https://www.nxp.com/docs/en/data-sheet/FXOS8700CQ.pdf + * + * @author Joakim Nohlgård + * @} + */ + +#include /* for NULL */ +#include "sens0.h" +#include "sens0/specs/fxos8700cq.h" +#ifdef MODULE_SAUL +#include "saul.h" +#endif + +static const sens0_reg_t sens0_fxos8700cq_reset_regs[] = { + { .reg = 0x2bu, .value = 0x40u, /* CTRL_REG2, perform reset, will auto clear */ }, +}; + +/* Hybrid mode (accelerometer + magnetometer) */ +static const sens0_reg_t sens0_fxos8700cq_init_regs_hybrid[] = { + { .reg = 0x2au, .value = 0x10u, /* CTRL_REG1, set 100 Hz hybrid ODR */ }, + { .reg = 0x0eu, .value = 0x02u, /* XYZ_DATA_CFG, +/- 8 g full scale */ }, + { .reg = 0x5bu, .value = 0x1fu, /* M_CTRL_REG1, hybrid mode, OSR=7 */ }, +}; + +static const sens0_output_t sens0_fxos8700cq_outputs[] = { + { + /* Accelerometer */ + .flags = SENS0_BIG_ENDIAN | SENS0_SIGNED, + .nelem = 3, + .elem_size = 2, + .reg = 0x01u, + .conv_func = NULL, + .conv_frac_num = 976, /* Raw value is 14 bits left adjusted, LSB=0.976 mG */ + .conv_frac_den = 4000, /* divide by 4 to eliminate the rightmost dummy bits */ + .unit = UNIT_G, + .scale = -3, + }, + { + /* Magnetometer */ + .flags = SENS0_BIG_ENDIAN | SENS0_SIGNED, + .nelem = 3, + .elem_size = 2, + .reg = 0x33u, + .conv_func = NULL, + .conv_frac_num = 1, /* Raw value is 16 bits signed, LSB=0.1 µT = 0.001 gauss */ + .conv_frac_den = 1, /* no need to scale the raw value */ + .unit = UNIT_GS, + .scale = -3, + }, +}; + +const sens0_specs_t sens0_specs_fxos8700cq = { + .id = { .reg = 0x0du, .mask = 0xffu, .value = 0xc7u, }, + .reset_regs_nelem = sizeof(sens0_fxos8700cq_reset_regs) / sizeof(sens0_fxos8700cq_reset_regs[0]), + .reset_regs = sens0_fxos8700cq_reset_regs, + .reset_delay = 1000u, /* reset takes 1 ms */ + .init_regs_nelem = sizeof(sens0_fxos8700cq_init_regs_hybrid) / sizeof(sens0_fxos8700cq_init_regs_hybrid[0]), + .init_regs = sens0_fxos8700cq_init_regs_hybrid, + .measurement_req = { .reg = 0, .mask = 0, .value = 0, }, /* No req needed */ + .measurement_delay = 0, /* No delay needed */ + .outputs_nelem = sizeof(sens0_fxos8700cq_outputs) / sizeof(sens0_fxos8700cq_outputs[0]), + .outputs = sens0_fxos8700cq_outputs, + .power_reg = 0x2au, /* CTRL_REG1 */ + .power_mask = 0x01u, /* Active bit */ + .power_value_active = 0x01u, + .power_value_standby = 0x00u, +}; + +#ifdef MODULE_SAUL +const saul_driver_t sens0_saul_drv_fxos8700cq_i2c_acc = { + .read = sens0_i2c_read_output0, + .write = saul_notsup, + .type = SAUL_SENSE_ACCEL, +}; + +const saul_driver_t sens0_saul_drv_fxos8700cq_i2c_mag = { + .read = sens0_i2c_read_output1, + .write = saul_notsup, + .type = SAUL_SENSE_MAG, +}; +#endif /* MODULE_SAUL */ From 64dcdf7ec9232b3d470e1486f0f3609c85cd09b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Fri, 4 May 2018 10:20:23 +0200 Subject: [PATCH 5/7] sens0: Add test application --- tests/driver_sens0/Makefile | 12 +++ tests/driver_sens0/README.md | 15 ++++ tests/driver_sens0/main.c | 139 +++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 tests/driver_sens0/Makefile create mode 100644 tests/driver_sens0/README.md create mode 100644 tests/driver_sens0/main.c diff --git a/tests/driver_sens0/Makefile b/tests/driver_sens0/Makefile new file mode 100644 index 000000000000..b4865fa98f8d --- /dev/null +++ b/tests/driver_sens0/Makefile @@ -0,0 +1,12 @@ +include ../Makefile.tests_common + +FEATURES_REQUIRED += periph_i2c +USEMODULE += sens0_i2c +USEMODULE += saul_reg + +# For xtimer_periodic_wakeup +USEMODULE += xtimer +# For phydat_dump +USEMODULE += phydat + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_sens0/README.md b/tests/driver_sens0/README.md new file mode 100644 index 000000000000..3b963df41270 --- /dev/null +++ b/tests/driver_sens0/README.md @@ -0,0 +1,15 @@ +Expected result +=============== + +This test application attempts to initialize some configured sens0 devices, +followed by polling all available SAUL devices periodically for their data. +This data is then printed to STDIO. + +Background +========== + +The actual devices that are actually polled depend on the devices that are +configured for a particular platform. +The main purpose of the application is to ensure that sens0 is compile tested by +the CI system, as well as giving a basic example of how to configure and +initialize sens0 devices. diff --git a/tests/driver_sens0/main.c b/tests/driver_sens0/main.c new file mode 100644 index 000000000000..33be2bc8d2b7 --- /dev/null +++ b/tests/driver_sens0/main.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * + * @file + * @brief Basic test of Sens0 sensors. + * + * @author Joakim Nohlgård + * + */ + +#include + +#include "xtimer.h" +#include "sens0.h" +#include "sens0/i2c.h" +#include "sens0/specs/fxos8700cq.h" +#include "sens0/specs/fxas21002c.h" +#ifdef MODULE_SAUL_REG +#include "saul_reg.h" +#endif + +/** + * @brief Read sensors every second + */ +#define INTERVAL (1LU * US_PER_SEC) + + +/* The sensor configuration below was written for a FRDM-K64F board with a + * FRDM-STBC-AGM01 9DOF shield, but might work on other boards, especially other + * NXP FRDM variants */ +static const sens0_i2c_t sens0devs[] = { + { + .specs = &sens0_specs_fxos8700cq, + .params = &(sens0_i2c_params_t){ .i2c = I2C_DEV(0), .addr = 0x1d, }, + }, + { + .specs = &sens0_specs_fxos8700cq, + .params = &(sens0_i2c_params_t){ .i2c = I2C_DEV(0), .addr = 0x1e, }, + }, + { + .specs = &sens0_specs_fxas21002c, + .params = &(sens0_i2c_params_t){ .i2c = I2C_DEV(0), .addr = 0x20, }, + }, +}; +#ifdef MODULE_SAUL_REG +static saul_reg_t saul_entries[] = { + { .name = "sens0_frdm_acc", .dev = (void *)&sens0devs[0], .driver = &sens0_saul_drv_fxos8700cq_i2c_acc, }, + { .name = "sens0_frdm_mag", .dev = (void *)&sens0devs[0], .driver = &sens0_saul_drv_fxos8700cq_i2c_mag, }, + { .name = "sens0_agm01_acc", .dev = (void *)&sens0devs[1], .driver = &sens0_saul_drv_fxos8700cq_i2c_acc, }, + { .name = "sens0_agm01_mag", .dev = (void *)&sens0devs[1], .driver = &sens0_saul_drv_fxos8700cq_i2c_mag, }, + { .name = "sens0_agm01_gyro", .dev = (void *)&sens0devs[2], .driver = &sens0_saul_drv_fxas21002c_i2c, }, +}; +#endif /* MODULE_SAUL_REG */ + +int main(void) +{ + xtimer_ticks32_t last_wakeup = xtimer_now(); + + puts("Sens0 test application"); + + puts("Initialize sensors"); +#ifdef MODULE_SAUL_REG + unsigned j = 0; +#endif /* MODULE_SAUL_REG */ + for (unsigned k = 0; k < sizeof(sens0devs) / sizeof(sens0devs[0]); ++k) { + const sens0_i2c_t *s0 = &sens0devs[k]; + int res = sens0_i2c_init(s0); + if (res < 0) { + printf("sens0 init %u failed, res = %d\n", k, res); +#ifdef MODULE_SAUL_REG + /* Skip all SAUL entries for this device to avoid leaving entries + * for uninitialized/missing devices */ + /* This assumes the saul_entries array is sorted in the same order + * as the sens0devs array */ + while ((j < sizeof(saul_entries) / sizeof(saul_entries[0])) && + (saul_entries[j].dev == s0)) { + ++j; + } +#endif /* MODULE_SAUL_REG */ + continue; + } + /* Bring sensor out of standby */ + sens0_i2c_set_active(s0); +#ifdef MODULE_SAUL_REG + while ((j < sizeof(saul_entries) / sizeof(saul_entries[0])) && + (saul_entries[j].dev == s0)) { + saul_reg_add(&(saul_entries[j])); + ++j; + } +#endif /* MODULE_SAUL_REG */ + } + + while (1) { + puts("Direct sens0 API read:"); + phydat_t buf; + for (unsigned k = 0; k < sizeof(sens0devs) / sizeof(sens0devs[0]); ++k) { + const sens0_i2c_t *s0 = &sens0devs[k]; + for (unsigned ch = 0; ch < s0->specs->outputs_nelem; ++ch) { + printf("dev %u, channel %u:\n", k, ch); + int dim = sens0_i2c_read(s0, &buf, ch); + if (dim < 0) { + printf(" Read error: %d\n", dim); + continue; + } + phydat_dump(&buf, dim); + } + } +#ifdef MODULE_SAUL_REG + puts("SAUL devices:"); + saul_reg_t *dev = saul_reg; + + if (dev == NULL) { + puts("No SAUL devices present"); + return 1; + } + + while (dev) { + int dim = saul_reg_read(dev, &buf); + printf("\nDev: %s\tType: %s\n", dev->name, + saul_class_to_str(dev->driver->type)); + phydat_dump(&buf, dim); + dev = dev->next; + } +#endif /* MODULE_SAUL_REG */ + puts("\n##########################"); + + xtimer_periodic_wakeup(&last_wakeup, INTERVAL); + } + + return 0; +} From 42861387eea4df72b268842a98b31370d1b215f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Wed, 30 May 2018 07:32:35 +0200 Subject: [PATCH 6/7] squash sens0 test new i2c --- tests/driver_sens0/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/driver_sens0/main.c b/tests/driver_sens0/main.c index 33be2bc8d2b7..8765d65e9db1 100644 --- a/tests/driver_sens0/main.c +++ b/tests/driver_sens0/main.c @@ -30,7 +30,7 @@ /** * @brief Read sensors every second */ -#define INTERVAL (1LU * US_PER_SEC) +#define INTERVAL (1000LU * US_PER_SEC) /* The sensor configuration below was written for a FRDM-K64F board with a From c5ff740212cf74066b7a4ac6f5dfc85eaae3999a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Sat, 2 Jun 2018 00:13:51 +0200 Subject: [PATCH 7/7] squash sens0 i2c api fixes --- drivers/sens0/sens0_i2c.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/sens0/sens0_i2c.c b/drivers/sens0/sens0_i2c.c index d1a2b78040f2..f654013d2233 100644 --- a/drivers/sens0/sens0_i2c.c +++ b/drivers/sens0/sens0_i2c.c @@ -43,7 +43,7 @@ static int sens0_i2c_write_seq(i2c_t i2c, uint8_t addr, uint8_t nelem, const sen int res = i2c_write_reg(i2c, addr, regs[k].reg, regs[k].value, 0); DEBUG("sens0: write i2c %u, addr 0x%02x, reg 0x%02x, value 0x%02x\n", (unsigned)i2c, (unsigned)addr, (unsigned)regs[k].reg, (unsigned)regs[k].value); - if (res != I2C_ACK) { + if (res < 0) { DEBUG("sens0: error writing i2c %u, addr 0x%02x, reg 0x%02x: %d\n", (unsigned)i2c, (unsigned)addr, (unsigned)regs[k].reg, res); return -EIO; @@ -72,7 +72,7 @@ int sens0_i2c_init(const sens0_i2c_t *dev) if (specs->id.mask) { /* Check hardware identification */ res = i2c_read_reg(params->i2c, params->addr, specs->id.reg, ®, 0); - if (res != I2C_ACK) { + if (res < 0) { LOG_ERROR("sens0: error reading hardware ID: %d\n", res); ret = -EIO; break; @@ -122,13 +122,13 @@ static void sens0_i2c_set_power(const sens0_i2c_t *dev, uint8_t value) do { uint8_t tmp = 0; res = i2c_read_reg(params->i2c, params->addr, specs->power_reg, &tmp, 0); - if (res != I2C_ACK) { + if (res < 0) { LOG_ERROR("sens0: error reading power reg: %d\n", res); break; } tmp = (tmp & ~(specs->power_mask)) | value; res = i2c_write_reg(params->i2c, params->addr, specs->power_reg, tmp, 0); - if (res != I2C_ACK) { + if (res < 0) { LOG_ERROR("sens0: error writing power reg: %d\n", res); break; } @@ -165,7 +165,6 @@ int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) LOG_ERROR("sens0: i2c_acquire error: %d\n", res); return -EINVAL; } - int ret = 0; do { if (specs->measurement_req.mask == 0) { /* Skip measurement request if mask is zero */ @@ -175,24 +174,22 @@ int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) if (specs->measurement_req.mask < 0xffu) { /* Read modify write */ res = i2c_read_reg(params->i2c, params->addr, specs->measurement_req.reg, &tmp, 0); - if (res != I2C_ACK) { + if (res < 0) { LOG_ERROR("sens0: error reading measurement request reg: %d\n", res); - ret = -EIO; break; } tmp &= ~(specs->measurement_req.mask); } tmp |= specs->measurement_req.value; res = i2c_write_reg(params->i2c, params->addr, specs->measurement_req.reg, tmp, 0); - if (res != I2C_ACK) { + if (res < 0) { LOG_ERROR("sens0: error writing measurement request: %d\n", res); - ret = -EIO; break; } } while(0); i2c_release(params->i2c); - if (ret != 0) { - return ret; + if (res < 0) { + return res; } if (specs->measurement_delay > 0) { xtimer_usleep(specs->measurement_delay); @@ -204,7 +201,7 @@ int sens0_i2c_read(const sens0_i2c_t *dev, phydat_t *data, uint8_t iout) } res = i2c_read_regs(params->i2c, params->addr, out_spec->reg, buf, raw_size, 0); i2c_release(params->i2c); - if (res != I2C_ACK) { + if (res < 0) { LOG_ERROR("sens0: error reading values (i2c=%u, addr=0x%02x, reg=0x%02x, size=%u): %d\n", params->i2c, params->addr, out_spec->reg, raw_size, res); return -EIO;