Incorrectly sent data on I2C Arudino UNO
I am running some of the code below to make an I2C loopback interface on an Arduino UNO rev3. The Arduino board acts as a slave on the I2C bus, and after it has received a packet, it picks up a string that triggers a read operation by the master. The Arduino simply responds with the same data it received in the first place. The code shown below looks good:
#include <stdint.h>
#include <Wire.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#define I2C_DATA_SIZE 350
#define I2C_IRQ_PIN 13
typedef struct {
uint8_t data[I2C_DATA_SIZE];
uint16_t count;
uint16_t size;
bool ready;
} i2c_packet_t;
static i2c_packet_t i2c_pkt;
void setup() {
Serial.begin(115200); // start serial for output
Wire.begin(0x29); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent);
memset(&i2c_pkt, 0, sizeof(i2c_packet_t));
pinMode(I2C_IRQ_PIN, OUTPUT);
digitalWrite(I2C_IRQ_PIN, false);
/* Disable internall pullups */
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
// deactivate internal pull-ups for twi
// as per note from atmega8 manual pg167
cbi(PORTC, 4);
cbi(PORTC, 5);
#else
// deactivate internal pull-ups for twi
// as per note from atmega128 manual pg204
cbi(PORTD, 0);
cbi(PORTD, 1);
#endif
}
void loop() {
digitalWrite(I2C_IRQ_PIN, i2c_pkt.ready);
delay(100);
}
void requestEvent(void) {
digitalWrite(I2C_IRQ_PIN, false);
Wire.write(i2c_pkt.data, i2c_pkt.size);
memset(&i2c_pkt, 0, sizeof(i2c_packet_t));
}
void receiveEvent(int howMany) {
if (i2c_pkt.count == I2C_DATA_SIZE) {
Serial.println("I2C packet too large");
}
for (int i = 0; i < howMany; i++) {
i2c_pkt.data[i2c_pkt.count++] = Wire.read();
if (i2c_pkt.count == 2) {
i2c_pkt.size = (i2c_pkt.data[0] << 8) | i2c_pkt.data[1];
i2c_pkt.ready = true;
}
}
}
I know that Wire callbacks work on I2C interrupts, so I tried to move the bit Wire.write()
to loop()
. I just added a query in i2c_packet_t
, and now loop()
it requestEvent()
looks like this:
void loop() {
digitalWrite(I2C_IRQ_PIN, !i2c_pkt.request && i2c_pkt.ready);
if (i2c_pkt.request) {
if (i2c_pkt.ready) {
digitalWrite(I2C_IRQ_PIN, false);
Wire.write(i2c_pkt.data, i2c_pkt.size);
memset(&i2c_pkt, 0, sizeof(i2c_packet_t));
} else {
Serial.println("ERROR: I2C request but no data available");
}
}
}
void requestEvent(void) {
i2c_pkt.request = true;
}
For some reason, this solution doesn't work: the master always gets "0xFF". I am using the master north development board which acts as internal pull-up resistors on the SDA and SCL lines.
This really puzzled me, so any ideas are appreciated.
source to share
No one has answered this question yet
Check out similar questions: