code_relocation: Extend the nocopy sample to nRF5340dk
The nRF5340dk is shipping an external QSPI flash that can be used to do XIP from. Extend the code_relocation nocopy sample to support this platform so that part of the functions are executed from internal flash and others from external flash. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
d3203dc70d
commit
ac6060f966
8 changed files with 173 additions and 2 deletions
|
@ -7,6 +7,7 @@ project(code_relocation_nocopy)
|
||||||
|
|
||||||
FILE(GLOB app_sources src/*.c)
|
FILE(GLOB app_sources src/*.c)
|
||||||
target_sources(app PRIVATE ${app_sources})
|
target_sources(app PRIVATE ${app_sources})
|
||||||
|
target_sources_ifdef(CONFIG_NRFX_QSPI app PRIVATE boards/nrf5340dk_nrf5340_cpuapp/ext_mem_init.c)
|
||||||
|
|
||||||
# Run ext_code from the external flash (XIP). No need to copy.
|
# Run ext_code from the external flash (XIP). No need to copy.
|
||||||
zephyr_code_relocate(src/ext_code.c EXTFLASH_TEXT NOCOPY)
|
zephyr_code_relocate(src/ext_code.c EXTFLASH_TEXT NOCOPY)
|
||||||
|
|
|
@ -11,3 +11,36 @@ using a custom linker script.
|
||||||
Differently from the code relocation sample, this sample is relocating the
|
Differently from the code relocation sample, this sample is relocating the
|
||||||
content of the ext_code.c file to a different FLASH section and the code is XIP
|
content of the ext_code.c file to a different FLASH section and the code is XIP
|
||||||
directly from there without the need to copy / relocate the code.
|
directly from there without the need to copy / relocate the code.
|
||||||
|
|
||||||
|
nRF5340dk platform instructions
|
||||||
|
*******************************
|
||||||
|
|
||||||
|
The nRF5340 PDK has a 64 Mb external flash memory supporting Quad SPI. It is
|
||||||
|
possible to do XIP from the external flash memory.
|
||||||
|
|
||||||
|
The external flash memory is mapped to 0x10000000.
|
||||||
|
|
||||||
|
In this sample we relocate some of the code to the external flash memory with
|
||||||
|
the remaining Zephyr kernel in the internal flash.
|
||||||
|
|
||||||
|
Compile the code:
|
||||||
|
$ west build -b nrf5340dk_nrf5340_cpuapp samples/application_development/code_relocation_nocopy --pristine
|
||||||
|
|
||||||
|
Get the HEX file from the ELF:
|
||||||
|
$ arm-linux-gnueabihf-objcopy -O ihex build/zephyr/zephyr.elf zephyr.hex
|
||||||
|
|
||||||
|
Erase the external FLASH (just to be sure):
|
||||||
|
$ nrfjprog --qspicustominit --qspieraseall
|
||||||
|
|
||||||
|
Write the HEX to internal and external FLASH:
|
||||||
|
$ nrfjprog --coprocessor CP_APPLICATION --sectorerase --qspisectorerase --program zephyr.hex
|
||||||
|
|
||||||
|
Execution output:
|
||||||
|
|
||||||
|
*** Booting Zephyr OS build v3.0.0-rc3-25-g0df32cec1ff2 ***
|
||||||
|
Address of main function 0x4f9
|
||||||
|
Address of function_in_ext_flash 0x10000001
|
||||||
|
Address of var_ext_sram_data 0x200000a0 (10)
|
||||||
|
Address of function_in_sram 0x20000001
|
||||||
|
Address of var_sram_data 0x200000a4 (10)
|
||||||
|
Hello World! nrf5340dk_nrf5340_cpuapp
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_NRFX_QSPI=y
|
||||||
|
CONFIG_GPIO=y
|
||||||
|
CONFIG_NRF_ENABLE_CACHE=n
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Nordic Semiconductor ASA.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <nrfx_qspi.h>
|
||||||
|
#include <hal/nrf_clock.h>
|
||||||
|
|
||||||
|
#define QSPI_STD_CMD_WRSR 0x01
|
||||||
|
#define QSPI_STD_CMD_WRDI 0x04
|
||||||
|
#define QSPI_STD_CMD_RSTEN 0x66
|
||||||
|
#define QSPI_STD_CMD_RST 0x99
|
||||||
|
|
||||||
|
#define QSPI_NODE DT_NODELABEL(qspi)
|
||||||
|
#define QSPI_PROP_AT(prop, idx) DT_PROP_BY_IDX(QSPI_NODE, prop, idx)
|
||||||
|
|
||||||
|
static inline int qspi_get_zephyr_ret_code(nrfx_err_t res)
|
||||||
|
{
|
||||||
|
switch (res) {
|
||||||
|
case NRFX_SUCCESS:
|
||||||
|
return 0;
|
||||||
|
case NRFX_ERROR_INVALID_PARAM:
|
||||||
|
case NRFX_ERROR_INVALID_ADDR:
|
||||||
|
return -EINVAL;
|
||||||
|
case NRFX_ERROR_INVALID_STATE:
|
||||||
|
return -ECANCELED;
|
||||||
|
case NRFX_ERROR_BUSY:
|
||||||
|
case NRFX_ERROR_TIMEOUT:
|
||||||
|
default:
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qspi_ext_mem_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_1);
|
||||||
|
|
||||||
|
static nrfx_qspi_config_t qspi_config = {
|
||||||
|
.pins = {
|
||||||
|
.sck_pin = DT_PROP(QSPI_NODE, sck_pin),
|
||||||
|
.csn_pin = QSPI_PROP_AT(csn_pins, 0),
|
||||||
|
.io0_pin = QSPI_PROP_AT(io_pins, 0),
|
||||||
|
.io1_pin = QSPI_PROP_AT(io_pins, 1),
|
||||||
|
.io2_pin = QSPI_PROP_AT(io_pins, 2),
|
||||||
|
.io3_pin = QSPI_PROP_AT(io_pins, 3),
|
||||||
|
},
|
||||||
|
.irq_priority = NRFX_QSPI_DEFAULT_CONFIG_IRQ_PRIORITY,
|
||||||
|
.prot_if = {
|
||||||
|
.readoc = NRF_QSPI_READOC_READ4IO,
|
||||||
|
.writeoc = NRF_QSPI_WRITEOC_PP4IO,
|
||||||
|
.addrmode = NRF_QSPI_ADDRMODE_24BIT,
|
||||||
|
.dpmconfig = false
|
||||||
|
},
|
||||||
|
.phy_if = {
|
||||||
|
.sck_freq = 1,
|
||||||
|
.sck_delay = 0x05,
|
||||||
|
.spi_mode = NRF_QSPI_MODE_0,
|
||||||
|
.dpmen = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
nrfx_err_t res = nrfx_qspi_init(&qspi_config, NULL, NULL);
|
||||||
|
|
||||||
|
ret = qspi_get_zephyr_ret_code(res);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable XiP */
|
||||||
|
nrf_qspi_xip_set(NRF_QSPI, true);
|
||||||
|
|
||||||
|
uint8_t temporary = 0x40;
|
||||||
|
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,
|
||||||
|
.wren = true
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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 qspi mode and high performance */
|
||||||
|
cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
|
||||||
|
cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
|
||||||
|
nrfx_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);
|
||||||
|
|
||||||
|
/* Send write disable command */
|
||||||
|
cinstr_cfg.opcode = QSPI_STD_CMD_WRDI;
|
||||||
|
cinstr_cfg.wren = false;
|
||||||
|
cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_1B;
|
||||||
|
nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(qspi_ext_mem_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
|
|
@ -18,6 +18,19 @@
|
||||||
#include <linker/linker-defs.h>
|
#include <linker/linker-defs.h>
|
||||||
#include <linker/linker-tool.h>
|
#include <linker/linker-tool.h>
|
||||||
|
|
||||||
|
#if CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nRF5340dk is shipping a QSPI external flash mapped at 0x1000_0000 that can
|
||||||
|
* be used for XIP
|
||||||
|
*/
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
EXTFLASH (wx) : ORIGIN = 0x10000000, LENGTH = 0x800000
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add another fake portion of FLASH to simulate a secondary or external FLASH
|
* Add another fake portion of FLASH to simulate a secondary or external FLASH
|
||||||
* that we can do XIP from.
|
* that we can do XIP from.
|
||||||
|
@ -30,4 +43,6 @@ MEMORY
|
||||||
EXTFLASH (wx) : ORIGIN = 0x5000, LENGTH = EXTFLASH_SIZE
|
EXTFLASH (wx) : ORIGIN = 0x5000, LENGTH = EXTFLASH_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP */
|
||||||
|
|
||||||
#include <arch/arm/aarch32/cortex_m/scripts/linker.ld>
|
#include <arch/arm/aarch32/cortex_m/scripts/linker.ld>
|
||||||
|
|
|
@ -3,3 +3,4 @@ CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y
|
||||||
CONFIG_CUSTOM_LINKER_SCRIPT="linker_arm_nocopy.ld"
|
CONFIG_CUSTOM_LINKER_SCRIPT="linker_arm_nocopy.ld"
|
||||||
CONFIG_COVERAGE=n
|
CONFIG_COVERAGE=n
|
||||||
CONFIG_XIP=y
|
CONFIG_XIP=y
|
||||||
|
CONFIG_LOG=y
|
||||||
|
|
|
@ -3,7 +3,7 @@ sample:
|
||||||
name: code relocation nocopy
|
name: code relocation nocopy
|
||||||
tests:
|
tests:
|
||||||
sample.application_development.code_relocation_nocopy:
|
sample.application_development.code_relocation_nocopy:
|
||||||
platform_allow: qemu_cortex_m3
|
platform_allow: qemu_cortex_m3 nrf5340dk_nrf5340_cpuapp
|
||||||
tags: linker
|
tags: linker
|
||||||
harness: console
|
harness: console
|
||||||
harness_config:
|
harness_config:
|
||||||
|
|
|
@ -27,12 +27,18 @@ void disable_mpu_rasr_xn(void)
|
||||||
*/
|
*/
|
||||||
for (index = 0U; index < 8; index++) {
|
for (index = 0U; index < 8; index++) {
|
||||||
MPU->RNR = 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) {
|
if (MPU->RASR & MPU_RASR_XN_Msk) {
|
||||||
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 */
|
#endif /* CONFIG_ARM_MPU */
|
||||||
|
|
||||||
extern void function_in_ext_flash(void);
|
extern void function_in_ext_flash(void);
|
||||||
extern void function_in_sram(void);
|
extern void function_in_sram(void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue