亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2124 | 回復(fù): 0
打印 上一主題 下一主題

【學(xué)習筆記】IAR中cortex-m4啟動流程分析 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2011-12-21 08:41 |只看該作者 |倒序瀏覽
  軟件環(huán)境:windows7旗艦版,IAR V6105(EWARM-EV-WEB-6105)
ARM芯片:飛思卡爾K60N512VMD100 (cortex-m4核心)
示例程序:飛思卡爾官方的 KINETIS512_SC
======================

最近分析了一下飛思卡爾官方提供的k60系列demo程序在IAR上的啟動流程,現(xiàn)寫一下筆記,以備以后參考。先看一下K60N512VMD100內(nèi)部存儲器的分布情況,飛思卡爾K60N512VMD100有512K的flash和128k的SRAM.其中:

Flash地址空間: 0x00000000--0x00080000,共512k
SRAM地址空間: SRAM1 0x1FFF0000--0x20000000 64k
SRAM2 0x20000000--0x20010000 64k
總共的SRAM大小是128k

我要在RAM中調(diào)試代碼,下面以代碼的執(zhí)行過程為順序分析一下啟動流程。

首先看一下源文件中提供的128KB_Ram.icf文件。*.icf文件是IAR中的分散描述文件,相當于ADS中的*.src文件或keil中的*.sct文件或GNU中的*.lds鏈接腳本文件。
這個文件中前面部分是各個變量的定義,關(guān)鍵看后面部分:
  1. /*128KB_Ram.icf后面部分*/
  2. ***********
  3. place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
  4. place at address mem:__code_start__ { readonly section .noinit };

  5. place in RAM_region { readonly, block CodeRelocate };

  6. place in RAM_region { readwrite, block CodeRelocateRam,
  7. block CSTACK, block HEAP };
  8. ************
①place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }
  這段代碼表示要把.intvec代碼段中的只讀部分放在存儲空間(mem,前面已定義的名稱)中__ICFEDIT_intvec_start__ 地址上,前面部分已經(jīng)定義__ICFEDIT_intvec_start__=0x1fff0000,是SRAM的起始地址。也就是先把向量表放到內(nèi)存中的最前面。 .intvec 這個段是在vectors.c文件中出現(xiàn)的,
  1. /*vectors.c片段*/

  2. typedef void (*vector_entry)(void);

  3.     #pragma location = ".intvec"
  4.     const vector_entry __vector_table[] = //@ ".intvec" =

  5. {
  6.    VECTOR_000, /* Initial SP */
  7.    VECTOR_001, /* Initial PC */
  8.    VECTOR_002,
  9.    VECTOR_003,
  10.    ......(中間省略)
  11.    VECTOR_254,
  12.    VECTOR_255,
  13.    CONFIG_1,
  14.    CONFIG_2,
  15.    CONFIG_3,
  16.    CONFIG_4,

  17. };
從源文件中可以看到這里定義了一個向量表__vector_table(前面的const 很重要不能省,這樣才能保證向量表是只讀的),向量表中的每一項都是一個指向函數(shù)的指針,這里總共有256+4=260個指針,所以占據(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):
  1. SECTION .noinit : CODE
  2. EXPORT __startup
  3. __startup

  4. MOV r0,#0 ; Initialize the GPRs
  5. MOV r1,#0
  6. MOV r2,#0
  7. MOV r3,#0
  8. MOV r4,#0
  9. MOV r5,#0
  10. MOV r6,#0
  11. MOV r7,#0
  12. MOV r8,#0
  13. MOV r9,#0
  14. MOV r10,#0
  15. MOV r11,#0
  16. MOV r12,#0
  17. CPSIE i ; Unmask interrupts
  18. import start
  19. BL start ; call the C code
  20. __done
  21. B __done


  22. END
這段代碼算是芯片復(fù)位后執(zhí)行的第一段代碼(如果沒有其他異常的話)。作為一個通常的規(guī)則,推薦先把通用寄存器(R0-R12)清零。然后是使能中斷,跳轉(zhuǎn)到start標號(或函數(shù))處繼續(xù)執(zhí)行。

========================

