This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

&i2c1 status="ok" configures internal pull-up or similar?

Hello Devzone,

Working with nRF9160 SICA B1A system in package, and Nordic's ncs v1.6.1 (Zephyr RTOS 2.6.0) I recently observe that a device tree board setting i2c instance 1 to status "ok" increases floor current of a 9160 based custom board by 15uA.  I have the LTE modem in flight mode ( AT+CFUN=4 ).  I can alternately have serial configured on or off via CONFIG_SERIAL=[y|n], so long as when it's enabled in Kconfig I call a Zephyr power management API to suspend on board UART devices.

Suspending the UART | SPI | I2C devices achieves the greatest current savings out of a handful of compile time config steps Nordic Semi engineers have shared and explained over the past six weeks.  With UART suspended, e.g. high speed clock turned off in nRF9160 ARM processor, floor current drops from ~600uA to about 22uA.  This is a great savings in power use!

Most steps I've taken this Q2 of 2022 have centered about Kconfig settings in file `prj.conf`, rather than questions of hardware or lower level firmware constructs.  What is now clear however is that I can only reach single microamp floor currents when I disable all I2C peripherals in our custom board's primary board file, written of course in DTS.  To reach single uA current use, in this board file I must say:

&i2c1 {
compatible = "nordic,nrf-twim";
// status = "okay";
status = "disabled";
sda-pin = <6>;
scl-pin = <5>;
clock-frequency = <I2C_BITRATE_FAST>;
};

What additional Zephyr or hardware abstraction layer code does the `status="ok"` qualifier cause to be compiled for an I2C peripheral?  From electrical tests of our custom board, we narrowed the extra 15uA of current down to the SDA and SCL GPIOs coming out of our board's nRF9160.  We surmise there are internal pull up resistors enabled when i2c1 is itself enabled in DTS.  Is this a correct understanding?

Whether or not pull ups are responsible for SDA and SCL bleeding current onto a powered down rail, is there a Zephyr or an nrf API which can adjust pull up configs on SCL, SDA pin pairs at run time?  We need our I2C peripheral configured for active use during the fraction of time our firmware is fully active.  We need to adjust these pins' configuration as we enter deep sleep mode.  And then again as firmware wakes from deep sleep mode.

Is there a Zephyr or "HAL correct" way to make these pin changes on demand?  Or are we looking at need to write code that pries under the hood and must carefully work with the vetted, more formal and correct framework of Zephyr and Nordic libraries?

Thanks ahead of time to any who can help!

