S32K3学习笔记—链接文件及启动代码相关

S32K3学习笔记—链接文件及启动代码相关

一.链接(ld)文件

​ 链接文件解释了不同section怎样合并并生成可执行文件,还包括了数据段和代码段的地址和长度等信息。主要作用于链接过程。

关键词及其作用

1.ENTRY

​ 此命令用于设置可执行文件elf文件。这是MCU复位后执行的第一行代码。

ENTRY(Reset_Handler)

2.MEMORY

​ 此命令用于描述flash的不同段的划分及其的起始地址和大小

MEMORY
{
    int_pflash              : ORIGIN = 0x00400000, LENGTH = 0x003D4000    /* 4096KB - 176KB (sBAF + HSE)*/
    int_dflash              : ORIGIN = 0x10000000, LENGTH = 0x00020000    /* 128KB */
    int_itcm                : ORIGIN = 0x00000000, LENGTH = 0x00008000    /* 32KB */
    int_dtcm                : ORIGIN = 0x20000000, LENGTH = 0x0000F000    /* 60KB */
    int_stack_dtcm          : ORIGIN = 0x2000F000, LENGTH = 0x00001000    /* 4KB */
    int_sram                : ORIGIN = 0x20400000, LENGTH = 0x0002FF00    /* 192KB, needs to include 																					 int_sram_fls_rsv */
    int_sram_fls_rsv        : ORIGIN = 0x2042FF00, LENGTH = 0x00000100
    int_sram_no_cacheable   : ORIGIN = 0x20430000, LENGTH = 0x0000FF00    /* 64KB, needs to include 																					 int_sram_results  */
    int_sram_results        : ORIGIN = 0x2043FF00, LENGTH = 0x00000100
    int_sram_shareable      : ORIGIN = 0x20440000, LENGTH = 0x00004000    /* 16KB */
    ram_rsvd2               : ORIGIN = 0x20444000, LENGTH = 0             /* End of SRAM */
}

3.SECTIONS

​ 此命令主要是告诉编译器如何将输入sections映射到输出sections,以及怎么在内存中放置输出sections.

有四种典型的section:

​ text – code

​ rodata – read-only data

​ data – read-write initialized data

​ bss – read-write zero initialized data

此外还有两个概念:VMA & LMA

VMA: Virtual Memory Address or runtime address,

LMA : Load Memory Address or ROM address.

对于具有初始值的全局变量(数据部分),这些初始值存储在闪存中,并通过启动代码加载到RAM。因此,ROM地址是LMA,RAM地址是VMA。bss部分没有LMA。

  .sram_bss (NOLOAD) :/*there is no LMA */
  {
		...
      *(.bss)
      	...
  } > int_sram /*VMA is in int_sram */

  .sram_data : AT(__sram_data_rom) /*LMA is sram_data_rom */
  {
		...
      *(.data)
		...
  } > int_sram /*VMA is in int_sram */

4.Wildcard character (*)

​ 告诉编译器合并所有输入的sections

*(.text) /*merge the .text section of all the Input file*/

5.Location counter (.)

​ 链接器会自动用位置(地址)信息更新此符号。它可以用来跟踪和定义不同部分的边界。此位置计数器也可以设置为任何特定值。

_text_end = .; /*the symbol _text_end equals to currentaddress*/

. = ALIGN(4);/*increment the current address to the next 4-bytes aligned address*/

. += 0x100;/*increment the current address by 0x100*/

. = 0x20401000; /*locate the current address to 0x20401000*/

6.ALIGN

​ 此指令是用于对齐且对齐的地址必须是2的幂。

. = ALIGN(2048); /*increment the current address to the next 2048-bytes aligned address*/
. = ALIGN(10);/*It is wrong. 10 is not power of 2*/

7.AT

​ 此指令表示LMA of section

    .sram_data : AT(_sram_data_rom) /*LMA is _sram_data_rom */
    {
		...
        *(.data)
		...
    } > int_sram /*VMA is in int_sram */
	...

8.KEEP

此指令是标记不被编译器删除的部分

