Skip to main content

Switching ATtiny core

I was not getting reliable I2C communication between the D1 mini and the ATtiny85, starting with TinyWireS, then moving on to the more developed TinyWire. I would send out 5 bytes from the D1 mini, then try to get 16 bytes back. It will start off well, but a few hours later, something will break and the D1 mini will start getting 0xFFs from the ATtiny85.

Then I found "ATtinyCore" by Spence Konde (V1.1.5), which appears to be a more mature ATtiny core compared to the "attiny" core by David Mellis (V1.0.2). It has integrated I2C support that manifests as the familiar "Wire" library. The installation instructions are here. I did a manual upgrade to the latest git version as some I2C issues have been fixed in the V1.1.6 milestone but have not been officially released. As recommended by the instructions, I bumped up the Arduino version to 1.8.6.

Finally, happy to see reliable I2C communication between the 2 components! The communication has been going non-stop for 2 days now, with 1-minute interval between the send/receiving of messages.

From the D1 mini end, the I2C master code is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  byte outbuf[5];
  outbuf[0] = random(128); for (int i=1; i<sizeof(outbuf); i++) outbuf[i] = outbuf[0] + (i*2);
  Wire.beginTransmission(I2C_SLAVE_ADDR);
  int rc = Wire.write(outbuf, sizeof(outbuf));
  Wire.endTransmission();
  debug("Wire.write (%d): %X %X %X %X %X", rc, outbuf[0], outbuf[1], outbuf[2], outbuf[3], outbuf[4]);

  byte inbuf[15];
  Wire.requestFrom(I2C_SLAVE_ADDR, 15);
  Wire.readBytes(inbuf, 15);
  Serial.print("Wire.readBytes: ");
  for (int i=0; i<sizeof(inbuf); i++) { Serial.print(inbuf[i], HEX); Serial.print(' '); } Serial.println(' ');

From the ATtiny85, the corresponding I2C code is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
volatile byte msg[5], out[15];

void requestEvent() {
  Wire.write(out, 15);
}

void receiveEvent(uint8_t numbytes) {
  if (numbytes > sizeof(msg)) return;
  int idx = 0;
  while(idx < numbytes) {
    if (Wire.available()) 
      msg[idx++] = Wire.read();
  }
  out[0] = numbytes;
  for (int i=1; i<sizeof(out); i++) out[i] = msg[(i-1) % numbytes];
}  

For testing purposes, the D1 mini sends out 5 random bytes, and the ATtiny85 basically copies the received message into the outgoing buffer, with the first byte being the length of the received message (should be always '5').

I found that the maximum number of bytes that can be sent by each requestEvent() is 15 (one less the default value of TWI_RX_BUFFER_SIZE in Wire\src\USI_TWI_Slave\USI_TWI_Slave.h. That could be increased to 32, or 64 (powers of 2 up to 256, as noted in the comment). A workaround will be for the master to make multiple requestFrom() calls, and for the slave to keep track of which block of 15 bytes to send out in requestEvent().

ESPCLOCK1 / ESPCLOCK2 / ESPCLOCK3 / ESPCLOCK4

Comments