在start.c文件中找到了start函數(shù):

  1. /*start.c片段*/
  2. void start(void)
  3. {
  4.     /* Disable the watchdog timer */
  5.     wdog_disable();

  6.     /* Copy any vector or data sections that need to be in RAM */
  7.     common_startup();

  8.     /* Perform processor initialization */
  9.     sysinit();
  10.         
  11.     printf("\n\n");
  12.     
  13.     /* Determine the last cause(s) of reset */
  14.     if (MC_SRSH & MC_SRSH_SW_MASK)
  15.         printf("Software Reset\n");
  16.     if (MC_SRSH & MC_SRSH_LOCKUP_MASK)
  17.         printf("Core Lockup Event Reset\n");
  18.     if (MC_SRSH & MC_SRSH_JTAG_MASK)
  19.         printf("JTAG Reset\n");
  20.     
  21.     if (MC_SRSL & MC_SRSL_POR_MASK)
  22.         printf("Power-on Reset\n");
  23.     if (MC_SRSL & MC_SRSL_PIN_MASK)
  24.         printf("External Pin Reset\n");
  25.     if (MC_SRSL & MC_SRSL_COP_MASK)
  26.         printf("Watchdog(COP) Reset\n");
  27.     if (MC_SRSL & MC_SRSL_LOC_MASK)
  28.         printf("Loss of Clock Reset\n");
  29.     if (MC_SRSL & MC_SRSL_LVD_MASK)
  30.         printf("Low-voltage Detect Reset\n");
  31.     if (MC_SRSL & MC_SRSL_WAKEUP_MASK)
  32.         printf("LLWU Reset\n");    
  33.     

  34.     /* Determine specific Kinetis device and revision */
  35.     cpu_identify();
  36.     
  37.     /* Jump to main process */
  38.     main();

  39.     /* No actions to perform after this so wait forever */
  40.     while(1);
  41. }
start函數(shù)中,首先執(zhí)行 wdog_disable()函數(shù)來禁用看門狗,然后調(diào)用 common_startup()函數(shù)初始化RAM(復(fù)制向量表、清零.bss段等,為C語言運行環(huán)境做準備),接著執(zhí)行sysinit()函數(shù)初始化芯片(時鐘、用到的外設(shè)等)。下面依次分析這3個函數(shù)。
①wdog_disable()
對系統(tǒng)的設(shè)定無非是對各個寄存器值的修改。wdog_disable()函數(shù)在wdog.c文件中
  1. /*wdog.c片段*/

  2. void wdog_disable(void)
  3. {
  4.     /* First unlock the watchdog so that we can write to registers */
  5.     wdog_unlock();
  6.     
  7.     /* Clear the WDOGEN bit to disable the watchdog */
  8.     WDOG_STCTRLH &= ~WDOG_STCTRLH_WDOGEN_MASK;
  9. }

  10. void wdog_unlock(void)
  11. {
  12.   /* NOTE: DO NOT SINGLE STEP THROUGH THIS */
  13.   /* There are timing requirements for the execution of the unlock. If
  14.    * you single step through the code you will cause the CPU to reset.
  15.    */

  16.     /* This sequence must execute within 20 clock cycles, so disable
  17.          * interrupts will keep the code atomic and ensure the timing.
  18.          */
  19.         DisableInterrupts;
  20.     
  21.     /* Write 0xC520 to the unlock register */
  22.     WDOG_UNLOCK = 0xC520;
  23.     
  24.     /* Followed by 0xD928 to complete the unlock */
  25.     WDOG_UNLOCK = 0xD928;
  26.     
  27.     /* Re-enable interrupts now that we are done */    
  28.            EnableInterrupts;
  29. }
禁用看門狗流程很簡單:先是解鎖寄存器,然后更改看門狗寄存器里面的值來禁用看門狗。解鎖看門狗寄存器:向解鎖寄存器里連續(xù)寫入0xC520和0xD928,兩次寫入的時間必須小于20個時鐘周期。所以在解鎖過程中不能單步運行,期間也不能被中斷打斷,解鎖函數(shù)是 wdog_unlock()。上面DisableInterrupts和EnableInterrupts已經(jīng)在arm_cm4.h中定義過:
#define DisableInterrupts asm(" CPSID i");
#define EnableInterrupts asm(" CPSIE i");
解鎖看門狗寄存器后,向看門狗寄存器里寫入適當?shù)闹稻涂梢越每撮T狗了。
也就是把WDOG_STCTRLH 寄存器(地址是0x40052000)的第0位置0.