KEEP(*(.boot_header)) /*keep the .boot_header section not be eliminated */

9.Linker script sysbol

​ sysbol是指地址的名称。类似于C语言中的声明,大多用sysbol定义sections的边界并会在内存初始化的启动代码所引用。

__INT_SRAM_START = ORIGIN(int_sram); /*symbol _INT_SRAM_START equals the origin address ofmemory region int_ 										sram*/
__INT_ITCM_END  = ORIGIN(int_itcm) + LENGTH(int_itcm); /*symbol _INT_ITCM_END equals theorigin address of 														 memory region int_itcm plus its length*/
_ sram bss_ start = .; /*symbol _sram_bss_start equals current address*/

__BSS_SRAM_SIZE = __sram_bss_end - __sram_bss_start; /*symbol _BSS_SRAM SIZE equals the end of address of 											.sram_bss section minus the start address of .sram_bss section */

二.启动流程

​ MCU的启动过程指从上电到Main 函数中间的过程。芯片复位后,最先进入SBAF,即启动固件,这是芯片出厂就已经固化在芯片内部的,所有复位方式复位后都会运行。BAF初始化完成之后,就从Reset_Handler()执行到main,下图显示了启动代码的整个过程

在这里插入图片描述

三.启动代码

​ 启动代码是根据启动流程来实现的。

1.boot_header

​ boot_header包含启动配置、核心启动地址、生命周期等信息,且只能储存在5个固定的地址:0x00400000、0x00500000、0x00600000、0x00700000、0x10000000。详细信息请参考芯片手册

.section ".boot_header","ax"
  .long SBAF_BOOT_MARKER /* IVT marker */
  .long (CM7_0_ENABLE << CM7_0_ENABLE_SHIFT) | (CM7_1_ENABLE << CM7_1_ENABLE_SHIFT) | (CM7_2_ENABLE << 				 CM7_2_ENABLE_SHIFT) /* Boot configuration word */
  .long 0 /* Reserved */
  .long CM7_0_VTOR_ADDR /* CM7_0 Start address */
  .long 0 /* Reserved */
  .long CM7_1_VTOR_ADDR /* CM7_1 Start address */
  .long 0 /* Reserved */
  .long CM7_2_VTOR_ADDR /* CM7_2 Start address */
  .long 0 /* Reserved */
  .long XRDC_CONFIG_ADDR /* XRDC configuration pointer */
  .long LF_CONFIG_ADDR /* Lifecycle configuration pointer */
  .long 0 /* Reserved */

2. Disable global

​ S32K3在开始时会失能全局中断和清除R0-R7寄存器

/*****************************************************/
/* Skip normal entry point as nothing is initialized */
/*****************************************************/	
 cpsid i
 mov   r0, #0
 mov   r1, #0
 mov   r2, #0
 mov   r3, #0
 mov   r4, #0
 mov   r5, #0
 mov   r6, #0
 mov   r7, #0

3. Enable MSCM Clock

#ifndef NO_MSCM_CLOCK_INIT
InitMSCMClock:
  /* If the MSCM clock is enabled, skip this sequence */
  ldr r0, =MCME_PRTN1_COFB0_STAT
  ldr r1, [r0]
  ldr r2, =MCME_MSCM_REQ
  and r1, r1, r2
  cmp r1, 0
  bne SetVTOR

  /* Enable clock in PRTN1 */
  ldr r0, =MCME_PRTN1_COFB0_CLKEN
  ldr r1, [r0]
  ldr r2, =MCME_MSCM_REQ
  orr r1, r2
  str r1, [r0]

  /* Set PUPD field */
  ldr r0, =MCME_PRTN1_PUPD
  ldr r1, [r0]
  ldr r2, =1
  orr r1, r2
  str r1, [r0]

  /* Trigger update */
  ldr r0, =MCME_CTL_KEY
  ldr r1, =MCME_KEY
  str r1, [r0]
  ldr r1, =MCME_INV_KEY
  str r1, [r0]
