I2C: weirdness with communicating binary values

Hello!

I have been experiencing a strange problem, and I'm wondering if anyone knows what's going on.

I am sending a value from an ATTiny84 to an Arduino Mega master over I2C. This value is one byte, and I only ever use 4 bits of that byte (it's a value from 0-15).

This is the function the Mega uses to ask for the data:

#include <Wire.h>

void setup() {
  Wire.begin();
}

void loop() {
  int currentTime = millis();
  if (currentTime - prevTime >= 1000) {
    ask();
    prevTime = currentTime;
  }
  // put your main code here, to run repeatedly:
  

}

void ask() {    
    byte data;
    Wire.requestFrom(0x6F, 1);
    while (Wire.available()) {
      data = Wire.read();
    }
}

This is the function the Tiny uses to send the data it's asked for:

#define I2C_DEVICE_ADDRESS 0x6F // 111

#include <TinyWireS.h>

void setup() {
  TinyWireS.begin(I2C_DEVICE_ADDRESS); //
  TinyWireS.onRequest(requestEvent);
}

void requestEvent() {
  byte data = [some binary number from 0-15];
  TinyWireS.send(data);
}

void loop() {
  TinyWireS_stop_check();  
}

So far, so normal.

The weird part: If I send a single byte (such as 1001), it doesn't always arrive as intended. Sometimes it's truncated to 7 bits, sometimes it's mangled, sometimes it's both.

I did some testing (a lot of testing, but here's a small sample):

Test 1
Tiny sent: 10000000
Mega rec: 10000000

Test 2
Tiny sent: 11000000
Mega rec: 11000000

Test 3
Tiny sent: 10010001
Mega rec: 10010001

Test 4
Tiny sent: 00001111
Mega rec: 1001001

Test 5
Tiny sent: 11110000
Mega rec: 1110000

As you can see, transmissions 1-3 are fine. 4 arrived as 7 bits and a totally different value. 5 arrived as 7 bits and seems to be shifted left by 1. In testing these irregularities seem to be consistent.

I did eventually find a fix:Only use hex values. If I use hex values, there is no issue at all and everything works as expected; what the Tiny sends is what the Mega gets. I've also found that declaring device addresses as hex also means that the Tiny behaviour is much more reliable; declaring them as 7-bit binary numbers makes them inconsistent.

Does anyone have any insight as to why binary would be unreliable, but hex isn't? I'm curious, and I also wanted to leave this here in case anyone else is bewildered by this and goes looking for answers. :slight_smile:

Thanks so much for any insight you can lend!

Any time variables should be declared as unsigned long

I did eventually find a fix:Only use hex values.

All numbers in the computer are binary. "Hex" is a human readable representation of a binary number.

no_u:
I've also found that declaring device addresses as hex also means that the Tiny behaviour is much more reliable; declaring them as 7-bit binary numbers makes them inconsistent.

The address of an I2C device is indeed 7-bit; if speaking strictly, it should be represented as 0b1101111 rather than 0x6F (0110 1111). The R-W/ bit is added as necessary to form the 8-bit Control Byte.

You were prefixing the “binary” numbers you were sending with 0b , for example 0b00001111 ?
And you mentioned declaring a 7bit binary number. How did you attempt this ?

jremington:
All numbers in the computer are binary. "Hex" is a human readable representation of a binary number.

I have been trained to think that data in computer memory/register are in bit form rather than in binary form. The argument behind this saying is this -- while speaking that the data is in binary form, the concept of positional weight/value bn*2n comes in; but, all data cannot be interpreted with this binary positional weight. For example, the 32-bit representation/value for the floating point number float x = 1.23; cannot be interpreted with the binary positional weight; it should be interpreted according to binary32 rules.

6v6gt:
You were prefixing the “binary” numbers you were sending with 0b , for example 0b00001111 ?
And you mentioned declaring a 7bit binary number. How did you attempt this ?

In I2C Bus communication, I safely write the device address (7-bit form) in the following style while roll calling the BME280 --

Wire.beginTransmission(0b1110110);

or

#define deviceAddress 0b1110110  
//instead of #define deviceAddress 0x76 (0b01110110); I get confused with Control Byte of Post#3.

Wire.beginTransmission(deviceAddress);

GolamMostafa:
For example, the 32-bit representation/value for the floating point number float x = 1.23; cannot be interpreted with the binary positional weight; it should be interpreted according to binary32 rules.

All the subfields that make up a 32 bit float are binary encoded.

So following your argument a byte array of length 4 would also be not binary encoded.

Whandall:
All the subfields that make up a 32 bit float are binary encoded.

Except MS-bit which is decoded as : (-1)Sign; where, Sign (b31) = 0 or 1.

GolamMostafa:
Except MS-bit which is decoded as : (-1)Sign; where, Sign (b31) = 0 or 1.

Any single bit is always binary no matter what its value means.

Whandall:
Any single bit is always binary no matter what its value means.

That means : b020
===> 0
1 = 0

or

==> 1*1 = 1

//------------------------------------

For the case of binary32 format --

===> (-1)b31
===> (-1)0
===> 1

or

===> (-1)1
===> -1

From the OP:

Test 4
Tiny sent: 00001111
Mega rec: 1001001

sent 00001111 = Octal 1111 = Binary 1001001

Therefore, it does look like the binary prefix was missing.

@GolamMostafa

So you know how the binary fields of a float are to be interpreted to result in a floating point number, good for you.

I see no relation to the argument of binary vs non binary.