最近开始使用ST的stm32w108芯片(也是一款zigbee芯片)。开始看他的启动代码看的晕晕呼呼呼的。
还好在csdn上看到一片文章写的不错,分享下:
使用的芯片是 STM32F103VET,编译器使用 IAR ARM V5.5
设置头文件查找路径,例如:
$PROJ_DIR$\..\
$PROJ_DIR$\..\..\..\Libraries\CMSIS\CM3\CoreSupport
$PROJ_DIR$\..\..\..\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
$PROJ_DIR$\..\..\..\Libraries\STM32F10x_StdPeriph_Driver\inc
预定义的symbol 为,HD为high desity 的意思
USE_STDPERIPH_DRIVER
STM32F10X_HD
有两个符号是系统默认的,看名字就应该知道什么了。
$TOOLKIT_DIR$\ $PROJ_DIR$\
注意GPIO的端口操作是 16位的,否则送的数据无效
GPIOB_ODR = (uint16_t)0xff
__iar_program_start 是一个系统定义的标号,在自带的C库启动代码当中,IAR会自动连接到当然了,也可以自己定义一个
EXTERN __iar_program_start
LDR R0, =__iar_program_start
BX R0
另外一个必须有的符号就是 __vector_table 使用方法是
SECTION .intvec:CODE:NOROOT(2)
PUBLIC __vector_table
DATA
__vector_table
DCD sfe(CSTACK)
DCD Reset_Handler ; Reset Handler
......
首先中断向量独立在一个叫 .intvec 的段当中,这个段是 4字节对齐(2^2)所以用 DATA 来首先处理向量的入口地址为 4的倍数,然后放向量表。
需要注意的是 NOROOT(2) 和 ROOT(2) 的区别,如果NOROOT表示如果符号没有被关联的时候是被优化掉的,如果想不被优化则使用ROOT吧
其中向量表的第一个数据为堆栈的顶部,可以为一个确定的数值放在SRAM的尾部,这里演示代码使用的是使用固定连接脚本去处理,在连接脚本中定义了一个 CSTACK 的段,然后在启动代码中先声明这个段
SECTION CSTACK:DATA:NOROOT(3)
DCD sfe(CSTACK)
然后通过 SFE 运算得到改段的结束地址,注意这个运算是在link的时候完成。所以IAR 的处理办法就是先定义一个block作为堆栈区,然后将堆栈指针放到这个block的末端,因为STM32的堆栈是向下生长的。
剩下的就是各个中断向量。接着看怎么处理
THUMB
PUBWEAK Reset_Handler
SECTION .text:CODE:REORDER(2)
Reset_Handler
LDR R0, =SystemInit
BLX R0
LDR R0, =__iar_program_start
BX R0
PUBWEAK NMI_Handler
SECTION .text:CODE:REORDER(1)
NMI_Handler
B NMI_Handler
首先,因为之前是DATA模式,所以这里先切换回THUMB模式,PUBWEAK 应该是由2个单词组成,PUBLIC 和 WEAK ,PUBLIC 表示导出标号,WEAK表示弱属性,这个属性有一个好处就是,如果用户程序定义了这个标号,那么系统自带的这个中断处理程序则丢弃,使用用户的处理程序,如果用户没有定义则使用系统默认的中断处理程序,这样处理给用户有足够的*。
然后就装载 SystemInit 函数的地址,跳转去执行该函数,这个函数主要是设置系统的时钟。
最后装载 __iar_program_start 的地址,这个函数是在启动代码中 \arm\src\lib\thumb\下面的代码中找到,是系统自带的启动模块。在项目设置属性的 linker,library中勾选 Automatic runtime library 就可以自动装载了,然后在汇编代码中声明一下
EXTERN __iar_program_start
就可以调用这个函数了。如果将那个够选项取消后立刻提示没有找到这个标号。
至于另外一个符号 __vector_table 是有特殊意义的,所以必须注意添加进去
; The vector table is normally located at address 0.
; When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
; The name "__vector_table" has special meaning for C-SPY:
; it is where the SP start value is found, and the NVIC vector
; table register (VTOR) is initialized to this address if != 0.
还有一个最重要的标号就是 main ,初始化模块最后就是跳到 main 函数了,所以如果写C的话则写个main函数,如果写汇编的话同样也需要从main标号开始,很简单,导出一下就可以了。
PUBLIC main
main:
连接脚本
Config/generic_cortex.icf 就是通用的 cortex M3内核连接脚本,只需要修改几个地址就OK了
首先定义可寻址的逻辑地址,ARM是4G
define memory mem with size = 4G;
然后定义 region 也就是实际的物理地址
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
Etual
2010-7-21