一 ITCM 简介
ART-Pi 使用 STM32H750 做为主控。 STM32H7 使用的是 Cortex_M7 架构,中自带了ITCM(Instruction tightly coupled RAM)。下图可以看到 ITCM 与 Cortex_M7 内核直连,可实现 0 等待状态。
TCM RAM 与 CPU 是同频,其他 AHB 总线无法做到和 CPU 同频,所以使用 TCM 可以获得更好的性能。
虽然 TCM 的速度很快,但是他也有缺点,例如 DTCM 不能使用 DMA1 DMA2,ITCM 只能作为指令 RAM。
要使用 ITCM 得先知道他的地址:
通过上图可以看到 ITCM 的区域是 0x00000000 - 0x0000FFFF 的 64K。ITCM 从 0 地址就很尴尬了,一般在程序判断 NULL
就是用的 0 地址,所以最好的办法就是避开起始地址,为了某些情况下对齐操作,建议从 0x00000008 地址开始使用。
二 ITCM 在不同编译器下的使用
一个可执行程序是由 编译 --> 链接 这个过程的产生的。如何将函数指定到 ITCM ,其实就是将函数链接的地址设置在 ITCM 区域就可以了。
本文以 ART-Pi-LED 的示例代码来展示这一过程。
在 RTT Studio 中如何使用 ITCM
RTT Studio 中使用的编译器为 :GCC ,所以直接按照 GCC 链接脚本的方式去定义就好了。
在 RTT Studio 中如何指定某个函数到指定地址,需要三个步骤:
第一步:在链接文件中增加一个 ITCM 的描述信息
MEMORY
{
ROM (rx) : ORIGIN =0x90000000,LENGTH =8192k
RAM (rw) : ORIGIN =0x24000000,LENGTH =512k
RxDecripSection (rw) : ORIGIN =0x30040000,LENGTH =32k
TxDecripSection (rw) : ORIGIN =0x30040060,LENGTH =32k
RxArraySection (rw) : ORIGIN =0x30040200,LENGTH =32k
ITCM (rx) : ORIGIN =0x00000008,LENGTH =64k
}
最后一行增加了 ITCM 的描述信息
第二步:在链接文件中 SECTIONS 中增加 ITCM 的信息
SECTIONS
{
.ITCM :
{
. = ALIGN(4);
*(.ITCM)
*(.ITCM.*)
. = ALIGN(4);
} > ITCM = 0
.text :
{
. = ALIGN(4);
_stext = .;
KEEP(*(.isr_vector)) /* Startup code */
.
.
.
}
}
这里需要注意的是新增加的 .ITCM 一定要放到 .text 的前面
第三步,指定函数到 ITCM
__attribute__((section(".ITCM")))int main(void)
{
rt_uint32_t count = 0;
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
rt_kprintf("main adderss is 0x%08x\r\n",main);
rt_thread_mdelay(500);
led_light();
}
在修改之后重新 build 工程,查看 map 文件
*(.ITCM)
.ITCM 0x00000008 0x3c ./applications/main.o
0x00000008 main
可以看到 main 函数的地址已经被指定到 ITCM 的区域。
在 RTT Studio 中如何某个文件夹的所有函数到指定地址,需要两个步骤:
第一步:在链接文件中增加一个 ITCM 的描述信息
MEMORY
{
ROM (rx) : ORIGIN =0x90000000,LENGTH =8192k
RAM (rw) : ORIGIN =0x24000000,LENGTH =512k
RxDecripSection (rw) : ORIGIN =0x30040000,LENGTH =32k
TxDecripSection (rw) : ORIGIN =0x30040060,LENGTH =32k
RxArraySection (rw) : ORIGIN =0x30040200,LENGTH =32k
ITCM (rx) : ORIGIN =0x00000008,LENGTH =64k
}
最后一行增加了 ITCM 的描述信息
第二步:在链接文件中 SECTIONS 中增加 ITCM 的信息
SECTIONS
{
.ITCM :
{
. = ALIGN(4);
./applications/main.o (.text*)
*(.ITCM)
*(.ITCM.*)
. = ALIGN(4);
} > ITCM = 0
.text :
{
. = ALIGN(4);
_stext = .;
KEEP(*(.isr_vector)) /* Startup code */
.
.
.
}
}
这里将 ./applications/main.o 中的 .text 段都放入到了 ITCM
查看 map 文件
.text.led_light
0x00000024 0x38 ./applications/main.o
0x00000024 led_light
.text.main 0x0000005c 0x3c ./applications/main.o
0x0000005c main
.text.vtor_config
0x00000098 0x1c ./applications/main.o
可以看到 main.c 中的文件都被定义到了 ITCM 段
在 MDK 中如何使用 ITCM
在 MDK 中也需要修改对用的链接文件
在 MDK 中如何指定某个函数到指定地址,需要二个步骤:
第一步,修改链接文件
LR_IROM1 0x90000000 0x00800000 { ; load region size_region
ER_IROM1 0x90000000 0x00800000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM0 0x00000008 0x0000FFF8 { ; ITCM 64K
*(.ITCM)
}
RW_IRAM1 0x24000000 0x00080000 { ; AXI SRAM 512K
.ANY (+RW +ZI)
}
}
增加 ITCM 的描述
第二步,指定函数到 ITCM
__attribute__((section(".ITCM"))) void led_light(void)
{
rt_kprintf("main adderss is 0x%08x\r\n",led_light);
while(1)
{
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
}
}
查看 map 文件
led_light 0x00000009 Thumb Code 46 main.o
可以看到 led_light
函数已经被放到 ITCM 区域
在 MDK 中如何某个C文件的某些函数到指定地址,需要二个步骤:
第一步,修改链接文件
LR_IROM1 0x90000000 0x00800000 { ; load region size_region
ER_IROM1 0x90000000 0x00800000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM0 0x00000008 0x0000FFF8 { ; ITCM 64K
*(.ITCM)
}
RW_IRAM1 0x24000000 0x00080000 { ; AXI SRAM 512K
.ANY (+RW +ZI)
}
}
增加 ITCM 的描述
第二步,指定某些函数到 ITCM
可以在这些函数的前面和结束之后地方加上关键字,如下所示:
#pragma arm section code = ".ITCM"
void led_light(void)
{
rt_kprintf("main adderss is 0x%08x\r\n",led_light);
while(1)
{
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
}
}
int main(void)
{
rt_uint32_t count = 0;
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
rt_kprintf("main adderss is 0x%08x\r\n",main);
rt_thread_mdelay(500);
led_light();
return RT_EOK;
}
#pragma arm section
查看 map 文件
led_light 0x00000009 Thumb Code
$Super$$main 0x00000037 Thumb Code
三 注意事项
大家都知道 RAM 是掉电易失的,这种加速的方法如何在量产产品中使用呢?实际上使用以上的方法,MDK 会将特定的函数编译到 ROM 当中,在每次启动的时候都会将 ROM 中指定的函数拷贝到 RAM 放中。
但是上面的方法在 RTT Studio 中只会将函数写到指定的 RAM,这样掉电就丢失了,后续我会继续研究 RTT Studio 实现这个操作。