Raspberry i2cget to retrieve data from arduino

Hello,

I have connected an arduino ATmega328P with a Raspberry through i2c.

The arduino works as a sensor and it sends data when I ask it from the Raspberry using i2cget.

The problem is that it only sends 1 byte of data. I can't send more than that.

I send the command i2cget -y 1 0x04 and arduino replies with something like 0xnn

I'm using this code in the arduino :

void sendData(){

byte buffer[2]; buffer[0] = 0x25; buffer[1] = 0x75; Wire.write( buffer, 2);

}

I tried some variants of this code, but I only receive the first byte.

I do have other sensors connected to the raspberry and using i2cget I receive 16 bits values in format like 0xnnnn, so I guess it's not a problem of the raspberry.

I would appreciate any help.

Thanks

Try to use

i2cget -y 1 0x04 0x00 w

By default i2cget only reads one byte. Using mode "w" it reads a 16bit word.

Thanks.

It works the way you say but it doesn´t work always. I receive a "Error: Read failed" 5 of 6 times I try to retrieve the data. Sometimes I get the answer but few times.

I tested to retrieve only a byte and I also receive errors, but few times.

So, I wonder why this happens.

I connected the i2c directly from arduino pins to Raspberry pins as it is suposed there is no need to convert voltage levels ( I've read in some websites as for example this https://oscarliang.com/raspberry-pi-arduino-connected-i2c ).

Should the problem be caused because different voltage levels? If not, why I'm receiving this problems?

Thanks in advance

It works the way you say but it doesn´t work always. I receive a "Error: Read failed" 5 of 6 times I try to retrieve the data. Sometimes I get the answer but few times.

Sounds like a hardware problem. Post a wiring diagram of your setup! How long are your wires? For I2C they should be less than 50cm in total (or even less if you have a noisy environment).

I connected the i2c directly from arduino pins to Raspberry pins as it is suposed there is no need to convert voltage levels ( I've read in some websites as for example this https://oscarliang.com/raspberry-pi-arduino-connected-i2c ).

The level should be converted but if you wire it correctly and hold the I2C bus on 3.3V with very short wires you might get away without a level converter.

Post a wiring diagram of your setup!

I just connect PC5 to pin 5 of the raspberry and PC4 to pin 3 of the raspberry. Directly and nothing else.

How long are your wires?

It's in a PCB, no more than 10cm each other. The only thing I should check it is that I want to connect another device to the I2C bus but now nothing is connected so there are two wires wich eventually could have an antenna effect, but again, they are short, 5 cm max.

I'm very new to arduino. I've read some posts talking about the low of the arduino. Do you think this may be important or should I focus only in noise?

EDIT: Just in case anybody is looking for info, I resoldered a couple of times the microcontroller and finally the communication between the arduino and raspberry worked ok sending more than one byte at a time.

Again: Post a wiring diagram of your setup!

I just connect PC5 to pin 5 of the raspberry and PC4 to pin 3 of the raspberry. Directly and nothing else.

That cannot work, at least the GNDs must be connected. Instead of describing every pin connection: Post a wiring diagram. Remember, the Arduino runs on 5V while the Raspberry pi runs on 3V3. You need level converters or you have to patch the Wire library.

It's in a PCB, no more than 10cm each other. The only thing I should check it is that I want to connect another device to the I2C bus but now nothing is connected so there are two wires wich eventually could have an antenna effect, but again, they are short, 5 cm max.

That should be no problem. What pull-ups do you use (a wiring diagram would have shown all that)?

I'm very new to arduino. I've read some posts talking about the low of the arduino.

What's a "low of arduino"?

Sorry, I didn't know how to upload images :cold_sweat:

At the right it is the pin connector to the raspberry.

Yes, both raspberry pi and arduino are connected to the same power supply and GND.

No pull-ups in the I2C line.

"low of arduino" -> Sorry, "low speed of the arduino"

I've been testing with 2 bytes data using i2cget -y 1 0x04 0x00 w
What I receive is either an error or 00 in the second byte, so when the arduino sends 0x2345 what the raspi receives is 0x2300. It also happens some times when I try to receive only one byte, I get 0x00 instead of the real value.

I read this post I2C clock stretching - Raspberry Pi Forums

They talk about speed. I increased speed in Raspberry master to 400 khz and the result is that it fails most of the times. By reducing the speed below 100 khz, I don't appreciate any change.

I have to say that I replaced an ADC ( ADS1015 ) by the arduino, in the same place of the pcb and using almost the same wiring ( length and path ) to the Raspi. With the ADC, it worked perfectly.

They talk about speed. I increased speed in Raspberry master to 400 khz and the result is that it fails most of the times. By reducing the speed below 100 khz, I don't appreciate any change.

As far as I know the Raspberry Pi doesn't support clock stretching correctly. So if the Arduino stretches the clock to let the master wait until the Arduino finished it's I2C interrupt, it may send it's data to late as the Raspberry Pi went ahead without waiting.

At what frequency runs your ATmega328p?

pylon: At what frequency runs your ATmega328p?

16 MHz

pylon: That should be no problem. What pull-ups do you use (a wiring diagram would have shown all that)?

When you asked about the pull-ups, did you refer about the I2C lines? What for?

I guess I should add voltage conversion.

When you asked about the pull-ups, did you refer about the I2C lines? What for?

They are need to define the idle state of the bus, idle state is equal to the 1 (true) state. Theoretically you can use pull-ups to 3.3V (2k2) to define a state that both (Arduino and Raspberry Pi) understand. But keep in mind that this needs short wires between them otherwise the voltage level might not be sufficient to signal a 1 on the Arduino side.

Try to set the Rapsberry Pi I2C speed to 50kHz. Does that help?

Pylon, thank you so much for your help.

pylon: They are need to define the idle state of the bus, idle state is equal to the 1 (true) state.But keep in mind that this needs short wires between them otherwise the voltage level might not be sufficient to signal a 1 on the Arduino side.

I soldered 2K2 resistors from 3V3 to both lines SDA and SCL but I don't see any difference. The wires are 5 cms long.

pylon: Try to set the Rapsberry Pi I2C speed to 50kHz. Does that help?

It changes the behaviour.

This is very strange. I reduce the speed and reboot the raspberry but not the arduino and magically, if the arduino is sending 0xB4, the raspberry receives just the half 0x5A :o :o

Yesterday I decided to divide values and send a two bytes int in two different bytes. The code is pretty simple but the problem is, if the value is 255 and it changes to 256 in the middle of transmision, the arduino would send first 0xFF and later 0x10. To solve it, before reading, the raspberry sends a message to stop ADC and it restarts after the transmision.

This is very strange. I reduce the speed and reboot the raspberry but not the arduino and magically, if the arduino is sending 0xB4, the raspberry receives just the half 0x5A

This shows that the Raspberry Pi is the problem. The additional zero bit can be explained by the clock stretching which the Raspberry Pi don't detect.

Make your interrupt handler as efficient as possible. This way you shorten the clock stretching time and get more data transferred.

Hi!

pylon: Make your interrupt handler as efficient as possible. This way you shorten the clock stretching time and get more data transferred.

I started a sketch from scratch with this code below and now the raspberry receives two bytes together perfectly.

So... something is wrong in my code. I think there is nothing wrong with the hardware.

What I do not understand in the code is the delay. No matter I add a 5 secs delay, raspberry receives the answer inmediately. Why?

void receiveData(int byteCount){
  
  PointerI2C = (byte)Wire.read(); // Global vble
  // delay(10);    // Test to check if a delay here affects the transmision
  if( Wire.available())
  {
    dataI2C = (byte)Wire.read();   // Global vble
  }

  buffer[0] = PointerI2C;  // Global vble
  buffer[1] = 0x75;
}

// callback for sending data
// https://forum.arduino.cc/index.php?topic=288713.0
void sendData(){
    // delay(1000);   // // Test to check if a delay here affects the transmision
    Wire.write( buffer, 2); 
}

So… something is wrong in my code. I think there is nothing wrong with the hardware.

Read about I2C clock stretching. The Arduino is using that feature of I2C to allow code execution to supply the data requested by the master. But the Raspberry Pi doesn’t supply that I2C feature (although it’s not an optional feature) but just ignores it. So if the code you supply for the requestEvent is using more time than the acknowledge bit lasts the Raspberry Pi won’t read the first bits sent by the Arduino.

What I do not understand in the code is the delay. No matter I add a 5 secs delay, raspberry receives the answer inmediately. Why?

You must not use delay() inside interrupt handlers (and the slave I2C functions are called inside interrupt handlers)!

Finally :

I have 4 circuits. All equal.

2 Work perfectly. No problem with them. 1 Works half half. If I try to receive a 2 bytes number, it fails, but usually works OK with 1 byte. 1 Doesn't work most of the time and I have continuous "read failed" errors.

I didn't think about this situation ( some circuits working but not others ), and I was doing tests with them indistinctly.

I resoldered the two wich fail with no result and I don't see any problem with them. I changed raspberries from one circuit to another and all the raspberries work on the two circuits wich are OK.

The wires are short, no noisy environment, the soldering seems to be OK, the arduino uploads program and does all the work but not the I2C part.

I really don't know what happens. I would say that they are on the limit of specs and sometimes work and sometimes doesn't work. The only thing I think it could affect is the voltage difference between Raspberry and Arduino.

I really don't know what happens. I would say that they are on the limit of specs and sometimes work and sometimes doesn't work. The only thing I think it could affect is the voltage difference between Raspberry and Arduino.

Take a look at the I2C signals with a scope. Does the voltage reach more than 3 volts and hold it for a few µs? If you don't have pull-ups on the I2C lines the internal pull-ups of the ATmega328 may have large enough differences to explain that behavior.

Attached, the I2C communication.

There are two transmissions. The transmission in big it is by using the program I developed for my needs and the one in small, it is a simple program. In the first case, it replies 0x0011 but there should be another value instead of 00.

It seems it is the arduino who can’t reply the second byte with a big code. But I don’t know why in some circuits it works and why in other not. Maybe it is on the limit.

There are two transmissions. The transmission in big it is by using the program I developed for my needs and the one in small, it is a simple program. In the first case, it replies 0x0011 but there should be another value instead of 00.

Post the program used for the first transmission!