CW32L010适配GNU启动文件解析
前言
因为keil开发单片机实在是手感不太好,所以打算使用GNU工具链进行开发,因此找到了VSCode上的EIDE插件,但是GNU工具链的启动文件和keil的启动文件还是有一些区别的,所以打算记录一下GNU启动文件的结构,方便以后查阅。
ps:本文基于CW32L010的GNU启动文件进行解析,主要放在启动文件(.s文件)的解析。由于我也是新手一个,文章中可能存在错误,欢迎指正。
GNU启动文件的结构
首先需要定义汇编语法,定义处理器,浮点运算,指令集。
因为CW32l010是M0+内核,所以使用的是Cortex-M0+处理器,软件浮点运算(M0+无硬件FPU),Thumb指令集。
1 2 3 4
| .syntax unified .cpu cortex-m0plus .fpu softvfp .thumb
|
定义全局变量
- 定义一个全局符号g_pfnVectors之后用来存储中断向量表。
- 定义一个全局函数Default_Handler,用来处理中断向量表中的异常(防止程序跑飞)
1 2
| .global g_pfnVectors .global Default_Handler
|
定义几个重要的地址
在开始这段内容讲解前,我们需要先明白几个知识点
我们所编写的代码在上电之前都是存储在Flash中的,上电之后,代码会被加载到RAM中,所以我们需要定义一些地址,来表示Flash和RAM中的地址,完成初始化。
- .data data段存放着已经初始化过且不为0的全局变量和静态变量,一开始放在Flash中,上电之后,会被加载到RAM中。
- .bss BSS段存放着未初始化的或者初始化为0的全局变量和静态变量,一开始放在Flash中,上电之后,会被加载到RAM中。
- _sidata 定义的是在FLash中data段的起始地址
- _sdata 定义的是在RAM中data段的起始地址
- _edata 定义的是在RAM中data段的结束地址
- _sbss 定义的是在RAM中bss段的起始地址
- _ebss 定义的是在RAM中bss段的结束地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
```c
.word _sidata
.word _sdata
.word _edata
.word _sbss
.word _ebss
|
定义Reset_Handler函数
定义一个Reset_Handler函数,用于初始化RAM和系统调用main函数。
- 定义一个名为 .text.Reset_Handler 的代码段(Section),专门存放 Reset_Handler 函数的代码。
- 将 Reset_Handler 声明为 弱符号(Weak Symbol)。
- 将 Reset_Handler 声明为 函数类型(Function Type)。
1 2 3 4 5 6 7 8 9
| .section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
|
定义Reset_Handler函数的内容
- 设置栈指针,将栈指针指向_estack,也就是栈顶地址。
1 2 3
| Reset_Handler: ldr r0, =_estack mov sp, r0
|
- 将Flash中的初始化数据复制到RAM中,也就是将Flash中的data段复制到RAM中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ldr r0, =_sdata ldr r1, =_edata ldr r2, =_sidata movs r3, #0 b LoopCopyDataInit
CopyDataInit: ldr r4, [r2, r3] str r4, [r0, r3] adds r3, r3, #4
LoopCopyDataInit: adds r4, r0, r3 cmp r4, r1 bcc CopyDataInit
|
- 将BSS段清零,也就是将RAM中的bss段清零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
ldr r2, =_sbss ldr r4, =_ebss movs r3, #0 b LoopFillZerobss
FillZerobss: str r3, [r2] adds r2, r2, #4
LoopFillZerobss: cmp r2, r4 bcc FillZerobss
|
- 初始化系统时钟,初始化静态构造函数,调用main函数。最后进入死循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
bl SystemInit
bl __libc_init_array
bl main
LoopForever: b LoopForever
|
- 设置Reset_Handle的大小
1 2 3
| .size Reset_Handler, .-Reset_Handler
|
到这里可以说是设置好了整个Reset_Handler函数,接下来我们还需要设置Default_Handler函数,用于处理中断向量表中的异常(防止程序跑飞)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop: b Infinite_Loop
.size Default_Handler, .-Default_Handler
|
设置中断函数
1 2 3 4 5 6 7 8 9 10 11 12 13
|
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
|
设置中断向量表,不同内核中断向量表并不一致,这个需要参考对应的芯片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| g_pfnVectors: .word _estack .word Reset_Handler .word NMI_Handler .word HardFault_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word SVC_Handler .word Default_Handler .word Default_Handler .word PendSV_Handler .word SysTick_Handler
.word WDT_IRQHandler .word LVD_IRQHandler .word RTC_IRQHandler .word FLASHRAM_IRQHandler .word SYSCTRL_IRQHandler .word GPIOA_IRQHandler .word GPIOB_IRQHandler .word Default_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word Default_Handler .word ADC_IRQHandler .word ATIM_IRQHandler .word VC1_IRQHandler .word VC2_IRQHandler .word GTIM1_IRQHandler .word Default_Handler .word Default_Handler .word LPTIM_IRQHandler .word BTIM1_IRQHandler .word BTIM2_IRQHandler .word BTIM3_IRQHandler .word I2C1_IRQHandler .word Default_Handler .word SPI1_IRQHandler .word Default_Handler .word UART1_IRQHandler .word UART2_IRQHandler .word Default_Handler .word Default_Handler .word CLKFAULT_IRQHandler
|
弱定义函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
.weak NMI_Handler .thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler .thumb_set HardFault_Handler,Default_Handler
.weak SVC_Handler .thumb_set SVC_Handler,Default_Handler
.weak PendSV_Handler .thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler .thumb_set SysTick_Handler,Default_Handler
.weak WDT_IRQHandler .thumb_set WDT_IRQHandler,Default_Handler
.weak LVD_IRQHandler .thumb_set LVD_IRQHandler,Default_Handler
.weak RTC_IRQHandler .thumb_set RTC_IRQHandler,Default_Handler
.weak FLASHRAM_IRQHandler .thumb_set FLASHRAM_IRQHandler,Default_Handler
.weak SYSCTRL_IRQHandler .thumb_set SYSCTRL_IRQHandler,Default_Handler
.weak GPIOA_IRQHandler .thumb_set GPIOA_IRQHandler,Default_Handler
.weak GPIOB_IRQHandler .thumb_set GPIOB_IRQHandler,Default_Handler
.weak ADC_IRQHandler .thumb_set ADC_IRQHandler,Default_Handler
.weak ATIM_IRQHandler .thumb_set ATIM_IRQHandler,Default_Handler
.weak VC1_IRQHandler .thumb_set VC1_IRQHandler,Default_Handler
.weak VC2_IRQHandler .thumb_set VC2_IRQHandler,Default_Handler
.weak GTIM1_IRQHandler .thumb_set GTIM1_IRQHandler,Default_Handler
.weak LPTIM_IRQHandler .thumb_set LPTIM_IRQHandler,Default_Handler
.weak BTIM1_IRQHandler .thumb_set BTIM1_IRQHandler,Default_Handler
.weak BTIM2_IRQHandler .thumb_set BTIM2_IRQHandler,Default_Handler
.weak BTIM3_IRQHandler .thumb_set BTIM3_IRQHandler,Default_Handler
.weak I2C1_IRQHandler .thumb_set I2C1_IRQHandler,Default_Handler
.weak SPI1_IRQHandler .thumb_set SPI1_IRQHandler,Default_Handler
.weak UART1_IRQHandler .thumb_set UART1_IRQHandler,Default_Handler
.weak UART2_IRQHandler .thumb_set UART2_IRQHandler,Default_Handler
.weak CLKFAULT_IRQHandler .thumb_set CLKFAULT_IRQHandler,Default_Handler
|
这是一个基于CW32L010的EIDE模板,用于快速开发基于CW32L010的嵌入式项目。.s启动文件也已经同步上传,可以参考。