Adafruit_Seesaw icon indicating copy to clipboard operation
Adafruit_Seesaw copied to clipboard

NeoPixel::clear() writes more than 32 Bytes to I2C

Open unvirtual opened this issue 3 years ago • 3 comments

  • List the steps to reproduce the problem below (if possible attach a sketch or copy the sketch code in too):

    • Call seesaw_NeoPixel.clear() with DEBUG_SERIAL enabled

    • Neopixel is not updated and the following error is printed: I2CDevice could not write such a large buffer

  • Root cause:

    • The reason seems to be, that Neopixel::clear() calls Adafruit_seesaw::write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF, writeBuf, 32) with a size of 32 bytes, while seesaw::write() then prepends a prefix of size prefix_len=2 bytes for a total of 34 bytes.
  • Fix:

    • write at most 30 bytes in Adafruit_seesaw::write() from Neopixel::clear(). (Interestingly the offset is correctly calculated to make space for 4 Bytes of prefix + offsets).

Caller:

void seesaw_NeoPixel::clear() {
  // Clear local pixel buffer
  memset(pixels, 0, numBytes);

  // Now clear the pixels on the seesaw
  uint8_t writeBuf[32];
  memset(writeBuf, 0, 32);
  for(uint8_t offset = 0; offset < numBytes; offset += 32-4) {
    writeBuf[0] = (offset >> 8);
    writeBuf[1] = offset;
    this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF, writeBuf, 32);
  }
}

Callee:

bool Adafruit_seesaw::write(uint8_t regHigh, uint8_t regLow,
                            uint8_t *buf = NULL, uint8_t num = 0) {
  uint8_t prefix[2];
  prefix[0] = (uint8_t)regHigh;
  prefix[1] = (uint8_t)regLow;

  if (_flow != -1)
    while (!::digitalRead(_flow))
      yield();

  if (!_i2c_dev->write(buf, num, true, prefix, 2)) {
    return false;
  }

  return true;
}

unvirtual avatar May 24 '21 12:05 unvirtual