在上一篇文章《假美猴王之三極管與MOS管,誰是悟空,誰又是六耳猕猴》中我們講到了真假美猴王之三極管與MOS管的區别。今天來探讨一下武功秘籍的修煉,據說秘籍第一頁就寫道:欲練此功,必先自宮。意思就是說明一個道理,任何人要想成仙成佛,練就一身超神的本領,那麼是要付出的代價并做好準備工作的。
而今天我們的要探讨的主角STM32處理器也不例外,别看它運行起來玉樹臨風,似乎無所不能,啟動初期也要先苦練一番本領才行。那麼這一部分都做了哪些工作呢?
STM32這款處理器使用的是的arm的Cortex-M3内核,Cortex-M3内核有個特點就是在地址0x00000000存放的是全局的棧地址。緊接着從地址0x00000004執行(因為STM32是32位的處理器,一條指令正好對應4個字節),也就是從這個地址取出中斷向量表的地址,跳轉執行中斷處理函數。
M3内核複位後程序執行過程
在前面文章《敢問路在何方,STM32邁出的第一步,卻注定了它非凡的一生》中我們有介紹通過BOOT0和BOOT1引腳高低電平的不同組合,對應者三種不同的啟動方式,同樣也就對應着三種地址的映射: Flash system memory就是将0x00000000映射到了0x08000000;System memory就是将0x00000000映射到了0x1FFF0000;SRAM就是将0x00000000映射到了0x20000000。選擇了哪種啟動方式就會把0地址映射到對應物理地址。同樣該區的物理地址最前面存放的就是棧地址和中斷向量表。
DATA
__vector_table
DCD sfe(CSTACK)
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
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
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD RTC_IRQHandler ; RTC through EXTI Line
DCD FLASH_IRQHandler ; FLASH
DCD RCC_CRS_IRQHandler ; RCC_CRS
DCD EXTI0_1_IRQHandler ; EXTI Line 0 and 1
DCD EXTI2_3_IRQHandler ; EXTI Line 2 and 3
DCD EXTI4_15_IRQHandler ; EXTI Line 4 to 15
DCD TSC_IRQHandler ; TSC
DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1
DCD DMA1_Channel2_3_IRQHandler ; DMA1 Channel 2 and Channel 3
DCD DMA1_Channel4_5_6_7_IRQHandler ; DMA1 Channel 4, Channel 5, Channel 6 and Channel 7
DCD ADC1_COMP_IRQHandler ; ADC1, COMP1 and COMP2
DCD LPTIM1_IRQHandler ; LPTIM1
DCD 0 ; Reserved
DCD TIM2_IRQHandler ; TIM2
DCD 0 ; Reserved
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD TIM21_IRQHandler ; TIM21
DCD 0 ; Reserved
DCD TIM22_IRQHandler ; TIM22
DCD I2C1_IRQHandler ; I2C1
DCD I2C2_IRQHandler ; I2C2
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
DCD RNG_LPUART1_IRQHandler ; RNG and LPUART1
DCD LCD_IRQHandler ; LCD
DCD USB_IRQHandler ; USB
而中斷處理函數的第一個就是複位中斷處理函數Reset_Handler:
THUMB
PUBWEAK Reset_Handler
SECTION .text:CODE:NOROOT:REORDER(2)
Reset_Handler
LDR R0, =SystemInit
BLX R0
LDR R0, =__iar_program_start
BX R0
PUBWEAK NMI_Handler
SECTION .text:CODE:NOROOT:REORDER(1)
我們看下默認的複位中斷處理函數裡邊都做了什麼事情,首先将SystemInit函數的首地址存放到R0寄存器裡邊,然後跳轉到R0寄存器的地址,即去執行IAR本身庫文件中的SystemInit函數進行相關初始化。然後将__iar_program_start函數的首地址存放到R0寄存器裡邊,然後跳轉到R0寄存器的地址,即去執行__iar_program_start函數。
那麼__iar_program_start這個函數在哪裡呢?沒錯,你在整個彙編文件中都沒有找到!這個文件在IAR的安裝目錄裡邊,具體的路徑是C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.2\arm\src\lib\thumb,我是将IAR裝在C:\Program Files (x86)目錄下的,大家根據自己情況查找。在thumb目錄下有個cstartup_M.s文件,文件代碼如下:
MODULE ?cstartup
PUBLIC __iar_program_start
EXTERN __cmain
EXTERN __vector_table
EXTWEAK __iar_init_core
EXTWEAK __iar_init_vfp
SECTION .text:CODE:REORDER(1)
THUMB
__iar_program_start:
FUNCALL __iar_program_start, __iar_init_core
BL __iar_init_core
FUNCALL __iar_program_start, __iar_init_vfp
BL __iar_init_vfp
FUNCALL __iar_program_start, __cmain
BL __cmain
REQUIRE __vector_table
END
__iar_program_start中分别調用了__iar_init_core,__iar_init_vfp和__cmain三個函數。前面兩個函數式弱函數,在工程中沒有定義,大家可以根據實際情況重寫這兩個函數。最後一個函數__cmain也在同目錄下的cmain.s中定義:
THUMB
__cmain:
?main:
; Initialize segments.
; __segment_init and __low_level_init are assumed to use the same
; instruction set and to be reachable by BL from the ICODE segment
; (it is safest to link them in segment ICODE).
FUNCALL __cmain, __low_level_init
bl __low_level_init
cmp r0,#0
beq ?l1
FUNCALL __cmain, __iar_data_init3
bl __iar_data_init3
?l1:
REQUIRE ?l3
SECTION .text:CODE:NOROOT(2)
PUBLIC _main
PUBLIC _call_main
THUMB
__iar_init$$done: ; Copy initialization is done
?l3:
_call_main:
MOVS r0,#0 ; No parameters
FUNCALL __cmain, __iar_argc_argv
BL __iar_argc_argv ; Maybe setup command line
FUNCALL __cmain, main
BL main
_main:
FUNCALL __cmain, exit
BL exit
END
其實最後就是進行了一個底層的初始化,然後就永久的跳轉到main.c文件中的main函數了。至此,彙編部分代碼結束,開始執行大家在main中編寫的代碼。
喜歡就在文末點個“關注”或者 “轉發”,這樣可以讓更多的人學習哦!!!
有問題評論一起交流學習進步! 感謝!
更多優質文章請點擊我的頭像,選擇“文章”标簽!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!