SPIM (EasyDMA) power consumption

Hi,

We are working on power optimization for our project using the nRF5340 board. Our code implements an RTOS, BLE for data transfer, I2C and SPI for device communication, and UART for data logging.

When we disabled UART and all peripherals, including DFU, and enabled only BLE, we achieved a current consumption in the 245 µA range, which we previously discussed in our post

So we tried enabling spim in our code which is used for communicating with NAND flash, we observed the current consumption increased to around 3 mA. We tried deinitializing SPIM and setting the SPIM state to suspend after each communication using these functions :

/*deinit spim*/
nrfx_spim_uninit(self->spim);
/*suspend spim peripheral*/
ret = pm_device_action_run(self->spi_dev, PM_DEVICE_ACTION_SUSPEND);

, but the current consumption remained around 3mA.

This is our overlay configuration.
&spi4_sleep {
    group1 {
        psels = <NRF_PSEL(SPIM_MOSI, 0, 13)>,
                <NRF_PSEL(SPIM_MISO, 0, 14)>,
                <NRF_PSEL(SPIM_SCK, 0, 17)>;
        low-power-enable;
    };
};

&spi4 {
    status = "okay";
    label = "SPI_4";
    compatible = "nordic,nrf-spim";
    pinctrl-0 = < &spi4_default >;
    pinctrl-1 = < &spi4_sleep>;
    pinctrl-names = "default", "sleep";
    cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; 
    max-frequency = <DT_FREQ_M(32)>;    
};

Is there any way we can reduce the power consumption of SPIM?

