IAR中cortex-m4启动流程分析
时间:11-25
来源:互联网
点击:
最近分析了一下飞思卡尔官方提供的k60系列demo程序在IAR上的启动流程,现写一下笔记,以备以后参考。先看一下K60N512VMD100内部存储器的分布情况,飞思卡尔K60N512VMD100有512K的flash和128k的SRAM.其中:
Flash地址空间:
0x00000000--0x00080000,共512k
SRAM地址空间:
SRAM1 0x1FFF0000--0x20000000 64k
SRAM2 0x20000000--0x20010000 64k
总共的SRAM大小是128k
我要在RAM中调试代码,下面以代码的执行过程为顺序分析一下启动流程。
首先看一下源文件中提供的128KB_Ram.icf文件。*.icf文件是IAR中的分散描述文件,相当于ADS中的*.src文件或keil中的*.sct文件或GNU中的*.lds链接脚本文件。
这个文件中前面部分是各个变量的定义,关键看后面部分:
①place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }
这段代码表示要把.intvec代码段中的只读部分放在存储空间(mem,前面已定义的名称)中__ICFEDIT_intvec_start__ 地址上,前面部分已经定义__ICFEDIT_intvec_start__=0x1fff0000,是SRAM的起始地址。也就是先把向量表放到内存中的最前面。 .intvec 这个段是在vectors.c文件中出现的,
从源文件中可以看到这里定义了一个向量表__vector_table(前面的const 很重要不能省,这样才能保证向量表是只读的),向量表中的每一项都是一个指向函数的指针,这里总共有256+4=260个指针,所以占据空间为260*4=1040=0x410.
所以SRAM空间的前0x410的空间已经被向量表占据。即占据了0x1fff0000--0x1fff0410.
②place at address mem:__code_start__ { readonly section .noinit }
这段代码表示要把 .noinit段中的只读部分放到地址空间 __code_start__ 开始的地址上,前面有定义 __code_start__= 0x1fff0410 ,也就是把 .noinit段放到0x1fff0410开始的地址上。所以在内存中代码就连续了,先是向量表,接着的是.noinitd 段。
.noinit 段在crt0.s汇编文件中出现:
这段代码算是芯片复位后执行的第一段代码(如果没有其他异常的话)。作为一个通常的规则,推荐先把通用寄存器(R0-R12)清零。然后是使能中断,跳转到start标号(或函数)处继续执行。
========================
在start.c文件中找到了start函数:
start函数中,首先执行 wdog_disable()函数来禁用看门狗,然后调用 common_startup()函数初始化RAM(复制向量表、清零.bss段等,为C语言运行环境做准备),接着执行sysinit()函数初始化芯片(时钟、用到的外设等)。下面依次分析这3个函数。
①wdog_disable()
对系统的设定无非是对各个寄存器值的修改。wdog_disable()函数在wdog.c文件中
Flash地址空间:
0x00000000--0x00080000,共512k
SRAM地址空间:
SRAM1 0x1FFF0000--0x20000000 64k
SRAM2 0x20000000--0x20010000 64k
总共的SRAM大小是128k
我要在RAM中调试代码,下面以代码的执行过程为顺序分析一下启动流程。
首先看一下源文件中提供的128KB_Ram.icf文件。*.icf文件是IAR中的分散描述文件,相当于ADS中的*.src文件或keil中的*.sct文件或GNU中的*.lds链接脚本文件。
这个文件中前面部分是各个变量的定义,关键看后面部分:
- ***********
- 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代码段中的只读部分放在存储空间(mem,前面已定义的名称)中__ICFEDIT_intvec_start__ 地址上,前面部分已经定义__ICFEDIT_intvec_start__=0x1fff0000,是SRAM的起始地址。也就是先把向量表放到内存中的最前面。 .intvec 这个段是在vectors.c文件中出现的,
- 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, - };
从源文件中可以看到这里定义了一个向量表__vector_table(前面的const 很重要不能省,这样才能保证向量表是只读的),向量表中的每一项都是一个指向函数的指针,这里总共有256+4=260个指针,所以占据空间为260*4=1040=0x410.
所以SRAM空间的前0x410的空间已经被向量表占据。即占据了0x1fff0000--0x1fff0410.
②place at address mem:__code_start__ { readonly section .noinit }
这段代码表示要把 .noinit段中的只读部分放到地址空间 __code_start__ 开始的地址上,前面有定义 __code_start__= 0x1fff0410 ,也就是把 .noinit段放到0x1fff0410开始的地址上。所以在内存中代码就连续了,先是向量表,接着的是.noinitd 段。
.noinit 段在crt0.s汇编文件中出现:
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
这段代码算是芯片复位后执行的第一段代码(如果没有其他异常的话)。作为一个通常的规则,推荐先把通用寄存器(R0-R12)清零。然后是使能中断,跳转到start标号(或函数)处继续执行。
========================
在start.c文件中找到了start函数:
- /*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); - }
start函数中,首先执行 wdog_disable()函数来禁用看门狗,然后调用 common_startup()函数初始化RAM(复制向量表、清零.bss段等,为C语言运行环境做准备),接着执行sysinit()函数初始化芯片(时钟、用到的外设等)。下面依次分析这3个函数。
①wdog_disable()
对系统的设定无非是对各个寄存器值的修改。wdog_disable()函数在wdog.c文件中
IARcortex-m4启动流 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)