How to use stream.read( ) function for I2C communication?

I would like to use stream.read() function to get stream data from an I2C sensor device using Arduino Uno controller. there is a link to stream functions below, but there is no example to show how to use them.

https://www.arduino.cc/reference/en/language/functions/communication/stream/

Could I trouble someone to provide a link (or a code) to show as an example code for me to learn how to use them?

Thanks,
Gu

https://www.arduino.cc/en/Reference/WireRead

1 Like

Hi Juraj,

Did you mean just to follow the wire.read() to use stream.read()? is there a stream.begin() function to initiate the associated functions?

Regards,
Gu

The Stream class does not have a begin() function. Classes that inherit from Stream may or may not have a begin() function. Wire is an instance of the TwoWire class. The TwoWire class inherits from Stream and has a begin() function. From Wire.h:

class TwoWire : public Stream
void begin();
extern TwoWire Wire;

I am learning to use stream.read() to read 32 byes of stream data at a time, and got an error, expected primary-expression before “-” taken, at line if (Stream.available() =32) when compiling my code. I want to see the difference between read(), readBytes() and readString(). Could someone help me with the code? I do not know how to correct it.

   char data_buffer[32];
   Wire.requestFrom(addr, 32);  
   if (Stream.available() = 32){
      Serial.println(stream.read()); 
      Serial.println(stream.readBytes(data_buffer, 32)); 
      Serial.println(stream.readString());
      for ( int I = 0; I <= 32; I ++) {
        Serial.print(data_buffer[I]);   
      }
       Serial.println();
   }

Please always use the Wire functions for the I2C bus, for example Wire.read() and Wire.available() and so on.
When you call a Stream. or stream. function, then there is something wrong.

The I2C communication is with packages of data, and not really a stream. However, the Wire library is part of the Stream family. That is a class which is never used directly, because there is no object for it. It is always part of a real object, such as Wire, Serial, Serial1.

For example the Wire.readBytes() is from the Stream class and it can be used, but inside that function is a timeout which is wrong for the I2C bus.

Using the Wire.readString() would be strange. The I2C bus usually has fixed size binairy packages of data.

Testing the Stream functions with I2C will have strange results. Use the Serial functions to test them (but keep in mind that they are called Serial.readString(), Serial.readBytes()).

As noted, Stream is an abstract class. So you wouldn’t normally call functions on it. Try looking at the examples that come with the Wire library.

Thank you, Koepel and gfvalvo,

