一、概述
MDK開發ARM裸機程序時,在調試階段通常是先讓程序在SDRAM中執行,以加快調試速度,也避免頻繁燒寫Nor Flash,因此需要知道如何指定程序在哪個位置執行。本文以realarm 2410開發板為例,進行描述。該開發板使用S3C2410A做為CPU,有2MB的 Nor Flash,以及64MB的SDRAM,4KB的SRAM。程序可直接在Nor Flash中調試和運行,如果代碼小於4KB,也可以直接在SRAM中運行,然而在SDRAM 中運行,就需要事先用腳本初始化SDRAM,才能把程序加載到SDRAM中執行。
realarm2410使用Nor Flash時的內存映射,如下圖:
![]() |
圖1 |
下面詳細說明各種情況。
二、程序在Nor Flash中調試
由圖1可見,CPU復位后PC指針為0,正好代碼在Flash中執行,因此,無需修改PC指針,僅需在程序的初始化部分初始化SDRAM,以及分配好Stack以及Heap則可,要使用分散加載文件*.sct指定程序鏈接加載的位置,分散加載文件如下:
; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_ROM1 0x0 0x00200000 { ; load region size_region ER_ROM1 0x0 0x00200000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_STACK 0x33ff3000 { ; RW data *(STACK) } RW_HEAP 0x33ef3000 { ; RW data *(HEAP) } RW_RAM1 0x30000000 0x04000000 { ; RW data .ANY (+RW +ZI) } RW_IRAM1 0x40000000 0x00001000 { .ANY (+RW +ZI) } } |
分散加載文件LoadToFlash.sct |
該分散加載文件把RO指定到0x0開始大小為0x200000的位置,即2MB的Flash中,RW指定在起始地址為0x30000000大小為0x4000000的64MB的SDRAM中,0x40000000開始的大小為0x1000的4KB的SRAM也作為RW區使用,而Stack則在SDRAM的0x33ff3000開始,Heap則在0x33ef3000開始。大小在初始化程序中指定,如下:
UND_Stack_Size EQU 0x00000400
SVC_Stack_Size EQU 0x00001000
ABT_Stack_Size EQU 0x00000400
FIQ_Stack_Size EQU 0x00001000
IRQ_Stack_Size EQU 0x00001000
USR_Stack_Size EQU 0x00001800
Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
Stack_Top EQU Stack_Mem + Stack_Size
Heap_Size EQU 0x00100000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
Heap_Mem SPACE Heap_Size
那么,SDRAM除了20KB的Stack和1MB的 Heap外,都當成了RW。SDRAM分配圖如下:
圖2 |
總而言之,要實現Flash調試代碼,需實現以下步驟:
- 通過設計分散加載文件,指定RO在Flash,同時分配好其它的RW以及Stack和Heap的地址,並配置工程使用分散加載文件來鏈接;
- S3C2410A.s要初始化SDRAM,並分配好Stack和Heap;
- 工程中設置使用J-LINK為Flash編程,並設置好Flash的編程算法,勾選調試前需更新代碼;
- 在工程設置中設置為調試前更新代碼;具體需特別說明的工程設置圖如下:
![]() |
圖3:指定Link按照LoadToFlash.sct規則執行 |
![]() |
圖4:指定使用J-LINK/J-TRACK ARM來調試程序 |
![]() |
圖5:一定要勾選Update Target before Debugging |
圖5按下settings按鍵,設置Flash下載設置和編程算法,realarm2410使用的SST39VF1601,MDK有現成的編程算法,直接按下ADD按鍵,選擇芯片型號則可,如圖6。
![]() |
圖6:Flash編程設置 |
如此,在MDK中執行start debug則可進入Flash中調試代碼了。
提供跑馬燈程序的MDK工程,注意選擇好Target為DebugInFlash。
跑馬燈的MDK工程下載 |
三、程序在SRAM中調試
有了前面在Flash中調試所述的原理基礎,設置為SRAM中調試就好辦了,按以下步驟:
-
要保證程序小於4KB,RO放到SRAM中;
-
如果使用的RW段、Stack和Heap還是放到SDRAM中,那么依然要在S3C2410A.s中初始化;
-
Debug前要執行一個初始化腳本,因為SRAM 地址從0x40000000開始,因此需要在初始化腳本中把PC指針設置到0x40000000中;
-
一定不可勾選調試前更新代碼這個選項,否則start debug時會提示錯誤,實際上SRAM調試的代碼不可燒寫到Flash中執行。
附上分散加載文件和工程配置圖如下:
; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_ROM1 0x40000000 0x00001000 { ; load region size_region ER_ROM1 0x40000000 0x00001000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_STACK 0x33ff3000 { ; RW data *(STACK) } RW_HEAP 0x33ef3000 { ; RW data *(HEAP) } RW_RAM1 0x33000000 0x00e00000 { ; RW data .ANY (+RW +ZI) } } |
![]() |
圖7:設置Debug的初始化文件為init_sram_RunFromSram.ini |
init_sram_RunFromSram.ini文件如下:
FUNC void SetupForStart (void) {
// <o> Program Entry Point
PC = 0x40000000;
}
SetupForStart(); // Setup for Running
圖8:不可勾選Update target before Debugging,可設為使用外部工具 |
提供跑馬燈程序的MDK工程下載,注意選擇好Target為DebugInSram。
跑馬燈的MDK工程下載 |
四、程序在SDRAM中調試
有了前面所述的原理基礎,設置為SDRAM中調試基本和SRAM的相似,但是,有以下兩個不同點:
-
SDRAM不受4KB大小限制;
-
SDRAM需要初始化才能使用,因此在debug初始化文件中需要增加初始化SDRAM,並且把要調試程序的按照axf格式加載到SDRAM中;
-
初始化程序S3C2410A.s中不可再初始化,因為debug初始化腳本已經初始化過了,而且加載了程序,如果再初始化那會把程序給破壞點了。
還是用分散加載文件指定RO、RW、Stack以及Heap的位置,把RO分配到SDRAM的起始的2MB中,其它和前面一樣,文件如下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_ROM1 0x30000000 0x00200000 { ; load region size_region
ER_ROM1 0x30000000 0x00200000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_STACK 0x33ff3000 { ; RW data
*(STACK)
}
RW_HEAP 0x33ef3000 { ; RW data
*(HEAP)
}
RW_RAM1 0x31000000 0x03000000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM1 0x40000000 0x00001000 {
.ANY (+RW +ZI)
}
}
Debug初始化文件如下:
FUNC void SetupForStart (void) {
// <o> Program Entry Point
PC = 0x30000000;
}
FUNC void Init (void) {
_WDWORD(0x4A000008, 0xFFFFFFFF); // Disable All Interrupts
_WDWORD(0x53000000, 0x00000000); // Disable Watchdog Timer
// Clock Setup
// FCLK = 150 MHz, HCLK = FCLK/2 MHz, PCLK = HCLK/2 MHz
_WDWORD(0x4C000000, 0x0FFF0FFF); // LOCKTIME
_WDWORD(0x4C000014, 0x0000000F); // CLKDIVN
_WDWORD(0x4C000004, 0x00043011); // MPLLCON
_WDWORD(0x4C000008, 0x00038021); // UPLLCON
_WDWORD(0x4C00000C, 0x001FFFF0); // CLKCON
// Memory Controller Setup for SDRAM
_WDWORD(0x48000000, 0x22000000); // BWSCON
_WDWORD(0x4800001C, 0x00018005); // BANKCON6
_WDWORD(0x48000020, 0x00018005); // BANKCON7
_WDWORD(0x48000024, 0x008404F3); // REFRESH
_WDWORD(0x48000028, 0x00000032); // BANKSIZE
_WDWORD(0x4800002C, 0x00000020); // MRSRB6
_WDWORD(0x48000030, 0x00000020); // MRSRB7
_WDWORD(0x56000000, 0x000003FF); // GPACON: Enable Address lines for SDRAM
}
// Reset chip with watchdog, because nRST line is routed on hardware in a way
// that it can not be pulled low with ULINK
_WDWORD(0x40000000, 0xEAFFFFFE); // Load RAM addr 0 with branch to itself
CPSR = 0x000000D3; // Disable interrupts
PC = 0x40000000; // Position PC to start of RAM
_WDWORD(0x53000000, 0x00000021); // Enable Watchdog
g, 0 // Wait for Watchdog to reset chip
Init(); // Initialize memory
LOAD .\led_InSdram.axf INCREMENTAL // Download program
SetupForStart(); // Setup for Running
腳本中的Init函數對寄存器的操作含義可以查閱S3C2410的寄存器手冊,實現的就是關中斷,看門狗,設置時鍾,初始化內存控制器。LOAD .\led_InSdram.axf INCREMENTAL作用就是把led_InSdram.axf文件加載進去,axf為elf格式的文件,本身帶有加載的地址,因此只要分散加載文件按這只正確了,編譯鏈接后生成的axf文件就有了正確的加載地址;最后把PC設置到RO的基址0x30000000執行代碼。
S3C2410A.s需關閉內存控制器的初始化功能,找到這一行代碼:MC_SETUP EQU 1;改為MC_SETUP EQU 0。
提供跑馬燈程序的MDK工程下載,注意選擇好Target為DebugInSdrSram。並記得修改MC_SETUP EQU 0。
跑馬燈的MDK工程下載 |