跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
折叠
品牌标识

YunTu Forum

YTMicro.com
  1. 主页
  2. Discussion & Question
  3. YT SDK
  4. 云途启动文件(startup.s)详解

云途启动文件(startup.s)详解

已定时 已固定 已锁定 已移动 YT SDK
1 帖子 1 发布者 150 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • DerrickD 在线
    DerrickD 在线
    Derrick YunTu
    编写于 最后由 编辑
    #1

    前言:

    1. 本文将对云途启动文件(startup.s)进行详细介绍,不同IDE的启动文件大同小异,本文以IAR为例。
    2. 介绍云途不同型号芯片的启动时间(从复位到进入main函数,以及时钟初始化完成)。
    3. 针对特殊场景需要尽量减少启动时间,本文介绍几种优化方式。

    版本:

    Config Tool Version:2.7.6
    SDK version:1.3.1
    IDE:IAR

    1. 声明与定义

    MODULE  ?cstartup
    EXTERN  main
    EXTERN  SystemInit
    EXTERN  RamInit0
    EXTERN  RamInit1
    EXTERN  RamInit2
    EXTERN  VectorTableCopy
    EXTERN STACK_end
    
    PUBWEAK Reset_Handler
    SECTION .text:CODE:REORDER:NOROOT(2)
    THUMB
    
    • MODULE ?cstartup:声明当前汇编模块名为?cstartup,用于链接器识别模块。
    • EXTERN 指令:声明外部符号(函数),表示这些函数在其他文件(通常是 C 文件)中定义,此处需要调用。包括:
      • main:C 程序入口函数;
      • SystemInit:系统初始化;
      • RamInit0/1/2:RAM 分阶段初始化函数;
      • VectorTableCopy:中断向量表复制函数;
      • STACK_end:栈顶地址(链接脚本中定义)。
    • PUBWEAK Reset_Handler:定义一个公共弱符号Reset_Handler(复位中断处理函数)。PUB表示可被外部访问,WEAK表示若其他地方有同名强符号,会被覆盖(通常复位向量固定指向此处)。
    • SECTION .text:CODE:REORDER:NOROOT(2):定义代码段.text,属性为可执行代码(CODE),允许链接器重排(REORDER),非必需段(NOROOT,未被引用时可被链接器丢弃),优先级为 2。
    • THUMB:指定使用 ARM 的 THUMB 指令集(16 位指令,更紧凑,适合嵌入式场景)。

    2. 复位启动流程

    • 芯片复位后,硬件会自动跳转到复位向量(即Reset_Handler),开始执行以下步骤:

    2.1 关闭中断,初始化通用寄存器

    CPSID   I               ;关闭IRQ中断(防止初始化被中断干扰)
    LDR     R1,=0           ;初始化通用寄存器
    ...(R2到R7均设为0)
    MOV     R8,R7           ;R8到R12均设为0(R7已为0)
    ...
    MOV     R12,R7          ;R1-R12全为0
    
    • CPSID I:通过修改 CPSR(程序状态寄存器)关闭 IRQ 中断,确保初始化过程不被打断。
    • 因为复位后的通用寄存器R1-R12的值UnKnown,所以要重新初始化,清除寄存器残留值,保证初始状态一致。
      509cab12-ec71-4a79-94fa-46ba72a33aec-image.png

    2.2 RAM 第一阶段初始化(RamInit0)

    /* RamInit 0 Stage, focus on ecc init, asm code*/
        BL     RamInit0
    
    • SRAM存储器中的内容在上电之后内容是随机的,其中的有效数据和ECC数据并未建立起关联。此时,如果读取SRAM的内容并进行ECC校验,大概率上是会出现ECC错误的。
    • 在使用支持ECC的SRAM之前,需要手动对SRAM进行初始化操作(循环赋值0x5A,方便辨认)。
    • 另外YT_LINK中的RAM段的POR_ONLY属性就是在RamInit0和RamInit1中完成。读取RCU上电标志位,以判断是否执行这段RAM的初始化。(例如开辟一段空间存放Bootloader和APP的交互信息)
      3f3feff0-4279-44d2-b615-cc75694a58e9-image.png

    2.3 设置栈顶指针(SP)

    /* Initialize the stack pointer */
        LDR     r0,=STACK_end
        MOV     r13,r0
    
    • 栈是 C 语言运行的基础(用于函数调用、局部变量存储等)。STACK_end是栈的栈顶地址(由链接脚本定义,栈通常向下生长,即高地址向低地址生长)。
    • 此步骤为后续 C 函数调用(如RamInit1)准备栈环境。

    2.4 RAM 第二阶段初始化(RamInit1)

    /* RamInit 1 Stage, focus on copy data,clear bss, c code*/
        LDR     r0,=RamInit1
        BLX     r0
    
    • 注释:RamInit1,用于复制数据段(.data)、清除 BSS 段(未初始化全局变量),由 C 语言实现。
    • RamInit0是将RAM初始化为统一固定值0x5A,而RamInit1则是将定义在RAM中的全局变量初始化赋值。
    • 有初始值的定义在(.data段),初始化是从FLASH将初始值copy到RAM。另外如果设置了POR_ONLY属性的RAM段在无上电标志位时则不会copy;设置INIT_NULL属性的RAM也不会copy。
      0c6e1538-f689-4e24-bcf1-8f7973b19b15-image.png
    • 定义了但未赋值的全局变量则会定义在(.bss)段,会被清零。
      e59e886d-f82b-4d7b-965c-5389a005b219-image.png

    2.5 复制中断向量表

        /* Copy Vector Table for interrupt, c code */
    #ifndef __NO_VECTOR_TABLE_COPY
        /* Call the to copy vector table from flash to ram */
        ldr     r0,=VectorTableCopy
        blx     r0
    #endif
    

    19e38303-1188-4187-a36d-0da6f0eecb6a-image.png

    • 作用:中断向量表(存储各中断处理函数地址)默认存储在 Flash 程序的起始地址,复制到 RAM 可提高中断响应速度,或支持动态修改向量表。
    • 将中断向量表基地址(SCB->VTOR)偏移到 IVT_RAM_start(由链接脚本定义);
    • 中断向量表在链接脚本中默认1024Byte空间,在程序的起始地址,第一个字是栈顶指针,第二个字就是Reset_Handle的地址,后面是所有中断的地址入口。中断向量表在Vector.s中定义。
    • 可通过宏 __NO_VECTOR_TABLE_COPY 配置是否需要 VectorTableCopy。
      07653add-7bcd-4fce-8fb8-82782edfe7b4-image.png
      fae1ce37-c753-4d4d-9797-b2a120308a74-image.png

    2.6 系统初始化

    #ifndef __NO_SYSTEM_INIT
        LDR     r0,=SystemInit
        BLX     r0  ; 调用SystemInit
    #endif
    
    • 云途不同芯片的系统初始化内容有些许差异,以HA0为例,会使能FPU(浮点运算单元),Flash的Deep PowerDown Enable,关闭WDG。
    • 可通过宏 __NO_SYSTEM_INIT 配置是否需要 SystemInit。
      bb181722-3454-48b7-8e24-3095e246aca2-image.png

    2.7 RAM 第三阶段初始化(RamInit2)

    /* RamInit 2 Stage, focus on others ram init, c code */
    LDR     r0,=RamInit2
    BLX     r0
    
    • 作用:处理前两阶段未包含的 RAM 初始化需求(如特殊用途 RAM),由C语言实现。
    • 如图RamInit2为一个弱函数,用户可以重写(覆盖) 这个函数。
      3354cdbc-5dbd-4b62-8aaa-328bdc5ab0b1-image.png

    2.8 开启中断,跳转至main

    /* Unmask interrupts */
    CPSIE   I
    /* Call the main routine */
    BL      main
    
    • 开启 IRQ 中断,为进入main函数做准备
    • BL main:跳转到 C 语言的main函数,启动应用程序。

    2.9 死循环(main返回后)

    JumpToSelf:
        B       JumpToSelf
    
        END
    
    • 若main函数意外返回(正常情况下main不会返回),程序会进入死循环,防止跑飞(执行未知地址指令)。

    2.10 总结

    • 该启动文件的核心流程是:复位后关闭中断 → 初始化通用寄存器组 → 分阶段初始化 RAM(含 data段 / BSS、扩展 RAM) → 设置栈 → 复制向量表 → 系统初始化 → 跳转至main。整个过程为 C 程序运行准备了硬件环境(RAM、WDG、Flash、中断向量、FPU等等)和软件环境(栈、全局变量),是从硬件复位到应用程序启动的桥梁。

    3. 不同型号芯片启动时间

    优化等级:Low
    基于Helloword demo程序测试:
    db770b96-8d52-46d7-a687-6da907646f07-image.png

    LE0:

    d4010816-923a-4fee-86ef-85d6e9446732-image.png

    LE1:

    45acf8f4-1e35-4274-8972-6db1273a9fed-image.png

    MC0:

    06bf7614-b73c-44a2-871f-e978af156664-image.png

    MD1:

    96ef18f9-c380-4b3a-a730-eea2f646dc70-image.png

    MD2:

    0a3beceb-2038-49e0-80d2-3a539c68c3c4-image.png

    ME0:

    0bef586e-e34b-47c6-8b51-e9e30ef121b9-image.png

    HA0:

    40cd4029-aa9c-451e-a100-ecf1c622455a-image.png
    tips:

    • 上述时间仅供参考,因为不同优化等级,不同IDE,启动文件编辑都有可能造成启动时间差异。
    • HA的RAM是256K,相比于ME0(128K)初始化时间反而更短:
      • 因为 HA0 的内核是M7的并且是按照64bit去赋值RAM的,时间更短。
    • HA复位后到启动文件执行需要1ms左右,原因是HA有硬件安全启动(MC也有硬件安全启动,但HA流程相较于MC更复杂),增加了耗时。

    4. 启动时间优化

    • 在启动时RAM循环赋值可能出现多次从Flash取指令赋值时间较长(指令未对齐),造成启动时间变长的问题,而且具有随机性(低优化等级编译)。
    • 在一些特殊应用中,例如Powerdown周期性唤醒(唤醒即复位),因为要控制功耗,所以需尽可能减少启动时间,下面介绍启动时间优化的方式。

    4.1 RamInit0优化

    d188e5e7-1584-4454-a934-6e747ee5c2a7-image.png

    • 如上图在每一段RAM赋初值0x5A的前面加上ALIGNROM 4,确保后续代码 / 数据地址满足 4 字节对齐,提高访问正确性和效率。

    4.2 RamInit1优化

    • 如下图,使用C语言标准库函数memcopy,和memset代替RAMInit1的循环赋值操作,汇编优化更好:
      3adeb124-7ac4-4598-bcc3-b25706d6b0b1-image.png

      d8063910-647c-4b06-b593-9e6fb59ffa8b-image.png

    4.3 减少RAM初始化

    • 可通过YCT去配置RAM段的Init_Policy属性为NULL,这样就不会初始化这段RAM,当然为了防止RAM_ECC,也不能访问这段RAM,可在正常启动后重新以32bit为单位(ECC机制)向这段RAM写入初始值,就可以正常访问了。
    • 这种方法适用于对RAM需求量小的工况,例如powerdown周期性唤醒,唤醒复位后只需执行少量代码就继续进入powerdown。
      1bc02a7f-7f29-4295-970b-e35b74909e56-image.png

    4.4 打开I-Cache(HA,MD2)

    b84ed9fc-2c7f-4d3f-a2e6-fb50a25110f9-image.png

    • HA(M7内核)和MD2系列,也可以打开I-Cache,对于反复用到的指令,比如循环赋值指令,打开I-Cache可提高指令命中率,避免反复访问Flash取指令降低效率。

    • 在启动文件打开I-Cache参考下图代码(HA),可在进入main函数后关闭I-Cache。
      a20cd4e7-8823-48bf-aee5-c948b2a972f0-image.png

      03d570eb-894e-434b-af2c-207b353f316f-image.png

    1 条回复 最后回复
    3

  • 云途开发生态介绍

    快速上手云途开发生态

  • 云途论坛规则/Yuntu Forum Rules

    发帖前请查看

  • YT CONFIG TOOL调查问卷

    帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...

  • can
    19
    demo
    19
    uds
    13
    lin stack
    10
    md14
    6
    fbl
    5
    yt-link
    5
    adc模块
    4
    Online Users
    SBH_HZNS
    SBH_HZN
    swordsS
    swords
    jiankang_wangJ
    jiankang_wang
    guangnanG
    guangnan
    runR
    run
    LlllllL
    Llllll
    EkkoE
    Ekko
    DerrickD
    Derrick
    yifeng_xieY
    yifeng_xie
    hanxiaofeiH
    hanxiaofei
    FrankieF
    Frankie
    • 登录

    • 登录或注册以进行搜索。
    • 第一个帖子
      最后一个帖子
    0
    • 版块
    • 最新
    • 标签
    • 热门