#endif
/* Check MSCM clock in PRTN1 */
#ifndef SIM_TYPE_VDK
WaitForClock:
  ldr r0, =MCME_PRTN1_COFB0_STAT
  ldr r1, [r0]
  ldr r2, =MCME_MSCM_REQ
  and r1, r1, r2
  cmp r1, 0
  beq WaitForClock
#endif

4. Relocate vector table to Ram

​ 将中断向量表(intc_vector)复制到SRAM。设置中断向量表的基地址到VTOR(向量表偏移寄存器),这样core就可以根据不同的向量表数跳转到不同的ISR。将向量表定义到SRAM访问速率会比在Flash中快并且能满足客户修改ISR的名称。

SetVTOR:
/* relocate vector table to RAM */
ldr  r0, =VTOR_REG
ldr  r1, =__RAM_INTERRUPT_START
str  r1,[r0]

5.Initialize CPU Core Stack

​ 初始化堆栈指针MSP

/* Enable TCM and Disable RETEN bit */
LDR r1, =CM7_DTCMCR
LDR r0, [r1]
bic r0, r0, #0x4
orr r0, r0, #0x1
str r0, [r1]
/* Enable TCM and Disable RETEN bit */
LDR r1, =CM7_ITCMCR
LDR r0, [r1]
bic r0, r0, #0x4
orr r0, r0, #0x1
str r0, [r1]
/* set up stack; r13 SP*/
ldr  r0, =__Stack_dtcm_start
msr MSP, r0
/*GetCoreID*/
ldr  r0, =0x40260004
ldr  r1,[r0]

ldr  r0, =MAIN_CORE
cmp  r1,r0
beq	 DisableSWT0
#ifdef RAM_DATA_INIT_ON_ALL_CORES
  b RamInit
#else
  b DTCM_Init /* SWT1 clock is disabled at startup */
#endif

6.Disable SWT watchdog

​ 软件看门狗计时器默认启用,在启动的过程中需要关闭

/* Note from manual: For any operation to be performed on an SWT  */
/* instance, its respective core must be enabled.                 */
DisableSWT0:
  ldr  r0, =0x40270010
  ldr  r1, =0xC520
  str  r1, [r0]
  ldr  r1, =0xD928
  str  r1, [r0]
  ldr  r0, =0x40270000
  ldr  r1, =0xFF000040
  str  r1, [r0]
  b    RamInit

DisableSWT1:
  ldr  r0, =0x4046C010
  ldr  r1, =0xC520
  str  r1, [r0]
  ldr  r1, =0xD928
  str  r1, [r0]
  ldr  r0, =0x4046C000
  ldr  r1, =0xFF000040
  str  r1, [r0]
  b    RamInit

7. RAM ECC initialization

​ 芯片复位后,在使用RAM之前必须对其进行初始化,避免ECC错误。注意程序大小必须2 word对齐,对于SRAM、DTCM、ITCM也是同样的,这是启动中最耗时间的地方。

RamInit:
    /* Initialize SRAM ECC */
    ldr  r0, =__RAM_INIT
    cmp  r0, 0
    /* Skip if __RAM_INIT is not set */
    beq SRAM_LOOP_END

    ldr r0, =MCRGM_DES
    ldr r1, [r0]
    ldr r2, =MCRGM_DES_F_POR
    and r1, r1, r2
    cmp r1, 0
    beq NO_INIT_STANDBY_REGION
    ldr r1, =__INT_SRAM_START
    ldr r2, =__INT_SRAM_END
    b   ZERO_64B_RAM

NO_INIT_STANDBY_REGION:
#if defined(S32K310)||defined(S32M274)
    ldr r1, =__BSS_SRAM_NC_START
#else
    ldr r1, =__BSS_SRAM_START
#endif
    ldr r2, =__INT_SRAM_END

ZERO_64B_RAM:
    subs    r2, r1
    subs    r2, #1
    ble SRAM_LOOP_END

    movs    r0, 0
    movs    r3, 0
SRAM_LOOP:
    stm r1!, {r0,r3}
    subs r2, 8
    bge SRAM_LOOP
SRAM_LOOP_END:

