微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > IAR中cortex-m4启动流程分析

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 };
  • 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);
  • #pragmalocation=".intvec"
  • constvector_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 vectorordata sections that needtobeinRAM*/
  • 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 deviceandrevision*/
  • cpu_identify();
  • /*Jumptomain process*/
  • main();
  • /*No actionstoperform after this so wait forever*/
  • while(1);
  • }


start函数中,首先执行 wdog_disable()函数来禁用看门狗,然后调用 common_startup()函数初始化RAM(复制向量表、清零.bss段等,为C语言运行环境做准备),接着执行sysinit()函数初始化芯片(时钟、用到的外设等)。下面依次分析这3个函数。

①wdog_disable()

对系统的设定无非是对各个寄存器值的修改。wdog_disable()函数在wdog.c文件中

    Copyright © 2017-2020 微波EDA网 版权所有

    网站地图

    Top