Trying to get an I2C (AM2315) working with Wire

Hi,

Been Googling and haven’t found an answer. I have 2 I2C devices.

Then I have the AM2315. Using the Wire class, it does not work:
This code: https://github.com/adafruit/Adafruit_AM2315/blob/master/Adafruit_AM2315.cpp

Other info:

  • Wiring is verified, it’s all good. Pullup resistors in place, etc…
  • Only 1 device on the I2c bus while trying to debug this.
  • “cc3000_patch_version”: “1.29”

This is the very first thing I do and it fails.
boolean Adafruit_AM2315::readData(void) {
uint8_t reply[10];

// Wake up the sensor
Wire.beginTransmission(AM2315_I2CADDR);
delay(2);
end1 = Wire.endTransmission();

endTransmission returns 4 which means: other error.

If anyone has ideas or debugging ideas… :smiley:

Thanks, Matt.

Ooops, for clarity this is startup (forgot to show the .begin call)

Wire.begin();
uint8_t reply[10];

// Wake up the sensor
Wire.beginTransmission(AM2315_I2CADDR); // addr = 0x5C
delay(2);
// Returns 4 - which sounds like a timeout from reading the firmware code.
end1 = Wire.endTransmission();

I assume you have the SHT1x on different pins to the normal I2C lines and the AM2315 on the real I2C bus? The SHT1x is not true I2C. Putting it and a real I2C on the same pins means the 2 drivers will conflict with each other.

2 Likes

To simply debugging, the only thing connected to the spark for debugging this is the AM2315.

Since the AM2315 comes with sample code from AdaFruit for the Arduino - and I assume works on the Arduino using the Wire object. I’m going to assume there is some subtle difference between Arduino and Sparks implementation of Wire – so I’ll start digging there.

Thanks for the tip on the SHT1X - when I put both devices on the spark I’ll make sure to pin-locate properly.

m.

Did you ever get your AM2315 to communicate with the core?

I can’t seem to get it to even respond to a wake command.
I know my AM2315 is good, I can read it on an Arduino with pullups. I know the I2C bus is working correctly on my core because I can read other I2C sensors.

I have the AM2315 hooked up to the USB (Vin) Voltage so its Vcc > 3.5V.

I even have the clock speed set to CLOCK_SPEED_100KHZ.

I have a quick script to scan the I2C addresses, hitting every address twice with a 10uS delay just to be sure I give the AM2315 a chance to wake up. Other devices are detected but the AM2315 never responds.

Hi, no I was never able to get the AM2315 working on Spark. Just like you it works great on Arduino so I know it’s working. It would never respond on Spark.

If the guys @ Spark are listening, I’d be happy to send you my AM2315 and let you figure it out :smile:

m.

@mattgundersen, can you post your code just in case I can spot something? :smile:

Sure. It’s the AdaFruit example with no changes.

@mattgundersen, for scanning, have you seen the code in this topic?

I don’t see any reason why the AM2315 should not work. Have you tried having ONLY the AM2315 on the I2C bus? You are pulling up th 5V or 3.3V? Do you have a logic analyzer by any chance?

When you say it does not respond to the wake command, how did you observe that? Can you give more details? :smile:

I agree, the AM2315 should work. I tried 3.3V and 5V. No logic analyzer. Only tried on the I2C bus.

re: How did I observe the wake command not working? I copied the Adafruit AM2315 code into my ino file so I can capture things to local variables and printf to serial console. I changed the code in Adafruit_AM2315::readData to capture the return values of Write.endTransmission calls and Wire.write calls. Then I printed those to serial in loop().

At some point I started looking at the firmware code to Arduino’s Wire vs Spark’s Wire code and began to suspect timing or behavior differences between the two.

Snippets

// Local variables I added for use of capturing/debugging in readData
uint8_t sreply[10];
bool fail1 = false;
bool fail2 = false;
uint8_t end1 = 0;
uint8_t end2 = 0;
uint8_t write1 = 0;
uint8_t write2 = 0;
uint8_t write3 = 0;
uint8_t request1 = 0;

boolean Adafruit_AM2315::readData(void) {
  uint8_t reply[10];
  
  // Wake up the sensor
  Wire.beginTransmission(AM2315_I2CADDR);
  delay(2);
  end1 = Wire.endTransmission();

  // OK lets ready!
  Wire.beginTransmission(AM2315_I2CADDR);
  write1 = Wire.write(AM2315_READREG);
  write2 = Wire.write(0x00);  // start at address 0x0
  write3 = Wire.write(4);  // request 4 bytes data
  end2 = Wire.endTransmission();
  
  delay(10); // add delay between request and actual read!

  request1 = Wire.requestFrom(AM2315_I2CADDR, 8);
  for (uint8_t i=0; i<8; i++) {
    reply[i] = Wire.read();
    sreply[i] = reply[i];
  }
  
  if (reply[0] != AM2315_READREG) {
      fail1 = true;
      return false;
  }
  if (reply[1] != 4) {
      fail2 = true;
      return false; // bytes req'd
  }

  // everything forward is the same.

The results are:

/**
    end1: 4
  write1: 1
  write2: 1
  write3: 1
    end2: 4
request1: 0

0: success
1: data too long to fit in transmit buffer
2: received NACK on transmit of address
3: received NACK on transmit of data
4: other error

**/

Put this in loop or setup after calling am2315.begin

        if(fail1) Serial.println("BAD: reply != AM2315_READREG");
        if(fail2) Serial.println("BAD: Bytes req'd != 4");

        Serial.println("Bytes");
        for (uint8_t i=0; i<8; i++) {
            Serial.println(sreply[i], HEX);
        }

        Serial.print("    end1: "); Serial.println(end1, HEX);
        Serial.print("  write1: "); Serial.println(write1, HEX);
        Serial.print("  write2: "); Serial.println(write2, HEX);
        Serial.print("  write3: "); Serial.println(write3, HEX);
        Serial.print("    end2: "); Serial.println(end2, HEX);
        Serial.print("request1: "); Serial.println(request1, HEX);

No, it won't work on the Spark Core. Been there, done that. The AM2315 shares the same peculiar timing requirements as the AM2321 and like. If you take a deep dive into Section 7.2.4 I2C Communication Timing in the AdaFruit manual, you will find that the Spark Core Wire firmware will not be sufficient to meet the AM2315 requirements.

I have then followed the manufacturer's example and wrote a library for this. It was originally for the AM2321 but it should also work with the AM2315. You could give it a try and let me know if it works on your device. Note that I have hardcoded it to use D2 and D3 for the custom I2C and I don't think my code would allow you to share with other I2C devices on the Spark Core.

1 Like

Interesting, that the Wire library in the Spark Core doesn’t work for the AM2315 the same way as on an Atmel . I haven’t yet started wiring my AM2315 up to my Spark Core yet, but I did previously wire it up to an Electric Imp and it’s been running for over a year. The Electric Imp is also driven by an ARM Cortex M3 like the Spark Core, but does not have an Arduino-like API. I suspect, however, that since the Imp delegates I2C to the M3’s hardware, there may be more similarities in the way that I2C works on these two devices, compared to an actual Atmel driven Arduino.

When I started with the Electric Imp, I tried to port the Arduino code over, but couldn’t get the device to function that way.

Then, I stumbled across this posting:

https://forums.electricimp.com/discussion/1617/am2315

wIth code that did work for AM2315 using the Imp’s I2C stack.

Most of the code is the same, what looks like a direct port from C to the Squirrel language that the Imp uses, but there are a couple of key differences in the way the initialization sequence works.

The first is that the address of the device is bit shifted by 1 place (0x5C << 1), but may just be a difference in the way the Imp API works. The Wire library probably does this internally. In 7.2.4 of the datasheet, this seems to be why they send 0xB8 in the example transmission, since 0x5C << 1 = 0xB8.

Then, the initialization sequence is different. It sends a 0x00 to wake up the bus (without a delay) rather than doing an empty write (which I think is that the Wire.beginTransmission() followed immediate by Wire.endTransmission() will do). 7.2.4 of the data sheet cryptically says “if the host is a hardware I2C, you do not need to wait, to wait for hardware I2C automatically”.

After this, the code then sends 0x03 0x00 0x04 the same as the Arduino code, but waits 150ms rather than 10ms. 7.2.4 of the datasheet indicates a wait time of 1.5ms, so this may not be significant.

The remainder of the reply processing is the same.

Any progress with this? I would like to use the am2315 in my particle electron project but all roads lead to a dead end with the photon, I assume the same for the electron?

Since this is an old thread the info here might be well outdated.
There have been several bugfixes and system versions released since.

What have you tried and what doesn’t work.

1 Like

I have not purchased the sensor yet, i came across this thread while researching its implementation.