DTCM_Init:
    /* Initialize DTCM ECC */
    ldr  r0, =__DTCM_INIT
    cmp  r0, 0
    /* Skip if __DTCM_INIT is not set */
    beq DTCM_LOOP_END

    ldr r1, =__INT_DTCM_START
    ldr r2, =__INT_DTCM_END

    subs    r2, r1
    subs    r2, #1
    ble DTCM_LOOP_END

    movs    r0, 0
    movs    r3, 0
DTCM_LOOP:
    stm r1!, {r0,r3}
    subs r2, #8
    bge DTCM_LOOP
DTCM_LOOP_END:

ITCM_Init:
    /* Initialize ITCM ECC */
    ldr  r0, =__ITCM_INIT
    cmp  r0, 0
    /* Skip if __TCM_INIT is not set */
    beq ITCM_LOOP_END

    ldr r1, =__INT_ITCM_START
    ldr r2, =__INT_ITCM_END

    subs    r2, r1
    subs    r2, #1
    ble ITCM_LOOP_END

    movs    r0, 0
    movs    r3, 0
ITCM_LOOP:
    stm r1!, {r0,r3}
    subs r2, #8
    bge ITCM_LOOP
ITCM_LOOP_END:

8.Wait for debugger to hole core

​ 当在debug的时候需要保持住,调试器可以写一个固定的值0x5A5A5A5A到RESET_CATCH_CORE

DebuggerHeldCoreLoop:
  ldr  r0, =RESET_CATCH_CORE
  ldr  r0, [r0]
  ldr  r1, =0x5A5A5A5A
  cmp  r0, r1
  beq  DebuggerHeldCoreLoop

9.RAM data copy

​ 主要是将存在Flash中的数据copy到RAM中,主要包括以下几种情况:

a.将vector table 、initialized data(.data)、code从ROM复制到RAM

b.清除zero_initialized(.bss) section的数据

/* Table for copying and zeroing */
.section ".init_table", "a"
  .long 6
  .long __RAM_CACHEABLE_START
  .long __ROM_CACHEABLE_START
  .long __ROM_CACHEABLE_END
  .long __RAM_NO_CACHEABLE_START
  .long __ROM_NO_CACHEABLE_START
  .long __ROM_NO_CACHEABLE_END
  .long __RAM_SHAREABLE_START
  .long __ROM_SHAREABLE_START
  .long __ROM_SHAREABLE_END
  .long __RAM_INTERRUPT_START
  .long __INIT_INTERRUPT_START
  .long __INIT_INTERRUPT_END
  .long __RAM_ITCM_START
  .long __ROM_ITCM_START
  .long __ROM_ITCM_END
  .long __RAM_DTCM_DATA_START
  .long __ROM_DTCM_DATA_START
  .long __ROM_DTCM_END

​ 对于bss段,由于没有初始值存在flash,因此只有两个section: RAM_START、RAM_END

.section ".zero_table", "a"
  .long 3
  .long __BSS_SRAM_SH_START
  .long __BSS_SRAM_SH_END
  .long __BSS_SRAM_NC_START
  .long __BSS_SRAM_NC_END
  .long __BSS_SRAM_START
  .long __BSS_SRAM_END

​ init_data_bss 通过写入0来初始化zero_table

_INIT_DATA_BSS:
  bl init_data_bss

10.System Initialization

​ 系统初始化主要包括:

a.获取核ID,使能对应核的中断请求

b.使能FPU

c.使能MPU

d.使能 I/D cache

__SYSTEM_INIT:
  bl SystemInit

11. 跳转main

​ 这是启动代码的最后一部,会启动CPU全局的中断,如果是由AUTOSAR启动将会切换用户模式,最终跳转到main,之后与启动就无关

_MAIN:
  cpsie i
  bl startup_go_to_user_mode
  bl main

四.编译过程

​ 主要是指把源代码编译成可执行代码,编译过程主要几个过程: 预处理、编译、汇编、链接

1.预处理

​ 头文件展开:将#include的内容展开到当前位置,并删除#include

​ 宏展开:展开所有的宏定义,并删除#define

​ 展开条件编译:根据条件展开分支,其余代码删除

