解析使用RT-Thread Studio指定特殊函数加载到RAM的方法

描述

  用ITCM给ART-Pi(STM32H7)代码加速 , 这篇文章就提到了,将特殊的函数(如,算法相关)加载到速度更快的 ITCM,但是这篇文章中使用 GCC 编译器的时候,无法保证在断电复位后 RAM 段的代码不消失,所以本文来研究这个问题。

  众所周知,RAM 是掉电丢失数据的,为了做到产品中也能使用这种操作,就需要将代码编译到 ROM 中,然后启动的时候,从 ROM 拷贝到 RAM 当中,知道了原理,具体如何操作呢?

  二、RT-Thread Studio 指定特殊函数到RAM的办法

  为了实现这种操作,需要知道可执行程序的生成过程,预处理- 》编译 -》汇编-》 链接,可以从这几个地方去着手解决这个问题。RTT Studio 使用的是 GCC 的编译器,所以修改相应的 GCC 文件就可以了。

  1. 修改链接文件

  为了实现这个目的,所以需要在链接文件中增加对应的 .section.

  描述 ITCM 的属性

1MEMORY
2{
3ROM (rx) : ORIGIN =0x90000000,LENGTH =8192k
4RAM (rw) : ORIGIN =0x24000000,LENGTH =512k
5RxDecripSection (rw) : ORIGIN =0x30040000,LENGTH =32k
6TxDecripSection (rw) : ORIGIN =0x30040060,LENGTH =32k
7RxArraySection (rw) : ORIGIN =0x30040200,LENGTH =32k
8ITCM (rx) : ORIGIN =0x00000000,LENGTH =64k
9}

 

ITCM (rx) :名字是 ITCM,r: Read-only sections. , x : Sections containing executable code.
ORIGIN =0x00000000 : 起始地址
LENGTH =64k :总长度

构造 section

 1SECTIONS
 2{   
 3    .text :
 4    {
 5        . = ALIGN(4);
 6        _stext = .;
 7        KEEP(*(.isr_vector))            /* Startup code */
 8        . = ALIGN(4);
 9        *(.text.*)
10        *(.rodata)                      /* read-only data (constants) */
11        *(.rodata*)
12        *(.glue_7)
13        *(.glue_7t)
14        *(.gnu.linkonce.t*)
15
16        /* section information for finsh shell */
17        . = ALIGN(4);
18        __fsymtab_start = .;
19        KEEP(*(FSymTab))
20        __fsymtab_end = .;
21
22        . = ALIGN(4);
23        __vsymtab_start = .;
24        KEEP(*(VSymTab))
25        __vsymtab_end = .;
26
27        /* section information for utest */
28        . = ALIGN(4);
29        __rt_utest_tc_tab_start = .;
30        KEEP(*(UtestTcTab))
31        __rt_utest_tc_tab_end = .;
32
33        /* section information for at server */
34        . = ALIGN(4);
35        __rtatcmdtab_start = .;
36        KEEP(*(RtAtCmdTab))
37        __rtatcmdtab_end = .;
38        . = ALIGN(4);
39
40        /* section information for modules */
41        . = ALIGN(4);
42        __rtmsymtab_start = .;
43        KEEP(*(RTMSymTab))
44        __rtmsymtab_end = .;
45
46        /* section information for initial. */
47        . = ALIGN(4);
48        __rt_init_start = .;
49        KEEP(*(SORT(.rti_fn*)))
50        __rt_init_end = .;
51
52        . = ALIGN(4);
53
54        PROVIDE(__ctors_start__ = .);
55        KEEP (*(SORT(.init_array.*)))
56        KEEP (*(.init_array))
57        PROVIDE(__ctors_end__ = .);
58
59        . = ALIGN(4);
60
61        _etext = .;
62    } > ROM
63
64    .ITCM :
65    {
66        . = ALIGN(4);
67        __itcm_start = .;
68        *(.ITCM)
69        . = ALIGN(4);
70        __itcm_end = .;
71    } > ITCM AT>ROM
72    __itcm_rom_start = LOADADDR(.ITCM);
73    __itcm_size = SIZEOF(.ITCM);

 

这里链接文件的修改的作用是,将 __attribute__((section(".ITCM"))) int main(void)  这种指定函数到特殊区域的 ITCM 段的函数,编译后放到 ROM 里面,程序运行的时候从 RAM 取这个函数,这样可以在系统上电之后可以从 ROM 中把数据复制到 RAM 当中,这样就解决了上一篇文章的问题。这里定义了 2 个全局变量方便后续在汇编当中把函数从 ROM 拷贝到 RAM。

2. 修改启动汇编

startup_stm32h750xx.s 这里只做了,已初始化值的数据,从 ROM 拷贝到 RAM 的操作,所以需要增加一些代码来实现把函数从 ROM 拷贝到 RAM
修改部分:

 1Reset_Handler:   /* 程序复位后的启动地址 */
 2  ldr   sp, =_estack      /* 设置 SP */
 3
 4  ldr r0 ,=__itcm_rom_start  /* 加载 放在了 ROM 当中,需要加载到 ITCM 中数据的起始地址到 R0 */
 5  ldr r1 ,=__itcm_start /* 加载 ITCM 第一个函数的起始放置位置到 R1 */
 6  ldr r2 ,=__itcm_size /* 加载 ITCM 的大小到 R2 */
 7  add r2 , r1, r2  /* R1 加 R2 的值 放到 R2 */
 8
 91:
10  cmp r2, r1  /* 比较 R1 与 R2 */
11  beq 2f /* 如果上面的比较之后是相等的 则跳转到标签 2  */
12  ldr r3 ,[r0],#4 /*  将 R0 寄存器里面存放的地址处的代码,写入到 R3 寄存器里面。然后 R0 + 4 */
13  str r3 ,[r1],#4 /* 将R3中的数据写入以R1为地址的存储器中,然后 R1 + 4*/
14  b 1b /* 调回到标签 1,循环拷贝 */
152/* 以下是未修改之前的 GCC 启动汇编代码 */
16
17/* Copy the data segment initializers from flash to SRAM */  
18  movs  r1, #0
19  b  LoopCopyDataInit

 

这里使用了数字标签,所以跳转时候标签后缀为b或f,b==back ,f == forward。

这里的拷贝方法就是,知道程序下载之后放在了 ROM 的位置,然后从这个位置拷贝到 RAM 中去。

3. 将函数指定链接位置

1__attribute__((section(".ITCM")))
2int main(void)
3{
4    rt_uint32_t count = 0;
5
6    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
7}

 

三, 总结

1、用ITCM给ART-Pi(STM32H7)代码加速 提到的方法,MDK 可以实现启动的时候将 ROM 中的函数搬运到 RAM 当中的操作,使用 RTT Studio 也可以实现

2、在 GCC 的链接文件可以描述一个文件的 section 的中数据的存放地址和加载地址不一致。

3、在 RT-Thread Studio 中实现这个操作,确实比 MDK 会复杂很多,对于研究底层的人而言,在 MDK 中很难看到这些细节,喜欢自定义操作的人而言,GCC 就更加的灵活了。

编辑:jq


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分