From 4791f7b0b4144d27c60407086bf68cff27f711d0 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Fri, 2 Aug 2024 18:44:18 +0200 Subject: [PATCH] Test-Software I2C units running (not optimized) --- .../test_2024-07-23/src/adafruit/bme280.cpp | 2 +- .../test_2024-07-23/src/adafruit/bme280.h | 4 +- .../test_2024-07-23/src/adafruit/ens160.cpp | 21 +- .../test_2024-07-23/src/adafruit/ens160.h | 16 +- .../src/{i2cdevice.cpp => i2cmaster.cpp} | 90 +++--- .../src/{i2cdevice.hpp => i2cmaster.hpp} | 13 +- software/test_2024-07-23/src/i2cslave.cpp | 92 ++++++ software/test_2024-07-23/src/i2cslave.hpp | 32 +++ software/test_2024-07-23/src/main.cpp | 9 +- software/test_2024-07-23/src/units/i2c.cpp | 267 +++++++++--------- software/test_2024-07-23/src/units/i2c.hpp | 10 +- 11 files changed, 372 insertions(+), 184 deletions(-) rename software/test_2024-07-23/src/{i2cdevice.cpp => i2cmaster.cpp} (54%) rename software/test_2024-07-23/src/{i2cdevice.hpp => i2cmaster.hpp} (76%) create mode 100644 software/test_2024-07-23/src/i2cslave.cpp create mode 100644 software/test_2024-07-23/src/i2cslave.hpp diff --git a/software/test_2024-07-23/src/adafruit/bme280.cpp b/software/test_2024-07-23/src/adafruit/bme280.cpp index 6ff5bc8..95a0f49 100644 --- a/software/test_2024-07-23/src/adafruit/bme280.cpp +++ b/software/test_2024-07-23/src/adafruit/bme280.cpp @@ -8,7 +8,7 @@ Adafruit_BME280_Pressure bm280PressureSensor; Adafruit_BME280_Humidity bm280HumiditySensor; Adafruit_BME280::Adafruit_BME280() { - static I2cDevice i2cDevice; + static I2cMaster i2cDevice; t_fine_adjust = 0; temp_sensor = &bm280TempSensor; pressure_sensor = &bm280PressureSensor; diff --git a/software/test_2024-07-23/src/adafruit/bme280.h b/software/test_2024-07-23/src/adafruit/bme280.h index 94c3927..b842782 100644 --- a/software/test_2024-07-23/src/adafruit/bme280.h +++ b/software/test_2024-07-23/src/adafruit/bme280.h @@ -30,7 +30,7 @@ // #include -#include "../i2cdevice.hpp" +#include "../i2cmaster.hpp" #include "../main.hpp" #define byte uint8_t @@ -246,7 +246,7 @@ public: void setTemperatureCompensation(float); protected: - I2cDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface + I2cMaster *i2c_dev = NULL; ///< Pointer to I2C bus interface // Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface Adafruit_BME280_Temp *temp_sensor; diff --git a/software/test_2024-07-23/src/adafruit/ens160.cpp b/software/test_2024-07-23/src/adafruit/ens160.cpp index 85b98fa..ef23404 100644 --- a/software/test_2024-07-23/src/adafruit/ens160.cpp +++ b/software/test_2024-07-23/src/adafruit/ens160.cpp @@ -12,6 +12,8 @@ #include "ens160.h" #include "math.h" #include +#include +#include ScioSense_ENS160::ScioSense_ENS160 () { _revENS16x = 0; @@ -30,7 +32,6 @@ ScioSense_ENS160::ScioSense_ENS160 () { bool ScioSense_ENS160::begin () { i2cDevice.begin(ENS160_I2CADDR_1); _delay_ms(ENS160_BOOTING); - if (reset()) { if (checkPartID()) { if (setMode(ENS160_OPMODE_IDLE)) { @@ -93,12 +94,9 @@ bool ScioSense_ENS160::reset () { // 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); - + read16(ENS160_REG_PART_ID, &part_id); _delay_ms(ENS160_BOOTING); if (part_id == ENS160_PARTID) { @@ -249,6 +247,15 @@ bool ScioSense_ENS160::addCustomStep (uint16_t time, bool measureHP0, bool measu return true; } +bool ScioSense_ENS160::readStatus (uint8_t *status) { + return read8(ENS160_REG_DATA_STATUS, status); +} + +bool ScioSense_ENS160::readData (ENS160_DATA *data) { + uint8_t buffer[1] = { 0x21 }; + return i2cDevice.write_then_read(buffer, 1, (uint8_t *)data, sizeof(ENS160_DATA)); +} + // Perform prediction measurement and stores result in internal variables bool ScioSense_ENS160::measure (bool waitForNew) { uint8_t i2cbuf[8]; @@ -257,10 +264,10 @@ bool ScioSense_ENS160::measure (bool waitForNew) { // Set default status for early bail out if (waitForNew) { do { - _delay_ms(1); if (!read8(ENS160_REG_DATA_STATUS, &status)) { return false; } + _delay_ms(1); } while (!IS_NEWDAT(status)); } else { if (!read8(ENS160_REG_DATA_STATUS, &status)) { @@ -268,11 +275,13 @@ bool ScioSense_ENS160::measure (bool waitForNew) { } } + // Read predictions if (IS_NEWDAT(status)) { if (!readBytes(ENS160_REG_DATA_AQI, i2cbuf, 7)) { return false; } + return false; _data_aqi = i2cbuf[0]; _data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8); _data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8); diff --git a/software/test_2024-07-23/src/adafruit/ens160.h b/software/test_2024-07-23/src/adafruit/ens160.h index e3ecdcf..fb6925d 100644 --- a/software/test_2024-07-23/src/adafruit/ens160.h +++ b/software/test_2024-07-23/src/adafruit/ens160.h @@ -11,7 +11,7 @@ #ifndef __SCIOSENSE_ENS160_H_ #define __SCIOSENSE_ENS160_H_ -#include "../i2cdevice.hpp" +#include "../i2cmaster.hpp" #include #define byte uint8_t @@ -99,6 +99,12 @@ #define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11)) #define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048)) +typedef struct { + uint8_t aqi; + uint16_t tvoc; + uint16_t eco2; +} ENS160_DATA; + class ScioSense_ENS160 { public: @@ -114,8 +120,10 @@ class ScioSense_ENS160 { 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 readData (ENS160_DATA *data); + bool readStatus(uint8_t *status); + bool measure(bool waitForNew); // Perform measurement and stores result in internal variables + bool measureRaw(bool waitForNew); // 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 @@ -137,7 +145,7 @@ class ScioSense_ENS160 { uint8_t getMISR() { return this->_misr; } // Return status code of sensor private: - I2cDevice i2cDevice; + I2cMaster 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 diff --git a/software/test_2024-07-23/src/i2cdevice.cpp b/software/test_2024-07-23/src/i2cmaster.cpp similarity index 54% rename from software/test_2024-07-23/src/i2cdevice.cpp rename to software/test_2024-07-23/src/i2cmaster.cpp index 47be4af..21ff990 100644 --- a/software/test_2024-07-23/src/i2cdevice.cpp +++ b/software/test_2024-07-23/src/i2cmaster.cpp @@ -1,15 +1,20 @@ #include #include -#include "i2cdevice.hpp" +#include "i2cmaster.hpp" -I2cDevice i2cDevice; - -I2cDevice::I2cDevice () { +I2cMaster::I2cMaster () { address = 0; + timer = 0; +} + +void I2cMaster::tick1ms () { + if (timer > 0) { + timer--; + } } - -bool I2cDevice::begin (uint8_t addr) { + +bool I2cMaster::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); @@ -17,12 +22,24 @@ bool I2cDevice::begin (uint8_t addr) { return true; } -void I2cDevice::end () { +void I2cMaster::end () { TWCR = (1 << TWEN); TWBR = 0; } -bool I2cDevice::write (const uint8_t *buffer, uint8_t len) { +bool I2cMaster::read (uint8_t *buffer, uint8_t len) { + if (start(true)) { + if (readBytes(buffer, len)) { + if (stop()) { + return true; + } + } + } + return false; +} + + +bool I2cMaster::write (const uint8_t *buffer, uint8_t len) { if (start(false)) { if (writeBytes(buffer, len)) { if (stop()) { @@ -33,7 +50,24 @@ bool I2cDevice::write (const uint8_t *buffer, uint8_t len) { return false; } -bool I2cDevice::write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len) { +bool I2cMaster::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len) { + if (start(false)) { + 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; + } + return false; +} + + +bool I2cMaster::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)) { @@ -48,7 +82,9 @@ bool I2cDevice::write_then_read (const uint8_t *write_buffer, uint8_t write_len, return false; } -bool I2cDevice::readBytes (uint8_t *buffer, uint8_t len) { +// ------------------------------------------------------------- + +bool I2cMaster::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 @@ -65,51 +101,41 @@ bool I2cDevice::readBytes (uint8_t *buffer, uint8_t len) { return true; } -bool I2cDevice::writeBytes (const uint8_t *buffer, uint8_t len) { +bool I2cMaster::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) { + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + if (!timer || (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) { +bool I2cMaster::start (bool read) { TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done uint8_t sr = TWSR & 0xf8; - if (sr != 0x08 && sr != 0x10) { + if (!timer || (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 + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done sr = TWSR & 0xf8; - if ((!read && sr != 0x18) || (read && sr != 0x40)) { + if (!timer || (!read && sr != 0x18) || (read && sr != 0x40)) { return false; } return true; } -bool I2cDevice::stop () { +bool I2cMaster::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/i2cmaster.hpp similarity index 76% rename from software/test_2024-07-23/src/i2cdevice.hpp rename to software/test_2024-07-23/src/i2cmaster.hpp index e59d737..e70326c 100644 --- a/software/test_2024-07-23/src/i2cdevice.hpp +++ b/software/test_2024-07-23/src/i2cmaster.hpp @@ -1,27 +1,28 @@ -#ifndef I2C_DEVICE -#define I2C_DEVICE +#ifndef I2C_MASTER +#define I2C_MASTER #include -class I2cDevice { +class I2cMaster { public: static void end (); public: - I2cDevice (); + I2cMaster (); + void tick1ms (); bool begin (uint8_t addr); + bool read (uint8_t *buffer, uint8_t len); 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; + uint8_t timer; 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/i2cslave.cpp b/software/test_2024-07-23/src/i2cslave.cpp new file mode 100644 index 0000000..2bf6ac2 --- /dev/null +++ b/software/test_2024-07-23/src/i2cslave.cpp @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "i2cslave.hpp" + +I2cSlave::I2cSlave () { + timer = 0; + fromMaster.rIndex = 0; + fromMaster.wIndex = 0; + toMaster.rIndex = 0; + toMaster.wIndex = 0; +} + +void I2cSlave::tick1ms () { + if (timer > 0) { + timer--; + } +} + +bool I2cSlave::begin (uint8_t addr, bool acceptGeneralCalls) { + if (addr > 127) { + return false; + } + TWAR = addr << 1 | (acceptGeneralCalls ? 1 : 0); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE); + return true; +} + +void I2cSlave::end () { + TWCR = (1 << TWEN); + TWBR = 0; +} + +int I2cSlave::read () { + return getByte(fromMaster); +} + +void I2cSlave::write (uint8_t byte) { + putByte(toMaster, byte); +} + + +void I2cSlave::putByte (RingBuffer& buffer, uint8_t byte) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + buffer.data[buffer.wIndex++] = byte; + if (buffer.wIndex >= sizeof(buffer.data)) { + buffer.wIndex = 0; + } + if (buffer.wIndex == buffer.rIndex) { + buffer.rIndex++; + if (buffer.rIndex >= sizeof(buffer.data)) { + buffer.rIndex = 0; + } + } + } +} + +int I2cSlave::getByte (RingBuffer& buffer) { + uint8_t b; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (buffer.rIndex == buffer.wIndex) { + return EOF; + } + b = buffer.data[buffer.rIndex++]; + if (buffer.rIndex >= sizeof(buffer.data)) { + buffer.rIndex = 0; + } + } + return b; +} + +void I2cSlave::handleTWIIsr () { + uint8_t sr = TWSR & 0xf8; + switch (sr) { + case 0x80: { // Previously addressed with own SLA+W; data has been received; ACK has been returned + putByte(fromMaster, TWDR); + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted + break; + } + case 0xa8: { // Own SLA+R has been received; ACK has been returned + int response = getByte(toMaster);; + TWDR = response < 0 ? 0x00 : (uint8_t)response; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted + break; + } + default: TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE); break; + } + +} + diff --git a/software/test_2024-07-23/src/i2cslave.hpp b/software/test_2024-07-23/src/i2cslave.hpp new file mode 100644 index 0000000..2fe2dc7 --- /dev/null +++ b/software/test_2024-07-23/src/i2cslave.hpp @@ -0,0 +1,32 @@ +#ifndef I2C_SLAVE +#define I2C_SLAVE + +#include + +class I2cSlave { + private: + typedef struct { + uint8_t rIndex; + uint8_t wIndex; + uint8_t data[8]; + } RingBuffer; + + public: + I2cSlave (); + void tick1ms (); + bool begin (uint8_t addr, bool acceptGeneralCalls); + void end (); + void handleTWIIsr (); + int read (); + void write (uint8_t byte); + + private: + uint8_t timer; + RingBuffer fromMaster; + RingBuffer toMaster; + void putByte (RingBuffer& buffer, uint8_t byte); + int getByte (RingBuffer& buffer); + +}; + +#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 d64b6e0..c363d60 100644 --- a/software/test_2024-07-23/src/main.cpp +++ b/software/test_2024-07-23/src/main.cpp @@ -92,9 +92,9 @@ extern "C" { Uart1 uart1; Modbus modbus; Ieee485 ieee485; - I2c i2cSparkfun(SparkFunEnvCombo); - I2c i2cMaster(Master); - I2c i2cSlave(Slave); + I2c i2cSparkfun(I2c::SparkFunEnvCombo); + I2c i2cMaster(I2c::Master); + I2c i2cSlave(I2c::Slave); } @@ -242,6 +242,9 @@ ISR (TIMER2_COMPA_vect) { // every 100us timer1ms--; } systemMillis++; + i2cMaster.tick1ms(); + i2cSlave.tick1ms(); + i2cSparkfun.tick1ms(); } timer500ms++; diff --git a/software/test_2024-07-23/src/units/i2c.cpp b/software/test_2024-07-23/src/units/i2c.cpp index df1fe75..64454cd 100644 --- a/software/test_2024-07-23/src/units/i2c.cpp +++ b/software/test_2024-07-23/src/units/i2c.cpp @@ -1,9 +1,10 @@ #include #include #include +#include #include "i2c.hpp" -#include "../i2cdevice.hpp" +#include "../adafruit/bme280.h" #include "../main.hpp" @@ -26,6 +27,8 @@ void I2c::cleanup () { enabled = false; TWCR = (1 << TWEN); TWBR = 0; + ADMUX = 0; + ADCSRA = 0; } int8_t I2c::run (uint8_t subtest) { @@ -34,10 +37,12 @@ int8_t I2c::run (uint8_t subtest) { TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); TWCR = (1 << TWEN); + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 enabled = true; printf("init"); - } else if (subtest == 1 && mode == SparkFunEnvCombo) { + } else if (subtest == 1 && mode == I2c::SparkFunEnvCombo) { printf(" BM280 ... "); if (!bm280.begin()) { printf("ERROR"); @@ -48,151 +53,150 @@ int8_t I2c::run (uint8_t subtest) { printf("ERROR"); return -1; } + if (!ens160.setMode(ENS160_OPMODE_STD)) { + printf("ERROR"); + return -1; + } + if (!ens160.set_envdata(25.0, 65)) { + printf("ERROR"); + return -1; + } + printf("OK"); + float accTemp = 0, accHumidity = 0; + int8_t accCount = -1; do { + // BME280 float p = bm280.readPressure(); - printf("\n => pressure: %.3fhPa", (double)p); + printf("\n => BM280: P= %.3fbar", (double)p / 100000.0); float t = bm280.readTemperature(); - printf(", temp: %.2f°C", (double)t); + printf(", T= %.2f°C", (double)t); float h = bm280.readHumidity(); - printf(", humidity: %.2f%%", (double)h); - } while (wait(1000) == EOF); + printf(", H= %.2f%%", (double)h); - } else if (subtest == 1) { - int key = EOF; - uint8_t buffer[18]; - int errorCode; - while (key == EOF) { - printf("\n => START+WRITE -> "); - errorCode = startWrite(0x77); - if (errorCode > 0) { - stop(); - printf ("ERROR (0x%04x)", errorCode); - continue; + if (accCount >= 0 && !isnanf(h) && !isnan(t)) { + accTemp += t; + accHumidity += h; + accCount++; } - printf("OK"); - printf(", DATA 0xd0 ->"); - errorCode = writeByte(0xd0); - if (errorCode > 0) { - stop(); - printf ("ERROR (0x%04x)", errorCode); - continue; - } - printf("OK"); + bm280.setSampling( + Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::FILTER_OFF, + Adafruit_BME280::STANDBY_MS_1000 + ); - printf("\n => RESTART+READ -> "); - errorCode = startRead(0x77); - if (errorCode > 0) { - stop(); - printf ("ERROR (0x%04x)", errorCode); - continue; + // ENS160 only activated every 32s to avoid wrong temperature measuerment + // if ES160 would be continously active, the temperature would be 4°C higher + // -> ES160 has not enough distance to BM280 + // This solution causes only a +0.3°C higher temperatur value + if (accCount < 0 || accCount >= 32) { + printf(" | ENS160 ("); + if (accCount > 0) { + h = accHumidity / accCount; + t = accTemp / accCount; + accTemp = 0; + accHumidity = 0; + } + accCount = 0; + if (!ens160.set_envdata(t, h)) { + printf("E1)"); + } else { + printf("%.1f°C/%.1f%%): ", (double)t, (double)h); + if (!ens160.setMode(ENS160_OPMODE_STD)) { + printf("E2"); + } else { + for (uint8_t i = 0; i < 100; i++) { + _delay_ms(15); + uint8_t status; + if (ens160.readStatus(&status)) { + if (status & ENS160_DATA_STATUS_NEWDAT) { + ENS160_DATA data; + if (ens160.readData(&data)) { + printf(" aqi=%d(", data.aqi); + switch(data.aqi) { + case 1: printf("excellent"); break; + case 2: printf("good"); break; + case 3: printf("moderate"); break; + case 4: printf("poor"); break; + case 5: printf("unhealthy"); break; + default: printf("?"); break; + } + printf("), tvoc=%dppb", data.tvoc); + printf(", eco2=%d(", data.eco2); + if (data.eco2 < 400) { + printf("?"); + } else if (data.eco2 < 600) { + printf("excellent"); + } else if (data.eco2 < 800) { + printf("good"); + } else if (data.eco2 < 1000) { + printf("fair"); + } else if (data.eco2 < 1500) { + printf("poor"); + } else { + printf("dad"); + } + printf(")"); + } + break; + } + } + } + } + if (!ens160.setMode(ENS160_OPMODE_IDLE)) { + printf("E3"); + } + } } - printf("OK"); - printf(", DATA -> "); - errorCode = readData(1, buffer); - if (errorCode > 0) { - stop(); - printf ("ERROR (0x%04x)", errorCode); - continue; - } - printf("OK (%02x %02x)", buffer[0], buffer[1]); + } while (wait(1000) == EOF); - printf("\n => read trimming -> "); - errorCode = startWrite(0x77); - if (errorCode == 0) { - errorCode = writeByte(0x88); // dig_T1 - errorCode = errorCode != 0 ? 0x1000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = startRead(0x77); - errorCode = errorCode != 0 ? 0x2000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = readData(6, buffer); - errorCode = errorCode != 0 ? 0x3000 | errorCode : 0; + } else if (subtest == 1 && mode == I2c::Master) { + if (!master.begin(0x01)) { + printf("E1"); + return -1; + } + do { + uint8_t buffer[1]; + // read poti + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + buffer[0] = ADCH; + printf("\n write 0x%02x", buffer[0]); + if (!master.write(buffer, 1)) { + printf(" -> ERROR"); } - 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]); + printf(", read "); + if (master.read(buffer, 1)) { + printf("0x%02x", buffer[0]); } else { - stop(); - printf("ERROR(%04x)", errorCode); - continue; - } - - printf("\n => set ctrl register f2 and f4"); - errorCode = startWrite(0x77); - errorCode = errorCode != 0 ? 0x1000 | errorCode : 0; - if (errorCode == 0) { - errorCode = writeByte(0xf2); // ctl_hum - errorCode = errorCode != 0 ? 0x2000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = writeByte(0x01); // oversampling x 1 - errorCode = errorCode != 0 ? 0x3000 | errorCode : 0; + printf(" -> ERROR"); } + } while (wait(1000) == EOF); + master.end(); - if (errorCode == 0) { - errorCode = startWrite(0x77); - errorCode = errorCode != 0 ? 0x4000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = writeByte(0xf4); // ctl_meas - errorCode = errorCode != 0 ? 0x5000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = writeByte((3 << 4) | (3 << 2) | 3); // oversampling 1, normal mode - errorCode = errorCode != 0 ? 0x6000 | errorCode : 0; + } else if (subtest == 1 && mode == I2c::Slave) { + if (!slave.begin(0x01, false)) { + printf("E1"); + return -1; + } + do { + int fromMaster = slave.read(); + if (fromMaster != EOF) { + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + slave.write(ADCH); + printf("\n => from master: 0x%02x -> to master: 0x%02x", fromMaster, ADCH); } - - stop(); - _delay_us(200); - - do { - if (errorCode == 0) { - printf("\n => register 0xf7..0xff:"); - errorCode = startWrite(0x77); - errorCode = errorCode != 0 ? 0x7000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = writeByte(0xf7); - errorCode = errorCode != 0 ? 0x8000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = startRead(0x77); - errorCode = errorCode != 0 ? 0x9000 | errorCode : 0; - } - if (errorCode == 0) { - errorCode = readData(8, buffer); - errorCode = errorCode != 0 ? 0xa000 | errorCode : 0; - } - if (errorCode == 0) { - for (uint8_t i = 0; i < 8; i++) { - printf(" %02x", buffer[i]); - } - int32_t adcT = (int32_t)( ((uint32_t)(buffer[3] << 12)) | (uint16_t)(buffer[4] << 4) | (buffer[5] >> 4) ); - int32_t t = compensateBm280T(adcT); - printf(" T=%ld ", t); - } else { - printf("ERROR (%04x)", errorCode); - break; - } - stop(); - key = wait(5000); - } while (key == EOF); - - stop(); - printf("\n"); - - } while (wait(5000) == EOF); + } while (wait(0) == EOF); + slave.end(); } else { - I2cDevice::end(); printf("end"); return -1; } @@ -201,7 +205,14 @@ int8_t I2c::run (uint8_t subtest) { } void I2c::handleTwiIrq () { - TWCR |= (1 << TWINT); // clear Interrupt Request + if (mode == I2c::Slave) { + DDRD |= (1 << PD7); + PORTD |= (1 << PD7); + slave.handleTWIIsr(); + PORTD &= ~(1 << PD7); + } else { + TWCR |= (1 << TWINT); // clear Interrupt Request + } } uint16_t I2c::startRead (uint8_t address) { diff --git a/software/test_2024-07-23/src/units/i2c.hpp b/software/test_2024-07-23/src/units/i2c.hpp index 6e4a533..b439038 100644 --- a/software/test_2024-07-23/src/units/i2c.hpp +++ b/software/test_2024-07-23/src/units/i2c.hpp @@ -5,21 +5,27 @@ #include "../main.hpp" #include "../adafruit/bme280.h" #include "../adafruit/ens160.h" - -typedef enum I2cMode { SparkFunEnvCombo, Master, Slave } I2cMode; +#include "../i2cmaster.hpp" +#include "../i2cslave.hpp" class I2c : public TestUnit { + public: + typedef enum I2cMode { SparkFunEnvCombo, Master, Slave } I2cMode; + private: I2cMode mode; Adafruit_BME280 bm280; ScioSense_ENS160 ens160; + I2cMaster master; + I2cSlave slave; public: bool enabled; public: I2c (I2cMode mode) { enabled = false; this->mode = mode; } + void tick1ms () { master.tick1ms(); slave.tick1ms(); } virtual void cleanup (); virtual int8_t run (uint8_t subtest); virtual const char *getName (); -- 2.39.5