Parents
  • Hello,

    I have tried your both projects and got average current 620uA for both applications.

    These two files are same. I can not see any change. Did you upload the right file?

  • Hi, Kazi.

    I am also one of people who want to optimize power consumption for TWIM and SPIM.

    Since I am using NRFX driver (=not using zephyr since it's not accesible/controllable for easyDMA), I have to do something for my own.

    For  's answer, I can't understand how to disable the pins. Un-initializing SPIM, I understood but disabling pins, I don't get it.

    FYI, below is my code for TWIM and SPIM.

    /* TWIM with easyDMA */
    &i2c0 {
    	/* TWIM */
    	compatible = "nordic,nrf-twim";
    	status = "okay";
    	clock-frequency = <I2C_BITRATE_FAST>;
    	pinctrl-0 = <&i2c0_default>;
    	pinctrl-1 = <&i2c0_sleep>;
    	pinctrl-names = "default", "sleep";
    };
    
    /* SPIM with easyDMA */
    &spi1 {
    	compatible = "nordic,nrf-spim";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	pinctrl-names = "default", "sleep";
    };

    /* SPI(M) gpio */
    #define MOSI_PIN_SPIM 13 // SPIM pin number for MOSI.
    #define MISO_PIN_SPIM 12 // SPIM pin number for MISO.
    #define SCK_PIN_SPIM 14  // SPIM pin number for SCK.
    #define SS_PIN_SPIM 15   // SPIM pin number for CS.
    
    /* SPI SCLK (=clock) speed */
    #define SPIM_SCK_SPEED_MHZ 8
    
    /**
     * @brief Symbol specifying SPIM instance to be used.
     * note: SPI1 for ACCEL/GYRO sensor communication (I2C0 shares the device register with SPI0 and its already used for Magnetometer)
     */
    // #define SPIM_INST_IDX 0
    #define SPIM_INST_IDX 1
    
    /* Declare the SPIM instance variable using the macro directly */
    static const nrfx_spim_t spim_instance = NRFX_SPIM_INSTANCE(SPIM_INST_IDX);
    
    nrfx_err_t init_spim(nrfx_spim_evt_handler_t handler)
    {
        nrfx_err_t status;
    
        nrfx_spim_config_t spim_config = NRFX_SPIM_DEFAULT_CONFIG(SCK_PIN_SPIM, MOSI_PIN_SPIM, MISO_PIN_SPIM, SS_PIN_SPIM);
        spim_config.mode = NRF_SPIM_MODE_3;
        spim_config.frequency = NRFX_MHZ_TO_HZ(SPIM_SCK_SPEED_MHZ);
    
        status = nrfx_spim_init(&spim_instance, &spim_config, handler, NULL);
        if (status != NRFX_SUCCESS)
        {
            ACCEL_GYRO_SPIM_DEBUG("Failed to initialize SPIM instance: %d", status);
            return status;
        }
    
        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPIM_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_SPIM_INST_HANDLER_GET(SPIM_INST_IDX), 0, 0);
        irq_enable(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPIM_INST_IDX)));
    
        ACCEL_GYRO_SPIM_DEBUG("SPIM instance initialized successfully");
        return NRFX_SUCCESS;
    }

    #define SCL_PIN_TWIM 17
    #define SDA_PIN_TWIM 18
    
    /** @brief Symbol specifying TWIM instance to be used. */
    #define TWIM_INST_IDX 0
    
    /** @brief Structure containing TWIM driver instance. */
    static nrfx_twim_t twim_inst = NRFX_TWIM_INSTANCE(TWIM_INST_IDX);
    
    
    nrfx_err_t twim_init(nrfx_twim_evt_handler_t handler)
    {
        nrfx_err_t status;
    
        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TWIM_INST_GET(TWIM_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_TWIM_INST_HANDLER_GET(TWIM_INST_IDX), 0, 0);
    
        nrfx_twim_config_t twim_config = NRFX_TWIM_DEFAULT_CONFIG(SCL_PIN_TWIM, SDA_PIN_TWIM);
        twim_config.frequency = NRF_TWIM_FREQ_400K; // i2c speed: 400kHz
        // twim_config.frequency = NRF_TWIM_FREQ_390K; // i2c speed: 390kHz
        // twim_config.frequency = NRF_TWIM_FREQ_100K; // i2c speed: 100kHz
    
        void *p_context = "--> Master event: done - transfer completed";
        status = nrfx_twim_init(&twim_inst, &twim_config, handler, p_context);
        if (status != NRFX_SUCCESS)
        {
            MAGNETO_TWIM_DEBUG("twim_init() -> nrfx_twim_xfer() failed: %d\n", status);
            return status;
        }
    
        nrfx_twim_enable(&twim_inst);
    
        return status;
    }

    What community needs is simple.

    Just sample with the APIs for power saving mode for TWIM and SPIM.

    Even if I invested times to check the forum and technical document, I can't find proper ones.

