最简单的结构,只有一个数据段(只是为了不报错而已):
area Reset,data,readonly,align=3
如图所示
其中Reset为数据段段名,不可随意更改为别的名称。
在启动延迟之后,CPU从地址0x0000 0000获取堆栈顶的地址,并从启动
存储器的0x0000 0004指示的地址开始执行代码。 因为固定的存储器映像,代码区始终从地址0x0000 0000开始(通过ICode和DCode总线访问),而数据区(SRAM)始终从地址0x2000 0000开始(通过系统总线访问)。Cortex-M3的CPU始终从ICode总线获取复位向量,即启动仅适合于从代码区开始(典型地从Flash启动)。
Flash && SRAM:
area: 指令指示汇编程序汇编新的代码节或数据节。节是不可分的已命名独立代码或数据块,它们由链接器处理有关。
readwrite: 指定本段为可读可写。
data: 表明是数据段。
align: 2^3对齐(8字节对齐),字节对齐的主要原因是为了提高访问效率。
基本的结构:
;①.栈
area stack,noinit,readwrite,align=3 ;noinit:指定不初始化
Stack_Start
space 0x400 ;1024Byte
Stack_End ;栈顶地址(由高向低生长)
;②.堆(暂未用到)
area heap,noinit,readwrite,align=3
Heap_Start
space 0x200 ;512Byte
Heap_End
;③.数据段(只读的属性)
area Reset,data,readonly,align=3
;④.代码段
area |.text|,code,readonly,align=3
end ;汇编代码结束
基本的结构是这样,但目前还无法运行任何代码。因为还未设置SP,PC指针!
完整版:
;要使用的外设寄存器地址 GPIOC_13
RCC_APB2ENR equ 0x40021018
GPIOC_CRH equ 0x40011004
GPIOC_ODR equ 0x4001100C
;①.栈
area stack,noinit,readwrite,align=3 ;noinit:指定不初始化
Stack_Start
space 0x400 ;1024Byte
Stack_End
;②.堆(暂未用到)
area heap,noinit,readwrite,align=3
Heap_Start
space 0x200 ;512Byte
Heap_End
;③.数据段(只读的属性)
area Reset,data,readonly,align=3
dcd Stack_End ;开辟4个字节空间,MCU一上电将自动将此地址传给SP(R13)指针,等同于dcd 0x20000400
dcd reset__ ;开辟4个字节空间,地址传递给PC(R15),程序开始运行的地方。
;④.代码段
area |.text|,code,readonly,align=3
entry ;只有出现bl指令时,才能写entry
reset__ proc
bl LED_Init ;bl指令将自动把当前pc值赋给lr寄存器
endp
loop proc
bl LED_ON
ldr r0,=0xffff1 ;使用寄存器传递delay的参数
bl delay
bl LED_OFF
ldr r0,=0xffff1 ;使用寄存器传递delay的参数
bl delay
b loop ;无条件转移
endp
LED_Init proc
push{lr}
;RCC
ldr r0,=RCC_APB2ENR
ldr r1,=0x00000010
str r1,[r0]
;GPIOC_IO
ldr r0,=GPIOC_CRH
ldr r1,=0x00300000 ;推挽输出
str r1,[r0]
;LED ON
bl LED_ON
pop{pc}
endp
LED_ON proc
push{lr}
ldr r0,=GPIOC_ODR
ldr r1,=0xdfff
str r1,[r0]
pop{pc}
endp
LED_OFF proc
push{lr}
ldr r0,=GPIOC_ODR
ldr r1,=0x2000
str r1,[r0]
pop{pc}
endp
delay proc
sub r0,r0,#1
cmp r0,#0
bgt delay ;满足r0>=0这个条件时,跳转
mov pc,lr ;其实和push,pop实现的功能是一样的,将lr的值赋给pc,完成子函数的返回。
endp
end ;汇编代码结束
stack_size equ 0x400
area stack,noinit,readwrite,align=3 ;栈段
stack_start
space stack_size
stack_end
heap_size equ 0x200
area heap,noinit,readwrite,align=3 ;堆段
heap_base
space heap_size
heap_end
preserve8
thumb
area reset,data,readonly,align=3 ;数据段(只读)
export Verctors__
;不写Verctors__end && Verctors__size也不会启动失败
;export Verctors__end
;export Verctors__size
Verctors__ ;建立中断向量表
dcd stack_end
;如果dcd xxxx中断函数后,还要在code区域export
dcd Reset_Handler
;内核中断
dcd NMI_Handler ; NMI Handler
dcd HardFault_Handler ; Hard Fault Handler
dcd MemManage_Handler ; MPU Fault Handler
dcd BusFault_Handler ; Bus Fault Handler
dcd UsageFault_Handler ; Usage Fault Handler
dcd 0 ; Reserved
dcd 0 ; Reserved
dcd 0 ; Reserved
dcd 0 ; Reserved
dcd SVC_Handler ; SVCall Handler
dcd DebugMon_Handler ; Debug Monitor Handler
dcd 0 ; Reserved
dcd PendSV_Handler ; PendSV Handler
dcd SysTick_Handler ; SysTick Handler
;外部中断
dcd WWDG_IRQHandler ; Window Watchdog
dcd PVD_IRQHandler ; PVD through EXTI Line detect
dcd TAMPER_IRQHandler ; Tamper
dcd RTC_IRQHandler ; RTC
dcd FLASH_IRQHandler ; Flash
dcd RCC_IRQHandler ; RCC
dcd EXTI0_IRQHandler ; EXTI Line 0
dcd EXTI1_IRQHandler ; EXTI Line 1
dcd EXTI2_IRQHandler ; EXTI Line 2
dcd EXTI3_IRQHandler ; EXTI Line 3
dcd EXTI4_IRQHandler ; EXTI Line 4
dcd DMA1_Channel1_IRQHandler ; DMA1 Channel 1
dcd DMA1_Channel2_IRQHandler ; DMA1 Channel 2
dcd DMA1_Channel3_IRQHandler ; DMA1 Channel 3
dcd DMA1_Channel4_IRQHandler ; DMA1 Channel 4
dcd DMA1_Channel5_IRQHandler ; DMA1 Channel 5
dcd DMA1_Channel6_IRQHandler ; DMA1 Channel 6
dcd DMA1_Channel7_IRQHandler ; DMA1 Channel 7
dcd ADC1_2_IRQHandler ; ADC1_2
dcd USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX
dcd USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0
dcd CAN1_RX1_IRQHandler ; CAN1 RX1
dcd CAN1_SCE_IRQHandler ; CAN1 SCE
dcd EXTI9_5_IRQHandler ; EXTI Line 9..5
dcd TIM1_BRK_IRQHandler ; TIM1 Break
dcd TIM1_UP_IRQHandler ; TIM1 Update
dcd TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation
dcd TIM1_CC_IRQHandler ; TIM1 Capture Compare
dcd TIM2_IRQHandler ; TIM2
dcd TIM3_IRQHandler ; TIM3
dcd TIM4_IRQHandler ; TIM4
dcd I2C1_EV_IRQHandler ; I2C1 Event
dcd I2C1_ER_IRQHandler ; I2C1 Error
dcd I2C2_EV_IRQHandler ; I2C2 Event
dcd I2C2_ER_IRQHandler ; I2C2 Error
dcd SPI1_IRQHandler ; SPI1
dcd SPI2_IRQHandler ; SPI2
dcd USART1_IRQHandler ; USART1
dcd USART2_IRQHandler ; USART2
dcd USART3_IRQHandler ; USART3
dcd EXTI15_10_IRQHandler ; EXTI Line 15..10
dcd RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line
dcd USBWakeUp_IRQHandler ; USB Wakeup from suspend
Verctors__end
Verctors__size equ Verctors__end - Verctors__
area |.text|,code,readonly,align=3 ;代码段(只读)
entry
Reset_Handler proc ;由于Reset_Handler执行了SystemInit && __main函数所以要单独处理
;export Reset_Handler [weak]
import __main
import SystemInit
ldr r0,=SystemInit ;使用'='为ldr伪指令,不使用'='则为ldr指令
blx r0
ldr r1,=__main ;将__main地址传给r0寄存器
blx r1 ;执行r0中的地址函数
endp
;内核中断
CoreInterrupt proc
export Reset_Handler [weak]
export NMI_Handler [weak]
export HardFault_Handler [weak]
export MemManage_Handler [weak]
export BusFault_Handler [weak]
export UsageFault_Handler [weak]
export SVC_Handler [weak]
export DebugMon_Handler [weak]
export PendSV_Handler [weak]
export SysTick_Handler [weak]
NMI_Handler
HardFault_Handler
MemManage_Handler
BusFault_Handler
UsageFault_Handler
SVC_Handler
DebugMon_Handler
PendSV_Handler
SysTick_Handler
b .
endp
;外设中断
ExternInterrupt proc ;导出外部中断服务函数
export WWDG_IRQHandler [weak]
export PVD_IRQHandler [weak]
export TAMPER_IRQHandler [weak]
export RTC_IRQHandler [weak]
export FLASH_IRQHandler [weak]
export RCC_IRQHandler [weak]
export EXTI0_IRQHandler [weak]
export EXTI1_IRQHandler [weak]
export EXTI2_IRQHandler [weak]
export EXTI3_IRQHandler [weak]
export EXTI4_IRQHandler [weak]
export DMA1_Channel1_IRQHandler [weak]
export DMA1_Channel2_IRQHandler [weak]
export DMA1_Channel3_IRQHandler [weak]
export DMA1_Channel4_IRQHandler [weak]
export DMA1_Channel5_IRQHandler [weak]
export DMA1_Channel6_IRQHandler [weak]
export DMA1_Channel7_IRQHandler [weak]
export ADC1_2_IRQHandler [weak]
export USB_HP_CAN1_TX_IRQHandler [weak]
export USB_LP_CAN1_RX0_IRQHandler [weak]
export CAN1_RX1_IRQHandler [weak]
export CAN1_SCE_IRQHandler [weak]
export EXTI9_5_IRQHandler [weak]
export TIM1_BRK_IRQHandler [weak]
export TIM1_UP_IRQHandler [weak]
export TIM1_TRG_COM_IRQHandler [weak]
export TIM1_CC_IRQHandler [weak]
export TIM2_IRQHandler [weak]
export TIM3_IRQHandler [weak]
export TIM4_IRQHandler [weak]
export I2C1_EV_IRQHandler [weak]
export I2C1_ER_IRQHandler [weak]
export I2C2_EV_IRQHandler [weak]
export I2C2_ER_IRQHandler [weak]
export SPI1_IRQHandler [weak]
export SPI2_IRQHandler [weak]
export USART1_IRQHandler [weak]
export USART2_IRQHandler [weak]
export USART3_IRQHandler [weak]
export EXTI15_10_IRQHandler [weak]
export RTCAlarm_IRQHandler [weak]
export USBWakeUp_IRQHandler [weak]
WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IRQHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM4_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
USART3_IRQHandler
EXTI15_10_IRQHandler
RTCAlarm_IRQHandler
USBWakeUp_IRQHandler
b .
endp
; 在分散加载时,连接器会将用户的__user_initial_stackheap()函数
;代替C库函数默认的堆栈和堆初始化函数,并将其连接到用户的镜像文件中,
;用户可通过重新实现__user_initial_stackheap()函数来改变堆栈和堆的位置,从而适合自己的目标硬件。
;__user_initial_stackheap()可以用C或汇编语言来实现。它必须返回如下参数:
; R0—堆基地址(heap base)
; R1—堆栈基地址(Stack base)
; R2—堆长度限制值(heap limit)
; R3—堆栈长度限制值(Stacklimit)
;当用户使用分散加载功能的时候,必须重新实现__user_initial_stackheap ()
import __use_two_region_memory
export __user_initial_stackheap
__user_initial_stackheap
ldr R0, = heap_size
ldr R1, =(stack_start + stack_size)
ldr R2, = (heap_size + heap_size)
ldr R3, = stack_start
bx LR
align
end