因為STM32設計的Flash起始地址是在0x0800 0000位置開始的。全部代碼都只能在從這裏開始存儲。詳見STM32 referenc manual手冊第54頁。
那既然從這裏才能存儲代碼,就必須在MDK裏設置Flash地址為0x0800 0000,下面是MDK設置頁面,這個應該都看到過:
這樣就還有壹個問題,理論上,CM3中規定上電後CPU是從0地址開始執行,但是這裏中斷向量表卻被燒寫在0x0800 0000地址裏,這是因為STM32的Flash是從0x0800 0000開始才有。但SMT32也不能破壞ARM定下的“規矩”,所以它做了壹個啟動映射的過程,就是和芯片上總能見到的BOOT0和BOOT1有關了,當選擇從主Flash啟動模式後,芯片壹上電,Flash的0x0800 0000地址被映射到0地址處,不影響CM3內核的讀取,所以這時的CM3既可以在0地址處訪問中斷向量表,也可以在0x0800 0000地址處訪問中斷向量表,而代碼還是在0x0800 0000地址處存儲的。這就是最難理解的地方,其實,這是基本上所有ARM芯片采用的啟動映射方法。ARM7,ARM9沒有內部Flash的通常都是這樣做的。這個過程出自STM32 referenc manual手冊,裏面是有說明的:
還要註意,這個中斷向量表是可以在程序中再次被映射的。控制它的就是CM3已經規定的NVIC寄存器SCB->VTOR。在STM32庫中給出的啟動代碼裏,startup_stm32f10x_hd.s文件裏,第146行,是上電後讀取中斷向量表中的復位中斷位置,並執行復位中斷處理代碼,代碼如下:
; Reset handler
Reset_Handler? PROC
EXPORT? Reset_Handler [WEAK]
IMPORT? __main
IMPORT? SystemInit
LDR R0, =SystemInit
BLX R0?
LDR R0, =__main
BX? R0
ENDP
註意復位後第壹個被執行的是SystemInit代碼,這個代碼在庫目錄下的system_stm32f10x.c文件裏,它初始化了時鐘,NVIC等壹系列操作,這裏摘要與中斷向量有關的代碼:void SystemInit (void)
{
......
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */#endif
}
可以看出中斷向量重映射是壹個選擇性編譯,通常宏定義VECT_TAB_SRAM都沒有被定義,所以這裏執行結束後,SCB->VTOR就是FLASH_BASE了,值為0x0800 0000。以後CM3再取中斷向量裏,就會根據SCB->VTOR的設置,從這裏取向量執行了。中斷向量自此終於轉正。
註意這時連__main函數都還沒進,看起來中斷向量的重映射位置還是夠早的。