​ 删除注释:删掉所有的注释

​ 添加行号及文件名标识:编译过程中根据许需要显示这些信息,如警告,错误等

​ 保留#pragma命令:供编译器使用

2.编译

​ 编译器会做词法分析、语法分析、语义分析等操作,在检查没有错误信息后,会把代码翻译成汇编语句。

3.汇编

​ 将汇编代码翻译成二进制文件

4.链接

​ 编译器会根据链接器将目标文件以及所依赖的库文件进行链接、重定位组装成可执行文件

五.展望

​ 在了解S32K3xx启动相关的知识之后,后续打算实操,后续将基于S32K3xx实例修改一份启动代码和linker文件。

  • 39
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: s32k3xx是一款32位微控制器芯片家族,具有高性能、高可靠性和低功耗等特点,广泛应用于汽车、工业控制和电子设备等领域。s32k3xx示例代码是一组基于该芯片家族的代码模板,旨在帮助程序员快速开发各种应用。 s32k3xx示例代码包含多个示例程序,如GPIO控制、UART通讯、定时器应用、ADC采集、CAN总线控制等。这些示例代码提供了一个基础框架,开发人员可以在此基础上进行修改和开发。例如,GPIO控制示例可以帮助开发人员了解如何使用s32k3xx芯片的GPIO模块实现输入输出控制;UART通讯示例可以帮助开发人员了解如何使用s32k3xx芯片的UART模块进行串口通讯等。 除了示例代码s32k3xx还提供了完整的软件开发工具链,包括编译器、调试器、仿真器等,可与多个集成开发环境(IDE)集成。开发人员可以使用这些工具开发和调试s32k3xx芯片的应用程序。 总之,s32k3xx示例代码是一种方便开发人员快速入手的开发工具,在s32k3xx芯片的应用开发中具有重要意义。 ### 回答2: s32k3xx是一款汽车电子控制单元(ECU)微控制器系列,它是由恩智浦半导体公司推出的。s32k3xx微控制器系列具有强大的计算能力和低功耗特性,旨在满足汽车领域对可靠性、安全性和能效的要求。恩智浦公司提供了一系列示例代码,该代码可以帮助开发人员更快速、更高效地开发出汽车应用所需的软件。 s32k3xx示例代码涵盖了广泛的应用场景,包括控制器局域网(CAN)、PWM、ADC、DMA、FlexCAN、FlexPWM和FlexIO。这些示例代码可以用于快速设置和部署ECU系统,其中一些还包含测试、诊断和调试工具。 s32k3xx示例代码非常适合开发人员,因为它们提供了可重用的函数和代码库,可以帮助团队快速构建和测试汽车应用程序。此外,示例代码还提供了丰富的文档和演示,包括使用说明和教程,帮助开发人员理解和实现有关汽车电子控制的最佳实践。 综上所述,s32k3xx示例代码是一款非常有用的工具,可以为汽车电子控制器开发人员提供更高效、更可靠和更安全的软件开发平台。无论您需要开发什么类型的应用程序,s32k3xx示例代码都是一个良好的起点。 ### 回答3: S32K3xx是一款汽车电子芯片,其示例代码包含多个应用领域的demo,如CAN通信、PWM控制、UART通信等。这些代码具有一定的参考价值和实用性,可大大缩短开发时间和提高开发效率。 其中,CAN通信示例代码涵盖了CAN基础通信、CANFD通信以及CAN数据处理和过滤等方面,可以根据不同需求进行参考和修改。 PWM控制示例代码主要针对电机驱动领域,可以实现PWM波输出、电机起停控制、电机转速控制等功能,能够很好地配合电机控制器进行应用开发。 UART通信示例代码则提供了UART的发送、接收和中断处理等功能,可广泛应用于串口通信、蓝牙模块通信等领域。 除此之外,S32K3xx还提供了其他多个示例代码,如ADC采集、I2C通信、SPI通信等,可根据具体需求进行选择和使用。同时,在使用示例代码过程中,还需注意相关硬件环境和额外库函数的使用,确保代码正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值