user4478: How do you transmit and read a uint16_t over I2C?
I'm trying to read two uint16_t values from a slave device, and I'm seeing nonsensical readings.
This is the code on my slave Arduino Uno:
#include <Wire.h>

void send_wire_int(uint16_t num){

    // Send low byte
    Wire.write((uint8_t)num);

    // Send high byte
    num >>= 8;
    Wire.write((uint8_t)num);
}

// This is called from the I2C host.
void I2C_Send()
{

    //  send_wire_int(acount_abs);// Send encoder A count.
    //  send_wire_int(bcount_abs);// Send encoder B count.

    send_wire_int(0);
    send_wire_int(0);

}

void setup(){

    Wire.begin(30);                                                        // initialize I²C library and set slave address
    Wire.onRequest(I2C_Send);                                                   // define I²C slave transmit ISR

    Wire.flush();
    Wire.setTimeout(1000L);

}

void loop(){
    //stuff
}

All it does is wait for the master to request data. Originally, it was sending the values of two registers back, but these values were also garbled or non-changing, so I changed it to just send back 0s but I still get the identical garbled values.
This is the code on my master Arduino Uno:
#include <Wire.h>

uint16_t receive_wire_int(){

    while(Wire.available() < 1){}

    // Read low byte into rxnum
    uint16_t rxnum = Wire.read();

    while(Wire.available() < 1){}

    // Read high byte into rxnum
    rxnum += Wire.read() << 8;

    return rxnum;
}

void setup() {
    Wire.begin();        // join i2c bus (address optional for master)
    Wire.setTimeout(1000L);
    Serial.begin(9600);  // start serial for output
}

void loop() {
    Serial.println("Requesting data..."); Serial.flush();

    Wire.requestFrom(30, 4);

    uint16_t acount = receive_wire_int();
    uint16_t bcount = receive_wire_int();

    Serial.println(String("acount:")+String(acount)+String(" bcount:")+String(bcount));

    delay(500);
}

