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?
-
You’re not checking the error return. And you don’t appear to be resetting the system, as the documentation you quoted says you must.romkey– romkey2021年08月18日 22:50:15 +00:00Commented Aug 18, 2021 at 22:50
-
it's not full code, i check the error code and it's ok. And do the system reset, but value in register doesn't changeDmytro Kochuk– Dmytro Kochuk2021年08月18日 22:54:40 +00:00Commented Aug 18, 2021 at 22:54
-
It helps if you share the full code. At least share all the code relevant to the question, a complete minimal viable example that demonstrates the problem. Not just a snippet.romkey– romkey2021年08月19日 00:10:55 +00:00Commented Aug 19, 2021 at 0:10
-
@romkey i mostly use that code, but it's not have an snippet with writing random number in register with MSB&LSB: github.com/Senseair-AB/Sunrise-Examples---Arduino/blob/master/…Dmytro Kochuk– Dmytro Kochuk2021年08月19日 00:24:18 +00:00Commented Aug 19, 2021 at 0:24
-
Can you make up a minimal example that actually compiles and runs, which sets the register and then checks the register. We can't really debug "I mostly use that code" sort of stuff.Nick Gammon– Nick Gammon ♦2021年08月19日 05:51:51 +00:00Commented Aug 19, 2021 at 5:51
2 Answers 2
My main goal was to use the opportunity to get the value compensated by atmospheric pressure. But for this it was necessary to understand how to write in registers.
And did not understand what was the problem in the examples of code provided by the manufacturer, it did not correctly work with writing to register 2 bytes data or і did something wrong (most likely). So I rewrote it with the help of a man from the Arduino forum, and now everything works fine.
//Write pressure value to register BAROMETRIC_PRESSURE_VALUE
int16_t co2Pre = 9772; //977.2 hPa
// The wake-up is a write command to the I2C address of the sensor.
Wire.beginTransmission(SUNRISE_ADDR);
Wire.endTransmission(); // ignore the return value
Wire.beginTransmission(SUNRISE_ADDR);
Wire.write(BAROMETRIC_PRESSURE_VALUE);
Wire.write(highByte(co2Pre)); // sends MSB
Wire.write(lowByte(co2Pre)); // sends LSB
error = Wire.endTransmission(true);
delay(50);
if( error != 0) Serial.println( "ERROR, can't find the sensor");
int WireRequest(byte target, byte regAddr, int numBytes) {
// The wake-up is a write command to the I2C address of the sensor.
Wire.beginTransmission(target);
Wire.endTransmission(); // ignore the return value
// Set register address of the sensor
Wire.beginTransmission(target);
Wire.write(regAddr); // register address
int error = Wire.endTransmission(false); // false for a repeated start
if( error != 0) {
Serial.println( "ERROR, can't find the sensor");
return 1;
}
// Read the temperature (two bytes, representing a signed integer)
int n = Wire.requestFrom(target, numBytes); // request 2 bytes
if( n != numBytes) {
Serial.println( "ERROR, can't read data");
return 1;
}
return 0;
}
//read BAROMETRIC_PRESSURE_VALUE
error = WireRequest(SUNRISE_ADDR, BAROMETRIC_PRESSURE_VALUE, 2);
if(error != 0) {
Serial.println( "Failed to write to target.");
while(true);
}
msb = (byte) Wire.read();
lsb = (byte) Wire.read();
int16_t co2Pressure = word( msb, lsb);
float co2PressureValue = float( co2Pressure) / 10;
Serial.println("BAROMETRIC_PRESSURE_VALUE: " + (String) co2PressureValue);
And also working code snippets for writing registers, that need sensor restart, later i physically restart the sensor, but now do it in code.
// The wake-up is a write command to the I2C address of the sensor.
Wire.beginTransmission(SUNRISE_ADDR);
Wire.endTransmission(); // ignore the return value
Wire.beginTransmission(SUNRISE_ADDR);
Wire.write(MEASUREMENT_PERIOD);
Wire.write(highByte(mPeriod)); // sends MSB
Wire.write(lowByte(mPeriod)); // sends LSB
error = Wire.endTransmission(true);
delay(50);
if( error != 0) Serial.println( "ERROR, can't find the sensor");
//RESTART SENSOR
// The wake-up is a write command to the I2C address of the sensor.
Wire.beginTransmission(SUNRISE_ADDR);
Wire.endTransmission(); // ignore the return value
Wire.beginTransmission(SUNRISE_ADDR);
Wire.write(SENSOR_RESTART_SCR);
Wire.write(0xFF);
error = Wire.endTransmission(true);
if( error != 0) Serial.println( "ERROR, can't find the sensor");
Serial.println("\n\nSensor restart to apply changes\n\n");
delay(2500); //Wait after sensor restart
As written on page 14 of the linked document (emphasis by me):
All new written data to register (EE) can be read back after a sensor reset is completed.
But it seems as if you don't reset the sensor.
You will need to wait as documented, until all bytes are written.
-
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. I use that code: github.com/Senseair-AB/Sunrise-Examples---Arduino/blob/master/…Dmytro Kochuk– Dmytro Kochuk2021年08月19日 09:49:38 +00:00Commented Aug 19, 2021 at 9:49
-
Well, you did not show this in your question. Please add these important information by editing your question. -- However, then it is another problem.the busybee– the busybee2021年08月19日 09:58:39 +00:00Commented Aug 19, 2021 at 9:58
-
ok. I think that may be problem in my function of writing to register, i never to that later.Dmytro Kochuk– Dmytro Kochuk2021年08月19日 10:03:50 +00:00Commented Aug 19, 2021 at 10:03
-
i added a full code example, maybe you see where the problem might beDmytro Kochuk– Dmytro Kochuk2021年08月19日 10:15:53 +00:00Commented Aug 19, 2021 at 10:15