I first used wire.read() to do my code, reading data byte by byte (or data address by data address) using Arduino Uno , however, the data has approximately 10 times of noise (+/- 2.5 compared with the data obtained using the originally on-board micro-controller that uses software-timed stream data reading (+/- 0.25).

My understanding is that each wire.read() needs a wire.write first to specify data address. The write operation may be the cause for the noise increase. In a stream reading mode, only one time wire.write() to set stream reading mode in the settings, no write operation in reading loop, hence data noise is lower.

The software-timed stream reading has an operating system (OS) interruption occasionally. Arduino Uno is hardware-timed communication, it does eliminate the OS interruption, but created higher noise. This is the reason I am looking for hardware-timed stream reading.

Thanks,
Gu

Why not simply cut and paste the error message?

Here is the error message

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src/Wire.h:65:13: note: candidate 2: uint8_t TwoWire::requestFrom(uint8_t, uint8_t)

     uint8_t requestFrom(uint8_t, uint8_t);

             ^~~~~~~~~~~

Using library Wire at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire 

exit status 1

expected primary-expression before '.' token



C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src/Wire.h:65:13: note: candidate 2: uint8_t TwoWire::requestFrom(uint8_t, uint8_t)

     uint8_t requestFrom(uint8_t, uint8_t);

             ^~~~~~~~~~~

Using library Wire at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire 

exit status 1

'stream' was not declared in this scope


And the complete code?

Here below is the code. Just a start.


#include <Wire.h>
  uint8_t addr = 42;
  uint8_t stream_word_a[12]; // to hold comand "4C0501000601000104302A90"
  char data_buffer[32];          

void setup() {
  Serial.begin(115200);       
  Wire.begin();   
  Wire.setClock(100000); 
  delay(200);

// Set stream start  "4C0501000601000104302A90", command string to be writen for starting stream mode
      stream_word_a[0] = byte (0x4C);
      stream_word_a[1] = byte (0x05);
      stream_word_a[2] = byte (0x01);
      stream_word_a[3] = byte (0x00);
      stream_word_a[4] = byte (0x06);
      stream_word_a[5] = byte (0x01);
      stream_word_a[6] = byte (0x00);
      stream_word_a[7] = byte (0x01);
      stream_word_a[8] = byte (0x04);
      stream_word_a[9] = byte (0x30);
      stream_word_a[10] = byte (0x2A);
      stream_word_a[11] = byte (0x90);
                        
      Wire.beginTransmission(addr); 
      Wire.write(stream_word_a,12);
      Wire.endTransmission();
      delay(10); 
   
}
  
void loop (){ 

   char data_buffer[32];
   Wire.requestFrom(addr, 32);  
   if (Stream.available() == 32){
      Serial.println(stream.read()); 
      Serial.println(stream.readBytes(data_buffer, 32)); 
      Serial.println(stream.readString());
      for ( int I = 0; I <= 32; I ++) {
        Serial.print(data_buffer[I]);   
      }
       Serial.println();
   }
  
     
  delay(10);  
   
}

if (Stream.available() == 32){

As already stated, you should not be trying to call any functions on the Stream class.

      Serial.println(stream.read()); 
      Serial.println(stream.readBytes(data_buffer, 32)); 
      Serial.println(stream.readString());

‘stream’ (small s) isn’t even defined anywhere.

PLEASE get the idea of using Stream (or stream) out of your head.

I’m on this forum mainly to answer questions about I2C and millis(), but I don’t understand what you are saying.

The Wire.requestFrom() does a complete I2C session with START, address, read data, send ACK and STOP at the end. It does everything and puts the data in a buffer. Then the I2C bus becomes idle again.
After that, the data in the buffer can be retrieved with Wire.read(), or even Wire.readBytes() if you want to.

When writing data, the Wire.write() puts data in a buffer. Nothing happens on the I2C bus yet. Only with Wire.endTransmission() the buffer is used for a I2C session.

The I2C bus is not a bus for streaming serial data. Packages of data are sent and received.

Hi Koepel,

Thank you for your comment.
The Wire.readBytes() is not included in the Wire library.
https://www.arduino.cc/en/Reference/Wire

but, It is included in Stream library as Stream.readBytes()
https://www.arduino.cc/reference/en/language/functions/communication/stream/

Any stream function gives an error when compiling the code, do not know why?

Stop using Stream. or stream. functions. You can not use them. No one in the world can do that.

The Arduino reference talks about the Stream class. They assume that you know the C++ language and know what a class is. I agree that a little more explanation could be helpful.

A class definition is just a definition of how a class looks like. It is a description of a ‘type’, not the ‘variable’ itself.
The ‘object’ is a complex ‘variable’, and the compiler makes code for the object.

There is a Wire object, which uses a few classes, such as ‘TwoWire’ and ‘Stream’.
For example the Serial object uses the classes ‘Stream’ and ‘Print’ for Serial/UART communication.

The C++ language can make a derived class from another class. The object can use the functions of both. The object is “Wire” and you can use “Wire.read()” and “Wire.readBytes()”.

The Stream class is the base class. Because those are common functions, I look at it as if the Stream class is on top of the TwoWire class, since the TwoWire class has the actual interface with the hardware.

int i;   // reserve a memory location for 'i'
i = 3;   // write 3 to that memory location

int = 3; // compiler does not know what to do.

The class is just a definition of a type, just as ‘int’ or ‘long’ or ‘float’.
The object has a memory location.

The stream functions do not work, they should have been removed from Arduino web,
https://www.arduino.cc/reference/en/language/functions/communication/stream/

or some detailed descriptions should be added for a better understanding.

Thank you all who read and replied to this issues.

The Stream functions work fine. As you’ve already been told, you don’t call them on ‘Stream’ as that’s an abstract class, not an object.

Also (again as you’ve already been told), it makes little sense to do what you’re trying with I2C (even though the TwoWire class inherits from Stream) because of the nature of communications over that bus.

@edmuser I thought I made it very simple for you.

Do you see what is wrong here:

int = 3;

The compiler does not know where to store that 3. There is no memory location to store that 3. But that does not mean that int should be removed from the C++ language.

The int is a description, telling that it is a signed integer value.