stm32外部中断实验 在main之前,IAR都做了啥?

[更新]
·
·
分类:互联网
4587 阅读

stm32外部中断实验

在main之前,IAR都做了啥?

在main之前,IAR都做了啥?

最近要在Cortex-M3上写一个简单的操作系统,打算使用IAR,为了写好启动代码,花了一些时间了解了IAR在main()以前做了些什么事。t
首先系统复位时,Cortex-M3从代码区偏移0x00000000处获取栈顶地址,用来初始化MSP寄存器的值。t
接下来从代码区偏移0x00000004获取第一个指令的跳转地址。这些地址,是CM3要求放置中断向量表的地方。t
这里是一个程序的启动区的反汇编:t
__vector_table:t
08004000 2600 t
08004002 2000 t
08004004 7E1D t
08004006 0800 t
这个程序是由IAP程序来启动的,IAP程序获取0x08004000处的MSP值(0x20002600),并设置为MSP的值,即主堆栈最大t
范围是0x20000000~0x200025FF。接下来IAP程序获取0x08004004处的Reset_Handler的地址t
(0x08007E1D),并跳转到Reset_Handler()执行。t
IAP在这里完全是模仿了Cortex-M3的复位序列,也就是说,在没有IAP的系统上,CM3只能从0x08000000获取MSP,从t
0x08000004获取第一条指令所处地址。而IAP就存在在0x08000000这个地址上,IAP的启动,已经消耗掉了这个复位序列,所以t
IAP要启动UserApp程序的时候,也是完全模仿Cortex-M3的复位序列的。t
接下来我们看看复位后第一句指令——Reset_Handler()函数里有什么。t
若我们使用的是ST公司标准外设库,那么已经有了现成的Reset_Handler,不过他是弱定义——PUBWEAK,可以被我们重写的同名函数覆盖。一般来说,我们使用的都是ST提供的Reset_Handler,在V3.4版本的库中,可以在startup_stm32f10x_xx.s中找到这个函数:t
PUBWEAK Reset_Handlert
SECTION .text:CODE:REORDER(2)t
Reset_Handlert
LDR R0, SystemInitt
BLX R0t
LDR R0, __iar_program_startt
BX R0t
看来ST没有做太多的事,他只调用了自家库提供的SystemInit函数进行系统时钟、Flash读取的初始化,并把大权交给了t
__iar_program_start这个IAR提供的“内部函数”了,我们就跟紧这个__iar_program_start跳转,看看IAR做了什t
么,上面一段代码的反汇编如下:t
Reset_Handler:t
__iar_section$$root:t
08007E1C 4801 LDR R0, [PC, #0x4] LDR R0, SystemInitt
08007E1E 4780 BLX R0BLX R0t
08007E20 4801 LDR R0, [PC, #0x4]LDR R0, __iar_program_startt
08007E22 4700 BX R0BX R0t
08007E24 6C69 t
08007E26 0800 t
08007E28 7D8D t
08007E2A 0800 t
细心的观众会发现地址是0x08007E1C,比我们查到的0x08007E1D差了1,这是ARM家族的遗留问题,因为ARM处理器的指令至t
少是半字对齐的(16位THUMB指令集 or t
32位ARM指令集),所以PC指针的LSB是常为0的,为了充分利用寄存器,ARM公司给PC的LSB了一个重要的使命,那就是在执行分支跳转时,PCt
的LSB1,表示使用THUMB模式,LSB0,表示使用ARM模式,但在最新的Cortex-M3内核上,只使用了THUMB-2指令集挑大梁,所t
以这一位要常保持1,所以我们查到的地址是0x08007E1D(C1100,D1101),放心,我们的CM3内核会忽略掉LSB(除非为0,那t
么会引起一个fault),从而正确跳转到0x08007E1C。t
从0x08007E20处的加载指令,我们可以算出__iar_program_start所处的位置,就是当前PC指针t
(0x08007E24),再加上4,即0x08007E28处的所指向的地址——0x08007D8D(0x08007D8C),我们跟紧着跳t
转,__iar_program_start果然在这里:t
__iar_program_start:t
08007D8C F000F88C BL __low_level_initt
08007D90 2800 CMP R0, #0x0t
08007D92 D001 BEQ __iar_init$$donet
08007D94 F7FFFFDE BL __iar_data_init2t
08007D98 2000 MOVS R0, #0x0t
08007D9A F7FDFC49 BL maint
我们看到IAR提供了__low_level_init这个函数进行了“底层”的初始化,进一步跟踪,我们可以查到__low_level_init这个函数做了些什么,不是不是我们想象中的不可告人。t
__low_level_init:t
08007EA8 2001 MOVS R0, #0x1t
08007EAA 4770 BX LRt
__low_level_init出乎想象的简单,只是往R0寄存器写入了1,就立即执行

STM32的串口可以发送就是不可以接受谁帮我看下?

你需要打开接收中断啊~~~加上这句:USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);