KEIL环境下如何让代码在 RAM中运行
经常遇到有人使用KEIL时需要将部分或者全部程序代码放到RAM中运行的问题,现将其总结在本文中。通过STM32F411Nucleo的一个例子来介绍几种让程序在RAM中运行的方法。
我们先从ToggleLED函数在Flash中执行亮灭开始。下面是ToggleLED函数和它的调用情况。在main函数的while(1)里调用ToggleLED。
void ToggleLED(void)
{ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); /* Insert a 100ms delay */
HAL_Delay(100);
}int main(void)
{ …… /*##-3- Toggle PA05 IO in an infinite loop######*/
while (1) { ToggleLED(); }
}
编译环境的Linker的配置见下图:
Flash起始地址:0x08000000
RAM起始地址:0x20000000
编译后从map文件可以看到,ToggleLED以及其中调用到的HAL_GPIO_TogglePin和HAL_Delay函数的地址都在FLASH中。
将翻转LED的程序放到SRAM中执行
方法一:通过#pragma arm section code = “RAMCODE ”和#pragma arm section。参考Example1代码。
这种方式,可以同时将多个函数放到指定的section。具体方法如下:
1. 修改.sct文件,自定义一个叫做RAMCODE的section,放在RW_IRAM1执行区域,地址范围0x20000000~0x20020000。
LR_IROM1 0x08000000 0x00080000 { ; load region size_region
ER_IROM1 0x08000000 0x00080000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
} RW_IRAM1 0x20000000 0x00020000 { ; RW data
*.o(RAMCODE)
.ANY (+RW +ZI)
}
}
2. 在工程中使用前面修改的.sct文件
3.以#pragma arm section code = “RAMCODE” 开头,以#pragma arm section结尾。将所有需要放到RAMCODE section的函数包括进来。编译时,编译器会自动将这些函数放到RAMCODE所在0x20000000开始的区域。
#pragma arm section code = "RAMCODE"
void ToggleLED(void)
{ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); /* Insert a 100ms delay */
HAL_Delay(100);
}void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{ /* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->ODR ^= GPIO_Pin;
}uint32_t HAL_GetTick(void)
{ return tick;
}void HAL_Delay(__IO uint32_t Delay)
{ uint32_t tickstart = 0;
tickstart = HAL_GetTick();
while((HAL_GetTick() - tickstart) < Delay)
{
}
}
#pragma arm section
4.从map文件里,可以看到这四个函数都已经被放到了SRAM中。
方法二:通过__attribute__((section(“name ”)))
在KEIL中可以通过__attribute__((at(address)))的方式将变量放到指定的位置。
通过__attribute__((section(“name ”)))的方式将变量或者函数放到指定的位置。
下面我们来看看如何通过这种方式将程序放到SRAM中执行。
1.同样,我们需要修改.sct文件,自定义一个叫做RAMCODE的section,并在工程选项的linker页面中,选择定义好的.sct文件。(见方法一中的第1,2步)
LR_IROM1 0x08000000 0x00080000 { ; load region size_region ER_IROM1 0x08000000 0x00080000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RW data
*.o(RAMCODE)
.ANY (+RW +ZI)
}
}
2.在需要放到RAM中的函数前,用__attribute__((section("RAMCODE")))声明该函数放在RAMCODE section中。注意,该函数中调用到的所有函数也要放到RAMCODE section中。
__attribute__((section("RAMCODE")))
void ToggleLED(void)
{ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); /* Insert a 100ms delay */
HAL_Delay(100);
}__attribute__((section("RAMCODE")))
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{ /* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->ODR ^= GPIO_Pin;
}__attribute__((section("RAMCODE")))
__weak uint32_t HAL_GetTick(void)
{ return uwTick; }__attribute__((section("RAMCODE")))
__weak void HAL_Delay(__IO uint32_t Delay)
{ uint32_t tickstart = 0;
tickstart = HAL_GetTick();
while((HAL_GetTick() - tickstart) < Delay)
{ }
}
3.从编译后的map文件可以看出,ToggleLED以及它调用到的所有函数都被到了RAM中。
方法二可以覆盖方法一,也就是说如果你同时用方法一和方法二对同一个函数的执行区域做了说明。最终起作用的是方法二。还是通过上面提到的代码来说明。
修改.sct文件。将SRAM分为两个执行区RW_IRAM1和RW_IRAM2。Section RAMCODE1,RAMCODE2分别位于0x20000000开始,和0x20010000开始的两个64KB的区域。
KEIL环境代码RA 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)