国产超低功耗华大单片启动文件详解及SystemInit函数分析

启动代码文件名一般可命名为如startup_hc32xxxx.s。启动代码作用一般是:

1) 堆和栈的初始化

包括堆栈的大小,MSP(main stack pointer)值等。MSP的初始值在复位阶段取自存储区的第一个字(即0地址处的值)。

栈Stack: 由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。向低地址扩展。

堆Heap: 一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。向高地址扩展。

2) 向量表定义 
定义了各MSP初值,以及各个中断服务程序(ISR)的入口地址。

3) 中断服务程序 
CPU根据中断号从向量表中获取入口地址后,跳转至对应的ISR

4) 设置系统时钟频率
可在复位中断服务程序Reset_handler中调用系统时钟频率初始化程序

5) 中断寄存器的初始化

6)进入C应用程序
在复位中断服务程序即Reset_handler中实现进入C程序。如:

LDR  R0 , =_main  ;使用“=”表示LDR目前是伪指令。这里是把_main的地址给R0。

BX    R0                 ; BX是ARM指令集和THUMB指令集之间程序的跳转。

以下以华大单片机HC32L136K8TA的启动文件为例,对1) — 6)进行详细分析。

;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000

;然后在RAM中分配变量使用的堆

;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x0000_0000,该中断向量表就从这个起始地址开始分配

;分配完成后,再定义和实现相应的中断函数,

;所有的中断函数全部带有[weak]特性,即弱定义,如果编译器发现在别处文件中定义了同名函数,在链接时用别处的地址进行链接。

;中断函数仅仅实现了Reset_Handler,其他要么是死循环,要么仅仅定义了函数名称

;HC32被设置为从内部FLASH启动时(这也是最常见的一种情况),当HC32遇到复位信号后,

;从0x0000_0000处取出栈顶地址存放于MSP寄存器,从0x0000_0004处取出复位中断服务入口地址放入PC寄存器,

;继而执行复位中断服务程序Reset_Handler,

;Reset_Handler仅仅执行了两个函数调用,一个是SystemInit,另一个__main,

;SystemInit定义在system_hc32xxxx.c中,主要初始化了HC的时钟系统:RCH,RCL,XTH,XTL,PLL,SystemClk,HCLK,PCLK等等.

;__main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数,来到C的世界。

HC32L136K8TA芯片的中断向量表如下图所示:

国产超低功耗华大单片启动文件详解及SystemInit函数分析_第1张图片

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

本文旨在抛砖引玉,其余具体使用欢迎加群164973950交流。

 国产低功耗华大单片机主力型号如下:

HC32F003 HC32F005 HC32L110 HC32F030 HC32L136 HC32M140 HC32F146 HC32L150 HC32L156

芯片相关资料下载链接:https://blog.csdn.net/lvk/article/details/85260690

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

; Stack Configuration
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>

Stack_Size      EQU     0x00000200           ;定义堆栈大小
                AREA    STACK, NOINIT, READWRITE, ALIGN=3   
                                             ;定义一个数据段 按8字节对齐                                                                 ;AREA 伪指令用于定义一个代码段或数据段 
                                             ;NOINIT:指定此数据段仅仅保留了内存单元,
                                             ;而没有将各初始值写入内存单元,
                                             ;或者将各个内存单元值初始化为0

Stack_Mem       SPACE   Stack_Size           ;保留Stack_Size大小的堆栈空间分配连续
                                             ;Stack_Size字节的存储单元并初始化为 0
 
__initial_sp                                 ;标号,代表堆栈顶部地址,后面有用

; Heap Configuration
;  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>

Heap_Size       EQU     0x00000000           ;定义堆空间大小
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3    
                                             ;定义一个数据段,8字节对齐
__heap_base                                  ;标号,代表堆末底部地址,后面有用
Heap_Mem        SPACE   Heap_Size            ;保留Heap_Size的堆空间  
__heap_limit                                 ;标号,代表堆界限地址,后面有用
                                             ;PRESERVE8 指令指定当前文件保持堆栈八字节对齐。
                                             ;它设置 PRES8 编译属性以通知链接器。
                                             ;链接器检查要求堆栈八字节对齐的任何代码是否仅由
                                             ;保持堆栈八字节对齐的代码直接或间接地调用。

                PRESERVE8                    ;指示编译器8字节对齐
                THUMB                        ;指示编译器以后的指令为THUMB指令
