Shoud I set PM_DEVICE_ACTION_SUSPEND on I2C0 before sys_poweroff() ?

Dear Sir :

              We are now developing on nrf52840, with ncs v2.6.1 and zephyr.

We want to put I2C0 to PM_DEVICE_ACTION_SUSPEND before sys_poweroff().

Our code is below :

const struct device *const i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c0));

int rc = pm_device_action_run(i2c_dev, PM_DEVICE_ACTION_SUSPEND);

if (rc < 0) {
   printf("Could not suspend I2C (%d)\n", rc);
   return 0;
}

sys_poweroff();

But it always return "Could not suspend I2C (-120)".

Our I2C connects to an EEPROM and all read/write operations work fine.

We had search Nordic Q&A and someone said: only UART is not handled when using sys_poweroff(), others are handled automatically.

Does it mean that it is not necessary to put I2C to PM_DEVICE_ACTION_SUSPEND, becasue sys_poweroff will turn off I2C automatically?

Just run sys_poweroff() directly is enough or not?

Device tree overlay for reference :


&i2c0 {
compatible = "nordic,nrf-twim";
status = "okay";
clock-frequency = <100000>;
pinctrl-0 = <&i2c0_default>;
pinctrl-1 = <&i2c0_sleep>;
zephyr,concat-buf-size = <64>;
zephyr,flash-buf-max-size = <64>;

};

&pinctrl {
i2c0_default: i2c0_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
<NRF_PSEL(TWIM_SCL, 0, 27)>;
};
};

i2c0_sleep: i2c0_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
<NRF_PSEL(TWIM_SCL, 0, 27)>;
low-power-enable;
};
};
};

  • Hello,  I think the error code -120 you are receiving when trying to suspend the I2C device indicates that the suspend action failed. This might be due to various reasons such as incorrect configuration or conflicts with other operations.
    While some peripherals might be automatically handled during system shutdown, it's still recommended to properly manage the power state of peripherals like I2C to ensure data integrity and proper power management.

    I think you should test both scenarios - with and without explicitly suspending I2C - to see if there are any differences in power consumption or behavior during system shutdown.
    Code Modification:

    c
    const struct device *const i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c0));
    
    int rc = pm_device_state_set(i2c_dev, PM_DEVICE_STATE_SUSPEND);
    
    if (rc < 0) {
    printf("Could not suspend I2C (%d)\n", rc);
    return 0;
    }
    
    sys_poweroff();


    By explicitly suspending the I2C device before calling sys_poweroff(), you ensure that the I2C peripheral is properly handled before system shutdown. This aligns with best practices for power management and can help avoid potential issues related to data integrity or power consumption.

  • Hi! 

    Thanks for your suggestion. 

    We copy paste your code , but build failed. 

    Error Message : undefined reference to `pm_device_state_set'

    Mabye we need another include file, so we add

    #include <zephyr/pm/pm.h>

    but not works, still get error message undefined reference to `pm_device_state_set' when build code.

    VS code IDE intellisense list all functions starts with "pm_device_state", but only "pm_device_state_get" found, no "pm_device_state_set".

    And we find out that, set 

    CONFIG_PM_DEVICE_RUNTIME=y

    makes rc always return -120 in the following code.

    int rc = pm_device_action_run(i2c_dev, PM_DEVICE_ACTION_SUSPEND);

    After change "CONFIG_PM_DEVICE_RUNTIME=n " to "n", then return value rc become 0, and PM_DEVICE_ACTION_SUSPEND successed.

     

    Does set "CONFIG_PM_DEVICE_RUNTIME" to "n" has any disadvantage ?

  • Hello,

    It is recommended to suspend the I2C device before calling sys_poweroff(). 

    Did you add CONFIG_PM_DEVICE=y in prj.conf file?

    TWI shares registers and other resources with other peripherals that have the same ID as TWI.

    Therefore, you must disable all peripherals that have the same ID as TWI before TWI can be configured and used. Disabling a peripheral that has the same ID as TWI will not reset any of the registers that are shared with TWI. It is therefore important to configure all relevant TWI registers explicitly to secure that it operates correctly.

    You can check if SDA and SCL pins of I2C are not used for other peripherals.

  • Hi~

    Yes, I had add CONFIG_PM_DEVICE=y in prj.conf,

    At first, I add these lines:

    CONFIG_PM_DEVICE=y

    CONFIG_PM_DEVICE_RUNTIME=y

    CONFIG_POWEROFF=y

    Since "CONFIG_PM_DEVICE_RUNTIME=y" conflicts with PM_DEVICE_ACTION_SUSPEND, I remove it. 

    There are two relative setting left now:

    CONFIG_PM_DEVICE=y

    CONFIG_POWEROFF=y

    After remove "CONFIG_PM_DEVICE_RUNTIME", I2c can be.SUSPEND successfully.

    But I still don't know remove  CONFIG_PM_DEVICE_RUNTIME has any portential disadvantage?

  • Hello,

    ''But I still don't know remove CONFIG_PM_DEVICE_RUNTIME has any portential disadvantage?''

    This could potentially lead to conflicts if not managed properly.

    If you want to use PM_DEVICE_ACTION_SUSPEND, you have to set CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE as ''n''. It is enabled by default when CONFIG_PM_DEVICE_RUNTIME is enabled. You have disabled CONFIG_PM_DEVICE_RUNTIME. So, I think it's ok.

    you can read Device Runtime Power Management (nordicsemi.com) this documentation.

Related