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

  • 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