chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

在極海APM32系列MCU中如何把代碼重定位到SDRAM運行

Geehy極海半導體 ? 來源:21ic論壇極海半導體專區(qū) ? 2025-11-04 09:14 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

《APM32芯得》系列內(nèi)容為用戶使用APM32系列產(chǎn)品的經(jīng)驗總結(jié),均轉(zhuǎn)載自21ic論壇極海半導體專區(qū),全文未作任何修改,未經(jīng)原文作者授權(quán)禁止轉(zhuǎn)載。

在有些情況下,我們想要把代碼放到SDRAM運行。下面介紹在APM32的MCU中,如何把代碼重定位到SDRAM運行。對于不同APM32系列的MCU,方法都是一樣的。

1、APM32啟動模式

熟悉MCU都知道,可以通過配置 BOOT0/1 兩個引腳的高低電平,選擇不同的啟動方式。對于APM32來說也是一樣的,可以配置 BOOT0/1 引腳電平選擇不同的啟動模式,下表是我從APM32的用戶手冊截圖的啟動模式配置表:

9cdd345e-b654-11f0-8c8f-92fbcf53809c.png

有內(nèi)置SRAM、Flash、系統(tǒng)存儲區(qū)啟動3種模式。對于讓程序重定位到SDRAM運行,我們選擇Flash啟動即可。

不同的啟動模式,本質(zhì)其實就是MCU上電時,從哪個地址處讀取出數(shù)據(jù)然后賦值給PC寄存器,以及SP寄存器。比如選擇從Flash啟動,MCU上電時,0x08000000處起始的4個字節(jié)的數(shù)據(jù),賦值給SP寄存器,08000004處起始的4個字節(jié)的數(shù)據(jù)賦值給PC寄存器。設(shè)置了SP和PC寄存器,程序就可以正常運行了。

MCU上電,PC寄存器從哪里開始取值,和后面要講的把代碼搬運到SDRAM運行,是有關(guān)聯(lián)的,所以這里提一下APM32的啟動模式。

2、程序段概念的引入

一個程序的源碼被編譯之后,鏈接器會根據(jù)代碼中的不同屬性,把他們劃分為一個個不同的段,比如 .text段、.rodata段、.data段、.bss/.zi段等等,還有用戶也可以自定義一些段,比如把所有初始化的代碼,自定義一個初始化段。

.text段:代碼段或者文本段。我們編寫的代碼,鏈接器都是歸類在這個段的。對于MCU來說就是存放在內(nèi)部的Flash中。

.rodata段:只讀數(shù)據(jù)段。比如我們使用const定義的變量,或者定義的字符串這些,都被鏈接到只讀數(shù)據(jù)段。只讀數(shù)據(jù)段和代碼段,都是只能讀不能寫,所以都是存放在Flash中的。

.data段:可讀可寫的數(shù)據(jù)段。我們定義的初始化為非0的全局變量、非0的靜態(tài)局部變量,都是存放在這個段的。

.bss/.zi段:.bss段或者.zi段,都是同一個段,只是叫法不一樣。.bss段和.data段是一樣的,都是可讀可寫的數(shù)據(jù)段的一種。.bss段存放的就是初始值為0的全局變量或者初始值為0的靜態(tài)局部變量。

既然.data段和.bss段存放的內(nèi)容基本一樣,為什么要把這兩個段分開存放?這是因為.bss段的初值是0,不需要燒錄到Flash里面存放,在程序使用之前,我們把.bss段的對應(yīng)區(qū)域給清0就行了,這樣不需要浪費Flash空間。

堆:一段空閑的內(nèi)存空間,可以給程序員自由使用??梢酝ㄟ^一些內(nèi)存管理接口函數(shù)進行申請和釋放。

棧:也是一塊內(nèi)存空間,不過程序自行管理。C語言的運行需要棧,MCU上電時就需要把SP(棧)寄存器指向一片正??捎玫腞AM作為棧來使用。

用戶如果有需要,也可以自定義自己的段,然后鏈接器會根據(jù)用戶的要求,把指定的代碼編譯到自定義的段。

