Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Cannot exit deep power down mode (QSPI flash)

We designed a board based on the nRF52840, and are using nrf5 SDK 17.1.0 with S140 SoftDevice. We are using a QSPI flash, MX25U51245G (https://www.macronix.com/Lists/Datasheet/Attachments/8736/MX25U51245G%2054,%201.8V,%20512Mb,%20v1.2.pdf), we are using the 8-WSON version with no Reset pin

I have followed the QSPI example and the information provided here  Exiting QSPI DPM mode when opening QSPI (memory has been put into DPM previously before QSPI was closed) I can successfully access the QSPI flash, and I can put it in deep power down mode using the code provided, or sending the deep power down command as a QSPI command (CMD_DEEP_PWRDOWN 0xB9).

The problem is that this chip, unlike the one in the DK, does not exit deep power down by holding CS high for the proper time, but requires a command (RDP = 0xAB), see 10-4. Release from Deep Power-down (RDP). When I re-initialize the QSPI peripheral with the flash chip in power down, I get a NRF_ERROR_TIMEOUT because the chip doesn't seem to respond to whatever command the QSPI peripheral is using to wake up the device. nrfx_qspi_init fails when executing  NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY), QSPI_DEF_WAIT_ATTEMPTS, QSPI_DEF_WAIT_TIME_US, result);

I'm not sure I understand what nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE); is doing, but when my flash chip is in deep power down, that never completes and blocks the QSPI peripheral preventing to send any other command

Is there a way to send the 0xAB command to release my flash chip from deep sleep?

  • I just realized that this same issue has been found and reported on the Zephyr-based SDK Connect https://github.com/zephyrproject-rtos/zephyr/pull/64782

    Looking at the commit (https://github.com/zephyrproject-rtos/zephyr/commit/1727bbcc7046eb5870df7409310d58e0c9483233), they used a different strategy than mine: instead of defining IO1 as pulldown, the QSPI peripheral is initialized with NRF_QSPI_PIN_NOT_CONNECTED for every pin, the RDP command sent, then QSPI is re-enabled normally

     can you please provide input on the safest way to send an RDP for SDK 17.1.0? Use IO1 pulldown or disconnect the QSPI pins? I do realize that SDK 17.1.0 is in maintenance mode, so I'm not asking for a fix, just an opinion on the best option to work around it.

  • Hello,

    If you are able to make it work while disconnecting the QSPI pins, I would say that this is better. It doesn't require any extra GPIOs, and it doesn't actually output/input a physical signal to a disconnected GPIO.

    It shouldn't really matter, but it sounds "cleaner" in my opinion.

    Best regards,

    Edvin

  • Hey  !

    I just wanted to give a shoutout to your thorough investigation and good find on the zephyr commit! I faced this exact issue with my Seeed XIAO Sense board with the P25Q16H flash on it, but incorporating that trick solved the problem without needing to modify any SDK file. Thx a lot!

    If anyone faces this issue, this is how my fix looks like:

    static uint32_t *QSPI_Status_Ptr = (uint32_t*) 0x40029604;  // Setup for the SEEED XIAO BLE - nRF52840
    
    static nrfx_err_t QSPI_IsReady(void) {
        if (((*QSPI_Status_Ptr & 8) == 8) && (*QSPI_Status_Ptr & 0x01000000) == 0) {
            return NRFX_SUCCESS;
        } else {
            return NRFX_ERROR_BUSY;
        }
    }
    
    static nrfx_err_t QSPI_WaitForReady(void) {
        while (QSPI_IsReady() == NRFX_ERROR_BUSY) {
            // TODO timeout
        }
        return NRFX_SUCCESS;
    }
    
    static nrfx_err_t QSPI_RDPWorkaroundInit(void) {
        nrfx_err_t err_code;
        nrf_qspi_pins_t pins;
        nrf_qspi_pins_get(NRF_QSPI, &pins);
        nrf_qspi_pins_t disconnected_pins = {
    			.sck_pin = NRF_QSPI_PIN_NOT_CONNECTED,
    			.csn_pin = NRF_QSPI_PIN_NOT_CONNECTED,
    			.io0_pin = NRF_QSPI_PIN_NOT_CONNECTED,
    			.io1_pin = NRF_QSPI_PIN_NOT_CONNECTED,
    			.io2_pin = NRF_QSPI_PIN_NOT_CONNECTED,
    			.io3_pin = NRF_QSPI_PIN_NOT_CONNECTED,
        };
        nrf_qspi_pins_set(NRF_QSPI, &disconnected_pins);
    
        nrf_qspi_enable(NRF_QSPI);
        nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
        nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE);
    
        err_code = QSPI_WaitForReady();
        nrf_qspi_pins_set(NRF_QSPI, &pins);
        return err_code;
    }
    
    static nrfx_err_t QSPI_SendRDP(void) {
        nrfx_err_t err_code;
        
        // Send RDP cmd to wake up flash from DPM
        nrf_qspi_cinstr_conf_t cinstr_cfg_rdp = {
            .opcode    = 0xAB,
            .length    = NRF_QSPI_CINSTR_LEN_1B,
            .io2_level = true,
            .io3_level = true,
            .wipwait   = false,
            .wren      = true
        };
    
        err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg_rdp, NULL, NULL);
        QSPI_WaitForReady();
        return err_code;
    }
    
    nrfx_err_t QSPI_FlashInit(void) {
        nrfx_err_t err_code;
        nrfx_qspi_config_t config = NRFX_QSPI_DEFAULT_CONFIG;
        // TODO: set up config according to your needs
        err_code = nrfx_qspi_init(&config, NULL, NULL);
        if(err_code == NRFX_SUCCESS) {
            NRF_LOG_INFO("QSPI flash inited successfully");
        } else {
            NRF_LOG_ERROR("QSPI flash init error (%d), possibly due to flash RDP. Trying workaround...", err_code);
            if (QSPI_RDPWorkaroundInit() == NRFX_SUCCESS) {
                NRF_LOG_INFO("QSPI flash inited successfully with RDP workaround.");
                if (QSPI_SendRDP() != NRFX_SUCCESS) {
                    NRF_LOG_ERROR("Could not wake up flash from deep power-down mode!);
                } else {
                    return NRFX_SUCCESS;
                }
            } else {
                NRF_LOG_ERROR("QSPI flash init failed.");
            }
        }
        return err_code;
    }

Related