; Vector Table Mapped to Address 0 at Reset  ;中断向量表定义
                AREA    RESET, DATA, READONLY;定义只读数据段,其实放在CODE区,位于0地址
                EXPORT  __Vectors            ;EXPORT:在程序中声明一个全局的标号__Vectors,
                                             ;该标号可在其他的文件中引用
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
__Vectors                       
                DCD     __initial_sp         ;Top of Stack;给__initial_sp分配4字节32位的地址0x0
                DCD     Reset_Handler        ;Reset ; 给标号Reset Handler分配地址为0x00000004       
                DCD     NMI_Handler          ; NMI; 给标号NMI Handler分配地址0x00000008
                DCD     HardFault_Handler    ; Hard Fault
                DCD     0                    ; Reserved ; 这种形式就是保留地址,不给任何标号分配
                DCD     0                    ; Reserved
                DCD     0                    ; Reserved
                DCD     0                    ; Reserved
                DCD     0                    ; Reserved
                DCD     0                    ; Reserved
                DCD     0                    ; Reserved
                DCD     SVC_Handler          ; SVCall
                DCD     0                    ; Reserved
                DCD     0                    ; Reserved
                DCD     PendSV_Handler       ; PendSV
                DCD     SysTick_Handler      ; SysTick
                DCD     PORTA_IRQHandler
                DCD     PORTB_IRQHandler
                DCD     PORTC_IRQHandler
                DCD     PORTD_IRQHandler
                DCD     DMAC_IRQHandler
                DCD     TIM3_IRQHandler
                DCD     UART0_IRQHandler
                DCD     UART1_IRQHandler
                DCD     LPUART0_IRQHandler
                DCD     LPUART1_IRQHandler
                DCD     SPI0_IRQHandler
                DCD     SPI1_IRQHandler
                DCD     I2C0_IRQHandler
                DCD     I2C1_IRQHandler
                DCD     TIM0_IRQHandler
                DCD     TIM1_IRQHandler
                DCD     TIM2_IRQHandler
                DCD     LPTIM_IRQHandler
                DCD     TIM4_IRQHandler
                DCD     TIM5_IRQHandler
                DCD     TIM6_IRQHandler
                DCD     PCA_IRQHandler
                DCD     WDT_IRQHandler
                DCD     RTC_IRQHandler
                DCD     ADC_IRQHandler
                DCD     PCNT_IRQHandler
                DCD     VC0_IRQHandler
                DCD     VC1_IRQHandler
                DCD     LVD_IRQHandler
                DCD     LCD_IRQHandler
                DCD     EF_RAM_IRQHandler
                DCD     CLKTRIM_IRQHandler               
__Vectors_End
__Vectors_Size EQU     __Vectors_End - __Vectors
                AREA    |.text|, CODE, READONLY 
                                             ;代码段定义

; Reset Handler                              ;利用PROC、ENDP这一对伪指令把程序段分为若干
                                             ;个过程,使程序的结构加清晰
Reset_Handler   PROC                         ;过程的开始
                EXPORT  Reset_Handler    [WEAK] 
                                             ;[WEAK] 弱定义,意思是如果在别处也定义该标号
                                             ;(函数),在链接时用别处的地址。 如果没有其它地方
                                             ;定义,编译器也不报错,以此处地址进行链接。
                                             ;EXPORT提示编译器该标号可以为外部文件引用。

                IMPORT  SystemInit           ;代码中的系统初始化程序
                IMPORT  __main               ;通知编译器要使用的标号在其他文件

               ;reset NVIC if in rom debug
                LDR     R0, =0x20000000
                LDR     R2, =0x0
                MOVS    R1, #0               ; for warning,
                ADD     R1, PC,#0            ; for A1609W,
                CMP     R1, R0
                BLS     RAMCODE

              ; ram code base address.
                ADD     R2, R0,R2
RAMCODE
              ; reset Vector table address.
                LDR     R0, =0xE000ED08
                STR     R2, [R0]

                LDR     R0, =SystemInit     
                BLX     R0                   ;BX是ARM指令集和THUMB指令集之间程序的跳转   
                LDR     R0, =__main          ;使用“=”表示LDR目前是伪指令不是标准指令。
                                             ;这里是把__main的地址给RO。
                BX      R0                   ;BX是ARM指令集和THUMB指令集之间程序的跳转
                ENDP                         ;过程的结束

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler               [WEAK]
                B       .
                ENDP
 
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler         [WEAK]
                B       .                    ;原地跳转(即无限循环),等同于while(1);
                ENDP
SVC_Handler     PROC
                EXPORT  SVC_Handler               [WEAK]
                B       .
                ENDP