我們要把代碼重定位到SDRAM運行,本質(zhì)就是復(fù)制這些段的數(shù)據(jù),把這些數(shù)據(jù)復(fù)制到它們應(yīng)該位于的地方(代碼應(yīng)該要位于鏈接地址處運行)。

3. keil散列文件語法分析

前面提到,代碼的重定位,本質(zhì)就是數(shù)據(jù)的復(fù)制。數(shù)據(jù)的復(fù)制有3個要點要知道:從那里復(fù)制(源地址)、復(fù)制到哪里去(目的地址)、復(fù)制多長(長度)。

源地址:我們要從哪里開始復(fù)制數(shù)據(jù)呢?其實就是加載地址,我們程序燒錄到哪個位置,那就是加載地址。比如程序燒寫到內(nèi)部的Flash中,那么加載地址就是0x08000000 。程序存放到外部的SPI Flash中,加載地址就是存放在外部SPI Flash的地址。

目的地址:要把程序復(fù)制到這里的地址,就是程序的鏈接地址,程序的運行就是要位于它的鏈接地址處運行(當然如果寫的所有代碼都是位置無關(guān)碼,那么可以不在鏈接地址處運行)。

長度:復(fù)制多長。

上面提到的這些復(fù)制數(shù)據(jù)所需的信息,所有的這一切都可以從鏈接腳本中獲取到,它是用來指導鏈接器如何進行鏈接的一種規(guī)則文件。對于Keil來說,鏈接腳本指的就是散列文件。

3.1 Keil默認的散列文件示例

下面的代碼是keil自動生成的APM32F407ZG型號的散列文件:

; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************

LR_IROM1 0x08000000 0x00100000 { ; load region size_region

ER_IROM1 0x08000000 0x00100000 { ; load address = execution address

*.o (RESET, +First)

*(InRoot$Sections)

.ANY (+RO)

.ANY (+XO)

}

RW_IRAM1 0x20000000 0x00020000 { ; RW data

.ANY (+RW +ZI)

}

}

一個散列文件,是由多個加載域、執(zhí)行域和輸入段所組成??梢酝ㄟ^Keil幫助文檔獲得這些內(nèi)容的講解。

3.2 散列文件語法

上面的示例,每個數(shù)據(jù)、符號代表什么意義?這些內(nèi)容我們可以通過Keil的幫助文檔學習到,安裝了Keil軟件,就可以獲取到幫助文檔信息了。

9d427f08-b654-11f0-8c8f-92fbcf53809c.png

打開鏈接相關(guān)的文檔,找到散列文件的語法介紹。

下圖就是幫助文檔關(guān)于散列文件的組成結(jié)構(gòu):

9dab79e0-b654-11f0-8c8f-92fbcf53809c.png

根據(jù)上圖:一個散列文件可以一個或多個加載域,每個加載域又可以包含多個可執(zhí)行域,而可執(zhí)行域是由各個段(如代碼段、數(shù)據(jù)段等)組成的。

3.2.1加載域語法

load_region_description ::=

load_region_name ( base_address | ("+" offset )) [ attribute_list ] [ max_size ]

"{"

execution_region_description +

"}"

load_region_name就是加載域的名稱,base_address加載域的基地址,加載域的長度(就是整個程序燒錄的大?。?。然后加載域里面包含一個或多個可執(zhí)行域。

以上面的示例為例:

LR_IROM1 0x08000000 0x00100000 { ; load region size_region

}

加載域名稱就是 LR_IROM1,起始地址0x08000000,長度0x00100000。

3.2.2 可執(zhí)行域語法

execution_region_description ::=exec_region_name ( base_address | "+" offset ) [ attribute_list ] [ max_size | length ]"{"input_section_description *"}"

和加載域的描述也是類似的。然后可執(zhí)行域里面就是由各個段組成的。

3.2.3 輸入段

9e0ddab8-b654-11f0-8c8f-92fbcf53809c.png

前面是選擇代碼的哪些區(qū)域空間鏈接進這個段,后面是段的名字。

比如:main.o(+RO) 就是說main.o文件鏈接到RO段。

常見段類型的解析:

*.o (RESET, +First) :指的是所有的.o文件的RESET段,+First就是要求RESET段要鏈接到程序最開始的地方。

*(InRoot$$Sections):鏈接器去鏈接Keil自帶的一部分代碼。這部分代碼的作用主要是數(shù)據(jù)段的重定位和清除bss段

.ANY (+RO):.ANY作用和 * 一樣,指的是所有的意思,但是優(yōu)先級比 * 低。這里說是把所有文件的RO段(Read Only段)放到這里。

.ANY (+XO):所有的 execute-only 段。

3.3如何通過散列文件獲取源、目的、長度

我們學習散列文件的目的就是為了得到代碼重定位的源(加載地址)、目的(鏈接地址)、和長度。那么我們?nèi)绾瓮ㄟ^散列文件獲取這些信息?

