具體加載哪個,在DebugInExram->ARM Linker->Scatter定義,鏈接類型選擇Scattered,image entry point一定要跟ROM_LOAD值一樣
//ROM_LOAD 爲加載區的名稱,其後面的0x00000000 表示加載區的起始地址(存放程序代碼的起始地址)
ROM_LOAD 0x0
{
//ROM_EXEC 描述了執行區的地址,放在第一塊位置定義
ROM_EXEC 0x00000000
{
//從起始地址開始放置向量表(即Startup.o(vectors, +First),其中Startup.o 爲Startup.s 的目標文件)
//+First表示Vectors段放在最前面
Startup.o (vectors, +First)
//接着放置其它代碼(即* (+RO)),* 是通配符,類似WINDOW下搜索用的通配符
* (+RO)
}
//變量區IRAM 的起始地址爲0x40000000
IRAM 0x40000000
{
//放置mystacks.o (MyStack爲段名)
mystacks.o (MyStacks)
}
//+0表示接着上一段,UNINIT 表示不初始化
STACKS_BOTTOM +0 UNINIT
{
//放置AREA StackBottom, DATA, NOINIT
Startup.o (StackBottom)
}
//接着從0x40004000 開始,放置 AREA Stacks, DATA, NOINIT,UNINIT 表示不初始化
STACKS 0x40004000 UNINIT
{
Startup.o (Stacks)
}
//外部RAM從0x80000000開始爲變量區
//如果片外RAM起始地址不爲0x8000 0000,則需要修改mem_.scf文件
ERAM 0x80000000
{
* (+RW,+ZI)
}
//+0表示接着上一段,UNINIT 表示不初始化
HEAP +0 UNINIT
{
//放置堆底, AREA Heap, DATA, NOINIT
Startup.o (Heap)
}
//接着在外部0x80080000 放置堆頂
//這個地址是片外RAM 的結束地址,根據實際情況修改
HEAP_BOTTOM 0x80080000 UNINIT
{
Startup.o (HeapTop)
}
}
//重定向__user_initial_stackheap 函數
//分配新的bottom_of_heap地址等,R0-R3是函數必須的返回值,返回bottom_of_heap的值
//通過分散加載描述文件,重定向其位置,bottom_of_heap等已經在Startup.s中定義爲DATA類型
__user_initial_stackheap
LDR r0,=bottom_of_heap
; LDR r1,=StackUsr
LDR r2,=top_of_heap
LDR r3,=bottom_of_Stacks
MOV pc,lr
變量區IRAM 的起始地址爲0x40000000,放置Startup.o (MyStacks);
變量區ERAM 的起始地址爲0x80000000,放置除Startup.o 文件之外的其它文件的變量(即* (+RW,+ZI));
緊靠ERAM 變量區之後的是系統堆空間(HEAP),放置描述爲Startup.o (Heap);
堆棧區STACKS 使用片內RAM,由於ARM 的堆棧一般採用滿遞減堆棧,所以堆棧區起始地址設置爲0x40004000,
放置描述爲Startup.o (Stacks)。
通過分散加載文件把代碼從flash裏拷貝到ram裏運行, 基於LPC1788。
先貼下我的sct文件:
- LR_IROM1 0x00000000 0x00002000
- {
- ER_IROM1 0x00000000 0x00020000
- {
- *.o (RESET, +First)
- *(InRoot$$Sections)
- startup_lpc177x_8x.o (+RO)
- system_LPC177x_8x.o (+RO)
- }
- RW_IRAM1 0x20000000 0x00004000
- {
- .ANY (+RW +ZI)
- }
- }
- LR_IROM2 0x00002000 0x0007E000
- {
- VECTOR 0x10000000 EMPTY 0xE4
- {
- }
- ER_IRAM1 +0
- {
- .ANY (+RO)
- }
- }
這裏有兩個加載域(load region)LR_IROM1和LR_IROM2,LR_IROM1是初始化程序,拷貝代碼等,
從ROM的地址0開始,LR_ROM2是應用程序,從ROM的0x2000開始。+RO表示只讀,代碼或者只
讀數據,一般用來表示代碼,+RW表示可讀可寫的數據,+ZI表示初始化爲0的數據。大括號裏面的
爲運行域(execution region),一個加載域可以包含幾個運行域,LR_ROM2裏面有兩個運行域,
VECTOR和ER_IRAM1,我用VECTOR來表示中斷向量區域,ER_IRAM1來表示應用程序區,+0表示
緊接着VECTOR排放,EMPTY表示空的,這裏空出0xE4的大小,用來放中斷向量,.ANY表示除了
上面用到的代碼之外的代碼,官網上有專門解釋.ANY的一節。
下面用一張圖來表示這個程序的加載域和執行域:
其實加載域的empty這塊區域是不用空出來的,主要是運行域要空出來,用來拷貝中斷向量,看個人喜好了,
我覺得空出來方便引用這塊區域的執行域地址。
這樣框架就比較清楚了,拷貝的程序清單如下:
- extern unsigned char Image Base;
- extern unsigned char Image Length;
- extern unsigned char Load Base;
- extern unsigned char Image Base;
- extern unsigned char Image Length;
- void CopyCode2Ram ()
- {
- unsigned char *pSrc, *pDes;
- unsigned int count;
- SCB->VTOR = 0x10000000;
- pSrc = 0;
- pDes = (unsigned char*)&Image Base;
- count = 0xE4;
- while (count--)
- {
- *pDes++ = *pSrc++;
- }
- count = (unsigned int)&Image Length;
- pDes = (unsigned char*)&Image Base;
- pSrc = (unsigned char*)(&Load Base + 0xE4);
- while (count--)
- {
- *pDes++ = *pSrc++;
- }
- }
其中拷貝中斷向量的時候要指定中斷向量的偏移地址。Load Base表示執行域ER_IRAM1的加載地址;Image Base表示執行域ER_IRAM1的執行地址;Image Length表示執行域ER_IRAM1的實際長度,VECTOR區域因爲是EMPTY,所以實際長度是0,