I2C Arduino with 3rd party Command Response

I have an Arduino master and a black box slave. The black box slave is to respond to a command information. SO i send an ASCII value of "050010" and it returns a bunch of information of varying length depending on what is being read.

Arduino code

 while(true){
      Wire.beginTransmission(0x30); 
      Wire.write(stuffToSend, 7); 
      Wire.endTransmission(); 
  
      Wire.requestFrom(0x30, 32); 
      i = 0;
      delay(50);                   //give time to fill buffer
      while (Wire.available()) { // slave may send less than requested
        response[i] = Wire.read();
        i++;
      }

      response[i] = '\0';
      Serial.println(response);
        
      delay(1000);
    }

response should have the following result printed to the terminal continually in my mind

000184400800801912FFFF12E0

however i get the following

⸮12FFFF12E0
000184400800801912FF
⸮FF12E0
000184400800801912FFFF12
⸮E0
000184400800801912FFFF12E0
0
⸮00184400800801912FFFF12E0
00018
⸮4400800801912FFFF12E0
000184400
⸮800801912FFFF12E0
0001844008008
⸮01912FFFF12E0
00018440080080191
⸮2FFFF12E0
000184400800801912FFF
⸮F12E0
000184400800801912FFFF12E
⸮0
000184400800801912FFFF12E0
00
⸮0184400800801912FFFF12E0
000184
⸮400800801912FFFF12E0
0001844008
⸮00801912FFFF12E0
00018440080080
⸮1912FFFF12E0
000184400800801912
⸮FFFF12E0
000184400800801912FFFF
⸮12E0
000184400800801912FFFF12E0
⸮
000184400800801912FFFF12E0
000
⸮184400800801912FFFF12E0
0001844
⸮00800801912FFFF12E0
00018440080

I copy and pasted from the terminal monitor in arduino, however even though it appears there are some '\r' in the text when i pasted it, in locations i expect. on the terminal, they are not present and I only see irony mark and the string of numbers per line.

is there something wrong with my Arduino code which is causing issues with getting information from the black box?

My understanding and why i am confused is i should send a command request for information to the black box. It gets information and stores in its out going buffer. I send a requestFrom command and it outputs from its outgoing buffer x number of bytes I request and than send stop if i requested more bytes than in buffer, otherwise it should clear its buffer after sending.

When the Master does a Wire.requestFRom(), the Slave can try to send more or less, but the Master defines how many bytes will be read. If you read 32 bytes and the Slave acknowledges to its address, then you get 32 bytes, valid or not.

When reading data with Wire.requestFrom(), the Slave acknowledges its I2C address, but the Master gives the acknowledge for each data byte. At the end, the Master does not acknowledge the last byte (although it does not hurt if it does) and issues a stop.

That is how the I2C protocol works. The Slave can not send a stop when the Master reads data.

On top of that is the Wire library. When you read 32 bytes with Wire.requestFrom(), it is not possible to stop in the middle when a certain byte is received.

Can you please remove that delay() between Wire.requestFrom() and Wire.available() ? There is no such thing as giving it time.

dmleone1979:
Wire.requestFrom(0x30, 32);

response should have the following result printed to the terminal continually in my mind
000184400800801912FFFF12E0

The black box slave is a passive I2C slave. It is better to say that it has registers/memory locations rather than saying it has buffer.

By sending this command ("050010") to the slave, you have already set the base address of the register/memory location from which data read to begin.

Wire.requestFrom(0x30, 32); command is a looping/waiting command. The Master receives the ACK signal from the slave in the event of address matching. The Master proceeds to generate 32x(8+1) SCL pulses to receive 32-byte of character type data from the slave should ACK happens after each byte transfer. And accordingly, the Master is supposed to receive 32 characters from slave and not 26 (000184400800801912FFFF12E0). What happens to the remaining 6? The 2nd argument of the Wire.requestFrom(0x30, 32) command is a strictly known value to the user as he knows very well how many bytes of data to read from slave.

The execution of Wire.requestFrom(0x30, 32) command has already taken (assume no communication failure) 32 byte data from the slave and has stored them in the FIFO buffer. Therefore, issuance of delay() and Wire.avialable() instructions after the Wire.requestFrom(0x30, 32) command are not really needed.

When reading data, the Master puts a acknowledge on the bus after each data byte, not the Slave.

The Slave can try to scream: "I have no more data" or jump up and down. There is nothing the Slave can do to stop transferring the whole 32 bytes. In most cases the SDA stays high when the Slave has no more data and the Master receives 0xFF for the remaining data.

When the Master writes data, then the Slave acknowledges to its I2C address and to all the data bytes.

So if I understand. Once I do a Wire.requestFrom(), the info is now stored internally since all data has been received?

So then when I do a Wire.available() I am checking internal data not external? Meaning data on Arduino not data coming from black box.

Correct.

If I remember it well, there are three buffers in the Wire library of 32 bytes each (for the Arduino Due and Zero it is 64 bytes and has been recently increased to 255 bytes).

The Wire.requestFrom() puts all received data in a buffer and waits until the I2C transaction has finished.
The Wire.available() returns the number of bytes that are in that buffer.

Is there a command to start or a means to start at the buffer location zero. It seems I sometimes do not start always at beginning. So if you look at my output. I always do not start at same spot every time.

Or is there a way to clear the FIFO I2C buffer so I can read all 0's?

It seems to do exactly something i can work with. But I need to have my first bytes be 0001 and that is not always the case. An irony mark shows a fresh read from when I do a while available loop

There is not need to clear buffers. The Wire library is part of the Arduino Stream class, but it does not use a stream of data, it uses packets of data.
When the Wire.requestFrom() is called, the buffer are cleared before the I2C bus is used.

Microcontrollers and processors might need a little delay between writing the register address and reading data. Only 1 ms should be enough.

Wire.beginTransmission(0x30);
Wire.write(stuffToSend, 7);
Wire.endTransmission();

delay( 1);     // extra delay, the slave might need some.
 
Wire.requestFrom(0x30, 32);

To avoid confusion, you could filter the text with the old 'C' function isprint(), but at least mark the begin and the end.

Serial.print( "[");  // marker for begin  
Serial.print( response);
Serial.print( "]");  // marker for end
Serial.println();

The thing is why does the output change. When I do a request from call. Every time it should return 0001 as the first 4 bytes every time. And end with 2E0. But when I do the calls it does not always start with 0001 a fresh line starts with the irony mark or box if you can not have a Unicode show.

Since my response never comes out with what I expect I cannot parse it for what I need.

If the i2c buffer is cleared Everytime than I am not getting the bits back from the slave in the proper order. Which I don't think is case.

Which Arduino board and which Arduino IDE version do you use ?

Did you try the '[' and ']' marker ? I mentioned that for a reason.
You receive very consistant data of 26 bytes, which all start with 0001 and all end with 2E0.

Didn't you see the pattern ?

There is however a weird character and a newline at a certain offset (not random). I don't know if that is from the I2C bus or the Serial communication to the computer.
Perhaps the Serial communication is messed up with 0xFF characters, then you should use the isprint() function.

Between all the data that is received, there is a single line without the weird characters. That line is exactly the same as the line of text that is expected: "000184400800801912FFFF12E0".
If you are sure that size of the data is always 26 bytes, then you should request 26 bytes.

What baudrate do you use with the Serial communication to the computer ?

Can you show a complete sketch ? Preferably a minimal working sketch that shows the problem.

Thanks for all the help Koepel.

I saw the pattern and i did not make myself clear at the beginning. The pattern is what is i am trying to solve. For whatever reason it looks like i get the right data but wrong start position. but you see pattern I dont know how to explain it

I did the print request see attached image. You can see it works for a little then something goes wrong with a read and fails to gives right data order.

as for the 0xFF character, It is ever present and i dont know why the first character is nothing in the read buffer. But it counts towards my read. so if i want ot see 4 bytes i have ot request 5. i have to account for the 0xFF.

The sketch i posted is my minimal sketch. I dont know how i could minimize it more. i just didnt show the setup and #includes. I can if you want.

It seems added the start '[' and end ']' may the printout more stable a little but not complete

Baudrate for serial is 19200
IDE: 1.8.5

i2coutput.png

The offset for the '?' is now not spreading in the message but at the begin. That might indicate that the I2C bus is okay.

I can think of many things to try, but they could make no sense, because there are many things that I don't know. It could even be the "response[]" buffer which is somehow declared in the wrong way. I thought this was about the I2C bus, but perhaps the I2C bus is the only thing that is working :confused:

Things I don't know: Which Arduino board; What is the sketch; How long is the cable; What cable; Is the device expecting a 3.3V I2C bus or a 5V I2C bus; Is there a manual for the device; What device is it; Does it use I2C or SMBus or PMBus; Is it always 26 bytes or can it be more;
Things to try: Other Arduino board; Other baudrate; Add extra power supply to Arduino board; Use logic analyzer with protocol analysis on both the Serial and I2C pins; Add a lot more delays in the sketch; Try less then 26 bytes and see if the '?' disappears; Compare the response of the device with the known text in the sketch itself; Test the serial communication extensively; Don't use a buffer but print the Wire.read() directly with Serial.print;