IAR中cortex-m4啟動(dòng)流程分析
Flash地址空間:
0x00000000--0x00080000,共512k
SRAM地址空間:
SRAM1 0x1FFF0000--0x20000000 64k
SRAM2 0x20000000--0x20010000 64k
總共的SRAM大小是128k
我要在RAM中調(diào)試代碼,下面以代碼的執(zhí)行過(guò)程為順序分析一下啟動(dòng)流程。
首先看一下源文件中提供的128KB_Ram.icf文件。*.icf文件是IAR中的分散描述文件,相當(dāng)于ADS中的*.src文件或keil中的*.sct文件或GNU中的*.lds鏈接腳本文件。
這個(gè)文件中前面部分是各個(gè)變量的定義,關(guān)鍵看后面部分:
- ***********
- place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
- place at address mem:__code_start__ { readonly section .noinit };
- place in RAM_region { readonly, block CodeRelocate };
- place in RAM_region { readwrite, block CodeRelocateRam,
- block CSTACK, block HEAP };
- ************
①place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }
這段代碼表示要把.intvec代碼段中的只讀部分放在存儲(chǔ)空間(mem,前面已定義的名稱)中__ICFEDIT_intvec_start__ 地址上,前面部分已經(jīng)定義__ICFEDIT_intvec_start__=0x1fff0000,是SRAM的起始地址。也就是先把向量表放到內(nèi)存中的最前面。 .intvec 這個(gè)段是在vectors.c文件中出現(xiàn)的,
- typedef void
(*vector_entry)(void); #pragma location = ".intvec" const vector_entry __vector_table[] = //@ ".intvec" = - {
VECTOR_000, /* Initial SP */ VECTOR_001, /* Initial PC */ VECTOR_002, VECTOR_003, ......(中間省略) VECTOR_254, VECTOR_255, CONFIG_1, CONFIG_2, CONFIG_3, CONFIG_4, - };
從源文件中可以看到這里定義了一個(gè)向量表__vector_table(前面的const 很重要不能省,這樣才能保證向量表是只讀的),向量表中的每一項(xiàng)都是一個(gè)指向函數(shù)的指針,這里總共有256+4=260個(gè)指針,所以占據(jù)空間為260*4=1040=0x410.
所以SRAM空間的前0x410的空間已經(jīng)被向量表占據(jù)。即占據(jù)了0x1fff0000--0x1fff0410.
②place at address mem:__code_start__ { readonly section .noinit }
這段代碼表示要把 .noinit段中的只讀部分放到地址空間 __code_start__ 開始的地址上,前面有定義 __code_start__= 0x1fff0410 ,也就是把 .noinit段放到0x1fff0410開始的地址上。所以在內(nèi)存中代碼就連續(xù)了,先是向量表,接著的是.noinitd 段。
.noinit 段在crt0.s匯編文件中出現(xiàn):
SECTION .noinit : CODE
EXPORT __startup- __startup
MOV r0,#0 ; Initialize the GPRs
MOV r1,#0
MOV r2,#0
MOV r3,#0
MOV r4,#0
MOV r5,#0
MOV r6,#0
MOV r7,#0
MOV r8,#0
MOV r9,#0
MOV r10,#0
MOV r11,#0
MOV r12,#0
CPSIE i ; Unmask interrupts
import start
BL start ; call the C code- __done
B __done
END
這段代碼算是芯片復(fù)位后執(zhí)行的第一段代碼(如果沒有其他異常的話)。作為一個(gè)通常的規(guī)則,推薦先把通用寄存器(R0-R12)清零。然后是使能中斷,跳轉(zhuǎn)到start標(biāo)號(hào)(或函數(shù))處繼續(xù)執(zhí)行。
========================
在start.c文件中找到了start函數(shù):
- /*start.c片段*/
- void start(void)
- {
/* Disable the watchdog timer */ wdog_disable(); /* Copy any vector or data sections that need to be in RAM */ common_startup(); /* Perform processor initialization */ sysinit(); printf(""); /* Determine the last cause(s) of reset */ if (MC_SRSH & MC_SRSH_SW_MASK) printf("Software Reset"); if (MC_SRSH & MC_SRSH_LOCKUP_MASK) printf("Core Lockup Event Reset"); if (MC_SRSH & MC_SRSH_JTAG_MASK) printf("JTAG Reset"); if (MC_SRSL & MC_SRSL_POR_MASK) printf("Power-on Reset"); if (MC_SRSL & MC_SRSL_PIN_MASK) printf("External Pin Reset"); if (MC_SRSL & MC_SRSL_COP_MASK) printf("Watchdog(COP) Reset"); if (MC_SRSL & MC_SRSL_LOC_MASK) printf("Loss of Clock Reset"); if (MC_SRSL & MC_SRSL_LVD_MASK) printf("Low-voltage Detect Reset"); if (MC_SRSL & MC_SRSL_WAKEUP_MASK) printf("LLWU Reset"); /* Determine specific Kinetis device and revision */ cpu_identify(); /* Jump to main process */ main(); /* No actions to perform after this so wait forever */ while(1); - }
評(píng)論