前言
经常遇到有人使用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; }
评论
查看更多