From a655f2090f5cf8b7332f5c4db30a78a77b79f0e8 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Thu, 1 Aug 2024 19:16:46 +0200 Subject: [PATCH] ... --- .../test_2024-07-23/src/adafruit/arduino.cpp | 28 -- .../test_2024-07-23/src/adafruit/arduino.h | 46 --- .../test_2024-07-23/src/adafruit/bme280.cpp | 219 ++++------- .../test_2024-07-23/src/adafruit/bme280.h | 11 +- .../test_2024-07-23/src/adafruit/ens160.cpp | 365 ++++++++++++++++++ .../test_2024-07-23/src/adafruit/ens160.h | 180 +++++++++ .../test_2024-07-23/src/adafruit/sensor.cpp | 123 ------ .../test_2024-07-23/src/adafruit/sensor.h | 29 +- software/test_2024-07-23/src/i2cdevice.cpp | 117 ++++++ software/test_2024-07-23/src/i2cdevice.hpp | 27 ++ software/test_2024-07-23/src/main.cpp | 9 + software/test_2024-07-23/src/main.hpp | 1 - software/test_2024-07-23/src/units/i2c.cpp | 45 ++- software/test_2024-07-23/src/units/i2c.hpp | 9 +- 14 files changed, 837 insertions(+), 372 deletions(-) delete mode 100644 software/test_2024-07-23/src/adafruit/arduino.cpp delete mode 100644 software/test_2024-07-23/src/adafruit/arduino.h create mode 100644 software/test_2024-07-23/src/adafruit/ens160.cpp create mode 100644 software/test_2024-07-23/src/adafruit/ens160.h delete mode 100644 software/test_2024-07-23/src/adafruit/sensor.cpp create mode 100644 software/test_2024-07-23/src/i2cdevice.cpp create mode 100644 software/test_2024-07-23/src/i2cdevice.hpp diff --git a/software/test_2024-07-23/src/adafruit/arduino.cpp b/software/test_2024-07-23/src/adafruit/arduino.cpp deleted file mode 100644 index 055b842..0000000 --- a/software/test_2024-07-23/src/adafruit/arduino.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "arduino.h" - -Adafruit_I2CDevice::Adafruit_I2CDevice (uint8_t addr) { -} - - -bool Adafruit_I2CDevice::begin (bool addr_detect) { - return false; -} - -void Adafruit_I2CDevice::end (void) { - -} - -bool Adafruit_I2CDevice::read (uint8_t *buffer, size_t len, bool stop) { - return false; -} - -bool Adafruit_I2CDevice::write (const uint8_t *buffer, size_t len) { - return false; -} - -// bool write(const uint8_t *buffer, size_t len, bool stop = true, -// const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0); - -bool Adafruit_I2CDevice::write_then_read (const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, bool stop) { - return false; -} diff --git a/software/test_2024-07-23/src/adafruit/arduino.h b/software/test_2024-07-23/src/adafruit/arduino.h deleted file mode 100644 index 8ec8334..0000000 --- a/software/test_2024-07-23/src/adafruit/arduino.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __ARDUINO_H__ -#define __ARDUINO_H__ - -#include -#include - -#define byte uint8_t - - - -class Adafruit_SPIDevice {}; - -class SPIClass {}; - -class TwoWire {}; - -extern SPIClass SPI; -extern TwoWire Wire; -extern uint32_t millis (); - -class Adafruit_I2CDevice { - public: - Adafruit_I2CDevice(uint8_t addr); - bool begin(bool addr_detect = true); - void end(void); - bool read(uint8_t *buffer, size_t len, bool stop = true); - bool write(const uint8_t *buffer, size_t len); - // bool write(const uint8_t *buffer, size_t len, bool stop = true, - // const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0); - - bool write_then_read(const uint8_t *write_buffer, size_t write_len, - uint8_t *read_buffer, size_t read_len, - bool stop = false); - - - private: - uint8_t _addr; - TwoWire *_wire; - bool _begun; - size_t _maxBufferSize; - bool _read(uint8_t *buffer, size_t len, bool stop); -}; - - - -#endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/adafruit/bme280.cpp b/software/test_2024-07-23/src/adafruit/bme280.cpp index 049e9a6..6ff5bc8 100644 --- a/software/test_2024-07-23/src/adafruit/bme280.cpp +++ b/software/test_2024-07-23/src/adafruit/bme280.cpp @@ -1,109 +1,46 @@ -/*! - * @file Adafruit_BME280.cpp - * - * @mainpage Adafruit BME280 humidity, temperature & pressure sensor - * - * @section intro_sec Introduction - * - * Driver for the BME280 humidity, temperature & pressure sensor - * - * These sensors use I2C or SPI to communicate, 2 or 4 pins are required - * to interface. - * - * Designed specifically to work with the Adafruit BME280 Breakout - * ----> http://www.adafruit.com/products/2652 - * - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * @section author Author - * - * Written by Kevin "KTOWN" Townsend for Adafruit Industries. - * - * @section license License - * - * BSD license, all text here must be included in any redistribution. - * See the LICENSE file for details. - * - */ - -// #include "Adafruit_BME280.h" -// #include "Arduino.h" - #include "bme280.h" -#include "arduino.h" #include +#include Adafruit_BME280 theBME280; Adafruit_BME280_Temp bm280TempSensor; Adafruit_BME280_Pressure bm280PressureSensor; Adafruit_BME280_Humidity bm280HumiditySensor; - - -/*! - * @brief class constructor - */ Adafruit_BME280::Adafruit_BME280() { - t_fine_adjust = 0; - temp_sensor = &bm280TempSensor; - pressure_sensor = &bm280PressureSensor; - humidity_sensor = &bm280HumiditySensor; + static I2cDevice i2cDevice; + t_fine_adjust = 0; + temp_sensor = &bm280TempSensor; + pressure_sensor = &bm280PressureSensor; + humidity_sensor = &bm280HumiditySensor; + i2c_dev = &i2cDevice; } -// /*! -// * @brief class constructor if using hardware SPI -// * @param cspin the chip select pin to use -// * @param *theSPI -// * optional SPI object -// */ -// Adafruit_BME280::Adafruit_BME280(int8_t cspin, SPIClass *theSPI) { -// spi_dev = new Adafruit_SPIDevice(cspin, 1000000, SPI_BITORDER_MSBFIRST, -// SPI_MODE0, theSPI); -// } - -/*! - * @brief Initialise sensor with given parameters / settings - * @param addr the I2C address the device can be found on - * @param theWire the I2C object to use, defaults to &Wire - * @returns true on success, false otherwise - */ bool Adafruit_BME280::begin (uint8_t addr) { - if (!i2c_dev->begin()) { - return false; - } - return init(); + if (!i2c_dev->begin(addr)) { + return false; + } + return init(); } -/*! - * @brief Initialise sensor with given parameters / settings - * @returns true on success, false otherwise - */ bool Adafruit_BME280::init() { - // check if sensor, i.e. the chip ID is correct - _sensorID = read8(BME280_REGISTER_CHIPID); - if (_sensorID != 0x60) - return false; - - // reset the device using soft-reset - // this makes sure the IIR is off, etc. - write8(BME280_REGISTER_SOFTRESET, 0xB6); - - // wait for chip to wake up. - _delay_ms(10); - - // if chip is still reading calibration, delay - while (isReadingCalibration()) - _delay_ms(10); - - readCoefficients(); // read trimming parameters, see DS 4.2.2 - - setSampling(); // use defaults - - _delay_ms(100); - - return true; + _sensorID = read8(BME280_REGISTER_CHIPID); + if (_sensorID != 0x60) { + return false; + } + write8(BME280_REGISTER_SOFTRESET, 0xB6); + _delay_ms(10); // wait for chip to wake up. + + // if chip is still reading calibration, delay + while (isReadingCalibration()) { + _delay_ms(10); + } + + readCoefficients(); // read trimming parameters, see DS 4.2.2 + setSampling(); // use defaults + _delay_ms(100); + + return true; } /*! @@ -119,11 +56,11 @@ bool Adafruit_BME280::init() { * @param duration the standby duration to use */ void Adafruit_BME280::setSampling(sensor_mode mode, - sensor_sampling tempSampling, - sensor_sampling pressSampling, - sensor_sampling humSampling, - sensor_filter filter, - standby_duration duration) { + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration) { _measReg.mode = mode; _measReg.osrs_t = tempSampling; _measReg.osrs_p = pressSampling; @@ -154,8 +91,8 @@ void Adafruit_BME280::write8(byte reg, byte value) { byte buffer[2]; buffer[1] = value; if (i2c_dev) { - buffer[0] = reg; - i2c_dev->write(buffer, 2); + buffer[0] = reg; + i2c_dev->write(buffer, 2); } } @@ -167,8 +104,8 @@ void Adafruit_BME280::write8(byte reg, byte value) { uint8_t Adafruit_BME280::read8(byte reg) { uint8_t buffer[1]; if (i2c_dev) { - buffer[0] = uint8_t(reg); - i2c_dev->write_then_read(buffer, 1, buffer, 1); + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 1); } return buffer[0]; } @@ -182,8 +119,8 @@ uint16_t Adafruit_BME280::read16(byte reg) { uint8_t buffer[2]; if (i2c_dev) { - buffer[0] = uint8_t(reg); - i2c_dev->write_then_read(buffer, 1, buffer, 2); + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 2); } return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]); } @@ -223,16 +160,16 @@ uint32_t Adafruit_BME280::read24(byte reg) { uint8_t buffer[3]; if (i2c_dev) { - buffer[0] = uint8_t(reg); - i2c_dev->write_then_read(buffer, 1, buffer, 3); + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 3); } return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 | - uint32_t(buffer[2]); + uint32_t(buffer[2]); } /*! * @brief Take a new measurement (only possible in forced mode) - @returns true in case of success else false + @returns true in case of success else false */ bool Adafruit_BME280::takeForcedMeasurement(void) { bool return_value = false; @@ -241,21 +178,21 @@ bool Adafruit_BME280::takeForcedMeasurement(void) { // it will take the next measurement and then return to sleep again. // In normal mode simply does new measurements periodically. if (_measReg.mode == MODE_FORCED) { - return_value = true; - // set to forced mode, i.e. "take next measurement" - write8(BME280_REGISTER_CONTROL, _measReg.get()); - // Store current time to measure the timeout - uint32_t timeout_start = millis(); - // wait until measurement has been completed, otherwise we would read the - // the values from the last measurement or the timeout occurred after 2 sec. - while (read8(BME280_REGISTER_STATUS) & 0x08) { - // In case of a timeout, stop the while loop - if ((millis() - timeout_start) > 2000) { - return_value = false; - break; - } - _delay_ms(1); - } + return_value = true; + // set to forced mode, i.e. "take next measurement" + write8(BME280_REGISTER_CONTROL, _measReg.get()); + // Store current time to measure the timeout + uint32_t timeout_start = millis(); + // wait until measurement has been completed, otherwise we would read the + // the values from the last measurement or the timeout occurred after 2 sec. + while (read8(BME280_REGISTER_STATUS) & 0x08) { + // In case of a timeout, stop the while loop + if ((millis() - timeout_start) > 2000) { + return_value = false; + break; + } + _delay_ms(1); + } } return return_value; } @@ -282,9 +219,9 @@ void Adafruit_BME280::readCoefficients(void) { _bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2); _bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3); _bme280_calib.dig_H4 = ((int8_t)read8(BME280_REGISTER_DIG_H4) << 4) | - (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); + (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); _bme280_calib.dig_H5 = ((int8_t)read8(BME280_REGISTER_DIG_H5 + 1) << 4) | - (read8(BME280_REGISTER_DIG_H5) >> 4); + (read8(BME280_REGISTER_DIG_H5) >> 4); _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); } @@ -307,7 +244,7 @@ float Adafruit_BME280::readTemperature(void) { int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); if (adc_T == 0x800000) // value in case temp measurement was disabled - return NAN; + return NAN; adc_T >>= 4; var1 = (int32_t)((adc_T / 8) - ((int32_t)_bme280_calib.dig_T1 * 2)); @@ -333,7 +270,7 @@ float Adafruit_BME280::readPressure(void) { int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); if (adc_P == 0x800000) // value in case pressure measurement was disabled - return NAN; + return NAN; adc_P >>= 4; var1 = ((int64_t)t_fine) - 128000; @@ -341,18 +278,18 @@ float Adafruit_BME280::readPressure(void) { var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) * 131072); var2 = var2 + (((int64_t)_bme280_calib.dig_P4) * 34359738368); var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) / 256) + - ((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096)); + ((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096)); var3 = ((int64_t)1) * 140737488355328; var1 = (var3 + var1) * ((int64_t)_bme280_calib.dig_P1) / 8589934592; if (var1 == 0) { - return 0; // avoid exception caused by division by zero + return 0; // avoid exception caused by division by zero } var4 = 1048576 - adc_P; var4 = (((var4 * 2147483648UL) - var2) * 3125) / var1; var1 = (((int64_t)_bme280_calib.dig_P9) * (var4 / 8192) * (var4 / 8192)) / - 33554432; + 33554432; var2 = (((int64_t)_bme280_calib.dig_P8) * var4) / 524288; var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_bme280_calib.dig_P7) * 16); @@ -372,7 +309,7 @@ float Adafruit_BME280::readHumidity(void) { int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); if (adc_H == 0x8000) // value in case humidity measurement was disabled - return NAN; + return NAN; var1 = t_fine - ((int32_t)76800); var2 = (int32_t)(adc_H * 16384); @@ -456,7 +393,7 @@ void Adafruit_BME280::setTemperatureCompensation(float adjustment) { /**************************************************************************/ /*! - @brief Gets the sensor_t data for the BME280's temperature sensor + @brief Gets the sensor_t data for the BME280's temperature sensor */ /**************************************************************************/ void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) { @@ -477,9 +414,9 @@ void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) { /**************************************************************************/ /*! - @brief Gets the temperature as a standard sensor event - @param event Sensor event object that will be populated - @returns True + @brief Gets the temperature as a standard sensor event + @param event Sensor event object that will be populated + @returns True */ /**************************************************************************/ bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) { @@ -496,7 +433,7 @@ bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) { /**************************************************************************/ /*! - @brief Gets the sensor_t data for the BME280's pressure sensor + @brief Gets the sensor_t data for the BME280's pressure sensor */ /**************************************************************************/ void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) { @@ -517,9 +454,9 @@ void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) { /**************************************************************************/ /*! - @brief Gets the pressure as a standard sensor event - @param event Sensor event object that will be populated - @returns True + @brief Gets the pressure as a standard sensor event + @param event Sensor event object that will be populated + @returns True */ /**************************************************************************/ bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) { @@ -536,7 +473,7 @@ bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) { /**************************************************************************/ /*! - @brief Gets the sensor_t data for the BME280's humidity sensor + @brief Gets the sensor_t data for the BME280's humidity sensor */ /**************************************************************************/ void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) { @@ -557,9 +494,9 @@ void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) { /**************************************************************************/ /*! - @brief Gets the humidity as a standard sensor event - @param event Sensor event object that will be populated - @returns True + @brief Gets the humidity as a standard sensor event + @param event Sensor event object that will be populated + @returns True */ /**************************************************************************/ bool Adafruit_BME280_Humidity::getEvent(sensors_event_t *event) { diff --git a/software/test_2024-07-23/src/adafruit/bme280.h b/software/test_2024-07-23/src/adafruit/bme280.h index dd59f79..94c3927 100644 --- a/software/test_2024-07-23/src/adafruit/bme280.h +++ b/software/test_2024-07-23/src/adafruit/bme280.h @@ -30,9 +30,14 @@ // #include +#include "../i2cdevice.hpp" +#include "../main.hpp" +#define byte uint8_t + + + #include #include -#include "arduino.h" #include "sensor.h" /*! @@ -241,8 +246,8 @@ public: void setTemperatureCompensation(float); protected: - Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface - Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface + I2cDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface + // Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface Adafruit_BME280_Temp *temp_sensor; Adafruit_BME280_Pressure *pressure_sensor; diff --git a/software/test_2024-07-23/src/adafruit/ens160.cpp b/software/test_2024-07-23/src/adafruit/ens160.cpp new file mode 100644 index 0000000..85b98fa --- /dev/null +++ b/software/test_2024-07-23/src/adafruit/ens160.cpp @@ -0,0 +1,365 @@ +/* + ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense + 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release + 2021 Nov 25 v5 Martin Herold Custom mode timing fixed + 2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#include "ens160.h" +#include "math.h" +#include + +ScioSense_ENS160::ScioSense_ENS160 () { + _revENS16x = 0; + + //Isotherm, HP0 252°C / HP1 350°C / HP2 250°C / HP3 324°C / measure every 1008ms + _seq_steps[0][0] = 0x7c; + _seq_steps[0][1] = 0x0a; + _seq_steps[0][2] = 0x7e; + _seq_steps[0][3] = 0xaf; + _seq_steps[0][4] = 0xaf; + _seq_steps[0][5] = 0xa2; + _seq_steps[0][6] = 0x00; + _seq_steps[0][7] = 0x80; +} + +bool ScioSense_ENS160::begin () { + i2cDevice.begin(ENS160_I2CADDR_1); + _delay_ms(ENS160_BOOTING); + + if (reset()) { + if (checkPartID()) { + if (setMode(ENS160_OPMODE_IDLE)) { + if (clearCommand()) { + if (getFirmware()) { + return true; + } + } + } + } + } + return false; + +} + +bool ScioSense_ENS160::write8 (byte reg, byte value) { + byte buffer[2]; + buffer[1] = value; + buffer[0] = reg; + return i2cDevice.write(buffer, 2); +} + +bool ScioSense_ENS160::read8 (byte reg, byte *value) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, value, 1); +} + +bool ScioSense_ENS160::read16 (byte reg, uint16_t *value) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, (uint8_t *)value, 2); +} + +bool ScioSense_ENS160::read16LE (byte reg, uint16_t *value) { + uint16_t tmp; + if (read16(reg, &tmp)) { + *value = ((tmp & 0xff) << 8) | (tmp >> 8); + return true; + } + return false; +} + +bool ScioSense_ENS160::readBytes (byte reg, uint8_t *bytes, uint8_t len) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, buffer, len); +} + + +// Sends a reset to the ENS160. Returns false on I2C problems. +bool ScioSense_ENS160::reset () { + if (write8(ENS160_REG_OPMODE, ENS160_OPMODE_RESET)) { + _delay_ms(ENS160_BOOTING); + return true; + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Reads the part ID and confirms valid sensor +bool ScioSense_ENS160::checkPartID () { + uint8_t i2cbuf[2]; + uint16_t part_id; + + read16(ENS160_REG_PART_ID, &part_id); + part_id = i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8); + + _delay_ms(ENS160_BOOTING); + + if (part_id == ENS160_PARTID) { + _revENS16x = 0; + return true; + + } else if (part_id == ENS161_PARTID) { + _revENS16x = 1; + return true; + } + + return false; +} + +// Initialize idle mode and confirms +bool ScioSense_ENS160::clearCommand () { + uint8_t status; + + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_NOP)) { + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR)) { + _delay_ms(ENS160_BOOTING); + if (read8(ENS160_REG_DATA_STATUS, &status)) { + return true; + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Read firmware revisions +bool ScioSense_ENS160::getFirmware () { + uint8_t i2cbuf[3]; + + if (clearCommand()) { + _delay_ms(ENS160_BOOTING); + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER)) { + if (readBytes(ENS160_REG_GPR_READ_4, i2cbuf, 3)) { + _fw_ver_major = i2cbuf[0]; + _fw_ver_minor = i2cbuf[1]; + _fw_ver_build = i2cbuf[2]; + _revENS16x = this->_fw_ver_major > 6 ? 1 : 0; + _delay_ms(ENS160_BOOTING); + return true; + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Set operation mode of sensor +bool ScioSense_ENS160::setMode (uint8_t mode) { + //LP only valid for rev>0 + if ((mode == ENS160_OPMODE_LP) and (_revENS16x == 0)) { + return false; + } + if (write8(ENS160_REG_OPMODE, mode)) { + _delay_ms(ENS160_BOOTING); + return true; + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Initialize definition of custom mode with steps +bool ScioSense_ENS160::initCustomMode (uint16_t stepNum) { + if (stepNum > 0) { + _stepCount = stepNum; + if (setMode(ENS160_OPMODE_IDLE)) { + if (clearCommand()) { + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_SETSEQ)) { + _delay_ms(ENS160_BOOTING); + return true; + } + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate +bool ScioSense_ENS160::addCustomStep (uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3) { + uint8_t seq_ack; + uint8_t temp; + + _delay_ms(ENS160_BOOTING); + + temp = (uint8_t)(((time / 24) - 1) << 6); + if (measureHP0) { + temp = temp | 0x20; + } + if (measureHP1) { + temp = temp | 0x10; + } + if (measureHP2) { + temp = temp | 0x08; + } + if (measureHP3) { + temp = temp | 0x04; + } + if (!write8(ENS160_REG_GPR_WRITE_0, temp)) { + return false; + } + temp = (uint8_t)(((time / 24) - 1) >> 2); + if (!write8(ENS160_REG_GPR_WRITE_1, temp)) { + return false; + } + if (!write8(ENS160_REG_GPR_WRITE_2, (uint8_t)(tempHP0 / 2))) { + return false; + } + if (!write8(ENS160_REG_GPR_WRITE_3, (uint8_t)(tempHP1 / 2))) { + return false; + } + if (write8(ENS160_REG_GPR_WRITE_4, (uint8_t)(tempHP2 / 2))) { + return false; + } + if (write8(ENS160_REG_GPR_WRITE_5, (uint8_t)(tempHP3 / 2))) { + return false; + } + + if (write8(ENS160_REG_GPR_WRITE_6, (uint8_t)(_stepCount - 1))) { + return false; + } + + if (_stepCount == 1) { + if (!write8(ENS160_REG_GPR_WRITE_7, 128)) { + return false; + } + } else { + if (!write8(ENS160_REG_GPR_WRITE_7, 0)) { + return false; + } + } + _delay_ms(ENS160_BOOTING); + + if (!read8(ENS160_REG_GPR_READ_7, &seq_ack)) { + return false; + } + _delay_ms(ENS160_BOOTING); + + if ((ENS160_SEQ_ACK_COMPLETE | _stepCount) != seq_ack) { + _stepCount++; + return false; + } + + return true; +} + +// Perform prediction measurement and stores result in internal variables +bool ScioSense_ENS160::measure (bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + + // Set default status for early bail out + if (waitForNew) { + do { + _delay_ms(1); + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } while (!IS_NEWDAT(status)); + } else { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } + + // Read predictions + if (IS_NEWDAT(status)) { + if (!readBytes(ENS160_REG_DATA_AQI, i2cbuf, 7)) { + return false; + } + _data_aqi = i2cbuf[0]; + _data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8); + _data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8); + if (_revENS16x > 0) { + _data_aqi500 = ((uint16_t)i2cbuf[5]) | ((uint16_t)i2cbuf[6] << 8); + } else { + _data_aqi500 = 0; + } + return true; + } + + return false; +} + +// Perfrom raw measurement and stores result in internal variables +bool ScioSense_ENS160::measureRaw (bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + + // Set default status for early bail out + if (waitForNew) { + do { + _delay_ms(1); + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } while (!IS_NEWGPR(status)); + } else { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } + + if (IS_NEWGPR(status)) { + + // Read raw resistance values + if (!readBytes(ENS160_REG_GPR_READ_0, i2cbuf, 8)) { + return false; + } + _hp0_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + // Read baselines + if (!readBytes(ENS160_REG_DATA_BL, i2cbuf, 8)) { + return false; + } + _hp0_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + if (!read8(ENS160_REG_DATA_MISR, i2cbuf)) { + return false; + } + _misr = i2cbuf[0]; + return true; + } + + return false; +} + + +// Writes t (degC) and h (%rh) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS160::set_envdata (float t, float h) { + uint16_t t_data = (uint16_t)((t + 273.15f) * 64.0f); + uint16_t rh_data = (uint16_t)(h * 512.0f); + return this->set_envdata210(t_data, rh_data); +} + +// Writes t and h (in ENS210 format) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS160::set_envdata210 (uint16_t t, uint16_t h) { + //uint16_t temp; + uint8_t trh_in[4]; + + //temp = (uint16_t)((t + 273.15f) * 64.0f); + trh_in[0] = t & 0xff; + trh_in[1] = (t >> 8) & 0xff; + + //temp = (uint16_t)(h * 512.0f); + trh_in[2] = h & 0xff; + trh_in[3] = (h >> 8) & 0xff; + + if (!i2cDevice.writeByteAndBuffer(ENS160_REG_TEMP_IN, trh_in, 4)) { + return false; + } + + return true; +} diff --git a/software/test_2024-07-23/src/adafruit/ens160.h b/software/test_2024-07-23/src/adafruit/ens160.h new file mode 100644 index 0000000..e3ecdcf --- /dev/null +++ b/software/test_2024-07-23/src/adafruit/ens160.h @@ -0,0 +1,180 @@ +/* + ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense + 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release + 2021 July 29 v4 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#ifndef __SCIOSENSE_ENS160_H_ +#define __SCIOSENSE_ENS160_H_ + +#include "../i2cdevice.hpp" +#include +#define byte uint8_t + +// #if (ARDUINO >= 100) +// #include "Arduino.h" +// #else +// #include "WProgram.h" +// #endif + +// #include + +// Chip constants +#define ENS160_PARTID 0x0160 +#define ENS161_PARTID 0x0161 +#define ENS160_BOOTING 10 + +// 7-bit I2C slave address of the ENS160 +#define ENS160_I2CADDR_0 0x52 //ADDR low +#define ENS160_I2CADDR_1 0x53 //ADDR high + +// ENS160 registers for version V0 +#define ENS160_REG_PART_ID 0x00 // 2 byte register +#define ENS160_REG_OPMODE 0x10 +#define ENS160_REG_CONFIG 0x11 +#define ENS160_REG_COMMAND 0x12 +#define ENS160_REG_TEMP_IN 0x13 +#define ENS160_REG_RH_IN 0x15 +#define ENS160_REG_DATA_STATUS 0x20 +#define ENS160_REG_DATA_AQI 0x21 +#define ENS160_REG_DATA_TVOC 0x22 +#define ENS160_REG_DATA_ECO2 0x24 +#define ENS160_REG_DATA_BL 0x28 +#define ENS160_REG_DATA_T 0x30 +#define ENS160_REG_DATA_RH 0x32 +#define ENS160_REG_DATA_MISR 0x38 +#define ENS160_REG_GPR_WRITE_0 0x40 +#define ENS160_REG_GPR_WRITE_1 ENS160_REG_GPR_WRITE_0 + 1 +#define ENS160_REG_GPR_WRITE_2 ENS160_REG_GPR_WRITE_0 + 2 +#define ENS160_REG_GPR_WRITE_3 ENS160_REG_GPR_WRITE_0 + 3 +#define ENS160_REG_GPR_WRITE_4 ENS160_REG_GPR_WRITE_0 + 4 +#define ENS160_REG_GPR_WRITE_5 ENS160_REG_GPR_WRITE_0 + 5 +#define ENS160_REG_GPR_WRITE_6 ENS160_REG_GPR_WRITE_0 + 6 +#define ENS160_REG_GPR_WRITE_7 ENS160_REG_GPR_WRITE_0 + 7 +#define ENS160_REG_GPR_READ_0 0x48 +#define ENS160_REG_GPR_READ_4 ENS160_REG_GPR_READ_0 + 4 +#define ENS160_REG_GPR_READ_6 ENS160_REG_GPR_READ_0 + 6 +#define ENS160_REG_GPR_READ_7 ENS160_REG_GPR_READ_0 + 7 + +//ENS160 data register fields +#define ENS160_COMMAND_NOP 0x00 +#define ENS160_COMMAND_CLRGPR 0xCC +#define ENS160_COMMAND_GET_APPVER 0x0E +#define ENS160_COMMAND_SETTH 0x02 +#define ENS160_COMMAND_SETSEQ 0xC2 + +#define ENS160_OPMODE_RESET 0xF0 +#define ENS160_OPMODE_DEP_SLEEP 0x00 +#define ENS160_OPMODE_IDLE 0x01 +#define ENS160_OPMODE_STD 0x02 +#define ENS160_OPMODE_LP 0x03 +#define ENS160_OPMODE_CUSTOM 0xC0 + +#define ENS160_BL_CMD_START 0x02 +#define ENS160_BL_CMD_ERASE_APP 0x04 +#define ENS160_BL_CMD_ERASE_BLINE 0x06 +#define ENS160_BL_CMD_WRITE 0x08 +#define ENS160_BL_CMD_VERIFY 0x0A +#define ENS160_BL_CMD_GET_BLVER 0x0C +#define ENS160_BL_CMD_GET_APPVER 0x0E +#define ENS160_BL_CMD_EXITBL 0x12 + +#define ENS160_SEQ_ACK_NOTCOMPLETE 0x80 +#define ENS160_SEQ_ACK_COMPLETE 0xC0 + +#define IS_ENS160_SEQ_ACK_NOT_COMPLETE(x) (ENS160_SEQ_ACK_NOTCOMPLETE == (ENS160_SEQ_ACK_NOTCOMPLETE & (x))) +#define IS_ENS160_SEQ_ACK_COMPLETE(x) (ENS160_SEQ_ACK_COMPLETE == (ENS160_SEQ_ACK_COMPLETE & (x))) + +#define ENS160_DATA_STATUS_NEWDAT 0x02 +#define ENS160_DATA_STATUS_NEWGPR 0x01 + +#define IS_NEWDAT(x) (ENS160_DATA_STATUS_NEWDAT == (ENS160_DATA_STATUS_NEWDAT & (x))) +#define IS_NEWGPR(x) (ENS160_DATA_STATUS_NEWGPR == (ENS160_DATA_STATUS_NEWGPR & (x))) +#define IS_NEW_DATA_AVAILABLE(x) (0 != ((ENS160_DATA_STATUS_NEWDAT | ENS160_DATA_STATUS_NEWGPR ) & (x))) + +#define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11)) +#define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048)) + +class ScioSense_ENS160 { + + public: + ScioSense_ENS160(); + + void setI2C(uint8_t sda, uint8_t scl); // Function to redefine I2C pins + + bool begin(); // Init I2C communication, resets ENS160 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. + uint8_t revENS16x() { return this->_revENS16x; } // Report version of sensor (0: ENS160, 1: ENS161) + bool setMode(uint8_t mode); // Set operation mode of sensor + + bool initCustomMode(uint16_t stepNum); // Initialize definition of custom mode with steps + bool addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3); + // Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate + + bool measure(bool waitForNew = true); // Perform measurement and stores result in internal variables + bool measureRaw(bool waitForNew = true); // Perform raw measurement and stores result in internal variables + bool set_envdata(float t, float h); // Writes t (degC) and h (%rh) to ENV_DATA. Returns "0" if I2C transmission is successful + bool set_envdata210(uint16_t t, uint16_t h); // Writes t and h (in ENS210 format) to ENV_DATA. Returns "0" if I2C transmission is successful + uint8_t getMajorRev() { return this->_fw_ver_major; } // Get major revision number of used firmware + uint8_t getMinorRev() { return this->_fw_ver_minor; } // Get minor revision number of used firmware + uint8_t getBuild() { return this->_fw_ver_build; } // Get build revision number of used firmware + + uint8_t getAQI() { return this->_data_aqi; } // Get AQI value of last measurement + uint16_t getTVOC() { return this->_data_tvoc; } // Get TVOC value of last measurement + uint16_t geteCO2() { return this->_data_eco2; } // Get eCO2 value of last measurement + uint16_t getAQI500() { return this->_data_aqi500; } // Get AQI500 value of last measurement + uint32_t getHP0() { return this->_hp0_rs; } // Get resistance of HP0 of last measurement + uint32_t getHP1() { return this->_hp1_rs; } // Get resistance of HP1 of last measurement + uint32_t getHP2() { return this->_hp2_rs; } // Get resistance of HP2 of last measurement + uint32_t getHP3() { return this->_hp3_rs; } // Get resistance of HP3 of last measurement + uint32_t getHP0BL() { return this->_hp0_bl; } // Get baseline resistance of HP0 of last measurement + uint32_t getHP1BL() { return this->_hp1_bl; } // Get baseline resistance of HP1 of last measurement + uint32_t getHP2BL() { return this->_hp2_bl; } // Get baseline resistance of HP2 of last measurement + uint32_t getHP3BL() { return this->_hp3_bl; } // Get baseline resistance of HP3 of last measurement + uint8_t getMISR() { return this->_misr; } // Return status code of sensor + + private: + I2cDevice i2cDevice; + bool reset(); // Sends a reset to the ENS160. Returns false on I2C problems. + bool checkPartID(); // Reads the part ID and confirms valid sensor + bool clearCommand(); // Initialize idle mode and confirms + bool getFirmware(); // Read firmware revisions + + uint8_t _revENS16x; // ENS160 or ENS161 connected? (FW >7) + + uint8_t _fw_ver_major; + uint8_t _fw_ver_minor; + uint8_t _fw_ver_build; + + uint16_t _stepCount; // Counter for custom sequence + + uint8_t _data_aqi; + uint16_t _data_tvoc; + uint16_t _data_eco2; + uint16_t _data_aqi500; + uint32_t _hp0_rs; + uint32_t _hp0_bl; + uint32_t _hp1_rs; + uint32_t _hp1_bl; + uint32_t _hp2_rs; + uint32_t _hp2_bl; + uint32_t _hp3_rs; + uint32_t _hp3_bl; + uint16_t _temp; + int _slaveaddr; // Slave address of the ENS160 + uint8_t _misr; + + uint8_t _seq_steps[1][8]; + + bool write8(byte reg, byte value); + bool read8 (byte reg, byte *value); + bool read16 (byte reg, uint16_t *value); + bool read16LE (byte reg, uint16_t *value); + bool readBytes (byte reg, uint8_t *bytes, uint8_t len); +}; + + +#endif diff --git a/software/test_2024-07-23/src/adafruit/sensor.cpp b/software/test_2024-07-23/src/adafruit/sensor.cpp deleted file mode 100644 index c180fd1..0000000 --- a/software/test_2024-07-23/src/adafruit/sensor.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// https://github.com/adafruit/Adafruit_Sensor - -// #include "Adafruit_Sensor.h" -#include "sensor.h" - -/**************************************************************************/ -/*! - @brief Prints sensor information to serial console -*/ -/**************************************************************************/ -void Adafruit_Sensor::printSensorDetails(void) { -// sensor_t sensor; -// getSensor(&sensor); -// Serial.println(F("------------------------------------")); -// Serial.print(F("Sensor: ")); -// Serial.println(sensor.name); -// Serial.print(F("Type: ")); -// switch ((sensors_type_t)sensor.type) { -// case SENSOR_TYPE_ACCELEROMETER: -// Serial.print(F("Acceleration (m/s2)")); -// break; -// case SENSOR_TYPE_MAGNETIC_FIELD: -// Serial.print(F("Magnetic (uT)")); -// break; -// case SENSOR_TYPE_ORIENTATION: -// Serial.print(F("Orientation (degrees)")); -// break; -// case SENSOR_TYPE_GYROSCOPE: -// Serial.print(F("Gyroscopic (rad/s)")); -// break; -// case SENSOR_TYPE_LIGHT: -// Serial.print(F("Light (lux)")); -// break; -// case SENSOR_TYPE_PRESSURE: -// Serial.print(F("Pressure (hPa)")); -// break; -// case SENSOR_TYPE_PROXIMITY: -// Serial.print(F("Distance (cm)")); -// break; -// case SENSOR_TYPE_GRAVITY: -// Serial.print(F("Gravity (m/s2)")); -// break; -// case SENSOR_TYPE_LINEAR_ACCELERATION: -// Serial.print(F("Linear Acceleration (m/s2)")); -// break; -// case SENSOR_TYPE_ROTATION_VECTOR: -// Serial.print(F("Rotation vector")); -// break; -// case SENSOR_TYPE_RELATIVE_HUMIDITY: -// Serial.print(F("Relative Humidity (%)")); -// break; -// case SENSOR_TYPE_AMBIENT_TEMPERATURE: -// Serial.print(F("Ambient Temp (C)")); -// break; -// case SENSOR_TYPE_OBJECT_TEMPERATURE: -// Serial.print(F("Object Temp (C)")); -// break; -// case SENSOR_TYPE_VOLTAGE: -// Serial.print(F("Voltage (V)")); -// break; -// case SENSOR_TYPE_CURRENT: -// Serial.print(F("Current (mA)")); -// break; -// case SENSOR_TYPE_COLOR: -// Serial.print(F("Color (RGBA)")); -// break; -// case SENSOR_TYPE_TVOC: -// Serial.print(F("Total Volatile Organic Compounds (ppb)")); -// break; -// case SENSOR_TYPE_VOC_INDEX: -// Serial.print(F("Volatile Organic Compounds (Index)")); -// break; -// case SENSOR_TYPE_NOX_INDEX: -// Serial.print(F("Nitrogen Oxides (Index)")); -// break; -// case SENSOR_TYPE_CO2: -// Serial.print(F("Carbon Dioxide (ppm)")); -// break; -// case SENSOR_TYPE_ECO2: -// Serial.print(F("Equivalent/estimated CO2 (ppm)")); -// break; -// case SENSOR_TYPE_PM10_STD: -// Serial.print(F("Standard Particulate Matter 1.0 (ppm)")); -// break; -// case SENSOR_TYPE_PM25_STD: -// Serial.print(F("Standard Particulate Matter 2.5 (ppm)")); -// break; -// case SENSOR_TYPE_PM100_STD: -// Serial.print(F("Standard Particulate Matter 10.0 (ppm)")); -// break; -// case SENSOR_TYPE_PM10_ENV: -// Serial.print(F("Environmental Particulate Matter 1.0 (ppm)")); -// break; -// case SENSOR_TYPE_PM25_ENV: -// Serial.print(F("Environmental Particulate Matter 2.5 (ppm)")); -// break; -// case SENSOR_TYPE_PM100_ENV: -// Serial.print(F("Environmental Particulate Matter 10.0 (ppm)")); -// break; -// case SENSOR_TYPE_GAS_RESISTANCE: -// Serial.print(F("Gas Resistance (ohms)")); -// break; -// case SENSOR_TYPE_UNITLESS_PERCENT: -// Serial.print(F("Unitless Percent (%)")); -// break; -// case SENSOR_TYPE_ALTITUDE: -// Serial.print(F("Altitude (m)")); -// break; -// } - -// Serial.println(); -// Serial.print(F("Driver Ver: ")); -// Serial.println(sensor.version); -// Serial.print(F("Unique ID: ")); -// Serial.println(sensor.sensor_id); -// Serial.print(F("Min Value: ")); -// Serial.println(sensor.min_value); -// Serial.print(F("Max Value: ")); -// Serial.println(sensor.max_value); -// Serial.print(F("Resolution: ")); -// Serial.println(sensor.resolution); -// Serial.println(F("------------------------------------\n")); -} diff --git a/software/test_2024-07-23/src/adafruit/sensor.h b/software/test_2024-07-23/src/adafruit/sensor.h index 72cf981..ac7e454 100644 --- a/software/test_2024-07-23/src/adafruit/sensor.h +++ b/software/test_2024-07-23/src/adafruit/sensor.h @@ -1,5 +1,3 @@ -// https://github.com/adafruit/Adafruit_Sensor - /* * Copyright (C) 2008 The Android Open Source Project * @@ -203,23 +201,24 @@ class Adafruit_Sensor { public: // Constructor(s) Adafruit_Sensor() {} +// virtual ~Adafruit_Sensor() {} - // These must be defined by the subclass +// // These must be defined by the subclass - /*! @brief Whether we should automatically change the range (if possible) for - higher precision - @param enabled True if we will try to autorange */ - virtual void enableAutoRange(bool enabled) { - (void)enabled; /* suppress unused warning */ - }; +// /*! @brief Whether we should automatically change the range (if possible) for +// higher precision +// @param enabled True if we will try to autorange */ +// virtual void enableAutoRange(bool enabled) { +// (void)enabled; /* suppress unused warning */ +// }; - /*! @brief Get the latest sensor event - @returns True if able to fetch an event */ - virtual bool getEvent(sensors_event_t *) = 0; - /*! @brief Get info about the sensor itself */ - virtual void getSensor(sensor_t *) = 0; +// /*! @brief Get the latest sensor event +// @returns True if able to fetch an event */ +// virtual bool getEvent(sensors_event_t *) = 0; +// /*! @brief Get info about the sensor itself */ +// virtual void getSensor(sensor_t *) = 0; - void printSensorDetails(void); +// void printSensorDetails(void); }; #endif diff --git a/software/test_2024-07-23/src/i2cdevice.cpp b/software/test_2024-07-23/src/i2cdevice.cpp new file mode 100644 index 0000000..47be4af --- /dev/null +++ b/software/test_2024-07-23/src/i2cdevice.cpp @@ -0,0 +1,117 @@ +#include +#include + +#include "i2cdevice.hpp" + +I2cDevice i2cDevice; + +I2cDevice::I2cDevice () { + address = 0; +} + +bool I2cDevice::begin (uint8_t addr) { + this->address = addr; + // TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + return true; +} + +void I2cDevice::end () { + TWCR = (1 << TWEN); + TWBR = 0; +} + +bool I2cDevice::write (const uint8_t *buffer, uint8_t len) { + if (start(false)) { + if (writeBytes(buffer, len)) { + if (stop()) { + return true; + } + } + } + return false; +} + +bool I2cDevice::write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len) { + if (start(false)) { + if (writeBytes(write_buffer, write_len)) { + if (start(true)) { + if (readBytes(read_buffer, read_len)) { + if (stop()) { + return true; + } + } + } + } + } + return false; +} + +bool I2cDevice::readBytes (uint8_t *buffer, uint8_t len) { + while (len-- > 0) { + if (len > 0) { + TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled + } else { + TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled + } + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + uint8_t sr = TWSR & 0xf8; + if ((len > 0 && sr != 0x50) || (len == 0 && sr != 0x58)) { + return false; + } + *buffer++ = TWDR; + } + return true; +} + +bool I2cDevice::writeBytes (const uint8_t *buffer, uint8_t len) { + while (len-- > 0) { + // printf("[wB:len=%d, byte=%02x]", len + 1, *buffer); + TWDR = *buffer++; + TWCR = (1 << TWINT) | (1 << TWEN); // send data byte + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + //printf("TWSR=%02x", TWSR); + if ((TWSR & 0xf8) != 0x28) { + return false; + } + } + return true; +} + +bool I2cDevice::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len) { + do { + TWDR = byte; + TWCR = (1 << TWINT) | (1 << TWEN); // send byte + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + if ((TWSR & 0xf8) != 0x28) { + return false; + } + byte = *buffer++; + } while (len-- > 0); + return true; +} + +bool I2cDevice::start (bool read) { + TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + uint8_t sr = TWSR & 0xf8; + if (sr != 0x08 && sr != 0x10) { + return false; + } + TWDR = (address << 1) | (read ? 1 : 0); // address + R/nW + TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + sr = TWSR & 0xf8; + if ((!read && sr != 0x18) || (read && sr != 0x40)) { + return false; + } + return true; +} + +bool I2cDevice::stop () { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + while (TWCR & ( 1 << TWSTO)); + return true; +} + diff --git a/software/test_2024-07-23/src/i2cdevice.hpp b/software/test_2024-07-23/src/i2cdevice.hpp new file mode 100644 index 0000000..e59d737 --- /dev/null +++ b/software/test_2024-07-23/src/i2cdevice.hpp @@ -0,0 +1,27 @@ +#ifndef I2C_DEVICE +#define I2C_DEVICE + +#include + +class I2cDevice { + public: + static void end (); + + public: + I2cDevice (); + bool begin (uint8_t addr); + bool write(const uint8_t *buffer, uint8_t len); + bool write_then_read(const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len); + bool writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len); + + private: + uint8_t address; + bool start (bool read); + bool stop (); + bool writeBytes (const uint8_t *buffer, uint8_t len); + bool readBytes (uint8_t *buffer, uint8_t len); +}; + +extern I2cDevice i2cDevice; + +#endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/main.cpp b/software/test_2024-07-23/src/main.cpp index 1079eb0..d64b6e0 100644 --- a/software/test_2024-07-23/src/main.cpp +++ b/software/test_2024-07-23/src/main.cpp @@ -25,6 +25,15 @@ extern "C" { void __cxa_pure_virtual () { } + int __cxa_guard_acquire(uint8_t *g) { + return 0; + } + + void __cxa_guard_release(uint8_t *g) {} + + void __cxa_guard_abort(uint8_t *g) {} + + int uart_putchar(char c, FILE *stream) { if (c == '\n') { uart_putchar('\r', stream); diff --git a/software/test_2024-07-23/src/main.hpp b/software/test_2024-07-23/src/main.hpp index 4490ff3..de2c1e1 100644 --- a/software/test_2024-07-23/src/main.hpp +++ b/software/test_2024-07-23/src/main.hpp @@ -7,7 +7,6 @@ #define CTRLC '\003' extern int wait (uint32_t ms); -extern int waitOnKey (char key); extern uint64_t millis (); class TestUnit { diff --git a/software/test_2024-07-23/src/units/i2c.cpp b/software/test_2024-07-23/src/units/i2c.cpp index 9858aa1..df1fe75 100644 --- a/software/test_2024-07-23/src/units/i2c.cpp +++ b/software/test_2024-07-23/src/units/i2c.cpp @@ -3,6 +3,7 @@ #include #include "i2c.hpp" +#include "../i2cdevice.hpp" #include "../main.hpp" @@ -37,6 +38,28 @@ int8_t I2c::run (uint8_t subtest) { printf("init"); } else if (subtest == 1 && mode == SparkFunEnvCombo) { + printf(" BM280 ... "); + if (!bm280.begin()) { + printf("ERROR"); + return -1; + } + printf("OK, ENS160 ... "); + if (!ens160.begin()) { + printf("ERROR"); + return -1; + } + printf("OK"); + + do { + float p = bm280.readPressure(); + printf("\n => pressure: %.3fhPa", (double)p); + float t = bm280.readTemperature(); + printf(", temp: %.2f°C", (double)t); + float h = bm280.readHumidity(); + printf(", humidity: %.2f%%", (double)h); + } while (wait(1000) == EOF); + + } else if (subtest == 1) { int key = EOF; uint8_t buffer[18]; int errorCode; @@ -92,10 +115,10 @@ int8_t I2c::run (uint8_t subtest) { errorCode = errorCode != 0 ? 0x3000 | errorCode : 0; } if (errorCode == 0) { - bm280.digT[0] = ((uint16_t)buffer[1] << 8) | buffer[0]; - bm280.digT[1] = ((uint16_t)buffer[3] << 8) | buffer[2]; - bm280.digT[2] = ((uint16_t)buffer[5] << 8) | buffer[4]; - printf(" T(%04x %04x %04x)", bm280.digT[0], bm280.digT[1], bm280.digT[2]); + // bm280.digT[0] = ((uint16_t)buffer[1] << 8) | buffer[0]; + // bm280.digT[1] = ((uint16_t)buffer[3] << 8) | buffer[2]; + // bm280.digT[2] = ((uint16_t)buffer[5] << 8) | buffer[4]; + // printf(" T(%04x %04x %04x)", bm280.digT[0], bm280.digT[1], bm280.digT[2]); } else { stop(); printf("ERROR(%04x)", errorCode); @@ -169,6 +192,7 @@ int8_t I2c::run (uint8_t subtest) { } while (wait(5000) == EOF); } else { + I2cDevice::end(); printf("end"); return -1; } @@ -255,10 +279,11 @@ uint16_t I2c::readData (uint8_t size, uint8_t *data) { } int32_t I2c::compensateBm280T (int32_t adcT) { - int32_t var1, var2, t; - var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11; - var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14; - bm280.tFine = var1 + var2; - t = (bm280.tFine * 5 + 128) >> 8; - return t; + // int32_t var1, var2, t; + // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11; + // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14; + // bm280.tFine = var1 + var2; + // t = (bm280.tFine * 5 + 128) >> 8; + // return t; + return -1; } \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/i2c.hpp b/software/test_2024-07-23/src/units/i2c.hpp index 96a3f23..6e4a533 100644 --- a/software/test_2024-07-23/src/units/i2c.hpp +++ b/software/test_2024-07-23/src/units/i2c.hpp @@ -3,18 +3,17 @@ #include #include "../main.hpp" +#include "../adafruit/bme280.h" +#include "../adafruit/ens160.h" typedef enum I2cMode { SparkFunEnvCombo, Master, Slave } I2cMode; -typedef struct { - int32_t tFine; - uint16_t digT[3]; -} I2cBm280; class I2c : public TestUnit { private: I2cMode mode; - I2cBm280 bm280; + Adafruit_BME280 bm280; + ScioSense_ENS160 ens160; public: bool enabled; -- 2.39.5