nRF 9160-DK i2c sleep current consumption

Hello!

I've been playing around with nRF9160DK for a while now and so far the device seems great and the vast majority of available resources for development is really great. But I've stumbled upon an issue for the last couple of days and can't find what might be the reason. 
The issue:
I decided to update the existing cellular UDP sample code so that it reads data from an actual sensor and sends them to the desired endpoint. I enable i2c, added the devicetree node and got the sensor working. The reading was held in another work task independent from UDP upload task. So far so good. Then I checked the current consumption and saw that the current in PSM jumped from ~4uA to ~370 uA - all clear, the i2c driver is not sleeping and it added the current draw. Spent some time figuring out the correct way to put peripheral to sleep but I got it working. Calling pm_device_action_run(DEVICE_DT_GET(DT_NODELABEL(i2c2)), PM_DEVICE_ACTION_SUSPEND); and pm_device_action_run(DEVICE_DT_GET(DT_NODELABEL(i2c2)), PM_DEVICE_ACTION_RESUME); returns success and seems like the peripheral should be sleeping, but when I checked nRF9160 current profile, I saw the same ~370uA in PSM mode - not the result I was looking for. I spent a lot of time debugging this issue but nothing helped and then I decided to try the same Power manager functions on uart0 (the serial output peripheral) and everything worked just fine - in PSM I saw the same ~4uA and in active mode the serial output was printing to console meaning that module was indeed in low power mode.

Now comes the question what is wrong with i2c, why I did not see any current drop when i2c is in sleep mode? Could it be a hardware issue? Currently I don't have second DK but its ordered and on its way. I'll test this whenever I get my hands on it. But maybe its something else I missed? 

proj.conf:

#
# Copyright (c) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

# General config
CONFIG_PICOLIBC_IO_FLOAT=y
CONFIG_NCS_SAMPLES_DEFAULTS=y
CONFIG_SERIAL=y

# Network
CONFIG_NETWORKING=y
CONFIG_NET_NATIVE=n
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_OFFLOAD=y

# LTE link control
CONFIG_LTE_LINK_CONTROL=y

# Modem library
CONFIG_NRF_MODEM_LIB=y

# Heap and stacks
CONFIG_HEAP_MEM_POOL_SIZE=1024
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

# LTE parameters
## Network Mode / LTE category
CONFIG_LTE_NETWORK_MODE_LTE_M=y

## PSM
CONFIG_UDP_PSM_ENABLE=y
CONFIG_LTE_PSM_REQ_RPTAU="00100001"
CONFIG_LTE_PSM_REQ_RAT="00000000"

## eDRX
CONFIG_UDP_EDRX_ENABLE=y
CONFIG_LTE_EDRX_REQ_VALUE_LTE_M="1001"

## RAI
CONFIG_UDP_RAI_ENABLE=y
CONFIG_UDP_DATA_UPLOAD_FREQUENCY_SECONDS=10

## Additional peripherals
CONFIG_I2C=y
CONFIG_PM_DEVICE=y

function suspending and resuming i2c:

void read_sensor_measurements() {
  /* Function variables */ 
  static bool firstLoop = true;
  int error;
  int numBytes = 7;
  uint8_t data[numBytes];
  enum pm_device_state state;
  if(!firstLoop) //skip first iteration
  {
    error = pm_device_action_run(DEVICE_DT_GET(DT_NODELABEL(i2c2)), PM_DEVICE_ACTION_RESUME);
    if(error !=0)
    {
      printf("i2c RESUME failed %d\n", error);
    }
    pm_device_state_get(DEVICE_DT_GET(DT_NODELABEL(i2c2)), &state);
    printf("Current state after resume: %d\n", state);
  }

  /* Wakeup */
  if(!(_wakeup())) {
    printf("Failed to wake up sensor.\n");
    return;
  }

  /* Request values */ 
  error = i2c_write_dt(&dev_i2c, &ERROR_STATUS, 1);
  error = i2c_read_dt(&dev_i2c, data, numBytes);
  if(error != 0 ) {  
    printf("Failed to read values. Error code: %d\n", error);
    return;
  }

  /* Read values */
  /* Error status */
  uint8_t eStatus = data[0];

  /* Reserved */
  uint8_t byteHi = data[1];
  uint8_t byteLo = data[2];

  byteHi = data[3];
  byteLo = data[4];

  /* CO2 value */
  byteHi = data[5];
  byteLo = data[6];
  uint16_t co2Val = ((int16_t)(int8_t) byteHi << 8) | (uint16_t)byteLo;
  firstLoop = false;
 
  error = pm_device_action_run(DEVICE_DT_GET(DT_NODELABEL(i2c2)), PM_DEVICE_ACTION_SUSPEND);
  if(error != 0 ) {  
    printf("Failed to suspend i2c %d\n", error);
  }

  k_sleep(K_MSEC(500));
  pm_device_state_get(DEVICE_DT_GET(DT_NODELABEL(i2c2)), &state);

  printf("Current state after suspend: %d\n", state);

  printf("CO2: %d ppm\n", co2Val);

  printf("Error Status: 0x%X\n", eStatus);
}

