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,

     

    tedhavelka said:
    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.

    If you use vscode and our plugins, you can also get a bit of free help by using the DeviceTree: Copy C identifier after marking the DT text.

    I included some members as reference in the screenshot:

     

    It makes it much easier to reference from DT -> C.

    tedhavelka said:
    I am not sure what mean NRF_GPIO_PIN_S0S1 and NRF_GPIO_PIN_NOSENSE

    These are fields "DRIVE" and "SENSE" in NRF_P0->PIN_CNF[] register:

    https://infocenter.nordicsemi.com/topic/ps_nrf9160/gpio.html?#register.PIN_CNF

    The function essentially sets the gpio into the reset-value.

    tedhavelka said:
    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?

    Yes, you are correct. In most cases, you have to include a "go to sleep" configuration, as well as an "active" configuration.

    For GPIOs connected to bus-peripherals (SPI/TWI/UART), they're configured when re-init'ing the function, but it is still good to include a step for setting the specific GPIOs as "active" again.

    tedhavelka said:
    Håkon thank you again for the detailed help!

    Always happy to help out, Ted! I hope you have a wonderful weekend, and please let me know if anything is unclear or unanswered!

     

    Kind regards,

    Håkon

  • Hello Håkon,

    Regarding this ticket and your guidance to look into the Nordic GPIO configuration API routines such as `nrf_gpio_cfg_default()`, I want to share a recent success.  With the info you provided I was able to include modules/hal/nordic/nrfx/hal/nrf_gpio.h in our ncs v1.6.1 based project, and re-enable our I2C sensor module in firmware, and still achieve a floor current of about 4.5uA on a custom board.

    In our project's primary config file prj.conf I restored the assignment:

       CONFIG_I2C=y

    In CMakeLists.txt I added:

       zephyr_include_directories(../modules/hal/nordic/nrfx/hal)

    And in a test routine which enters our custom board and Nordic SiP into deep sleep mode, then returns to active mode I added:

            uint32_t pin_number = 0;
            NRF_GPIO_Type * reg = 0;
            uint32_t cnf_scl = 0;
            uint32_t cnf_sda = 0;
    
    // Save pin configuration flags of SCL and SDA pins:
    
            pin_number = I2C1_SCL_PIN;
            reg = nrf_gpio_pin_port_decode(&pin_number);
            cnf_scl = reg->PIN_CNF[I2C1_SCL_PIN];
    
            pin_number = I2C1_SDA_PIN;
            reg = nrf_gpio_pin_port_decode(&pin_number);
            cnf_sda = reg->PIN_CNF[I2C1_SCL_PIN];
            
    // Disconnect nRF9160 internal pull-ups:
            
            nrf_gpio_cfg_default(I2C1_SCL_PIN);
            nrf_gpio_cfg_default(I2C1_SDA_PIN);

    In the middle of the test routine its code calls Zephyr RTOS k_msleep().  At this point we are able to measure the lowest current, what I see your team has dubbed "floor current".  To restore the configuration flags of SCL and SDA pins I added this code after the call to k_msleep().  This code depends on the assignment of conf' register values to the local variables `cnf_scl` and `cnf_sda`:

            reg->PIN_CNF[I2C1_SDA_PIN] = cnf_sda;
    
            pin_number = I2C1_SCL_PIN;
            reg = nrf_gpio_pin_port_decode(&pin_number);
            reg->PIN_CNF[I2C1_SCL_PIN] = cnf_scl;

    There are several useful APIs in Nordic library header file `nrf_gpio.h`, this header being found in ncs v1.6.1.  I did not however find an API routine to read and return the entire GPIO configuration register, hence I wrote the above code to capture those values explicitly.  My code is based on the way I could see nrf_gpio.h handle reads and write of pin config registers.

    This outside-of-driver configuration code seems to function correctly in our nRF9160, Zephyr 2.6.0 based project, to permit us to reach single microamp operation on demand and for arbitrary periods of time.  I had some challenge when I re-enabled Zephyr's in-tree I2C support.  That raised our idle time floor current from ~5uA to about ~67uA.

    It is my goal is to incorporate this solution with PSM or eDRX, whichever of these LTE power savings modes we can be granted by our network operators.  Getting either of these to be granted is yet a standing issue and problem for us.

    Håkon one last question for this ticket:  what is the proper status of this ticket today, given that you have provided a working answer and we validated this to work?  I don't think this ticket should appear as 'Waiting' or 'Open'.  From my viewpoint this ticket is 'Answered'.  Could you change the status as appropriate?  I think this will help when others search for answers.

    Thank you again for your help.  Good weekend to you Håkon!

    - Ted

  • Hi Ted,

     

    tedhavelka said:

    There are several useful APIs in Nordic library header file `nrf_gpio.h`, this header being found in ncs v1.6.1.  I did not however find an API routine to read and return the entire GPIO configuration register, hence I wrote the above code to capture those values explicitly.  My code is based on the way I could see nrf_gpio.h handle reads and write of pin config registers.

    This outside-of-driver configuration code seems to function correctly in our nRF9160, Zephyr 2.6.0 based project, to permit us to reach single microamp operation on demand and for arbitrary periods of time.  I had some challenge when I re-enabled Zephyr's in-tree I2C support.  That raised our idle time floor current from ~5uA to about ~67uA.

    It is my goal is to incorporate this solution with PSM or eDRX, whichever of these LTE power savings modes we can be granted by our network operators.  Getting either of these to be granted is yet a standing issue and problem for us.

    I'm glad to hear that the issue was worked around! Please let us know if you run into any issues or have any questions in the future! We're always here on stand-by!

     

    tedhavelka said:

    Håkon one last question for this ticket:  what is the proper status of this ticket today, given that you have provided a working answer and we validated this to work?  I don't think this ticket should appear as 'Waiting' or 'Open'.  From my viewpoint this ticket is 'Answered'.  Could you change the status as appropriate?  I think this will help when others search for answers.

    Thank you again for your help.  Good weekend to you Håkon!

    Thank you! I'm always happy to help out. I hope your weekend was great as well, Ted.

     

    I can close a thread or verify an answer directly, but I usually leave that to the owner of the thread, as my answers might not always answer the original question directly (I might misinterpret or not provide a complete answer, ie. need follow up answering).

    To change the state of a thread, you can mark a specific post as answered, by clicking this:

     

    In some cases, the "more" button disappears, and you have to refresh the page (shortcut: F5). This is an issue that we're looking into.

     

    Kind regards,

    Håkon

Related