felias-fogg / SoftI2CMaster

Software I2C Arduino library
GNU General Public License v3.0
368 stars 100 forks source link

Read not acknowledged #39

Closed Zitt closed 5 years ago

Zitt commented 5 years ago

Running Arduino 1.8.0 on a custom design based on ATmega32u2 using HoodLoader2 as a boot loader. Board has 32u2 configured with 16MHz external XTAL and communicates via CDC Serial. Trying to interface to two different instances of I2C IS31FL3196As … one AD tied high; the other AD tied low.

Read of the IS31FL3196As (all registers) never return values due to read after register isn't acknowledged. My Oscope seems to confirm that the Reads aren't being acknowledged. The ino returns: I2C device didn't ACK XX read during read attempts.

Have defined the following:

#define SCL_PIN 1 /*D14 = PD1*/
#define SCL_PORT PORTD
#define SDA_PIN 3
#define SDA_PORT PORTD /*D16 = PD3*/
#define I2C_HARDWARE 0
#define I2C_SLOWMODE 1
#include <SoftI2CMaster.h>

#define SDB_I2C            17 /*D17 = PD4*/
#define HUB_I2C_ADR (0b1100100 << 1)
#define RNG_I2C_ADR (0b1100111 << 1)

with the I2C_SLOWMODE defined to facilitate early debug. Writes to the 3196As seem to pass; but without a functional read; I can't "confirm" they operate properly.

Implementation of the Read function is as follows:

byte i2c_ByteRead( byte addr, byte reg, bool last = true, uint16_t waitsdb_us = 8333, bool *error = NULL ) {
  DEBUGPRINTF( F("i2c_ByteRead(%02x,%02x,%d,%x,%p)\r\n"),addr, reg, last, waitsdb_us, error ); 
  if (!i2c_start(addr|I2C_WRITE)) { // start transfer
        if (error != NULL)  *error = true;
        DEBUGPRINTF( F("I2C device busy\r\n") );
        pinMode(SDB_I2C, INPUT_PULLUP);
        return 0;
   }
   if ( !i2c_write(reg) ) { // send memory address
        if (error != NULL)  *error = true;
        i2c_stop(); // send stop condition 
        DEBUGPRINTF( F("I2C device didn't ACK %02x write\r\n"), reg );
        pinMode(SDB_I2C, INPUT_PULLUP);
        return 0;
   }
   if ( !i2c_rep_start(addr|I2C_READ) ) { // restart for reading
        if (error != NULL)  *error = true;
        i2c_stop(); // send stop condition 
        DEBUGPRINTF( F("I2C device didn't ACK %02x read\r\n"), reg );        
        pinMode(SDB_I2C, INPUT_PULLUP);
        return 0;
   }
   byte retval = i2c_read(last); // read one byte and send NAK to terminate
   if (last) i2c_stop(); // send stop condition  

   pinMode(SDB_I2C, INPUT_PULLUP);
   if (error != NULL) *error = false;
   delayMicroseconds( 10 ); 
   return retval;
}

which basically lifted from the readme.md doc but with added fault tolerance. Calling the above function with this example: tbyte = i2c_ByteRead( HUB_I2C_ADR, 0x00, true, 8333, &gotError);

Are there any known issues with the current tip w/ regards to I2C reads? Any further debug you might suggest to help isolate the failure? I'm wondering if my implementation isn't release the sda line soon enough for the 3196A to acknowledge.

Zitt commented 5 years ago

I captured what looks like a good write with acknowledges: https://www.flickr.com/photos/52968060@N00/39936919373/sizes/l

And the failed Reads that don't have acknowledges: https://www.flickr.com/photos/52968060@N00/39936916883/sizes/l

Suggestions?

Zitt commented 5 years ago

Nevermind. RTFM. page 7 of the datasheet was clear:

The IS31FL3196A has a 7-bit slave address (A7:A1), followed by the R/W bit, A0. Since IS31FL3196A only supports write operations, A0 must always be “0”.

Doh!