- Ted

  • Hi Ted!

     

    Suspending the UART | SPI | I2C devices achieves the greatest current savings out of a handful of compile time config steps Nordic Semi engineers have shared and explained over the past six weeks.  With UART suspended, e.g. high speed clock turned off in nRF9160 ARM processor, floor current drops from ~600uA to about 22uA.  This is a great savings in power use!

    Thanks for linking to related threads, this helps me to understand which features/API's/etc you're using!

    What additional Zephyr or hardware abstraction layer code does the `status="ok"` qualifier cause to be compiled for an I2C peripheral?  From electrical tests of our custom board, we narrowed the extra 15uA of current down to the SDA and SCL GPIOs coming out of our board's nRF9160.  We surmise there are internal pull up resistors enabled when i2c1 is itself enabled in DTS.  Is this a correct understanding?

    15 uA sounds like a GPIO that is floating, causing excessive current consumption on either the nRF or the externally connected device.

    What happens when you suspend the device (using zephyr's power management API), is that this function is called:

    https://github.com/nrfconnect/sdk-zephyr/blob/v2.7.99-ncs1-1/drivers/i2c/i2c_nrfx_twim.c#L309

    which again uninit's the TWIM module and eventually also disconnects the GPIOs (disconnected pin input buffer, line floats):

    https://github.com/nrfconnect/sdk-hal_nordic/blob/v1.5.2/nrfx/drivers/src/nrfx_twim.c#L315-L316

     

    Disconnecting the GPIOs in this way is not a problem for the NRF itself, as it is also disconnects the internal pin buffer. However, if there's an external IC connected on those lines, the external ICs inputs will float, which can cause excessive current consumption in sleep.

    Do you have any external pull-resistors on the SDA/SCL lines?

     

    If not, you could try to use the internal pull-ups after suspending the peripheral:

    nrf_gpio_cfg_input(my_sda_pin, NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(my_scl_pin, NRF_GPIO_PIN_PULLUP);

     

    Kind regards,

    Håkon

  • Hi Håkon,

    To your questions:

    What happens when you suspend the device (using zephyr's power management API)...?

    Answer:  I do not find any instance of an API routine named static int twim_nrfx_pm_action(const . . . ) in the releases of ncs v1.6.1 and corresponding Zephyr v2.6.0.  I generally mention these versions at top of my Devzone posts, as features change across releases.  Even in past eight months I have observed significant changes and new feature introductions in Zephyr RTOS project alone.

    I am about to adjust (or create a copy of) our project and amend the top level ncs manifest file to point to the version of Nordic ncs which includes a fork of Zephyr 2.7.0.  I'm hoping the routines you share are there.  Please let me know if I need to migrate our work here further, to Zephyr 3.0.0 and corresponding newer release of ncs code base.

    Do you have any external pull-resistors on the SDA/SCL lines?

    Yes, we employ external pull up resistors in our custom board, but removed them a couple weeks ago as they were drawing several microamps of current.  With no external pull ups we see correct, integral functioning of our I2C bus and attached sensors, so this removal may be permanent for us.

    In other words, it looks qualitatively as though interal pull ups in the nRF9160 are sufficient to support I2C bus operating at 400kHz in our circuit design.  Given that our overall project / product is battery powered, and given that internal pull ups in our employed 9160 SiP are leaking several microamps current, we need dynamic access to enable and disable them.

    I suspect that we face this SDA, SCL originated leak current because our circuit permits me to turn off external-to-SiP power rails.  This puts I2C based sensors and other ICs at ground level on their VDD pins.  The only power rails I cannot turn off are those connected to nRF9160 VDD1, VDD2 and VDD_GPIO.  When I turn all external rails off, the only possible leak current sources are the GPIOs of the SiP.  I have those all configured as GPIO_DISCONNECTED, save SDA and SCL.  The reason for this is that I cannot reference these pins a second time in my project.  They're already in use by DTS and other code related to peripheral &i2c1.

    I tried to create DTS nodes in a scoped block whose first stanza and DTS qualifier is `compatible = "gpio-leds";`, but build time errors result from these SDA and SCL references.  These errors are related to Zephyr device macros not expanding correctly.

    All other GPIOs we're employing for digital signalling are in this `gpio-leds` DTS block of code, and they're functioning as expected.

    Can you say for sure which release of Nordic nrf SDK we should build against, to have your recommended device config APIs available?

    - Ted

  • Hi Ted,

     

    tedhavelka said:
    In other words, it looks qualitatively as though interal pull ups in the nRF9160 are sufficient to support I2C bus operating at 400kHz in our circuit design. 

    I do not think that this is relevant to the current consumption issue you're seeing, but I'm mentioning this as a side-note:

    The internal pull-ups on the nRF is too weak to drive a 400kHz I2C signal. They're fine for 100kHz.

     

    tedhavelka said:
    I suspect that we face this SDA, SCL originated leak current because our circuit permits me to turn off external-to-SiP power rails.

    Ah, thanks for updating with this information.

    Yes, when powering off all external sensors, it is very important that any pull-up resistors are disabled/removed to avoid back-powering the IC.

    tedhavelka said:
    I have those all configured as GPIO_DISCONNECTED, save SDA and SCL.  The reason for this is that I cannot reference these pins a second time in my project.  They're already in use by DTS and other code related to peripheral &i2c1.

    I am not sure how you have disconnected the gpio's, but I would recommend that you do that directly using the nrf_gpio.h helper functions.

    For instance:

    #include <hal/nrf_gpio.h>
    
    ...
    
    
    nrf_gpio_cfg_default(5);
    nrf_gpio_cfg_default(6);
     
    You could also swap the '5' and '6' with the device tree helper macros:
    nrf_gpio_cfg_default(DT_PROP(DT_NODELABEL(i2c1), sda_pin));
    nrf_gpio_cfg_default(DT_PROP(DT_NODELABEL(i2c1), scl_pin));

    tedhavelka said:
    Can you say for sure which release of Nordic nrf SDK we should build against, to have your recommended device config APIs available?

    The zephyr sdk for ncs v1.6.0 is this tag:

    https://github.com/nrfconnect/sdk-zephyr/blob/v2.6.0-rc1-ncs1/drivers/i2c/i2c_nrfx_twim.c#L287-L292

    Which is this specific hash of hal_nordic:

    https://github.com/nrfconnect/sdk-hal_nordic/blob/74b3b21f60aa3dc9a4364ffc28dbb47ad8b699a9/nrfx/drivers/src/nrfx_twim.c#L349-L353

    This shall also disconnect the GPIOs to avoid excessive current consumption.

     

    Kind regards,

    Håkon

  • Hi Håkon,

    Thank you for the important note on nRF9160 internal SDA and SCL pull-ups, and their limitation in supporting only bus speeds up to 100kHz. I'll speak with our team hardware lead and make sure they know this.  They may already be aware, but looks like we'll want to keep external pull-ups in the schematic design.

    To your question on my present manner to disconnect GPIOs at run time I am calling a Zephyr 2.6.0 API function as follows:

    rstatus = gpio_pin_configure(device_flash_cs, FLASH_CS_PIN, GPIO_DISCONNECTED);

    In the above code snippet device_flash_cs is of type 'static const struct device *'.

    Thank you also for sharing the Zephyr macro pairing (DT_PROP(DT_NODELABEL(x)).  While many of Zephyr's macro constructs are yet confusing to me, I try to use them whenever I can do so with justification and understanding.  These in your example will be better than "magic numbers", as I'll be able to change selected GPIOs in a board file, and not have to track down and update hard-coded pin numbers elsewhere.

    Ok searching in my ncs 1.6.1 workspace ( a Zephyr / west workspace ) I find API routine nrf_gpio_cfg_default() in `west_workspace/modules/hal/nordic/nrfx/hal/nrf_gpio.h`.  It's possible also that I have the API routines you mentioned in your first reply to this ticket.  I had searched `[west_workspace]/zephyr` and `[west_workspace]/nrf` but I had not searched for APIs in the `modules` sub-dir.

    Just as a mention, I am working through some symbol and API signature changes to build my team's firmware project against ncs 1.9.1.  We started with and are using ncs 1.6.1, here is our project `west` manifest file:

    manifest:
      remotes:
        - name: nrfconnect
          url-base: https://github.com/nrfconnect
      projects:
        - name: nrf 
          repo-path: sdk-nrf
          remote: nrfconnect
          revision: v1.6.1
          import: true 
      self:
        # This repository should be cloned to 
        path: aws-iot-stand-alone
    

    We are about eight months into nRF9160 development and that far along time wise on the ncs + Zephyr + west and friends learning curve.  It seems reasonable to at least test project builds against new release tags of the SDK.  There were some pretty big changes in Zephyr from its 2.4.x releases to 2.5.x, so I feel fortunate we hopped on the train at an ncs release that forked Zephyr Project 2.6.0.

    I can see also that API routine nrf_gpio_cfg_default() appears to set pin configuration to minimize power consumption.  From modules/hal/nordic/nrfx/hal/nrf_gpio.h I read:

    620 NRF_STATIC_INLINE void nrf_gpio_cfg_default(uint32_t pin_number)
    621 {
    622     nrf_gpio_cfg(
    623         pin_number,
    624         NRF_GPIO_PIN_DIR_INPUT,
    625         NRF_GPIO_PIN_INPUT_DISCONNECT,
    626         NRF_GPIO_PIN_NOPULL,
    627         NRF_GPIO_PIN_S0S1,
    628         NRF_GPIO_PIN_NOSENSE);
    629 }
    

    I am not sure what mean NRF_GPIO_PIN_S0S1 and NRF_GPIO_PIN_NOSENSE, but the other configuration symbols are clear.  And this API and its symbols are in `modules/hal/...` because the RTOS must remain target processor agnostic, correct?

    From your example line `nrf_gpio_cfg_default(DT_PROP(DT_NODELABEL(i2c1), scl_pin));` it looks like we have the specific nRF9160 HAL API call which would permit us to manually disconnect I2C pins, during a power down sequence.  We could then reconnect and reconfigure them on power up.  This method would not respect Zephyr's device encapsulation, but may be required because we are removing power from all rails external to the SiP.  Is this a fair high level understanding?

    Håkon thank you again for the detailed help!

    - Ted

  • Hi again Håkon,

    To confirm yes, I do indeed find nrf_gpio_cfg_input() in the Nordic nrf_gpio.h header file of ncs v1.6.1.  My mistake for not searching the SDK directory named 'modules'!

    - Ted

Related