how to close spi in low power state? (52840)

Dear, I'm developing on nordic 52840 with ncs2.6.1. 

I found that the Current will reach to 600+uA in k_sleep state by enable SPI in device_tree and if i disable the spi, the current will increase to 100uA.

I have try to enable CONFIG_PM_DEVICE(As far as i know that CONFIG_PM is not support by nrf52840 in ncs2.6.1) and call the function 

pm_device_action_run(spi1_dev, PM_DEVICE_ACTION_SUSPEND)
before k_sleep, but there is no difference in the results。
here is my dts config:(i have removed spi0 which was used by twi0)
&spi1 {
	compatible = "nordic,nrf-spim";
	status = "okay";
	pinctrl-0 = <&spi1_default>;
	pinctrl-1 = <&spi1_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>, <&gpio0 17 GPIO_ACTIVE_LOW>;
	imu: imu@0 {
		compatible = "imu";
		lable = "imu";
		reg = <0>;
	};
	sdcard: sdcard@1 {
		compatible = "sdcard";
		reg = <1>;
		lable = "sdcard";
	};

	status = "okay";
};
and the main() function is just call a k_sleep without doing anything else.
  • In your application, before calling k_sleep(), explicitly disable the SPI interface using the spi_release() function.
    This will ensure that the SPI interface is not active and consuming power during the low-power state.
    Here's an example of how you can do this:

    #include <device.h>
    #include <drivers/spi.h>

    void main(void)
    {
    const struct device *spi_dev = DEVICE_DT_GET(DT_NODELABEL(spi0));

    while (1) {
    /* Disable the SPI interface */
    spi_release(spi_dev);

    /* Enter low-power state */
    k_sleep(K_SECONDS(5));

    /* Re-enable the SPI interface when needed */
    // spi_configure(spi_dev, ...);
    // spi_transceive(spi_dev, ...);
    }
    }

    Edited by slope 1 day ago

  • You can use Low Power Modes:
    Here is a simple example that demonstrates closing the SPI and entering a low power state:

    #include "nrf_gpio.h"
    #include "nrf_spi.h"
    #include "nrf_power.h"

    void close_spi_low_power(void) {
    // Disable SPI
    NRF_SPI0->ENABLE = SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos;

    Edited by slope game 1 day ago

  • I think...

    • Double-Check Support: While you suspect CONFIG_PM_DEVICE isn't fully supported on the nRF52840 in NCS 2.6.1, absolutely confirm this. The Zephyr documentation might have been updated. Check the release notes and the Kconfig files for your specific board/SoC. If it is supported, make sure it's correctly enabled and that the spi1_dev you're passing to pm_device_action_run() is the correct device structure for your SPI1 peripheral. Print its address or name to be certain.
    • Timing: Ensure pm_device_action_run() is called immediately before k_sleep(). Any code execution between these calls could re-enable the SPI peripheral or prevent it from entering the suspended state.
    • Return Value: Check the return value of pm_device_action_run(). A non-zero return indicates an error. Print the error code to understand why the suspend operation might be failing. slope
  • I have the same problem. When I configure spi2 on a xiao rev2 chip disabled, I get low power around 40uA, but enabled it is around 180uA.

    &spi2 {    
    	status = "okay";
    	cs-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;	
    	
    	gendev: gendev@0 {
    		
    		compatible = "vnd,spi-device";
    		reg = <0>;
    		spi-max-frequency = <DT_FREQ_M(1)>;
    		
    		label = "GenDev";
    		status = "okay";
    	}; 
    };

    const struct spi_dt_spec spiDevice = SPI_DT_SPEC_GET(DT_NODELABEL(gendev), SPIOP, 0);
    
    pm_device_action_run(spiDevice.bus, PM_DEVICE_ACTION_SUSPEND);

    The above code returns 0, no error, but also no effect.

  • Found the cause, the the cs-gpio pin had to be disabled. Now power consumption is 7uA with 5seconds ble advertising interval.

        NRF_P1->PIN_CNF[12] =
            (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
            (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
            (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
            (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
            (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);

Related