devicetree overlay file (copied from BME680 sample so some comments might be irrelevant):

/*
 * Copyright (c) 2020, Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

 &i2c2 {
  compatible = "nordic,nrf-twim";
  // status = "okay";
  clock-frequency = <I2C_BITRATE_STANDARD>;  

  /* The I2C address could be one of two, here 0x77 is assumed */
  sensor: sensor@68 {
    compatible = "i2c-device";
    status = "okay";
    reg = <0x68>;
  };
};

And here is the .zip of project 2134.udp_sample_i2c.zip

In case you need anything else to help me resolve this issue let me know.

Regards,

Andris

Parents
  • Now comes the question what is wrong with i2c, why I did not see any current drop when i2c is in sleep mode?

    Here are three thoughts to begin with:

    1) It could be that a TWI clock request is not released. In that case one will have to look at the driver implementation.

    2) Another cause could be the GPIO configuration, for example that there is a pull-up on some of the lines and that it is pulled down externally. In order to investigate this further you could read out the GPIO registers to see if everything is as expected(nrfjprog --memrd <address>). TWI typically has a pull-up on SDA and SCL, and perhaps this is removed when suspending. This could lead to floating lines and a target(slave) drawing excessive current.

    3) A third scenario with high current consumption could be if the GPIOs are set to LOW in suspend, while at the same time there is an external pull-up. Current will then flow through the resistors.

  • So I did some investigation and it turns out everything works okay. There were series of my own mistakes which led me to think that there is something wrong with HW. 
    First about the previous response. As I said, I tried to test I2C sleep without I2C lines connected to slave device - there was a bug in code and the i2c peripheral wasn't suspended, that is why I saw the same ~370uA.

    About the original issue. The slave device was powered from nRF9160-DK (5V and GND on P1). It turns out that 5V is 0V when powered externally and I only noticed this when I connected Salae to SDA and SCL and did not understand why the lines are pulled low instead of high. I connected the + to VDD and now everything works as expected. I guess the slave device was draining SDA and SCL trying to source itself while on VIN there were no voltage.

    It was my fault that I didn't check DK schematic were it is obvious that 5V is only available when USB is connected. Anyway, thank you for your help, the problem is solved now and I can move on with next steps! 

Reply
  • So I did some investigation and it turns out everything works okay. There were series of my own mistakes which led me to think that there is something wrong with HW. 
    First about the previous response. As I said, I tried to test I2C sleep without I2C lines connected to slave device - there was a bug in code and the i2c peripheral wasn't suspended, that is why I saw the same ~370uA.

    About the original issue. The slave device was powered from nRF9160-DK (5V and GND on P1). It turns out that 5V is 0V when powered externally and I only noticed this when I connected Salae to SDA and SCL and did not understand why the lines are pulled low instead of high. I connected the + to VDD and now everything works as expected. I guess the slave device was draining SDA and SCL trying to source itself while on VIN there were no voltage.

    It was my fault that I didn't check DK schematic were it is obvious that 5V is only available when USB is connected. Anyway, thank you for your help, the problem is solved now and I can move on with next steps! 

Children
  • Hi Andris,

    Great that you found the cause. Thank you very much for posting the solution, this is helpful to others as the DK is flexible but complex. 

    5V comes directly from VBUS. If you short SB40 in the image below, the voltage will then bypass the diode, going back to 5V5. This will let the External supply net also go out to 5V on J1. (In case you are not using nRF9160 DK Revision 1.1.0: Double check the solder bridge number in the schematics as this potentially could vary from revision to revision.)

  • Hi Håkon,

    Okay, thanks for the heads up. For now the VDD is good enough! 

    I did some investigation about why I saw the 370uA when sensor wasn't working and i2c should be suspended. Without digging deep in code my assumption is that if one of I2C line is pulled low (in my case when 5V was actually 0, both SDA and SCL was pulled low) the I2C peripheral wasn't actually suspended. The driver probably thinks that slave is pulling the line low so it can't suspend the peripheral when there is ongoing communication.

    Anyway, this issue is solved now and hope this can help someone in future! Thanks for the assistance Håkon!

Related