locked
Waking up a I2C device RRS feed

  • Question

  • I'm trying to get temperature and humidity data from a sensor, but having problems implementing a special wake up procedure in Windows IoT.  

    Product: https://www.adafruit.com/products/1293

    Datasheet: https://cdn-shop.adafruit.com/datasheets/AM2315.pdf 

    To wake this sensor up, I need to send the I2C address, but the sensor will not respond with ACK. Page 14 of the datasheet has more detailed information, but in short I need to send the following data over I2C:

    I2C start signal -> 0xB8 -> wait (800 us - 3 ms) -> I2C stop signal

    Then i can do a regular ic2device.WriteRead() to get my data.

    is this possible with Windows IoT?

    Thursday, May 19, 2016 11:34 AM

Answers

  • I got an AM2315 and verified that the wakeup sequence works by stretching the clock. When the device is asleep and you send it a write command, it will NAK the slave address, then stretch the clock until it's done waking up. 

    i2ctesttool 0x5C; write {ff}

    You'll see SlaveAddressNotAcknowledged returned from the API, which is correct because the device does not acknowledge the slave address. Since you're expecting the device to NAK the slave address, use WritePartial() and ignore the return code:

    var buf = new byte[] {0};
    device.WritePartial(buf);

    Now that the device is woken up, send the commands to read the data register.

    Here's how I tested the device:

    Create a file named am2315.txt at c:\data on the device and give it the following contents:

    write {0}
    write {3 0 4}
    read 8

    SSH into the device and run (Get I2cTestTool from https://github.com/ms-iot/samples/tree/develop/I2cTestTool).

    I2cTestTool 0x5C < am2315.txt

    You should see output similar to the following:

    C:\Data>I2cTestTool.exe 0x5C < am2315.txt 
    Type 'help' for a list of commands
    > Slave address was not acknowledged
    > >  3 4 1 69 0 f9 e0 4a
    >

    'Slave address was not acknowledged' is from the wakeup sequence and is expected. The next write and read succeeded, and the returned data is the temperature and humidity data.

    Here's the rest of the sequence after the wakeup:

    

    Wednesday, June 22, 2016 10:43 PM

All replies

  • i have not tried it by myself but i would test with WritePartial(...) Member of Windows.Devices.I2c.I2cDevice

    Thursday, May 19, 2016 12:21 PM
  • I cant seem wake the unit using any read or write function. I think this is because when you initiate an I2CDevice object, you specify the 7 bit address, and some properties. So whenever you preform an read/write operation on that object, its going to handle the addressing automaticly and expect an ACK from the device before continuing with the read/write operation.

    The data im trying to send (0xB8) is the 7 bit address of the sensor, followed by a 0 (indicating a write operation), but since the sensor does not pull the line down (ACK) the operation is terminated. 

    From Sparkfuns I2C tutorial: If the receiving device does not pull the SDA line low before the 9th clock pulse, it can be inferred that the receiving device either did not receive the data or did not know how to parse the message. In that case, the exchange halts, and it’s up to the master of the system to decide how to proceed.

    As the "master of the system" I want to continue and send the I2C stop signal. But i cant find any way of doing that in Windows IoT


    • Edited by haavarddw Thursday, May 19, 2016 1:13 PM
    Thursday, May 19, 2016 1:12 PM
  • looks like you need to implement software i2c, at least to wake up that device
    Thursday, May 19, 2016 1:23 PM
  • You could take a look at the Adafruit samples to see if those might help...https://developer.microsoft.com/en-us/windows/iot/win10/adafruitMakerKit
    Thursday, May 19, 2016 10:31 PM
  • The Adafruit samples for Windows IoT only contains "regular" I2C interactions. There is no waking procedure in them. 

    Adafruit provides sample code for Arduino for this sensor, and the waking procedure there is simply this: 

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

    It is frustrating that such a simple implementation on Arduino is so hard on Windows IoT. Right now it seems like my options is either bitbang I2C protocol manually on two GPIO's, or buy an Arduino unit to handle the sensor communication, and then pull the data from that unit over to Windows IoT. 

    Friday, May 20, 2016 7:01 AM
  • Do you have a wiring diagram you could share?
    Tuesday, May 24, 2016 6:39 PM
  • I don't think this code is working the way the author intended.

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

    Wire.beginTransmission() doesn't actually initiate a hardware operation. beginTransmission() prepares an internal buffer for filling by write() when it is subsequently called. Here's the implementation of beginTransmission():

      void TwoWire::beginTransmission(uint8_t address)
    {
      // indicate that we are transmitting
      transmitting = 1;
      // set address of targeted slave
      txAddress = address;
      // reset tx buffer iterator vars
      txBufferIndex = 0;
      txBufferLength = 0;
    }

    The hardware isn't touched until endTransmission() is called. endTransmission() takes the buffer that was filled by the previous write() calls and passes it to twi_writeTo() which outputs the data over the wire.

    uint8_t TwoWire::endTransmission(uint8_t sendStop)
    {
      // transmit buffer (blocking)
      uint8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
      // reset tx buffer iterator vars
      txBufferIndex = 0;
      txBufferLength = 0;
      // indicate that we are done transmitting
      transmitting = 0;
      return ret;
    }

    So inserting a call to delay(2) between the call to beginTramission() and endTransmission() doesn't actually do anything.

    The following sentence from the AM2315 datasheet seems to suggest that the AM2315 does clock stretching:

    "if the host is a hardware I2C, you do not need to wait, to wait for hardware I2C automatically"

    If the AM2315 does clock stretching it would explain why the Arduino code above successfully wakes up the device without actually delaying between the address byte and the stop condition. If that's what's actually happening, the following Windows code should work for the wakeup sequence. It is equivalent other than that it sends a dummy byte during the write sequence. 

    var dis = await DeviceInformation.FindAllAsync(I2cDevice.GetDeviceSelector());
    var device = await I2cDevice.FromIdAsync(dis[0].Id, new I2cConnectionSettings(0x5C));
    var buf = new byte[] {0};
    device.WritePartial(buf);

    Can you try this and report back if it works?



    • Edited by Jordan Rhee Tuesday, May 24, 2016 10:30 PM grammar
    Tuesday, May 24, 2016 10:22 PM
  • Hi haavarddw,

    Have you been able to confirm Jordan's solution? Can you please report back?

    Sincere thanks,

    IoTGirl

    Wednesday, June 8, 2016 6:13 PM
  • I got an AM2315 and verified that the wakeup sequence works by stretching the clock. When the device is asleep and you send it a write command, it will NAK the slave address, then stretch the clock until it's done waking up. 

    i2ctesttool 0x5C; write {ff}

    You'll see SlaveAddressNotAcknowledged returned from the API, which is correct because the device does not acknowledge the slave address. Since you're expecting the device to NAK the slave address, use WritePartial() and ignore the return code:

    var buf = new byte[] {0};
    device.WritePartial(buf);

    Now that the device is woken up, send the commands to read the data register.

    Here's how I tested the device:

    Create a file named am2315.txt at c:\data on the device and give it the following contents:

    write {0}
    write {3 0 4}
    read 8

    SSH into the device and run (Get I2cTestTool from https://github.com/ms-iot/samples/tree/develop/I2cTestTool).

    I2cTestTool 0x5C < am2315.txt

    You should see output similar to the following:

    C:\Data>I2cTestTool.exe 0x5C < am2315.txt 
    Type 'help' for a list of commands
    > Slave address was not acknowledged
    > >  3 4 1 69 0 f9 e0 4a
    >

    'Slave address was not acknowledged' is from the wakeup sequence and is expected. The next write and read succeeded, and the returned data is the temperature and humidity data.

    Here's the rest of the sequence after the wakeup:

    

    Wednesday, June 22, 2016 10:43 PM