We are using QSPI XIP mode to access data in external flash for our project. We are trying put QSPI peripheral in standby mode.
However, we can't uninitialized QSPI peripheral by calling nrfx_qspi_uninit() even though XIP mode is disabled and no data is being accessed . The following are the code that we use to test. And, it's based on the example project in SDK (i.e. zephyr\samples\application_development\code_relocation_nocopy) with some minor modification.
ext_mem_init.c
const struct device *dev;
int qspi_ext_mem_init(void) {
ARG_UNUSED(dev);
static const nrfx_qspi_config_t qspi_config = {
.prot_if = {
.readoc = NRF_QSPI_READOC_READ4IO,
.writeoc = NRF_QSPI_WRITEOC_PP4IO,
.addrmode = NRF_QSPI_ADDRMODE_24BIT,
},
.phy_if = {
/* Frequency = PCLK192M / 2 * (sck_freq + 1) -> 32 MHz.
* 33 MHz is the maximum for WRSR, even in the High
* Performance mode.
*/
.sck_freq = 2,
.sck_delay = 0x05,
.spi_mode = NRF_QSPI_MODE_0,
},
.skip_gpio_cfg = true,
.skip_psel_cfg = true,
};
static const nrf_qspi_phy_conf_t qspi_phy_48mhz = {
/* After sending WRSR, use 48 MHz (96 MHz cannot be used,
* as 80 MHz is the maximum for the MX25R6435F chip).
*/
.sck_freq = 1,
.sck_delay = 0x05,
.spi_mode = NRF_QSPI_MODE_0,
};
nrf_qspi_cinstr_conf_t cinstr_cfg = {
.opcode = QSPI_STD_CMD_RSTEN,
.length = NRF_QSPI_CINSTR_LEN_1B,
.io2_level = true,
.io3_level = true,
.wipwait = true,
};
static const uint8_t flash_chip_cfg[] = {
/* QE (Quad Enable) bit = 1 */
BIT(6),
0x00,
/* L/H Switch bit = 1 -> High Performance mode */
BIT(1),
};
nrfx_err_t err;
int ret;
PINCTRL_DT_DEFINE(QSPI_NODE);
ret = pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(QSPI_NODE),
PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
err = nrfx_qspi_init(&qspi_config, NULL, NULL);
if (err != NRFX_SUCCESS) {
return -EIO;
}
nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_1);
/* Send reset enable */
nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
/* Send reset command */
cinstr_cfg.opcode = QSPI_STD_CMD_RST;
nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
/* Switch to Quad I/O and High Performance mode */
cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
cinstr_cfg.wren = true;
cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_4B;
nrfx_qspi_cinstr_xfer(&cinstr_cfg, &flash_chip_cfg, NULL);
nrf_qspi_ifconfig1_set(NRF_QSPI, &qspi_phy_48mhz);
/* Enable XiP */
nrf_qspi_xip_set(NRF_QSPI, true);
/* Send deep sleep mode command */
cinstr_cfg.opcode = QSPI_STD_CMD_DP;
nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
return 0;
}
int qspi_ext_mem_uninit(void)
{
nrf_qspi_xip_set(NRF_QSPI, false);
nrfx_qspi_uninit();
printk("qspi_ext_mem_uninit successfully\n");
return 0;
}
//SYS_INIT(qspi_ext_mem_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
main.c /* * Copyright (c) 2018 Intel Corporation. * Copyright (c) 2022 Carlo Caione <[email protected]> * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/kernel.h> #include <zephyr/sys/printk.h> /* * This function will allow execute from sram region. This is needed only for * this sample because by default all soc will disable the execute from SRAM. * An application that requires that the code be executed from SRAM will have * to configure the region appropriately in arm_mpu_regions.c. */ #ifdef CONFIG_ARM_MPU #include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h> void disable_mpu_rasr_xn(void) { uint32_t index; /* * Kept the max index as 8(irrespective of soc) because the sram would * most likely be set at index 2. */ for (index = 0U; index < 8; index++) { MPU->RNR = index; #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) if (MPU->RBAR & MPU_RBAR_XN_Msk) { MPU->RBAR ^= MPU_RBAR_XN_Msk; } #else if (MPU->RASR & MPU_RASR_XN_Msk) { MPU->RASR ^= MPU_RASR_XN_Msk; } #endif /* CONFIG_ARMV8_M_BASELINE || CONFIG_ARMV8_M_MAINLINE */ } } #endif /* CONFIG_ARM_MPU */ extern void function_in_ext_flash(void); extern void function_in_sram(void); void main(void) { #ifdef CONFIG_ARM_MPU disable_mpu_rasr_xn(); #endif /* CONFIG_ARM_MPU */ qspi_ext_mem_init(); printk("Address of %s function %p\n", __func__, &main); function_in_ext_flash(); function_in_sram(); printk("Hello World! %s\n", CONFIG_BOARD); qspi_ext_mem_uninit(); }
After flashing the program into NRF5304DK, it's unable to run this instruction: printk("qspi_ext_mem_uninit successfully\n");
May we know how we can uninitialized QSPI peripheral with XIP mode successfully in order to save power consumption?