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
1 Answer 1
Use a logic level conversion IC. enter image description here
picture source http://msx-elektronika.pl/en/logic-level-converter
-
I bought two, I'll give it a try this weekendStefano Borini– Stefano Borini10/25/2019 10:38:30Commented Oct 25, 2019 at 10:38
-
-
I added the logic level converter but I still get the same kind of errors. I am unsure at this point what is the reason. I decided that for the time being I just use a traditional keyboard microcontroller, but it's definitely something I have to revisit. I am adding a picture of my setup later tonightStefano Borini– Stefano Borini11/04/2019 16:39:44Commented Nov 4, 2019 at 16:39
-
@StefanoBorini, ok. I collected the half of the bounty and two upvotes, so if you now or in the future want to put a bounty on a question, write a comment here and I will put a 50 points bounty on that question (but only if I can't write a useful answer to it :-) )11/04/2019 16:46:03Commented Nov 4, 2019 at 16:46
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.