Reply
  • Hi, Kazi.

    I am also one of people who want to optimize power consumption for TWIM and SPIM.

    Since I am using NRFX driver (=not using zephyr since it's not accesible/controllable for easyDMA), I have to do something for my own.

    For  's answer, I can't understand how to disable the pins. Un-initializing SPIM, I understood but disabling pins, I don't get it.

    FYI, below is my code for TWIM and SPIM.

    /* TWIM with easyDMA */
    &i2c0 {
    	/* TWIM */
    	compatible = "nordic,nrf-twim";
    	status = "okay";
    	clock-frequency = <I2C_BITRATE_FAST>;
    	pinctrl-0 = <&i2c0_default>;
    	pinctrl-1 = <&i2c0_sleep>;
    	pinctrl-names = "default", "sleep";
    };
    
    /* SPIM with easyDMA */
    &spi1 {
    	compatible = "nordic,nrf-spim";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	pinctrl-names = "default", "sleep";
    };

    /* SPI(M) gpio */
    #define MOSI_PIN_SPIM 13 // SPIM pin number for MOSI.
    #define MISO_PIN_SPIM 12 // SPIM pin number for MISO.
    #define SCK_PIN_SPIM 14  // SPIM pin number for SCK.
    #define SS_PIN_SPIM 15   // SPIM pin number for CS.
    
    /* SPI SCLK (=clock) speed */
    #define SPIM_SCK_SPEED_MHZ 8
    
    /**
     * @brief Symbol specifying SPIM instance to be used.
     * note: SPI1 for ACCEL/GYRO sensor communication (I2C0 shares the device register with SPI0 and its already used for Magnetometer)
     */
    // #define SPIM_INST_IDX 0
    #define SPIM_INST_IDX 1
    
    /* Declare the SPIM instance variable using the macro directly */
    static const nrfx_spim_t spim_instance = NRFX_SPIM_INSTANCE(SPIM_INST_IDX);
    
    nrfx_err_t init_spim(nrfx_spim_evt_handler_t handler)
    {
        nrfx_err_t status;
    
        nrfx_spim_config_t spim_config = NRFX_SPIM_DEFAULT_CONFIG(SCK_PIN_SPIM, MOSI_PIN_SPIM, MISO_PIN_SPIM, SS_PIN_SPIM);
        spim_config.mode = NRF_SPIM_MODE_3;
        spim_config.frequency = NRFX_MHZ_TO_HZ(SPIM_SCK_SPEED_MHZ);
    
        status = nrfx_spim_init(&spim_instance, &spim_config, handler, NULL);
        if (status != NRFX_SUCCESS)
        {
            ACCEL_GYRO_SPIM_DEBUG("Failed to initialize SPIM instance: %d", status);
            return status;
        }
    
        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPIM_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_SPIM_INST_HANDLER_GET(SPIM_INST_IDX), 0, 0);
        irq_enable(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPIM_INST_IDX)));
    
        ACCEL_GYRO_SPIM_DEBUG("SPIM instance initialized successfully");
        return NRFX_SUCCESS;
    }

    #define SCL_PIN_TWIM 17
    #define SDA_PIN_TWIM 18
    
    /** @brief Symbol specifying TWIM instance to be used. */
    #define TWIM_INST_IDX 0
    
    /** @brief Structure containing TWIM driver instance. */
    static nrfx_twim_t twim_inst = NRFX_TWIM_INSTANCE(TWIM_INST_IDX);
    
    
    nrfx_err_t twim_init(nrfx_twim_evt_handler_t handler)
    {
        nrfx_err_t status;
    
        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TWIM_INST_GET(TWIM_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_TWIM_INST_HANDLER_GET(TWIM_INST_IDX), 0, 0);
    
        nrfx_twim_config_t twim_config = NRFX_TWIM_DEFAULT_CONFIG(SCL_PIN_TWIM, SDA_PIN_TWIM);
        twim_config.frequency = NRF_TWIM_FREQ_400K; // i2c speed: 400kHz
        // twim_config.frequency = NRF_TWIM_FREQ_390K; // i2c speed: 390kHz
        // twim_config.frequency = NRF_TWIM_FREQ_100K; // i2c speed: 100kHz
    
        void *p_context = "--> Master event: done - transfer completed";
        status = nrfx_twim_init(&twim_inst, &twim_config, handler, p_context);
        if (status != NRFX_SUCCESS)
        {
            MAGNETO_TWIM_DEBUG("twim_init() -> nrfx_twim_xfer() failed: %d\n", status);
            return status;
        }
    
        nrfx_twim_enable(&twim_inst);
    
        return status;
    }

    What community needs is simple.

    Just sample with the APIs for power saving mode for TWIM and SPIM.

    Even if I invested times to check the forum and technical document, I can't find proper ones.

Children
  • Hello,

    your SPIM is active on pincontrol file 

    ''/* SPIM with easyDMA */
    &spi1 {
    compatible = "nordic,nrf-spim";
    status = "okay";
    pinctrl-0 = <&spi1_default>;
    pinctrl-1 = <&spi1_sleep>;
    pinctrl-names = "default", "sleep";
    };''

    You can use  nrfx_spim_uninit function to uninitialize the SPIM from your code. You also can try to disable the SPIM from device tree overlay file by disabling the peripheral. 

    &spi1{
    status = "disabled";
    };
Related