I am trying to write to a specific register, but value doesn't change.
Working with SenseAir Sunrise CO2: Info from i2c guideline from sensor manufacter https://rmtplusstoragesenseair.blob.core.windows.net/docs/Dev/publicerat/TDE5531.pdf
Measurement Period (EE) 0x96 (MSB) 0x97 (LSB)
Measurement period in seconds (range from 2 to 65534). Odd numbers will be rounded up to nearest even number. A system reset is required after changing configuration. Default value is 16.
And that's my code snippet
#include <Wire.h>
/* WARINING!!!
Some wire driver implementations do not corectly implement Wire.endTransmission(false) function,
so please check this before disable WIRE_WORKAROUND!
For example, known "bad" implementations are: Nucleo STM32
*/
#define WIRE_WORKAROUND (0)
#define LED_BUILTIN 2
/* Define serial EN pin */
const int SUNRISE_EN = 4;
/* Sunrise communication address, both for Modbus and I2C */
const uint8_t SUNRISE_ADDR = 0x68;
/* Amount of wakeup attempts before time-out */
const int ATTEMPTS = 5;
/* It takes 25ms to write one EE register */
const int EEPROM_UPDATE_DELAY_MS = 25;
/* Register Addresses */
const uint8_t ERROR_STATUS = 0x01;
const uint8_t MEASUREMENT_MODE = 0x95;
const uint8_t METER_CONTROL = 0xA5;
/* Reading period, in milliseconds. Default is 4 seconds */
int readPeriodMs = 2000;
void setup()
{
/* I2C */
/* Initialize I2C and use default pins defined for the board */
reInitI2C();
Serial.begin(115200);
Serial.println("Initialization complete\n");
change_measurement_period(SUNRISE_ADDR);
/* Read the sensor's configs */
Serial.println("Sensor Measurement Configurations:");
read_sensor_config(SUNRISE_ADDR);
Serial.println();
}
void change_measurement_period(uint8_t target) {
/* Function variables */
int error;
/* Wakeup */
if(!(_wakeup(target))) {
Serial.print("Failed to wake up sensor.");
/* FATAL ERROR */
while(true);
}
Serial.println("Changing Measurement Period...");
uint16_t mPeriod = 12;
Wire.beginTransmission(target);
Wire.write(0x96);
Wire.write(highByte(mPeriod)); // sends MSB
Wire.write(lowByte(mPeriod)); // sends LSB
error = Wire.endTransmission(true);
delay(EEPROM_UPDATE_DELAY_MS);
if(error != 0) {
Serial.print("Failed to send request. Error code: ");
Serial.println(error);
/* FATAL ERROR */
while(true);
}
Serial.println("\n\n\nSensor restart is required to apply changes\n\n\n");
}
/**
* @brief Reads and prints the sensor's current measurement mode,
* measurement period and number of samples.
*
* @param target: The sensor's communication address
* @note This example shows a simple way to read the sensor's
* measurement configurations.
* @retval None
*/
void read_sensor_config(uint8_t target) {
/* Function variables */
int error;
int numBytes = 7;
/* Wakeup */
if(!(_wakeup(target))) {
Serial.print("Failed to wake up sensor.");
return;
}
/* Request values */
error = WireRequestFrom(target, numBytes, MEASUREMENT_MODE /* from address*/, true /* STOP*/);
if(error != numBytes ) {
Serial.print("Failed to write to target. Error code : ");
Serial.println(error);
return;
}
/* Read values */
/* Measurement mode */
uint8_t measMode = Wire.read();
/* Measurement period */
uint8_t byteHi = Wire.read();
uint8_t byteLo = Wire.read();
uint16_t measPeriod = ((int16_t)(int8_t) byteHi << 8) | (uint16_t)byteLo;
/* Number of samples */
byteHi = Wire.read();
byteLo = Wire.read();
uint16_t numSamples = ((int16_t)(int8_t) byteHi << 8) | (uint16_t)byteLo;
/* ABCPeriod */
byteHi = Wire.read();
byteLo = Wire.read();
uint16_t abcPeriod = ((int16_t)(int8_t) byteHi << 8) | (uint16_t)byteLo;
/* Most propable that the sensor will not go into sleep mode, but to be insure...*/
/* Wakeup */
if(!(_wakeup(target))) {
Serial.print("Failed to wake up sensor.");
return;
}
/* Request values */
error = WireRequestFrom(target, 1, METER_CONTROL /* from address*/, true /* STOP*/);
if(error != 1 ) {
Serial.print("Failed to write to target. Error code : ");
Serial.println(error);
return;
}
uint8_t meterControl = Wire.read();
Serial.print("Measurement Mode: ");
Serial.println(measMode);
readPeriodMs = measPeriod * 1000;
Serial.print("Measurement Period, sec: ");
Serial.println(measPeriod);
Serial.print("Number of Samples: ");
Serial.println(numSamples);
if((0U == abcPeriod) || (0xFFFFU == abcPeriod) || (meterControl & 0x02U)) {
Serial.println("ABCPeriod: disabled");
} else {
Serial.print("ABCPeriod, hours: ");
Serial.println(abcPeriod);
}
Serial.println("MeterControl: ");
Serial.println("Bit [0]:" + (String)bitRead(meterControl,0));
Serial.println("Bit [1]:" + (String)bitRead(meterControl,1));
Serial.println("Bit [2]:" + (String)bitRead(meterControl,2));
Serial.println("Bit [3]:" + (String)bitRead(meterControl,3));
Serial.println("Bit [4]:" + (String)bitRead(meterControl,4));
Serial.println("Bit [5]:" + (String)bitRead(meterControl,5));
Serial.println("Bit [6]:" + (String)bitRead(meterControl,6));
Serial.println("Bit [7]:" + (String)bitRead(meterControl,7));
Serial.println(meterControl, BIN);
}
/* Initialize I2C bus and pins */
void reInitI2C() {
/* Initialize I2C and use default pins defined for the board */
Wire.begin();
/* Setup I2C clock to 100kHz */
Wire.setClock(100000);
}
/* Workaround regarding BAD implementations of Wire.endTransmission(false) function */
int WireRequestFrom(uint8_t dev_addr, uint8_t bytes_numbers, uint8_t offset_to_read, bool stop) {
int error;
#if (WIRE_WORKAROUND == 1)
error = Wire.requestFrom((uint8_t)dev_addr, (uint8_t)bytes_numbers /* how many bytes */, (uint32_t)offset_to_read /* from address*/, (uint8_t)1/* Address size - 1 byte*/, stop /* STOP*/);
#else
Wire.beginTransmission(dev_addr);
Wire.write(offset_to_read); //starting register address, from which read data
Wire.endTransmission(false);
error = Wire.requestFrom((uint8_t)dev_addr, (uint8_t)bytes_numbers /* how many bytes */, (uint8_t)stop /* STOP*/);
#endif
return error;
}
/**
* @brief Wakes up the sensor by initializing a write operation
* with no data.
*
* @param target: The sensor's communication address
* @note This example shows a simple way to wake up the sensor.
* @retval true if successful, false if failed
*/
bool _wakeup(uint8_t target)
{
int attemps = ATTEMPTS;
int error;
do {
uint8_t byte_0;
/* */
Wire.beginTransmission(target);
error = Wire.endTransmission(true);
} while(((error != 0 /*success */) && (error != 2 /*Received NACK on transmit of address*/) && (error != 1 /* BUG in STM32 library*/)) && (--attemps > 0));
/* STM32 driver can stack under some conditions */
if(error == 4) {
/* Reinitialize I2C*/
reInitI2C();
return false;
}
return (attemps > 0);
}
void loop() {
// put your main code here, to run repeatedly:
}
Mostly i use that code, but it's not have an snippet with writing random number in register with MSB&LSB: https://github.com/Senseair-AB/Sunrise-Examples---Arduino/blob/master/examples/i2c/sunrise_i2c_continuous/sunrise_i2c_continuous.ino
i reset sensor hardware(physically push the reset button and toogle power from sensor) after data was written and also i wait until all bytes are written
delay(EEPROM_UPDATE_DELAY_MS);
Also i read the sensor configuration after startup, and i see that values of registers doesn't change.
Problem in function change_measurement_period
What am i doing wrong? maybe someone can help with that?