前言
經常遇到有人使用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; }
評論
查看更多