②common_startup
初始化RAM(復(fù)制向量表、清零.bss段等,為C語言運行環(huán)境做準備)。
  1.      1 /* File: startup.c */
  2.      2 #include "common.h"

  3.      3 #pragma section = ".data"
  4.      4 #pragma section = ".data_init"
  5.      5 #pragma section = ".bss"
  6.      6 #pragma section = "CodeRelocate"
  7.      7 #pragma section = "CodeRelocateRam"

  8.      8 /********************************************************************/
  9.      9 void
  10.     10 common_startup(void)
  11.     11 {

  12.     12 /* Declare a counter we'll use in all of the copy loops */
  13.     13 uint32 n;

  14.     14 /* Declare pointers for various data sections. These pointers
  15.     15 * are initialized using values pulled in from the linker file
  16.     16 */
  17.     17 uint8 * data_ram, * data_rom, * data_rom_end;
  18.     18 uint8 * bss_start, * bss_end;

  19.     19 /* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
  20.     20 extern uint32 __VECTOR_TABLE[];
  21.     21 extern uint32 __VECTOR_RAM[];

  22.     22 /* Copy the vector table to RAM */
  23.     23 if (__VECTOR_RAM != __VECTOR_TABLE)
  24.     24 {
  25.     25 for (n = 0; n < 0x410; n++)
  26.     26 __VECTOR_RAM[n] = __VECTOR_TABLE[n];
  27.     27 }

  28.     28 /* Point the VTOR to the new copy of the vector table */
  29.     29 write_vtor((uint32)__VECTOR_RAM);

  30.     30 /* Get the addresses for the .data section (initialized data section) */
  31.     31 data_ram = __section_begin(".data");
  32.     32 data_rom = __section_begin(".data_init");
  33.     33 data_rom_end = __section_end(".data_init");
  34.     34 n = data_rom_end - data_rom;

  35.     35 /* Copy initialized data from ROM to RAM */
  36.     36 while (n--)
  37.     37 *data_ram++ = *data_rom++;

  38.     38 /* Get the addresses for the .bss section (zero-initialized data) */
  39.     39 bss_start = __section_begin(".bss");
  40.     40 bss_end = __section_end(".bss");

  41.     41 /* Clear the zero-initialized data section */
  42.     42 n = bss_end - bss_start;
  43.     43 while(n--)
  44.     44 *bss_start++ = 0;

  45.     45 /* Get addresses for any code sections that need to be copied from ROM to RAM.
  46.     46 * The IAR tools have a predefined keyword that can be used to mark individual
  47.     47 * functions for execution from RAM. Add "__ramfunc" before the return type in
  48.     48 * the function prototype for any routines you need to execute from RAM instead
  49.     49 * of ROM. ex: __ramfunc void foo(void);
  50.     50 */
  51.     51 uint8* code_relocate_ram = __section_begin("CodeRelocateRam");
  52.     52 uint8* code_relocate = __section_begin("CodeRelocate");
  53.     53 uint8* code_relocate_end = __section_end("CodeRelocate");

  54.     54 /* Copy functions from ROM to RAM */
  55.     55 n = code_relocate_end - code_relocate;
  56.     56 while (n--)
  57.     57 *code_relocate_ram++ = *code_relocate++;
  58.     58 }
在IAR中, #pragma section="NAME" [align] 用來在C語言中指定一個名稱是NAME的段,align指定對齊方式。指定的段可以被段操作符來引用,段操作符包括 __section_begin, __section_end, 和 __section_size.  個人理解.date、.date_init和.bss應(yīng)該是IAR中保留的段名稱,.date代表數(shù)據(jù)段中的常量,.date_init代表數(shù)據(jù)段中已初始化的變量,.bss代表未初始化的變量(zero)。
上面代碼中,先是指定了5個不同名稱的段(前3個是保留段名稱,代表這些段是從這里開始的),CodeRelocate和CodeRelocateRam是在*.icf文件中定義的塊(block):
define block CodeRelocate { section .textrw_init }; define block CodeRelocateRam { section .textrw };
quote:
The __ramfunc keyword makes a function execute in RAM. Two code
sections will be created: one for the RAM execution (.textrw), and one for the ROM initialization (.textrw_init).

外部變量引用
extern uint32 __VECTOR_TABLE[]; extern uint32 __VECTOR_RAM[];
來自IAR的鏈接文件(.icf),在.icf文件中已經(jīng)定義了變量 __VECTOR_TABLE 和 __VECTOR_RAM 其值都是0x1fff0000."Copy the vector table to RAM"這段代碼進行判斷,如果向量表不在RAM中,則把向量表拷貝到RAM開始的地址上,這里由于在RAM中調(diào)試,代碼是直接下載到RAM中的,所以不用拷貝。
向量表已經(jīng)在RAM中了,接下來要重定向向量表,以便在發(fā)生異常時到RAM中取得異常入口地址(默認情況下是在0x0。  write_vtor((uint32)__VECTOR_RAM) 這個函數(shù)用來寫向量表偏移寄存器(VTOR,地址0xE000_ED08),這里寫入的是RAM起始地址0x1FFF0000。注意這個地址是有要求的,并不是所有地址都能作為向量表起始地址,0x1FFF0000滿足要求(這個要求就是:必須先求出系統(tǒng)中共有多少個向量,再把這個數(shù)字向上增大到是 2 的整次冪,而起始地址必須對齊到后者的邊界上。例如,如果一共有 32 個中斷,則共有 32+16(系統(tǒng)異常)=48個向量,向上增大到 2的整次冪后值為 64,因此地址地址必須能被 64*4=256整除,從而合法的起始地址可以是:0x0,0x100,0x200 等----參見ARM Contex-M3權(quán)威指南)。另外,如果向量表在RAM區(qū)(相對于code區(qū)),需把bit[29]置位,這里0x1FFF0000也滿足要求。
后面的代碼是拷貝數(shù)據(jù)到RAM中,搭建好C語言運行環(huán)境。

sysinit()函數(shù)
(待續(xù)。。。)
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP