<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > KEIL環(huán)境下如何讓代碼在 RAM中運(yùn)行

          KEIL環(huán)境下如何讓代碼在 RAM中運(yùn)行

          作者: 時(shí)間:2016-11-13 來(lái)源:網(wǎng)絡(luò) 收藏
          前言

          經(jīng)常遇到有人使用KEIL時(shí)需要將部分或者全部程序代碼放到RAM中運(yùn)行的問(wèn)題,現(xiàn)將其總結(jié)在本文中。通過(guò)STM32F411Nucleo的一個(gè)例子來(lái)介紹幾種讓程序在RAM中運(yùn)行的方法。

          本文引用地址:http://www.ex-cimer.com/article/201611/316126.htm

          我們先從ToggleLED函數(shù)在Flash中執(zhí)行亮滅開(kāi)始。下面是ToggleLED函數(shù)和它的調(diào)用情況。在main函數(shù)的while(1)里調(diào)用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(); }
          }

          編譯環(huán)境的Linker的配置見(jiàn)下圖:
          Flash起始地址:0x08000000
          RAM起始地址:0x20000000

          編譯后從map文件可以看到,ToggleLED以及其中調(diào)用到的HAL_GPIO_TogglePin和HAL_Delay函數(shù)的地址都在FLASH中。


          將翻轉(zhuǎn)LED的程序放到SRAM中執(zhí)行
          方法一:通過(guò)#pragma arm section code = “RAMCODE ”和#pragma arm section。參考Example1代碼。
          這種方式,可以同時(shí)將多個(gè)函數(shù)放到指定的section。具體方法如下:
          1. 修改.sct文件,自定義一個(gè)叫做RAMCODE的section,放在RW_IRAM1執(zhí)行區(qū)域,地址范圍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” 開(kāi)頭,以#pragma arm section結(jié)尾。將所有需要放到RAMCODE section的函數(shù)包括進(jìn)來(lái)。編譯時(shí),編譯器會(huì)自動(dòng)將這些函數(shù)放到RAMCODE所在0x20000000開(kāi)始的區(qū)域。

          #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文件里,可以看到這四個(gè)函數(shù)都已經(jīng)被放到了SRAM中。

          方法二:通過(guò)__attribute__((section(“name ”)))
          在KEIL中可以通過(guò)__attribute__((at(address)))的方式將變量放到指定的位置。
          通過(guò)__attribute__((section(“name ”)))的方式將變量或者函數(shù)放到指定的位置。

          下面我們來(lái)看看如何通過(guò)這種方式將程序放到SRAM中執(zhí)行。
          1.同樣,我們需要修改.sct文件,自定義一個(gè)叫做RAMCODE的section,并在工程選項(xiàng)的linker頁(yè)面中,選擇定義好的.sct文件。(見(jiàn)方法一中的第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中的函數(shù)前,用__attribute__((section("RAMCODE")))聲明該函數(shù)放在RAMCODE section中。注意,該函數(shù)中調(diào)用到的所有函數(shù)也要放到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以及它調(diào)用到的所有函數(shù)都被到了RAM中。

          方法二可以覆蓋方法一,也就是說(shuō)如果你同時(shí)用方法一和方法二對(duì)同一個(gè)函數(shù)的執(zhí)行區(qū)域做了說(shuō)明。最終起作用的是方法二。還是通過(guò)上面提到的代碼來(lái)說(shuō)明。
          修改.sct文件。將SRAM分為兩個(gè)執(zhí)行區(qū)RW_IRAM1和RW_IRAM2。Section RAMCODE1,RAMCODE2分別位于0x20000000開(kāi)始,和0x20010000開(kāi)始的兩個(gè)64KB的區(qū)域。

          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 0x00010000 { ; RW data
          *.o(RAMCODE1)
          .ANY (+RW +ZI)
          }

          RW_IRAM2 0x20010000 0x00010000 {
          *.o(RAMCODE2) }
          }

          2.在代碼中, HAL_GetTick被放在了#pragma的作用域內(nèi)被聲明放在RAMCODE1 section,同時(shí)又用__attribute__( ( section ( "RAMCODE2" ) ) ) 將其放在RAMCODE2的section內(nèi)。

          #pragma arm section code = "RAMCODE1"
          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;
          }

          __attribute__( ( section ( "RAMCODE2" ) ) )
          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

          3.編譯完成后,我們看看map文件中HAL_GetTick被放到了哪個(gè)section。

          從map里可以看到,最終HAL_GetTick被放在了RAMCODE2 section中。

          **如何將整個(gè)程序放到SRAM中執(zhí)行
          前面介紹了將一個(gè)或多個(gè)程序放到指定地址執(zhí)行的方法。如果需要放到指定地址的程序比較多,我們還可以將這些需要放到指定地址的程序集中放到一個(gè)或幾個(gè)C文件中,然后在.sct文件中將這些C文件生成的目標(biāo)文件放到指定地址。
          在這里,我們將嘗試將整個(gè)程序放到SRAM中執(zhí)行。復(fù)位后程序從FLASH啟動(dòng),之后將從SRAM執(zhí)行所有的程序。下面是具體的步驟。
          1.將中斷向量表和中斷處理程序放到SRAM中
          新建一個(gè)startup_stm32f411xe_ram.s文件,放到0x20000000開(kāi)始的位置(在.sct文件中修改)。注意這里是新建,而不是直接將原來(lái)的文件放到SRAM中,為什么呢?大家可以思考一下。在startup_stm32f411xe_ram.s里定義新的SECTION,叫做RESET_ram(還有其他的修改,請(qǐng)對(duì)照參考代碼)。在后面的.sct中將把RESET_ram這個(gè)section放到SRAM開(kāi)始的位置上(見(jiàn)第3步)。

          Vector Table Mapped to Address 0 at Reset
          AREA RESET_ram, DATA, READONLY
          EXPORT __Vectors_ram
          EXPORT __Vectors_End_ram
          EXPORT __Vectors_Size_ram
          __Vectors_ram DCD 0 ; Top of Stack
          DCD 0 ; Reset Handler
          DCD NMI_Handler ; NMI Handler
          ……

          2.在SystemInit中將中斷向量表的偏移地址設(shè)置為0x20000000。使能VECT_TAB_SRAM。

          #ifdef VECT_TAB_SRAM
          SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
          #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
          #endif

          3.修改.sct文件,將運(yùn)行時(shí)需要的所有目標(biāo)文件都放到SRAM執(zhí)行區(qū)中。這里中斷向量表有同樣的兩份,一份在0x08000000開(kāi)始的位置,一份在0x20000000開(kāi)始的位置。

          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 (RESET_ram, +First)
          startup_stm32f411xe_ram.o(+RO)
          main.o(+RO +RW)
          stm32f4xx_it.o(+RO +RW)
          stm32f4xx_hal.o(+RO +RW)
          stm32f4xx_hal_gpio.o(+RO +RW)
          stm32f4xx_hal_rcc.o(+RO +RW)
          stm32f4xx_hal_cortex.o(+RO +RW)
          .ANY (+RW +ZI)
          }
          }

          4. 編譯完成后,從map文件或者跟蹤調(diào)試的結(jié)果都可以看到。系統(tǒng)復(fù)位以后,從main函數(shù)開(kāi)始,所有的程序都在RAM中運(yùn)行了。
          另外,如果你的程序中有用到ARM底層的庫(kù),可以在.sct文件中加入*armlib*(+RO)來(lái)將所有用到的庫(kù)文件放到SRAM中。



          關(guān)鍵詞: KEIL環(huán)境代碼RA

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();