在痞子衡旧文 《IAR下RT-Thread工程自定义函数段重定向失效分析》 里,我们知道 IAR 链接器处理自定义程序段重定向是有一些限制的,只要用户重写了底层 __low_level_init() 函数,那么这个函数里不能调用任何与自定义程序段相关的代码,否则自定义程序段就不会被 IAR 链接器(initialize by copy)正常处理。这其实对用户来说不太友好,既然如此,我们干脆就不用 IAR 链接器来做代码重定向了,今天痞子衡教大家手动拷贝程序段到 RAM 中的方法。
手动拷贝自定义程序段除了解决 IAR 链接器限制之外,还有另外一个用处,那就是拷贝的位置可以由用户决定。比如我们希望将程序重定向到外部 PSRAM 执行,但是在拷贝之前是需要先初始化外部 PSRAM 的,这时候我们完全可以在 main 函数里做完 PSRAM 初始化之后再做程序段的拷贝。
Note 1:阅读本文前需要对 《IAR链接文件(.icf)》、《IAR映射文件(.map)》 这两种文件有所了解。
Note 2:本文使用的 IAR EWARM 软件版本是 v9.30.1。
一、源文件里自定义程序段
首先我们要将需要重定向到 RAM 中执行的全部关键函数放到同一个自定义程序段里,具体方法参见痞子衡旧文 《在IAR下将关键函数重定向到RAM中执行的方法》 里 2.2 小节。
我们以最经典的 SDK_2.13.1_MIMXRT1170-EVKoardsevkmimxrt1170demo_appshello_worldcm7iar 例程( flexspi_nor_debug build)为例,将其 SysTick_DelayTicks() 函数放到自定义程序段 UserRelocateCode 里,写法如下:
#pragma location = "UserRelocateCode" void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }
二、链接文件里处理自定义程序段
有了自定义程序段 UserRelocateCode 后,现在我们需要告诉 IAR 链接器,这个程序段将由用户自己做初始化处理。打开工程链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.icf 添加如下语句。即将 UserRelocateCode 段重定向到 EXTRAM_region 里执行,并且这里最关键的是 initialize manually 这一句(区别于 SDK CodeQuickAccess 段重定向做法所用的 initialize by copy)。
define symbol m_external_ram_start = 0x60000000; define symbol m_external_ram_end = 0x6003FFFF; define region EXTRAM_region = mem:[from m_external_ram_start to m_external_ram_end]; initialize manually { section UserRelocateCode }; place in EXTRAM_region { section UserRelocateCode };
编译修改后的工程,查看其映射文件(.map),其中和 UserRelocateCode 段相关的内容如下,这里可以看到除了 P10 之外,P1 里还多了一个名为 UserRelocateCode_init 的段,这其实就是自定义程序段机器码在 Flash 里的存放位置(拷贝数据源)。
******************************************************************************* *** PLACEMENT SUMMARY *** "P10": place in [from 0x6000'0000 to 0x6003'ffff] { section UserRelocateCode }; initialize manually with packing = none { section UserRelocateCode }; Section Kind Address Size Object ------- ---- ------- ---- ------ "P1": 0x4738 UserRelocateCode_init 0x3000'6800 0x10Initializer bytes const 0x3000'6800 0x10 "P10": 0x10 UserRelocateCode 0x6000'0000 0x10 UserRelocateCode-1 0x6000'0000 0x10 UserRelocateCode inited 0x6000'0000 0x10 led_blinky.o [7] - 0x6000'0010 0x10
三、手动拷贝自定义程序段
上一节我们在映射文件里看到 UserRelocateCode_init 段的出现,这其实 IAR 的默认规定,可在 IAR SystemsEmbedded Workbench 9.30.1armdocEWARM_DevelopmentGuide.ENU.pdf 文档找到相应规则,即重定向的自定义段,其初始化值将被放到名为原自定义段名 + _init 后缀的段里。
一切准备就绪,拷贝代码的实现还是比较简单的,下面是示例拷贝函数 user_code_init()。有了它,我们就可以在 main 函数里自由决定其调用位置了。
#pragma section = "UserRelocateCode" #pragma section = "UserRelocateCode_init" void user_code_init(void) { uint8_t *dest_start, *src_start, *src_end; uint32_t codebytes; dest_start = __section_begin("UserRelocateCode"); src_start = __section_begin("UserRelocateCode_init"); src_end = __section_end("UserRelocateCode_init"); codebytes = src_end - src_start; while (codebytes--) { *dest_start++ = *src_start++; } } int main(void) { psram_init(); user_code_init(); // 代码省略... }
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !