iar设置函数跑在ram中加速运行--Apple的学习笔记
一,前言
让代码跑在ram中的情况主要为了执行速度快。在c代码中添加段有3种方法。而我主要学习链接脚本的修改方法。因为这类操作我曾经没用过。就拿之前stm32做的iar timer中断工程来实验。
二,实验
实验概览:主要目的是完成5个自定义小需求,以此来提升应用技巧。
image.png
- 实验对象是main.c中的testfun函数,正常情况函数放代码段就是0x8xx的。
main 0x800'071d 0x2c Code Gb main.o [1]
testcnt 0x2000'00ce 0x1 Data Gb main.o [1]
testfun 0x800'070d 0xa Code Gb main.o [1]
- 添加关键字__ramfunc改成__ramfunc void testfun(void)后编译,看到testfun的函数地址变为0x2xx的sram了。但是位置是自动分配的。
main 0x800'0741 0x2c Code Gb main.o [1]
testcnt 0x2000'00de 0x1 Data Gb main.o [1]
testfun 0x2000'0001 0x10 Code Gb main.o [1]
在ram中运行的代码,应该是先保存在flash中,然后flash中copy到ram中,能看到如下说明testfun函数保存的flash地址是0x8000980,运行的ram地址是0x20000000
Copy (__iar_copy_init3)
1 source range, total size 0x10:
0x800'0980 0x10
1 destination range, total size 0x10:
0x2000'0000 0x10
- 我们常见的应用中不可能只有一个函数,另外就是一般都会设计sector段来规范模块区域,而非让它自动分配地址。所以我要加一个rw sector段把函数放入固定ram位置。
修改icf链接文件
a. 把段名.APsramfun添加从rom自动copy到ram
initialize by copy { readwrite,section .APsarmfun };
b. 定义一个block作为这个段名的专属block
define block APramfun with alignment = 32, size = 1K {section .APsarmfun};
c. 将block放入自定义的sram区域
place in SRAM_region_my {block APramfun};
define region SRAM_region_my = mem:[from __ICFEDIT_region_SRAM2_start__ to __ICFEDIT_region_SRAM2_end__ ];
代码中函数首尾添加段区域名
#pragma default_function_attributes = @".APsarmfun"
/*#pragma location = ".APsarmfun"*/
/*__ramfunc void testfun(void)*/
void testfun(void)
{
testcnt++;
}
#pragma default_function_attributes =
检查编译的map文件,地址正确是sram2的首地址0x2001C000,怎么从1开始的?原来首尾是自动创建的,用于copy用途时候获取首尾地址。那么是正确的。
APramfun$$Base 0x2001'c000 -- Gb - Linker created -
APramfun$$Limit 0x2001'c400 -- Gb - Linker created –
main 0x800'0741 0x2c Code Gb main.o [1]
testcnt 0x2000'00ce 0x1 Data Gb main.o [1]
testfun 0x2001'c001 0x10 Code Gb main.o [1]
ram的位置固定到我预期的sram2区域了,不是自动分配了。
Copy (__iar_copy_init3)
1 source range, total size 0x10:
0x800'0834 0x10
1 destination range, total size 0x10:
0x2001'c000 0x10
-
把函数放入ram的期望的地址段问题已解决,但是函数在rom中的位置不是固定的,若要把rom位置也固定到自定义区域如何设置呢?
看了example及help文档,想想确实函数和data一样的操作方法,data不是bss,所以需要从rom复制初始化值到ram。按help一般都添加后缀_init,同一个.data拆分2个其中带后缀_init的放入ROM即可。
image.png
实战了,先添加一个rom的内存区域,在添加一个rom的block。最重要的就是sector要加后缀_init
define block APromfun with alignment = 32,size = 1K {section .APsarmfun_init};
生成的map文件中能看到rom也变成了预期的位置了,从0x80f0000开始
Copy (__iar_copy_init3)
1 source range, total size 0x10:
0x80f'0000 0x10
1 destination range, total size 0x10:
0x2001'c000 0x10
-
那么以前使用的链接文件,直接在代码中不加段名,也可以把代码放在固定段,直接把o文件或lib文件放入block即可,iar的链接文件应该也是支持的,但是要做成在ram中运行o文件中所有函数,那个_init和o文件应该怎么挂钩呢!
在帮助中找到了。sql数据库筛选都玩过吧,多条件的组合。如下筛选就是与的条件关系,正好满足我的需求某个o文件的只读属性,然后再与上sector,逐步缩小范围。
image.png
来实战了,按如下添加文件中的筛选组合段到block中,完美解决问题。main中的2个函数都放入ram运行,且存储在rom中都是从0x80f0000地址开始的。
在ram的block中添加readonly code object main.o筛选组合段
在对应rom的block中添加readonly code section *_init object main.o筛选组合段
在自动copy中添加readonly code object main.o筛选组合段
Copy (__iar_copy_init3)
1 source range, total size 0x64:
0x80f'0000 0x64
1 destination range, total size 0x64:
0x2000'0000 0x64
main 0x2000'0039 0x2c Code Gb main.o [1]
testcnt 0x2000'0132 0x1 Data Gb main.o [1]
testfun 0x2000'0029 0xa Code Gb main.o [1]
- 我要把main.o的一个文件改成多个文件,进行批处理,那么就是用模糊文件名即可,如下main.o改成了stm32f4xx为前缀的所有这些文件中的所有函数都copy到ram中运行。
define block APramfun with alignment = 32,size = 1K {section .APsarmfun,readonly code object stm32f4xx*.o};
define block APromfun with alignment = 32,size = 1K {section .APsarmfun_init,readonly code section *_init object stm32f4xx*.o};
initialize by copy { readwrite,section .APsarmfun,readonly code object stm32f4xx*.o };
生成的map文件中stm32f4xx*.c文件中所有函数的地址都是0x2001c开头符合预期
TIM_ClearITPendingBit 0x2001'c0cd 0x6 Code Gb stm32f4xx_tim.o [1]
TIM_Cmd 0x2001'c069 0x1a Code Gb stm32f4xx_tim.o [1]
TIM_GetITStatus 0x2001'c0b5 0x18 Code Gb stm32f4xx_tim.o [1]
TIM_ITConfig 0x2001'c0a1 0x14 Code Gb stm32f4xx_tim.o [1]
TIM_TimeBaseInit 0x2001'c001 0x68 Code Gb stm32f4xx_tim.o [1]
USART1_IRQHandler 0x800'04b9 0x68 Code Gb usart.o [1]
USART_GetITStatus 0x2001'c0ed 0x46 Code Gb stm32f4xx_usart.o [1]
USART_RX_BUF 0x2000'00ac 0xc8 Data Gb usart.o [1]
USART_RX_STA 0x2000'0174 0x2 Data Gb usart.o [1]
USART_ReceiveData 0x2001'c0e5 0x8 Code Gb stm32f4xx_usart.o [1]
UsageFault_Handler 0x2001'c0db 0x2 Code Gb stm32f4xx_it.o [1]
三,小结
完美解决所有自己提出的需求,我把需求的难度一步步提高,然后跟着help文档去找解决方案,通过做实验来闭环验证理解。every thing under the control,这种感觉真好~