使用的芯片是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为highdesity 的意思
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
BXR0
另外一个必须有的符号就是__vector_table 使用方法是
SECTION.intvec:CODE:NOROOT(2)
PUBLIC__vector_table
DATA
__vector_table
DCDsfe(CSTACK)
DCDReset_Handler ; Reset Handler
......
首先中断向量独立在一个叫 .intvec的段当中,这个段是 4字节对齐(2^2)所以用 DATA 来首先处理向量的入口地址为4的倍数,然后放向量表。
需要注意的是 NOROOT(2) 和ROOT(2)的区别,如果NOROOT表示如果符号没有被关联的时候是被优化掉的,如果想不被优化则使用ROOT吧
其中向量表的第一个数据为堆栈的顶部,可以为一个确定的数值放在SRAM的尾部,这里演示代码使用的是使用固定连接脚本去处理,在连接脚本中定义了一个CSTACK 的段,然后在启动代码中先声明这个段
SECTIONCSTACKATA:NOROOT(3)
DCDsfe(CSTACK)
然后通过 SFE运算得到改段的结束地址,注意这个运算是在link的时候完成。所以IAR的处理办法就是先定义一个block作为堆栈区,然后将堆栈指针放到这个block的末端,因为STM32的堆栈是向下生长的。
剩下的就是各个中断向量。接着看怎么处理
THUMB
PUBWEAKReset_Handler
SECTION.text:CODE:REORDER(2)
Reset_Handler
LDR R0,=SystemInit
BLXR0
LDR R0,=__iar_program_start
BXR0
PUBWEAKNMI_Handler
SECTION.text:CODE:REORDER(1)
NMI_Handler
BNMI_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 isnormally 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 SPstart value is found, and the NVIC vector
; table register (VTOR)is initialized to this address if != 0.
还有一个最重要的标号就是 main,初始化模块最后就是跳到 main函数了,所以如果写C的话则写个main函数,如果写汇编的话同样也需要从main标号开始,很简单,导出一下就可以了。
PUBLICmain
main:
连接脚本
Config/generic_cortex.icf 就是通用的 cortexM3内核连接脚本,只需要修改几个地址就OK了
首先定义可寻址的逻辑地址,ARM是4G
define memory mem withsize = 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__]; |