Electron Wire chunked reads - Odd behaviour, 1 second delay

I’m running into a really strange issue when using the wire library in Electron and am looking for some help.

Long story short, I’m writing a simple library for interfacing to an external EEPROM over I2C. Pretty much have everything working but there is odd behavior I’m unable to explain. The high level function is shown below, it allows you to read an arbitrary number of bytes(<129; 2xpage size) from the EEPROM.


/* Limited to < 129 bytes */
boolean AT24_EEPROM::readData(uint32_t addr, uint8_t *read_data, uint8_t size)
{
  uint32_t current_page = addr%(EEPROM_PAGE_SIZE);

  /* Check if read is crossing page boundary */
  if(size > ((current_page+1)*EEPROM_PAGE_SIZE - addr))
  {
    uint8_t page_1_size = (current_page+1)*EEPROM_PAGE_SIZE - addr;  
    uint8_t page_2_size = size - page_1_size;  
    uint32_t addr_2 = (current_page+1)*EEPROM_PAGE_SIZE; 


    /* Read first page */
    readPageData(addr, read_data, page_1_size);
    /* Read second page */
    readPageData(addr_2, read_data + page_1_size, page_2_size);
  }
  else
  {
    /* Just read data, no need to cross pages */
    readPageData(addr, read_data, size);
  }
  
  return true;

}

This function basically is just to ensure we can read data in case it splits over pages(EEPROM specific).

The lower level function readPageData() is shown below.

boolean AT24_EEPROM::readPageData(uint32_t addr, uint8_t *read_data, uint8_t size)
{
  uint8_t tempsize = size;
  uint8_t read_ptr = 0;

  while(tempsize != 0)
  {

    /* Particle only allows for 32 bytes writes, including address */
    if(tempsize > PARTICLE_WIRE_LIMIT_READ)
    {
      /* Start */
      Wire.beginTransmission((uint8_t)_i2caddr);
      /* MSB */
      Wire.write((uint8_t) ((addr+read_ptr)>>8));
      /* LSB */
      Wire.write((uint8_t) (addr+read_ptr));
      /* Send restart  */
      Wire.endTransmission(false);

      /* Request data  */
      Wire.requestFrom((uint8_t)_i2caddr, PARTICLE_WIRE_LIMIT_READ);

      if(Wire.available())
      {
        Wire.readBytes((char *) (read_data + read_ptr), PARTICLE_WIRE_LIMIT_READ);
      }

      tempsize -= PARTICLE_WIRE_LIMIT_READ;
      read_ptr += PARTICLE_WIRE_LIMIT_READ;

    }
    else
    {

      /* Read rest of bytes */
      Wire.beginTransmission((uint8_t)_i2caddr);
      /* MSB */
      Wire.write((uint8_t) ((addr+read_ptr)>>8));
      /* LSB */
      Wire.write((uint8_t) (addr+read_ptr));
      /* Send restart  */
      Wire.endTransmission(false);

      /* Request data  */
      Wire.requestFrom((uint8_t)_i2caddr, size);

      if(Wire.available())
      {
        Wire.readBytes((char *) (read_data + read_ptr), size);
      }
      tempsize -= tempsize;
    }

  }

  return true;
}

Not perhaps the most efficient way(I realize that I can hack the particle library in the HAL to get 64-byte reads but that’s for another day) but it works fine.

Now here’s the tricky part. When I run this code, there is a 1 second delay between where I call the

    /* Read first page */
    readPageData(addr, read_data, page_1_size);
    /* Read second page */
    readPageData(addr_2, read_data + page_1_size, page_2_size);

There are no delays I put in code but the logic analyzer shows a clear difference between the two function calls here. I’m unable to track down any reason why this should happen

I’m running on an electron with v1.0.0 of the device OS(v1.0.1 also exhibits the same behavior)

Any clues? I already tried using SYSTEM_THREAD(ENABLED); but that didn’t change anything.

I guess you are running in a timeout with that instruction.
When you have read all full-32-byte chunks you'd only be able to read the remaining bytes (tempsize or size % 32) and not the entire size

Oh yes. As always a embarrassing coding bug. Fixed it to tempsize and it works now

Thank you for reading the code so quickly and the reply.

Cheers

1 Like