PendSV_Handler  PROC
                EXPORT  PendSV_Handler            [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler           [WEAK]
                B       .
                ENDP

Default_Handler PROC
                EXPORT  PORTA_IRQHandler                [WEAK]
                EXPORT  PORTB_IRQHandler                [WEAK]
                EXPORT  PORTC_IRQHandler                [WEAK]
                EXPORT  PORTD_IRQHandler                [WEAK]
                EXPORT  DMAC_IRQHandler                 [WEAK]
                EXPORT  TIM3_IRQHandler                 [WEAK]
                EXPORT  UART0_IRQHandler                [WEAK]
                EXPORT  UART1_IRQHandler                [WEAK]
                EXPORT  LPUART0_IRQHandler              [WEAK]
                EXPORT  LPUART1_IRQHandler              [WEAK]
                EXPORT  SPI0_IRQHandler                 [WEAK]
                EXPORT  SPI1_IRQHandler                 [WEAK]
                EXPORT  I2C0_IRQHandler                 [WEAK]
                EXPORT  I2C1_IRQHandler                 [WEAK]
                EXPORT  TIM0_IRQHandler                 [WEAK]
                EXPORT  TIM1_IRQHandler                 [WEAK]
                EXPORT  TIM2_IRQHandler                 [WEAK]
                EXPORT  LPTIM_IRQHandler                [WEAK]
                EXPORT  TIM4_IRQHandler                 [WEAK]
                EXPORT  TIM5_IRQHandler                 [WEAK]
                EXPORT  TIM6_IRQHandler                 [WEAK]
                EXPORT  PCA_IRQHandler                  [WEAK]
                EXPORT  WDT_IRQHandler                  [WEAK]
                EXPORT  RTC_IRQHandler                  [WEAK]
                EXPORT  ADC_IRQHandler                  [WEAK]
                EXPORT  PCNT_IRQHandler                 [WEAK]
                EXPORT  VC0_IRQHandler                  [WEAK]
                EXPORT  VC1_IRQHandler                  [WEAK]
                EXPORT  LVD_IRQHandler                  [WEAK]
                EXPORT  LCD_IRQHandler                  [WEAK]
                EXPORT  EF_RAM_IRQHandler               [WEAK]
                EXPORT  CLKTRIM_IRQHandler              [WEAK]
PORTA_IRQHandler
PORTB_IRQHandler
PORTC_IRQHandler
PORTD_IRQHandler
DMAC_IRQHandler
TIM3_IRQHandler
UART0_IRQHandler
UART1_IRQHandler
LPUART0_IRQHandler
LPUART1_IRQHandler
SPI0_IRQHandler
SPI1_IRQHandler
I2C0_IRQHandler
I2C1_IRQHandler
TIM0_IRQHandler
TIM1_IRQHandler
TIM2_IRQHandler
LPTIM_IRQHandler
TIM4_IRQHandler
TIM5_IRQHandler
TIM6_IRQHandler
PCA_IRQHandler
WDT_IRQHandler
RTC_IRQHandler
ADC_IRQHandler
PCNT_IRQHandler
VC0_IRQHandler
VC1_IRQHandler
LVD_IRQHandler
LCD_IRQHandler
EF_RAM_IRQHandler
CLKTRIM_IRQHandler
   
                B .
                ENDP
                ALIGN                        ;填充字节使地址对齐

; User Initial Stack & Heap                  ;堆和栈的初始化
                IF      :DEF:__MICROLIB      ;“DEF”的用法:DEF:X就是说X定义了则为真,否则为
                                             ;如果定义了MICORLIB,
                EXPORT  __initial_sp         ;则将栈顶地址,
                EXPORT  __heap_base          ;堆起始地址赋予全局属性,
                EXPORT  __heap_limit         ;堆末端界限地址赋予全局属性,使外部程序可调用
                ELSE                         ;如果没定义__MICROLIB,则使用默认的C运行时库
                IMPORT  __use_two_region_memory  
                                             ;通知编译器要使用的标号在其他文件
                                             ;__use_two_region_memory    
                EXPORT  __user_initial_stackheap 
                                             ;声明全局标号__user_initial_stackheap,
                                             ;这样外程序也可调用此标号,则进行堆栈和堆的赋
                                             ;值,在__main函数执行过程中调用, 如果使用默认的
                                             ;C库,程序启动过程中就不会执行该标号下的代码

__user_initial_stackheap                     ;标号,表示用户堆栈初始化程序入口 
                                             ;进行堆栈和堆的赋值,在_main函数执行过程中调用。

                LDR     R0, =  Heap_Mem      ;保存堆始地址
                LDR     R1, =(Stack_Mem + Stack_Size) 
                                             ;保存栈的大小
                LDR     R2, = (Heap_Mem +  Heap_Size) 
                                             ;保存堆的大小
                LDR     R3, = Stack_Mem      ;保存栈顶指针
                BX      LR

                ALIGN                        ;填充字节使地址对齐

                ENDIF
                END

更多内容请点击链接加入群聊

【华大MCU应用交流】

 

你可能感兴趣的:(华大单片机使用)