I am having a behavior I cannot explain while using arduino mega as a I2C slave for a raspberry pi master.
I am showing here an idealised program that shows the issue. I experience pretty much the same behavior in the real application (a keyboard firmware). What I am doing is the following:
- the arduino issues an interrupt on pin 23 at evert loop to inform the raspi that there's some data to be read.
- the raspi sends a request as master to the arduino.
- arduino receives the request in the Wire handler, and issues a reply of 32 bytes. I fill these 32 bytes with a uint8 counter just as a check.
- the cycle starts again.
This is the code for the raspi
import time
import RPi.GPIO as GPIO
import smbus
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
bus = smbus.SMBus(1)
address = 0x42
def callback(channel):
data = bus.read_i2c_block_data(address, 0x00, 32)
print(data)
GPIO.add_event_detect(4, GPIO.RISING, callback=callback)
while True:
time.sleep(1)
GPIO.cleanup()
and this is the code of the arduino
#include <Wire.h>
byte IRQ_PIN = 23;
volatile unsigned int counter;
void setup() {
Serial.begin(115200);
pinMode(IRQ_PIN, OUTPUT);
digitalWrite(IRQ_PIN, LOW);
Wire.begin(0x42);
Wire.onRequest(requestEvent);
Wire.onReceive(receiveData);
}
void signalMaster() {
noInterrupts();
irq();
interrupts();
}
void irq() {
digitalWrite(IRQ_PIN, HIGH);
digitalWrite(IRQ_PIN, LOW);
}
void requestEvent() {
byte buf[32];
counter++;
memset(buf, counter, 32*sizeof(byte));
Wire.write(buf, 32);
}
void receiveData(int byteCount){
while(Wire.available()) {
Wire.read();
}
}
void loop() {
signalMaster();
delay(1);
}
As you can see, the point is that I am banging the I2C really, really fast, and the loop is very tight and fast. This is the point of the exercise and the problem to solve arises from this.
Now, once in a while I get an occasional IO error with the raspi python code. This code occasionally fails once, and then everything resumes to normal, but once in a while, it completely breaks down and never recover.
I attached a logic analyser to it, and this is what I found. D3 is the interrupt pin. The others the I2C bus. In a normal transaction, I can see everything working properly (disregard the different content of the response, it was an earlier run)
and a zoom in to the master request and the reply:
When I have a permanent failure, however, the picture is very different
Zoom in:
This makes little sense to me. Why would it perform a data write, and who is writing 0x85FF... in my buffer?
Thanks
write_i2c_block_data
instead ofread_i2c_block_data
. It must be some bug at the Raspberry end of things, possibly in the py-smbus library.