LVP工程XIP使用指南*
在嵌入是系统中,为了减少对内存的占用,通常会使用 XIP(eXecute In Place)
技术。下面几个链接可以帮助了解 XIP
是个什么东西。
1. 如何开启XIP*
- 打开
make menuconfig
,进入MCU setting
菜单,如下图所示: - 勾上上图的
Enable XIP
选项,就可以根据需求决策CPU
、NPU
是否run in flash
。LVP
工程提供了三种组合:- CPU run in flash, NPU run in sram:
XIP Strategy
选择Default Text In Flash
- *不要勾选 *
NPU Run In Flash
- CPU run in sram, NPU run in flash
XIP Strategy
选择Default Text In Sram
- 勾选
NPU Run In Flash
- CPU run in flash, NPU run in flash
XIP Strategy
选择Default Text In Flash
- 勾选
NPU Run In Flash
- CPU run in flash, NPU run in sram:
1.1 CPU run in flash (Default Text In Flash)*
通常来说,只要 XIP Strategy
选择 Default Text In Flash
,那么 .text
和 .rodata
就会默认通过 xip
运行。请看工程的链接脚本,如下:
arch/soc/grus/link.ld | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
XIP Strategy
选择Default Text In Flash
,那么宏CONFIG_MCU_DEFAULT_TEXT_IN_FLASH
会被定义;- 再来看上面的
link.ld
脚本高亮部分,分别表示是宏 RUN_AT_STAGE2_TEXT(必须放在sram中的 .o 文件) 意外的 .o 文件会默认放到 xip 中。
注意
- 如果某些函数不需要放到flash中运行,可以在函数定义的前面添加
__attribute__((section(".sram_text")))
,比如上面高亮中的宏lvp/common/snpu_engine/lvp_kws.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
...省略一万行 #ifdef CONFIG_LVP_ENABLE_KEYWORD_RECOGNITION DRAM0_STAGE2_SRAM_ATTR static int _SnpuCallback(int module_id, GX_SNPU_STATE state, void *priv) { if (s_snpu_callback && priv) { s_snpu_callback(module_id, state, priv); } # ifdef CONFIG_ENABLE_NPU_CYCLE_STATISTIC s_end_ms = gx_get_time_ms(); printf ("npu:%d ms\n", s_end_ms - s_start_ms); # endif return 0; } #endif ...省略一万行
DRAM0_STAGE2_SRAM_ATTR
其实就是__attribute__((section(".sram_text")))
,它在inclue/lvp_attr.h
中有定义。 - 如果某些 .o 文件都要放在
sram
中运行,那么可以参考link.ld
中的RUN_AT_STAGE2_TEXT
的方式仿照抄下。
1.2 NPU Run In Flash*
- 首先先看
LVP
工程的链接脚本,如下,我们会将.cmd
和.weight
等section
通过xip
来读取。arch/soc/grus/link.ld 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
...省略一万行 #ifdef CONFIG_MCU_ENABLE_XIP .stage2_xip_text : STAGE2_XIP_TEXT_LMA { _stage2_xip_start_text_ = .; ...省略一万行 # ifdef CONFIG_NPU_RUN_IN_FLASH . = ALIGN(4); KEEP(*(.cmd*)) . = ALIGN(4); KEEP(*(.weight*)) . = ALIGN(4); KEEP(*(.npu_section*)) . = ALIGN(4); KEEP(*(.vp_cmd*)) . = ALIGN(4); KEEP(*(.vp_weight*)) . = ALIGN(4); KEEP(*(.vp_npu_section*)) # endif ...省略一万行 . = ALIGN(4); _stage2_xip_end_text_ = .; } > stage2_xip #endif /* CONFIG_MCU_ENABLE_XIP */ ...省略一万行
- NPU模型文件内容如下,如果需要将 NPU run in flash,那么就要像下面高亮部分一样再后面增加
__attribute__((section(".cmd")))
和__attribute__((section(".weight")))
。
lvp/vui/kws/models/*/*/model.h | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
1.3 CPU run in sram (Default Text In Sram)*
如果我们在XIP Strategy
选择 Default Text In Sram
,那么意味着默认的 .text
和 .rodata
都会在 sram
中运行。如果需要将某些 函数 或者 只读数组 通过 xip 运行,请阅读下面的内容。
-
XIP的地址映射
- MCU 中 XIP数据 地址为数据在flash中的地址加 CONFIG_FLASH_XIP_BASE, CONFIG_FLASH_XIP_BASE 默认为 0x10200000,相关定义如下
... #define CONFIG_FLASH_XIP_BASE 0x10200000 ... #define CONFIG_STAGE2_XIP_BASE (CONFIG_FLASH_XIP_BASE + CONFIG_STAGE1_IRAM_SIZE) ...
- MCU 中 XIP数据 地址为数据在flash中的地址加 CONFIG_FLASH_XIP_BASE, CONFIG_FLASH_XIP_BASE 默认为 0x10200000,相关定义如下
-
参考编译配置
configs/release/nationalchip/grus_gx8002b_dev_1v_xip_demo.config
-
一般数据使用 XIP
-
使用如下的宏进行修饰即可将对应的变量或函数放到XIP
#define XIP_RODATA_ATTR __attribute__((section(".xip.rodata*")))
-
代码片段
#ifdef CONFIG_LVP_APP_XIP_DEMO_RODATA const unsigned char s_test_data_rodata[] XIP_RODATA_ATTR = #else const unsigned char s_test_data_rodata[] = #endif { 0x00, 0x00, 0x42, 0x01, 0x83, 0x02, 0xc5, 0x03, 0x06, 0x05, 0x48, 0x06, 0xfa, 0xfa, 0x3b, 0xfc, 0x7d, 0xfd, 0xbe, 0xfe }; static int _show_test_data() { printf("_show_test_data: 0x%x\n", _show_test_data); #ifdef CONFIG_LVP_APP_XIP_DEMO_RODATA printf("s_test_data_rodata: 0x%x\n", s_test_data_rodata); for (int i = 0; i < 16; i++) { printf("0x%x,", s_test_data_rodata[i]); } printf("\n"); #endif printf("\n\n"); }
- demo 串口输出:
... _show_test_data: 0x10014c7c s_test_data_rodata: 0x10203004 0x0,0x0,0x42,0x1,0x83,0x2,0xc5,0x3,0x6,0x5,0x48,0x6,0xfa,0xfa,0x3b,0xfc, ...
-
2. 注意事项*
- XIP地址只读。
- 使用XIP时不可使用flash驱动等其他方式访问flash,如有需要请通过关中断等方式确保XIP的访问已停止。