Keil的鏈接器定義了各種符號,通過這些符號我們可以獲取到這些信息。

3.3.1 可執(zhí)行域區(qū)域信息

9e72fe84-b654-11f0-8c8f-92fbcf53809c.png

通過可執(zhí)行域的這些符號,我們就知道把代碼復(fù)制到哪里去了。

3.3.2 加載域區(qū)域信息

9ed891c2-b654-11f0-8c8f-92fbcf53809c.png

通過加載域的這些信息,可以獲取到各個段(代碼段、數(shù)據(jù)段、bss段)的起始地址,和長度信息。

4. 代碼重定位到SDRAM的方法

我們?yōu)槭裁匆汛a重定位到SDRAM運行?

一般有兩種情況:

內(nèi)部Flash空間不足,不能存放下所有的代碼。這個時候我們就只能把編譯得到的bin文件燒錄到外部的存儲設(shè)備了,比如SPI Flash等。但是SPI Flash根本就不能運行代碼,所以MCU上電后就需要把SPI Flash的bin文件,搬運到SDRAM或者其他可運行代碼的存儲設(shè)備。

為了得到更快的執(zhí)行速率,這個時候我們可以把代碼搬運到SRAM或者SDRAM執(zhí)行。(但是對于MCU來說,我不確定是內(nèi)部的Flash執(zhí)行代碼更快還是SDRAM更快)

對于第一種情況,是很常用的。比如嵌入式Linux的設(shè)備,就是這種啟動方式,內(nèi)核鏡像存儲在外部EMMC、SD卡等這種大容量設(shè)備中,但是他們都無法執(zhí)行代碼,所以上電后會把內(nèi)核鏡像搬運到內(nèi)存中運行。

根據(jù)這兩種情況,我們可以有兩種方法把代碼搬運到SDRAM運行。

應(yīng)用程序自己復(fù)制自己

通過Bootloader程序,復(fù)制應(yīng)用程序

4.1 程序自己復(fù)制自己

當整個應(yīng)用程序都燒寫在MCU的內(nèi)部Flash時,這個時候我們可以使用這種方法,讓應(yīng)用程序自己復(fù)制自己到內(nèi)存中,比如SDRAM運行。

當然在這種情況中,我好像想不到把程序復(fù)制到SDRAM運行的意義。是為了獲得更快的代碼運行速度?但是我也不確定程序在內(nèi)部Flash運行更快還是SDRAM運行更快?

可能唯一的意義可以就是可以學習到代碼重定位相關(guān)的知識了吧......

廢話少說,程序它為什么可以自己復(fù)制自己?

我們前面介紹過,程序運行應(yīng)該位于它的鏈接地址上,但是當這個程序的所有代碼都是位置無關(guān)碼的時候,它就可以不在鏈接地址上運行。位置無關(guān)碼就是這段代碼可以在任何地址上正常運行,它與執(zhí)行的位置無關(guān)。

位置無關(guān)碼編寫要求:

匯編指令,不能使用絕對跳轉(zhuǎn)。比如對PC指針賦值跳轉(zhuǎn),或者使用跳轉(zhuǎn)指令,跳轉(zhuǎn)到某個地址值。比如下面這些就是絕對跳轉(zhuǎn)

; 下面這種跳轉(zhuǎn)方式就是絕對跳轉(zhuǎn)

ldr PC, =main

LDR R0, =SystemInit

BLX R0

; BL指令是相對跳轉(zhuǎn)指令

BL main

C言語,不能使用函數(shù)指針調(diào)用函數(shù)。因為函數(shù)指針調(diào)用方式就是指向一個確定的地址值,而這個地址是鏈接時分配的地址,代碼沒有在鏈接地址處運行的時候,跳轉(zhuǎn)過去程序只能崩潰

對于訪問數(shù)據(jù)的話,不要去訪問全局變量、靜態(tài)局部變量、字符串。

我們把應(yīng)用程序燒寫到MCU內(nèi)部的Flash時,可以在應(yīng)用程序的最前面一部分代碼, 放置重定位相關(guān)的代碼,這重定位相關(guān)的代碼編寫要求就是必須使用位置無關(guān)碼編寫。

因為當我們要把程序放到SDRAM運行時,就需要修改程序的鏈接地址指向SDRAM的內(nèi)存空間,而MCU剛上電,是從Flash的空間開始取指令運行的,所以Flash最開始的那一部分代碼必須是位置無關(guān)碼,否則就無法正常運行。

4.2 Bootloader復(fù)制應(yīng)用程序

當應(yīng)用程序太大,無法燒錄到內(nèi)部Flash時,就只能燒寫到外部Flash。

這個時候,就可以編寫一個簡單的程序(當然你也可以做得很復(fù)雜,做到適配各種外部存儲設(shè)備,各種協(xié)議什么的),它的主要作用就是復(fù)制應(yīng)用程序到鏈接地址處運行。

然后把這個程序燒寫到內(nèi)部的Flash上,MCU上電,可以先運行這段代碼,接著把外部的應(yīng)用程序復(fù)制到內(nèi)存(SDRAM)運行,復(fù)制完成之后再跳轉(zhuǎn)到內(nèi)存運行即可。這個程序通常被叫做Bootloader。

嵌入式Linux設(shè)備就是使用這種方式啟動的,當然啟動過程比這里說的還要復(fù)雜,但是總體啟動過程類似。

5. 代碼重定位到SDRAM運行的過程

前面講了很多內(nèi)容,大家可以不用看,只看最后這章,看看代碼怎么寫就行了。重定位的代碼其實也很簡單,本質(zhì)就是復(fù)制數(shù)據(jù),而復(fù)制數(shù)據(jù)調(diào)用一個memcpy函數(shù)就足夠了。

上面介紹了兩種代碼重定位到SDRAM運行的方法,下面我只講第一種方法。其實大家也可以把前面這部分重定位的代碼看作是Bootloader程序,只不過它比較簡單,和應(yīng)用程序鏈接在一起了。

重定位的這部分代碼編寫流程:

初始化系統(tǒng)時鐘

初始化SDRAM,因為訪問SDRAM需要設(shè)置SDRAM的時序參數(shù)

.text段重定位

.data段重定位

.bss/zi段清零

重新設(shè)置中斷向量表寄存器的基地址

絕對跳轉(zhuǎn)到SDRAM運行

然后我的開發(fā)板使用的是APM32F407ZG型號,下面的代碼是適配這個型號的。當然APM32系列的其他型號,重定位的思路方法都是一樣的,參考著來就行。

5.1 修改散列文件

我們的目的是要把程序放到SDRAM運行,所以我們必須修改鏈接地址在SDRAM的內(nèi)存空間,讓鏈接器根據(jù)這段內(nèi)存空間分配地址。而修改鏈接地址,對于Keil來說就要修改散列文件。

我使用的芯片型號是APM32F407ZG,而且外面接的SDRAM的起始地址是0x60000000,大小一共是2MB。所以修改出來的散列文件如下:

LR_IROM1 0x08000000 0x00100000 { ; load region size_region

ER_IROM1 0x60000000 0x00200000 { ; load address = execution address

*.o (RESET, +First)

;*(InRoot$Sections)

.ANY (+RO)

.ANY (+XO)

}

RW_IRAM1 0x20000000 0x00020000 { ; RW data

.ANY (+RW +ZI)

}

ARM_LIB_HEAP +0 EMPTY 0x0200 { ; Heap region growing up

}

ARM_LIB_STACK +0 EMPTY 0x0400 { ; Stack region growing down

}

}

加載域的地址不變,因為我們還是要下載到Flash中存儲程序的。但是執(zhí)行域修改為了SDRAM的起始地址和大小。然后可讀可寫的數(shù)據(jù)域地址和大小沒改,依舊是使用MCU內(nèi)部的SRAM作為數(shù)據(jù)存儲區(qū)。

但是下面我新增了兩個執(zhí)行域,那就是堆和棧,這兩個域的地址是緊接著 RW_IRAM1域進行編排地址的,大小分別是 0x200 和 0x400。為什么要加上這兩個域下面講解。

5.2 初始化系統(tǒng)時鐘和SDRAM

初始化時鐘相關(guān)的代碼,直接調(diào)用APM32 SDK提供的SystemInit函數(shù)即可,但是要更改一下調(diào)用方式為相對跳轉(zhuǎn)。

我們是要把代碼從MCU內(nèi)部的Flash復(fù)制到SDRAM運行,那么復(fù)制之前,必須能正確的讀寫SDRAM才能正常復(fù)制,而SDRAM的讀寫需要先初始化它的時序參數(shù)才行。

我的板子使用的SDRAM型號是:EM638165TS-7IG,然后關(guān)于這個SDRAM型號的初始化代碼,可以從官方的 APM32F4xx_EVAL_SDK_V1.0 這個SDK中,稍微修改下就可以拿過來使用了。

然后我們在匯編代碼的 Reset_Handler 函數(shù)(標號)中調(diào)用這幾個函數(shù):

BL SystemInit

BL SDRAM_GPIOConfig

BL SDRAM_Init

5.3 .text段重定位

各個段的重定位,就是數(shù)據(jù)的復(fù)制。我們必須要知道,源、目的、長度。而這些信息,都在散列文件中獲取到。前面花了很大篇幅講了散列文件作用就在這里。

代碼如下:

IMPORT |Image$ER_IROM1$Base|

IMPORT |Image$ER_IROM1$Length|

IMPORT |Load$ER_IROM1$Base|

; relocate text section

LDR R0, = |Image$ER_IROM1$Base| ; destination

LDR R1, = |Load$ER_IROM1$Base| ; source

LDR R2, = |Image$ER_IROM1$Length| ; lenth

BL mymemcpy

ER_IROM1 就段名,這個段就是 .text 代碼段的意思。

|Load$$ER_IROM1$$Base| :.text段加載地址,就是復(fù)制數(shù)據(jù)的源地址

|Image$$ER_IROM1$$Base| :.text段執(zhí)行域地址,也就是鏈接地址,就是復(fù)制數(shù)據(jù)的目的地址

|Image$$ER_IROM1$$Length| :.text段的長度

我們通過上面那幾個奇奇怪怪的符號,就可以獲得.text段的加載地址,鏈接地址,和長度了。知道這些信息,然后復(fù)制數(shù)據(jù)調(diào)用一個memcpy就可以把Flash的.text段復(fù)制到SDRAM了。

5.4 .data段重定位

.data段,存放的就是各種初值不是0的全局變量、靜態(tài)局部變量,我們也需要把這部分數(shù)據(jù)的初始值,從Flash空間中復(fù)制到對應(yīng)的內(nèi)存中去。

我們在散列文件,數(shù)據(jù)段的鏈接地址是設(shè)置在0x20000000地址處的。

重定位代碼如下:

IMPORT |Image$RW_IRAM1$Base|

IMPORT |Image$RW_IRAM1$Length|

IMPORT |Load$RW_IRAM1$Base|

; relocate data section

LDR R0, = |Image$RW_IRAM1$Base| ; destination

LDR R1, = |Load$RW_IRAM1$Base| ; source

LDR R2, = |Image$RW_IRAM1$Length| ; lenth

BL mymemcpy

代碼基本和.text段重定位差不多的,就是那幾個符號不一樣,是獲取.data段的加載地址、鏈接地址和長度的符號。

5.5 .bss/zi段清零

.bss/zi段 是初始值為0的全局變量和靜態(tài)局部變量存放的地址,但是這個段的內(nèi)容不會存放在Flash中,因為初值為0,我們在使用之前把這個段的內(nèi)存空間清0即可,無需浪費空間把編譯進bin文件里面。

IMPORT |Image$RW_IRAM1$ZI$Base|

IMPORT |Image$RW_IRAM1$ZI$Length|

; clear bss/zi

LDR R0, = |Image$RW_IRAM1$ZI$Base| ; destination

MOV R1, #0 ; Value

LDR R2, = |Image$RW_IRAM1$ZI$Length| ; lenth

BL bss_section_clear

|Image$$RW_IRAM1$$ZI$$Base| : 是bss/zi段的鏈接地址

|Image$$RW_IRAM1$$ZI$$Length| : bss/zi段的長度

我們調(diào)用一個memset函數(shù)就可以把對應(yīng)的內(nèi)存段清0了。

5.6 重新設(shè)置中斷向量表寄存器基地址

中斷向量表的基地址默認是0x08000000處的,當中斷發(fā)生時,MCU會自動到這個地址處找到對應(yīng)的中斷處理函數(shù),然后跳轉(zhuǎn)過去。

但是我們需要把代碼搬運到了SDRAM運行,如果還想要正常使用中斷處理函數(shù)的話,就必須修改中斷向量表的基地址到鏈接的起始地址,也就是0x60000000。

修改方法也很簡單,SCB->VTOR 修改這個寄存器的值就行了,這個寄存器是內(nèi)核相關(guān)的寄存器,它的地址是0xE000ED08.

代碼如下:

; set interrupt vector base address to 0x60000000

ldr r0, =__Vectors

ldr r1, =0xE000ED08 ; SCB->VTOR register address is 0xE000ED08

str r0, [r1]

ldr指令,把__Vectors的鏈接地址(其實就是0x60000000)加載到r0寄存器中,然后再使用str指令,把這個值寫到0xE000ED08地址處。

5.7 一些問題

做完前面的過程,基本就完成了把代碼重定位到SDRAM了,這個時候就可以使用絕對跳轉(zhuǎn)指令,跳轉(zhuǎn)到用戶應(yīng)用程序運行代碼了。

LDR R0, =mymain

BX R0

當執(zhí)行了上面兩條指令,那么就已經(jīng)是跳轉(zhuǎn)到SDRAM運行代碼了,因為mymain的函數(shù)鏈接地址,就是位于SDRAM那邊的。

但是我在這個過程中遇到了一些問題。

5.7.1 Reset_Handler 中斷問題

9f38434c-b654-11f0-8c8f-92fbcf53809c.png

file://E:/%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0/picture/image-20230808233404427.png?lastModify=1691512138

在中斷向量表的第二個位置,會放這個 Reset_Handler 的函數(shù)在那里。這個是MCU上電的時候,就會從這個位置,然后把這個 Reset_Handler 的函數(shù)地址賦值給PC指針,然后讓MCU從 Reset_Handler 開始不斷的執(zhí)行代碼。

程序被燒錄到內(nèi)部的Flash中,然后0x08000004地址開始存放的,就是 Reset_Handler 的地址了。

但是問題是 Reset_Handler 這個函數(shù)名,鏈接器是使用鏈接地址給它分配地址值的,也就是它的地址是 0x60000000 開始的某個地址。然后MCU上電,就把這個 0x60000000 開始的某個地址,賦值給了PC指針,這個時候會怎么樣?

因為這時還沒有把代碼復(fù)制到SDRAM,那MCU從那里取不到正確的指令,只能是無法執(zhí)行下去。

所以我們不能使用 Reset_Handler 函數(shù)名放在那個位置,而是要把 0x08000000 開始的某個地址放在那里,因為我們把程序燒錄到了 0x08000000 處。

然后這個數(shù)值怎么得到?通過反匯編文件。

9f991708-b654-11f0-8c8f-92fbcf53809c.png

file://E:/%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0/picture/image-20230808234433096.png?lastModify=1691512138

這里的 +1 是因為ARM公司有兩種指令集,ARM 指令集和 Thumb 指令集,其中指令的 bit0 位為1,那就代表是Thumb指令。而Cortex-M3/M4 內(nèi)核使用的就是Thumb指令集,所以會 +1.

所以才會看到中斷向量表的第二個位置放了個奇怪的數(shù)據(jù): 0x080003f5,就是這么來的。

5.7.2 清除bss/zi段時把堆棧也給清除了

在運行bss段清0的代碼時,我發(fā)現(xiàn)代碼就死掉了。通過 .map 文件分析,發(fā)現(xiàn)Keil把堆和棧的大小,也歸類為了bss里面了,這可能是 .s 文件定義堆棧的方式導致的,我沒有去深究。

如果把堆棧都歸類了bss段了,那么清除bss段時,就把堆棧給干掉了,堆可能關(guān)系還不大,因為還沒有用到堆內(nèi)存。但是把棧清0了,肯定不行,因我們前面的代碼有C語言寫的代碼,C函數(shù)的調(diào)用,局部變量都用到了棧。

解決方式其實很簡單,既然把堆棧都歸類為bss段,那么我們想辦法不讓Keil把堆棧歸類到bss段即可。

我是直接在散列文件那里定義堆棧的大小了,然后通過鏈接器的符號:|Image$$ARM_LIB_STACK$$ZI$$Limit|獲取到棧頂指針的地址值,然后在中斷向量表的第一個位置填這個符號即可。

a000f29c-b654-11f0-8c8f-92fbcf53809c.png

file://E:/%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0/picture/image-20230809000650638.png?lastModify=1691512138

當然,不使用散列文件的話,也有很多其他取巧的解決辦法,比如:

調(diào)用 bss 段清0函數(shù)之前,重新設(shè)置 SP 的值

bss 段清0函數(shù)內(nèi)部,長度信息減去堆棧的空間長度

以上就是程序自己復(fù)制自己,把自己重定位到SDRAM運行的介紹。

整個demo程序也上傳這里了,以供大家學習參考。

注:文章作者在原帖中提供了例程文件,有需要請至原文21ic論壇下載

原文地址:https://bbs.21ic.com/icview-3319862-1-1.html

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    147

    文章

    18881

    瀏覽量

    396664
  • SDRAM
    +關(guān)注

    關(guān)注

    7

    文章

    457

    瀏覽量

    57588
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5607

    瀏覽量

    129833
  • FlaSh
    +關(guān)注

    關(guān)注

    10

    文章

    1742

    瀏覽量

    155405
  • 引腳
    +關(guān)注

    關(guān)注

    16

    文章

    2110

    瀏覽量

    55605

原文標題:APM32芯得 EP.64 | APM32代碼重定位--如何讓整個程序在SDRAM運行

