External flash to sleep

My board (nrf52840 sense) has flash memory P25Q16H. When I put everything off, the board consumes 25uA. To save the last bit of current I would like to put the flash memory to deep sleep.

	spi_flash_dev = DEVICE_DT_GET(DT_ALIAS(spi_flash0));	
	if (!device_is_ready(spi_flash_dev)) {
		LOG_ERR("%s: device not ready.\n", spi_flash_dev->name);
		return ENODEV;
	}
	
	if(pm_device_action_run(spi_flash_dev, PM_DEVICE_ACTION_SUSPEND)) { //only consumes more power, 3mA ?!
		LOG_ERR("could not suspend qspi flash device %s", spi_flash_dev->name);
	}

In the debugger, eventually this function in file nrf_qspi_nor.c is executed:

#ifdef CONFIG_PM_DEVICE
static int enter_dpd(const struct device *const dev)
{
	if (IS_ENABLED(DT_INST_PROP(0, has_dpd))) {
		struct qspi_cmd cmd = {
			.op_code = SPI_NOR_CMD_DPD,
		};
		uint32_t t_enter_dpd = DT_INST_PROP_OR(0, t_enter_dpd, 0);
		int rc;

		rc = qspi_send_cmd(dev, &cmd, false);
		if (rc < 0) {
			return rc;
		}

		if (t_enter_dpd) {
			uint32_t t_enter_dpd_us =
				DIV_ROUND_UP(t_enter_dpd, NSEC_PER_USEC);

			k_busy_wait(t_enter_dpd_us);
		}
	}

	return 0;
}
#endif /* CONFIG_PM_DEVICE */

SPI_NOR_CMD_DPD is indeed to 0xB9, which is consistent with the datasheet.

Problem: after executing this command, the power rises to 3.94mA. I have no idea what is causing this.

I'm running zephyr 3.5.99 ncs 2.6.1

  • clarify what you mean by '+150 mA'

    Sorry my mistake, meant uA.

    I don't think I disabled QSPI, I just want to disable the flash device on the QSPI bus. I think indeed the flash device is using this much current, not the NRF52840, but I don't understand why. Thanks for your help anyway.

  • I know, but this was to help troubleshoot the problem. The PM suspend action will send the DPD command to the flash IC on the bus and then disable the QSPI peripheral afterward. 

  • Hi,

    I am very interested in a fix for this issue as well.

    My situation is the same except I am using a non-Sense Xiao BLE: approximately 20uA if I do not do anything to power off the external flash, and 2mA if I use pm_device_action_run.

    I did stumble upon a partial solution in this message: https://forum.seeedstudio.com/t/low-power-with-xiao-nrf52840-on-zephyr-rtos/270491/6. By adding flash.* from the zip-file linked to in the message  to my project and executing da_flash_init(); da_flash_command(0xB9); da_flash_uninit();, the power consumption gets down to 2.5uA, which is in line with my expectations.

    So it is possible to get there, and I can use this solution in the short run since I do not need the external flash for my current project, but I would very much prefer a solution that uses Zephyr's power management module.

    Best Regards,

    Peder

  • I read that too, I'll post his code for convenience.

    flash.c

    #include <nrfx_qspi.h>
    #include <zephyr/drivers/gpio.h>
    
    #define QSPI_SCK_PIN    21
    #define QSPI_CS_PIN     25
    #define QSPI_IO0_PIN   20
    #define QSPI_IO1_PIN    24
    #define QSPI_IO2_PIN    22
    #define QSPI_IO3_PIN    23
    
    int da_flash_init()
    {
        const struct device * dev = DEVICE_DT_GET(DT_NODELABEL(gpio0));
        if (!device_is_ready(dev))
        {
            return -ENODEV;
        }
        gpio_pin_configure(dev, QSPI_CS_PIN, GPIO_OUTPUT_HIGH);
    
        nrfx_qspi_config_t qspi_cfg =
        {
            .xip_offset = 0,
            .pins =
            {
                .sck_pin = QSPI_SCK_PIN,
                .csn_pin = QSPI_CS_PIN,
                .io0_pin = QSPI_IO0_PIN,
                .io1_pin = QSPI_IO1_PIN,
                .io2_pin = QSPI_IO2_PIN,
                .io3_pin = QSPI_IO3_PIN,
            },
            .prot_if = 
            {
                .readoc = NRF_QSPI_READOC_READ4O, // 0x6B read command
                .writeoc = NRF_QSPI_WRITEOC_PP4O, // 0x32 write command
                .addrmode = NRF_QSPI_ADDRMODE_24BIT,
                .dpmconfig = false
            },
            .phy_if =
            {
                .sck_delay = 10,
                .dpmen = false,
                .spi_mode = NRF_QSPI_MODE_0,
                .sck_freq = NRF_QSPI_FREQ_32MDIV16, // start with low 2 Mhz speed
            },
            .irq_priority = 7,
            .skip_gpio_cfg = true,
            .skip_psel_cfg = false
        };
    
        // No callback for blocking API
        nrfx_err_t err = nrfx_qspi_init(&qspi_cfg, NULL, NULL);
        if (err != NRFX_SUCCESS)
        {
            return -err;
        }
    
        return 0;
    } 
    
    void da_flash_uninit()
    {
        nrfx_qspi_uninit();
    }
    
    int da_flash_command(uint8_t command)
    {
        nrf_qspi_cinstr_conf_t cinstr_cfg = {.opcode = command,
                                             .length = NRF_QSPI_CINSTR_LEN_1B,
                                             .io2_level = true,
                                             .io3_level = true,
                                             .wipwait = false,
                                             .wren = false};
    
        nrfx_err_t err = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        if (err != NRFX_SUCCESS)
        {
            return -err;
        }
    
        return 0;
    }
    main.c

    da_flash_init();
    da_flash_command(0xB9);
    da_flash_uninit();
    

Related