As you can see, it simply requests the two uint16_t values in 4 bytes, and then prints them to the Serial (my laptop's terminal).
The output I'm seeing is:
acount:65280 bcount:65535

when I would expect:
acount:0 bcount:0

What I am I doing wrong?

user23841: So I've just tested your code and apparently you have to send all data at once. After some research: it sends characters into the function twi_transmit and this function just fills the buffer and actual data are sent asynchronously. So, if you are fast enough, you will overwrite the buffer with another bytes and it's still like you have only 1 character to send.
For example this works (AVRs are little endian):
#include <Wire.h>

// This is called from the I2C host.
void I2C_Send()
{
    uint16_t   uints[2] = {0xDEAD,0xBEEF};

    Wire.write((uint8_t*) uints, 4);
}

void setup(){
    Wire.begin(30);  // initialize I²C library and set slave address
    Wire.onRequest(I2C_Send); // define I²C slave transmit ISR

    Wire.flush();
    Wire.setTimeout(1000L);
}

void loop(){
    //stuff
}

And receiver with HEX prints:
#include <Wire.h>

uint16_t receive_wire_int(){

    while(Wire.available() < 1){}

    // Read low byte into rxnum
    uint16_t rxnum = Wire.read();

    while(Wire.available() < 1){}

    // Read high byte into rxnum
    rxnum += Wire.read() << 8;

    return rxnum;
}

void setup() {
    Wire.begin();        // join i2c bus (address optional for master)
    Wire.setTimeout(1000L);
    Serial.begin(9600);  // start serial for output
}

void loop() {
    Serial.println("Requesting data..."); Serial.flush();

    Wire.requestFrom(30, 4);

    uint16_t acount = receive_wire_int();
    uint16_t bcount = receive_wire_int();

    Serial.print("acount: 0x");
    Serial.print(acount,HEX);
    Serial.print("  bcount: 0x");
    Serial.println(bcount,HEX);

    delay(500);
}


user4478: The problem is that I'm using the wrong type of write() in my slave. As this blog explains, there are two overloaded write() methods in the Wire library. One that accepts a single byte, and another that accepts a byte array. I was sending each byte separately, which doesn't guarantee they'll be received together.
It works if I rewrite my slave's to:
void I2C_Send()
{
  byte myArray[4];

  myArray[0] = 0;
  myArray[1] = 0;
  myArray[2] = 0;
  myArray[3] = 0;

  Wire.write(myArray, 4);

}


4478: <p>How do you transmit and read a uint16_t over I2C?</p>

<p>I'm trying to read two uint16_t values from a slave device, and I'm seeing nonsensical readings.</p>

<p>This is the code on my slave Arduino Uno:</p>

<pre><code>#include &lt;Wire.h&gt;

void send_wire_int(uint16_t num){

    // Send low byte
    Wire.write((uint8_t)num);

    // Send high byte
    num &gt;&gt;= 8;
    Wire.write((uint8_t)num);
}

// This is called from the I2C host.
void I2C_Send()
{

    //  send_wire_int(acount_abs);// Send encoder A count.
    //  send_wire_int(bcount_abs);// Send encoder B count.

    send_wire_int(0);
    send_wire_int(0);

}

void setup(){

    Wire.begin(30);                                                        // initialize I²C library and set slave address
    Wire.onRequest(I2C_Send);                                                   // define I²C slave transmit ISR

    Wire.flush();
    Wire.setTimeout(1000L);

}

void loop(){
    //stuff
}
</code></pre>

<p>All it does is wait for the master to request data. Originally, it was sending the values of two registers back, but these values were also garbled or non-changing, so I changed it to just send back 0s but I still get the identical garbled values.</p>

<p>This is the code on my master Arduino Uno:</p>

<pre><code>#include &lt;Wire.h&gt;

uint16_t receive_wire_int(){

    while(Wire.available() &lt; 1){}

    // Read low byte into rxnum
    uint16_t rxnum = Wire.read();

    while(Wire.available() &lt; 1){}

    // Read high byte into rxnum
    rxnum += Wire.read() &lt;&lt; 8;

    return rxnum;
}

void setup() {
    Wire.begin();        // join i2c bus (address optional for master)
    Wire.setTimeout(1000L);
    Serial.begin(9600);  // start serial for output
}

void loop() {
    Serial.println("Requesting data..."); Serial.flush();

    Wire.requestFrom(30, 4);

    uint16_t acount = receive_wire_int();
    uint16_t bcount = receive_wire_int();

    Serial.println(String("acount:")+String(acount)+String(" bcount:")+String(bcount));

    delay(500);
}
</code></pre>

<p>As you can see, it simply requests the two uint16_t values in 4 bytes, and then prints them to the Serial (my laptop's terminal).</p>

<p>The output I'm seeing is:</p>

<pre><code>acount:65280 bcount:65535
</code></pre>

<p>when I would expect:</p>

<pre><code>acount:0 bcount:0
</code></pre>

<p>What I am I doing wrong?</p>
 23841: <p>So I've just tested your code and apparently you have to send all data at once. After some research: it sends characters into the function <code>twi_transmit</code> and this function just fills the buffer and actual data are sent asynchronously. So, if you are fast enough, you will overwrite the buffer with another bytes and it's still like you have only 1 character to send.</p>

<p>For example this works (AVRs are little endian):</p>

<pre><code>#include &lt;Wire.h&gt;

// This is called from the I2C host.
void I2C_Send()
{
    uint16_t   uints[2] = {0xDEAD,0xBEEF};

    Wire.write((uint8_t*) uints, 4);
}

void setup(){
    Wire.begin(30);  // initialize I²C library and set slave address
    Wire.onRequest(I2C_Send); // define I²C slave transmit ISR

    Wire.flush();
    Wire.setTimeout(1000L);
}

void loop(){
    //stuff
}
</code></pre>

<p>And receiver with <code>HEX</code> prints:</p>

<pre><code>#include &lt;Wire.h&gt;

uint16_t receive_wire_int(){

    while(Wire.available() &lt; 1){}

    // Read low byte into rxnum
    uint16_t rxnum = Wire.read();

    while(Wire.available() &lt; 1){}

    // Read high byte into rxnum
    rxnum += Wire.read() &lt;&lt; 8;

    return rxnum;
}

void setup() {
    Wire.begin();        // join i2c bus (address optional for master)
    Wire.setTimeout(1000L);
    Serial.begin(9600);  // start serial for output
}

void loop() {
    Serial.println("Requesting data..."); Serial.flush();

    Wire.requestFrom(30, 4);

    uint16_t acount = receive_wire_int();
    uint16_t bcount = receive_wire_int();

    Serial.print("acount: 0x");
    Serial.print(acount,HEX);
    Serial.print("  bcount: 0x");
    Serial.println(bcount,HEX);

    delay(500);
}
</code></pre>
 4478: <p>The problem is that I'm using the wrong type of <code>write()</code> in my slave. As <a href="https://thewanderingengineer.com/2015/05/02/1312/" rel="nofollow">this blog</a> explains, there are two overloaded <code>write()</code> methods in the Wire library. One that accepts a single byte, and another that accepts a byte array. I was sending each byte separately, which doesn't guarantee they'll be received together.</p>

<p>It works if I rewrite my slave's to:</p>

<pre><code>void I2C_Send()
{
  byte myArray[4];

  myArray[0] = 0;
  myArray[1] = 0;
  myArray[2] = 0;
  myArray[3] = 0;

  Wire.write(myArray, 4);

}
</code></pre>