文章出處:【微信號:geehysemi,微信公眾號:Geehy極海半導體】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    新品發(fā)布丨半導體推出工業(yè)級標準型APM32S103系列MCU

    半導體最新宣布推出,基于32位Arm Cortex-M3內(nèi)核的 工業(yè)級標準型 APM32S103系列MCU 。該
    的頭像 發(fā)表于 12-16 18:24 ?2984次閱讀

    推出APM32A系列車規(guī)級MCU芯片

    中量產(chǎn)驗證。下一代符合ISO 26262功能安全標準的G32A系列車規(guī)級MCU規(guī)劃。審
    發(fā)表于 02-21 14:21

    APM32工業(yè)級硬核抗寒體質(zhì),無懼-40℃寒潮!

    APM32系列MCU,工作溫度覆蓋-40℃~+105℃,ESD等級高達8KV,具有低功耗、高性能、安全可靠、可移植性好、客戶接受程度高
    發(fā)表于 01-14 17:13 ?3132次閱讀

    半導體新品上市—工業(yè)增強型APM32F091xC系列MCU

    半導體工業(yè)增強型APM32F091xC系列新品MCU,其
    發(fā)表于 07-26 14:27 ?7328次閱讀
    <b class='flag-5'>極</b><b class='flag-5'>海</b>半導體新品上市—工業(yè)增強型<b class='flag-5'>APM</b>32F091xC<b class='flag-5'>系列</b><b class='flag-5'>MCU</b>

    基于APM32 MCU的電動車BMS及電機控制應(yīng)用方案

    APM32系列工業(yè)級通用MCU,低功耗、高性能、高集成、易于移植、支持96位唯一設(shè)備ID(UID),ESD高達8KV,符合工業(yè)級可靠性標
    發(fā)表于 02-08 17:01 ?17次下載
    基于<b class='flag-5'>APM32</b> <b class='flag-5'>MCU</b>的電動車BMS及電機控制應(yīng)用方案

    嵌入式開發(fā)工具服務(wù)商IAR Systems工具鏈全面支持半導體APM32系列MCU

    嵌入式開發(fā)工具服務(wù)商IAR Systems工具鏈全面支持半導體APM32系列MCU. IAR Embedded Workbench fo
    發(fā)表于 07-13 17:08 ?2375次閱讀
    嵌入式開發(fā)工具服務(wù)商IAR Systems工具鏈全面支持<b class='flag-5'>極</b><b class='flag-5'>海</b>半導體<b class='flag-5'>APM32</b><b class='flag-5'>系列</b><b class='flag-5'>MCU</b>

    推出基于Arm Cortex-M4內(nèi)核的高性能、高安全APM32F405/415工業(yè)級MCU新品

    半導體注重并持續(xù)在產(chǎn)品需求、產(chǎn)品定義、迭代升級、應(yīng)用方面與各相關(guān)廠商加深合作,目前APM32系列工業(yè)級MCU
    的頭像 發(fā)表于 08-11 10:39 ?2383次閱讀

    Flasher在線燒錄器全面支持APM32系列MCU

    半導體常務(wù)副總經(jīng)理王遠學表示:“非常有幸能與SEGGER達成合作,目前APM32系列
    的頭像 發(fā)表于 09-08 11:10 ?3200次閱讀

    APM32系列工業(yè)級MCU GW88系列低功耗藍牙芯片選型

    APM32系列工業(yè)級MCU GW88系列低功耗藍牙芯片選型表免費下載。需要樣品可以留言下載,15994789587
    發(fā)表于 12-13 11:51 ?12次下載

    半導體32位APM32工業(yè)級MCU工控領(lǐng)域的出色表現(xiàn)

    工業(yè)級MCU應(yīng)用場景范圍十分廣泛,并對使用壽命、溫度、濕度、電磁輻射等有著嚴格的品質(zhì)要求。半導體長期深耕中高端工控市場,本期就以絕對值編碼器、高性能伺服驅(qū)動器及變頻器方案為例,詳細介紹
    發(fā)表于 11-03 17:14 ?4103次閱讀

    喜報頻傳!APM32工業(yè)級/車規(guī)級MCU產(chǎn)品接連榮獲三項大獎

    半導體喜報頻傳接連榮獲三項大獎。半導體“工業(yè)級高安全MCU APM32F415”、 “工
    發(fā)表于 11-21 15:17 ?1081次閱讀

    PEmicro全面支持APM32MCU

    高性能、高集成度、低功耗APM32工業(yè)級/車規(guī)級MCU,基于Arm Cortex-M0+/M3/M4內(nèi)核,擁有強大運算性能和增強型存儲空間,具有豐富的協(xié)處理功能和廣泛的外設(shè)資源。
    發(fā)表于 01-13 11:37 ?867次閱讀

    推出首款電機控制專用芯片APM32F035系列MCU

    宣布正式推出首款高性能、高可靠性、高性價比的電機控制專用芯片—APM32F035系列MCU,覆蓋多種電機應(yīng)用。
    的頭像 發(fā)表于 07-28 17:13 ?2762次閱讀
    <b class='flag-5'>極</b><b class='flag-5'>海</b>推出首款電機控制專用芯片<b class='flag-5'>APM</b>32F035<b class='flag-5'>系列</b><b class='flag-5'>MCU</b>

    APM32 MCU助力推動新型工業(yè)化發(fā)展

    國產(chǎn)APM32 MCU助力推動新型工業(yè)化發(fā)展
    的頭像 發(fā)表于 09-28 17:38 ?1591次閱讀
    <b class='flag-5'>APM32</b> <b class='flag-5'>MCU</b>助力推動新型工業(yè)化發(fā)展

    基于半導體APM32F407系列MCU的伺服控制器應(yīng)用方案

    基于半導體APM32F407系列MCU的伺服控制器應(yīng)用方案
    的頭像 發(fā)表于 09-19 16:48 ?2277次閱讀
    基于<b class='flag-5'>極</b><b class='flag-5'>海</b>半導體<b class='flag-5'>APM</b>32F407<b class='flag-5'>系列</b><b class='flag-5'>MCU</b>的伺服控制器應(yīng)用方案