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.

+3


source to share





All Articles