久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3072|回復: 1
打印 上一主題 下一主題
收起左側

STM32 IAP在線升級詳解

[復制鏈接]
跳轉到指定樓層
樓主
ID:104126 發表于 2016-1-23 00:40 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
(考慮到出廠時要先燒寫IAP 再燒寫APP應用程序要燒寫2次增加工人勞動力基礎上寫了“STM32 IAP+APP)

1.ST 官方IAP是什么針對什么芯片型號的,我們要用的又是什么芯片型號;

2.我們要用官方IAP適合我們芯片的程序升級使用,要在原有的基礎上做那些改變;

初略看了一下IAP源碼后,現在我們可以回答一下上面的2個問題了:

1.官網剛下載的IAP針對的是stm32f103c8芯片的,所以他的啟動代碼文件選擇的是 startup_stm32f10x_md.s,而我的芯片是stm32f100cb,所以我的啟動代碼文件選擇的是 startup_stm32f10x_md_lv.s

2 .第二個問題就是今天我們要做詳細分析才能回答的問題了;

(1).知道了IAP官方源碼的芯片和我們要用芯片的差異,首先我們要在源碼的基礎上做芯片級的改動;

A.首先改變編譯器keil的芯片型號上我們要改成我們的芯片類型---STM32F100CB;

B.在keil的options for targer 選項C/C++/PREPROMCESSOR symbols的Define欄里定義,把有關STM32F10X_MD的宏定義改成:STM32F10X_MD_VL

也可以在STM32F10X.H里用宏定義
  1. #if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
  2. #define STM32F10X_MD_VL
  3. #endif

上面代碼說的是如果沒有定義 STM32F10X_MD_VL, 則宏定義 STM32F10X_MD_VL

C.外部時鐘問價在stm32f10x.h 依據實際修改,原文是 說如果沒有宏定義外部時鐘HES_VALUE的值,但是宏定義了stm32f10x_cl 則外部時鐘設置為25MHZ, 否則外部時鐘都設置為8MHZ; 我用的外部晶振是8MHZ的所以不必修改這部分代碼;

  1. #if !defined HSE_VALUE
  2. #ifdef STM32F10X_CL
  3. #define HSE_VALUE ((uint32_t)25000000) // Value of the External oscillator in Hz #else #define HSE_VALUE ((uint32_t)8000000) //Value of the External oscillator in Hz #endif #endif

D.做系統主頻時鐘的更改

system_stm32f10x.c的系統主頻率,依實際情況修改 ;我用的芯片主頻時鐘是24MHZ;
  1. #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  2. #define SYSCLK_FREQ_24MHz 24000000
  3. #else
  4. #define SYSCLK_FREQ_24MHz 24000000
  5. #endif
E.下面是關鍵部分操作了,在說這部分操作前我們先來說一下內存映射:
下圖在stm32f100芯片手冊的29頁,我們只截取關鍵部分


從上圖我們看出幾個關鍵部分:

1.內部flash 是從0x0800 0000開始 到0x0801 FFFF 結束, 0x0801FFFF-0x0800 0000= 0x20000 =128k 128也就是flash的大小;

2.SRAM的開始地址是 0x2000 0000 ;

我們要把我們的在線升級程序IAP放到FLASH里以0x0800 0000 開始的位置, 應用程序放APP放到以0x08003000開始的位置,中斷向量表也放在0x0800 3000開始的位置;如圖


所以我們需要先查看一下misc.h文件中的中斷向量表的初始位置宏定義為 NVIC_VectTab_Flash 0x0800 0000

那么要就要設置編譯器keil 中的 options for target 的target選項中的 IROM1地址 為0x0800 0000 大小為 0x20000即128K;

IRAM1地址為0x2000 0000 大小為0x2000;

(提示:這一項IROM1 地址 即為當前程序下載到flash的地址的起始位置)

下面我們來分析一下修改后的IAP代碼:

  1. int main(void)
  2. {
  3. //Flash 解鎖
  4. FLASH_Unlock();
  5. //配置PA15管腳
  6. KEY_Configuration() ;
  7. //配置串口1
  8. IAP_Init();
  9. //PA15是否為低電平
  10. if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15) == 0x00)
  11. {
  12. //執行IAP驅動程序更新Flash程序
  13. SerialPutString("\r\n======================================================================");
  14. SerialPutString("\r\n= (C) COPYRIGHT 2011 Lierda =");
  15. SerialPutString("\r\n= =");
  16. SerialPutString("\r\n= In-Application Programming Application (Version 1.0.0) =");
  17. SerialPutString("\r\n= =");
  18. SerialPutString("\r\n= By wuguoyan =");
  19. SerialPutString("\r\n======================================================================");
  20. SerialPutString("\r\n\r\n");
  21. Main_Menu ();
  22. }
  23. //否則執行用戶程序
  24. else
  25. {
  26. //判斷用處是否已經下載了用戶程序,因為正常情況下此地址是棧地址
  27. //若沒有這一句話,即使沒有下載程序也會進入而導致跑飛。
  28. if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
  29. {
  30. SerialPutString("Execute user Program\r\n\n");
  31. //跳轉至用戶代碼
  32. JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
  33. Jump_To_Application = (pFunction) JumpAddress;
  34. //初始化用戶程序的堆棧指針
  35. __set_MSP(*(__IO uint32_t*) ApplicationAddress);
  36. Jump_To_Application();
  37. }
  38. else
  39. {
  40. SerialPutString("no user Program\r\n\n");
  41. }
  42. }

這里重點說一下幾句經典且非常重要的代碼:

第一句: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) //判斷棧定地址值是否在0x2000 0000 - 0x 2000 2000之間

怎么理解呢? (1),在程序里#define ApplicationAddress 0x8003000 ,*(__IO uint32_t*)ApplicationAddress) 即取0x8003000開始到0x8003003 的4個字節的值, 因為我們的應用程序APP中設置把 中斷向量表 放置在0x08003000 開始的位置;而中斷向量表里第一個放的就是棧頂地址的值

也就是說,這句話即通過判斷棧頂地址值是否正確(是否在0x2000 0000 - 0x 2000 2000之間) 來判斷是否應用程序已經下載了,因為應用程序的啟動文件剛開始就去初始化化棧空間,如果棧頂值對了,說應用程已經下載了啟動文件的初始化也執行了;


第二句: JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); [ common.c文件第18行定義了: pFunction Jump_To_Application;]

ApplicationAddress + 4 即為0x0800 3004 ,里面放的是中斷向量表的第二項“復位地址” JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); 之后此時JumpAddress

第三句: Jump_To_Application = (pFunction) JumpAddress;
startup_stm32f10x_md_lv. 文件中別名 typedef void (*pFunction)(void); 這個看上去有點奇怪;正常第一個整型變量 typedef int a; 就是給整型定義一個別名 a

void (*pFunction)(void); 是聲明一個函數指針,加上一個typedef 之后 pFunction只不過是類型 void (*)(void) 的一個別名;例如:

  1. pFunction a1,a2,a3;
  2. void fun(void)
  3. {
  4. ......
  5. }
  6. a1 = fun;

所以,Jump_To_Application = (pFunction) JumpAddress; 此時Jump_To_Application指向了復位函數所在的地址;

第四 、五句: __set_MSP(*(__IO uint32_t*) ApplicationAddress); \\設置主函數棧指針
Jump_To_Application(); \\執行復位函數

我們看一下啟動文件startup_stm32f10x_md_vl。s 中的啟動代碼,更容易理解


移植后的IAP代碼在我的資源(如果是stm32f100cb的芯片可以直接用):http://download.csdn.net/detail/yx_l128125/6475219

三、我們來簡單看下啟動文件中的啟動代碼,分析一下這更有利于我們對IAP的理解: (下面這篇文章寫的非常好,有木有!)


解析 STM32 的啟動過程

解析STM32的啟動過程

當前的嵌入式應用程序開發過程里,并且C語言成為了絕大部分場合的最佳選擇。如此一來main函數似乎成為了理所當然的起點——因為C程序往往從main函數開始執行。但一個經常會被忽略的問題是:微控制器(單片機)上電后,是如何尋找到并執行main函數的呢?很顯然微控制器無法從硬件上定位main函數的入口地址,因為使用C語言作為開發語言后,變量/函數的地址便由編譯器在編譯時自行分配,這樣一來main函數的入口地址在微控制器的內部存儲空間中不再是絕對不變的。相信讀者都可以回答這個問題,答案也許大同小異,但肯定都有個關鍵詞,叫啟動文件,用英文單詞來描述是Bootloader

無論性能高下,結構簡繁,價格貴賤,每一種微控制器(處理器)都必須有啟動文件,啟動文件的作用便是負責執行微控制器從復位開始執行main函數中間這段時間(稱為啟動過程)所必須進行的工作。最為常見的51AVRMSP430等微控制器當然也有對應啟動文件,但開發環境往往自動完整地提供了這個啟動文件,不需要開發人員再行干預啟動過程,只需要從main函數開始進行應用程序的設計即可。

話題轉到STM32微控制器,無論是keil
uvision4
還是IAR EWARM開發環境,ST公司都提供了現成的直接可用的啟動文件,程序開發人員可以直接引用啟動文件后直接進行C應用程序的開發。這樣能大大減小開發人員從其它微控制器平臺跳轉至STM32平臺,也降低了適應STM32微控制器的難度(對于上一代ARM的當家花旦ARM9,啟動文件往往是第一道難啃卻又無法逾越的坎)。

相對于ARM上一代的主流ARM7/ARM9內核架構,新一代Cortex內核架構的啟動方式有了比較大的變化。ARM7/ARM9內核的控制器在復位后,CPU會從存儲空間的絕對地址0x000000取出第一條指令執行復位中斷服務程序的方式啟動,即固定了復位后的起始地址為0x000000PC = 0x000000)同時中斷向量表的位置并不是固定的。而Cortex-M3內核則正好相反,有3種情況:
1
通過boot引腳設置可以將中斷向量表定位于SRAM區,即起始地址為0x2000000,同時復位后PC指針位于0x2000000處;
2
通過boot引腳設置可以將中斷向量表定位于FLASH區,即起始地址為0x8000000,同時復位后PC指針位于0x8000000處;
3
通過boot引腳設置可以將中斷向量表定位于內置Bootloader區,本文不對這種情況做論述;
Cortex-M3內核規定,起始地址必須存放堆頂指針,而第二個地址則必須存放復位中斷入口向量地址,這樣在Cortex-M3內核復位后,會自動從起始地址的下一個32位空間取出復位中斷入口向量,跳轉執行復位中斷服務程序。對比ARM7/ARM9內核,Cortex-M3內核則是固定了中斷向量表的位置而起始地址是可變化的。
有了上述準備只是后,下面以STM322.02固件庫提供的啟動文件stm32f10x_vector.s為模板,對STM32的啟動過程做一個簡要而全面的解析。
程序清單一:
;文件stm32f10x_vector.s,其中注釋為行號
DATA_IN_ExtSRAM EQU 0
1
Stack_Size EQU 0x00000400
2
AREA STACK, NOINIT, READWRITE, ALIGN = 3
3
Stack_Mem SPACE Stack_Size
4
__initial_sp
5
Heap_Size EQU 0x00000400
6
AREA HEAP, NOINIT, READWRITE, ALIGN = 3
7
__heap_base
8
Heap_Mem SPACE Heap_Size
9
__heap_limit
10
THUMB
11
PRESERVE8
12
IMPORT NMIException
13
IMPORT HardFaultException
14
IMPORT MemManageException
15
IMPORT BusFaultException
16
IMPORT UsageFaultException
17
IMPORT SVCHandler
18
IMPORT DebugMonitor
19
IMPORT PendSVC
20
IMPORT SysTickHandler
21
IMPORT WWDG_IRQHandler
22
IMPORT PVD_IRQHandler
23
IMPORT TAMPER_IRQHandler
24
IMPORT RTC_IRQHandler
25
IMPORT FLASH_IRQHandler
26
IMPORT RCC_IRQHandler
27
IMPORT EXTI0_IRQHandler
28
IMPORT EXTI1_IRQHandler
29
IMPORT EXTI2_IRQHandler
30
IMPORT EXTI3_IRQHandler
31
IMPORT EXTI4_IRQHandler
32
IMPORT DMA1_Channel1_IRQHandler
33
IMPORT DMA1_Channel2_IRQHandler
34
IMPORT DMA1_Channel3_IRQHandler
35
IMPORT DMA1_Channel4_IRQHandler
36
IMPORT DMA1_Channel5_IRQHandler
37
IMPORT DMA1_Channel6_IRQHandler
38
IMPORT DMA1_Channel7_IRQHandler
39
IMPORT ADC1_2_IRQHandler
40
IMPORT USB_HP_CAN_TX_IRQHandler
41
IMPORT USB_LP_CAN_RX0_IRQHandler
42
IMPORT CAN_RX1_IRQHandler
43
IMPORT CAN_SCE_IRQHandler
44
IMPORT EXTI9_5_IRQHandler
45
IMPORT TIM1_BRK_IRQHandler
46
IMPORT TIM1_UP_IRQHandler
47
IMPORT TIM1_TRG_COM_IRQHandler
48
IMPORT TIM1_CC_IRQHandler
49
IMPORT TIM2_IRQHandler
50
IMPORT TIM3_IRQHandler
51
IMPORT TIM4_IRQHandler
52
IMPORT I2C1_EV_IRQHandler
53
IMPORT I2C1_ER_IRQHandler
54
IMPORT I2C2_EV_IRQHandler
55
IMPORT I2C2_ER_IRQHandler
56
IMPORT SPI1_IRQHandler
57
IMPORT SPI2_IRQHandler
58
IMPORT USART1_IRQHandler
59
IMPORT USART2_IRQHandler
60
IMPORT USART3_IRQHandler
61
IMPORT EXTI15_10_IRQHandler
62
IMPORT RTCAlarm_IRQHandler
63
IMPORT USBWakeUp_IRQHandler
64
IMPORT TIM8_BRK_IRQHandler
65
IMPORT TIM8_UP_IRQHandler
66
IMPORT TIM8_TRG_COM_IRQHandler
67
IMPORT TIM8_CC_IRQHandler
68
IMPORT ADC3_IRQHandler
69
IMPORT FSMC_IRQHandler
70
IMPORT SDIO_IRQHandler
71
IMPORT TIM5_IRQHandler
72
IMPORT SPI3_IRQHandler
73
IMPORT UART4_IRQHandler
74
IMPORT UART5_IRQHandler
75
IMPORT TIM6_IRQHandler
76
IMPORT TIM7_IRQHandler
77
IMPORT DMA2_Channel1_IRQHandler
78
IMPORT DMA2_Channel2_IRQHandler
79
IMPORT DMA2_Channel3_IRQHandler
80
IMPORT DMA2_Channel4_5_IRQHandler
81
AREA RESET, DATA, READONLY
82
EXPORT __Vectors
83
__Vectors
84
DCD __initial_sp
85
DCD Reset_Handler
86
DCD NMIException
87
DCD HardFaultException
88
DCD MemManageException
89
DCD BusFaultException
90
DCD UsageFaultException
91
DCD 0
92
DCD 0
93
DCD 0
94
DCD 0
95
DCD SVCHandler
96
DCD DebugMonitor
97
DCD 0
98
DCD PendSVC
99
DCD SysTickHandler
100
DCD WWDG_IRQHandler
101
DCD PVD_IRQHandler
102
DCD TAMPER_IRQHandler
103
DCD RTC_IRQHandler
104
DCD FLASH_IRQHandler
105
DCD RCC_IRQHandler
106
DCD EXTI0_IRQHandler
107
DCD EXTI1_IRQHandler
108
DCD EXTI2_IRQHandler
109
DCD EXTI3_IRQHandler
110
DCD EXTI4_IRQHandler
111
DCD DMA1_Channel1_IRQHandler
112
DCD DMA1_Channel2_IRQHandler
113
DCD DMA1_Channel3_IRQHandler
114
DCD DMA1_Channel4_IRQHandler
115
DCD DMA1_Channel5_IRQHandler
116
DCD DMA1_Channel6_IRQHandler
117
DCD DMA1_Channel7_IRQHandler
118
DCD ADC1_2_IRQHandler
119
DCD USB_HP_CAN_TX_IRQHandler
120
DCD USB_LP_CAN_RX0_IRQHandler
121
DCD CAN_RX1_IRQHandler
122
DCD CAN_SCE_IRQHandler
123
DCD EXTI9_5_IRQHandler
124
DCD TIM1_BRK_IRQHandler
125
DCD TIM1_UP_IRQHandler
126
DCD TIM1_TRG_COM_IRQHandler
127
DCD TIM1_CC_IRQHandler
128
DCD TIM2_IRQHandler
129
DCD TIM3_IRQHandler
130
DCD TIM4_IRQHandler
131
DCD I2C1_EV_IRQHandler
132
DCD I2C1_ER_IRQHandler
133
DCD I2C2_EV_IRQHandler
134
DCD I2C2_ER_IRQHandler
135
DCD SPI1_IRQHandler
136
DCD SPI2_IRQHandler
137
DCD USART1_IRQHandler
138
DCD USART2_IRQHandler
139
DCD USART3_IRQHandler
140
DCD EXTI15_10_IRQHandler
141
DCD RTCAlarm_IRQHandler
142
DCD USBWakeUp_IRQHandler
143
DCD TIM8_BRK_IRQHandler
144
DCD TIM8_UP_IRQHandler
145
DCD TIM8_TRG_COM_IRQHandler
146
DCD TIM8_CC_IRQHandler
147
DCD ADC3_IRQHandler
148
DCD FSMC_IRQHandler
149
DCD SDIO_IRQHandler
150
DCD TIM5_IRQHandler
151
DCD SPI3_IRQHandler
152
DCD UART4_IRQHandler
153
DCD UART5_IRQHandler
154
DCD TIM6_IRQHandler
155
DCD TIM7_IRQHandler
156
DCD DMA2_Channel1_IRQHandler
157
DCD DMA2_Channel2_IRQHandler
158
DCD DMA2_Channel3_IRQHandler
159
DCD DMA2_Channel4_5_IRQHandler
160
AREA |.text|, CODE, READONLY
161
Reset_Handler PROC
162
EXPORT Reset_Handler
163
IF DATA_IN_ExtSRAM == 1
164
LDR R0,= 0x00000114
165
LDR R1,= 0x40021014
166
STR R0,[R1]
167
LDR R0,= 0x000001E0
168
LDR R1,= 0x40021018
169
STR R0,[R1]
170
LDR R0,= 0x44BB44BB
171
LDR R1,= 0x40011400
172
STR R0,[R1]
173
LDR R0,= 0xBBBBBBBB
174
LDR R1,= 0x40011404
175
STR R0,[R1]
176
LDR R0,= 0xB44444BB
177
LDR R1,= 0x40011800
178
STR R0,[R1]
179
LDR R0,= 0xBBBBBBBB
180
LDR R1,= 0x40011804
181
STR R0,[R1]
182
LDR R0,= 0x44BBBBBB
183
LDR R1,= 0x40011C00
184
STR R0,[R1]
185
LDR R0,= 0xBBBB4444
186
LDR R1,= 0x40011C04
187
STR R0,[R1]
188
LDR R0,= 0x44BBBBBB
189
LDR R1,= 0x40012000
190
STR R0,[R1]
191
LDR R0,= 0x44444B44
192
LDR R1,= 0x40012004
193
STR R0,[R1]
194
LDR R0,= 0x00001011
195
LDR R1,= 0xA0000010
196
STR R0,[R1]
197
LDR R0,= 0x00000200
198
LDR R1,= 0xA0000014
199
STR R0,[R1]
200
ENDIF
201
IMPORT __main
202
LDR R0, =__main
203
BX R0
204
ENDP
205
ALIGN
206
IF :DEF:__MICROLIB
207
EXPORT __initial_sp
208
EXPORT __heap_base
209
EXPORT __heap_limit
210
ELSE
211
IMPORT __use_two_region_memory
212
EXPORT __user_initial_stackheap
213
__user_initial_stackheap
214
LDR R0, = Heap_Mem
215
LDR R1, = (Stack_Mem + Stack_Size)
216
LDR R2, = (Heap_Mem + Heap_Size)
217
LDR R3, = Stack_Mem
218
BX LR
219
ALIGN
220
ENDIF
221
END
222
ENDIF
223
END
224

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:104126 發表于 2016-1-23 00:41 | 只看該作者
相對于ARM上一代的主流ARM7/ARM9內核架構,新一代Cortex內核架構的啟動方式有了比較大的變化。ARM7/ARM9內核的控制器在復位后,CPU會從存儲空間的絕對地址0x000000取出第一條指令執行復位中斷服務程序的方式啟動,即固定了復位后的起始地址為0x000000(PC
= 0x000000)同時中斷向量表的位置并不是固定的。而Cortex-M3內核則正好相反,有3種情況:

1、 通過boot引腳設置可以將中斷向量表定位于SRAM區,即起始地址為0x2000000,同時復位后PC指針位于0x2000000處;
2、 通過boot引腳設置可以將中斷向量表定位于FLASH區,即起始地址為0x8000000,同時復位后PC指針位于0x8000000處;
3、 通過boot引腳設置可以將中斷向量表定位于內置Bootloader區,本文不對這種情況做論述;
而Cortex-M3內核規定,起始地址必須存放堆頂指針,而第二個地址則必須存放復位中斷入口向量地址,這樣在Cortex-M3內核復位后,會自動從起始地址的下一個32位空間取出復位中斷入口向量,跳轉執行復位中斷服務程序。對比ARM7/ARM9內核,Cortex-M3內核則是固定了中斷向量表的位置而起始地址是可變化的。
有了上述準備只是后,下面以STM32的2.02固件庫提供的啟動文件“stm32f10x_vector.s”為模板,對STM32的啟動過程做一個簡要而全面的解析。

程序清單一:
;文件“stm32f10x_vector.s”,其中注釋為行號
DATA_IN_ExtSRAM EQU 0 ;1
Stack_Size EQU 0x00000400 ;2
AREA STACK, NOINIT, READWRITE, ALIGN = 3 ;3
Stack_Mem SPACE Stack_Size ;4
__initial_sp ;5
Heap_Size EQU 0x00000400 ;6
AREA HEAP, NOINIT, READWRITE, ALIGN = 3 ;7
__heap_base ;8
Heap_Mem SPACE Heap_Size ;9
__heap_limit ;10
THUMB ;11
PRESERVE8 ;12
IMPORT NMIException ;13
IMPORT HardFaultException ;14
IMPORT MemManageException ;15
IMPORT BusFaultException ;16
IMPORT UsageFaultException ;17
IMPORT SVCHandler ;18
IMPORT DebugMonitor ;19
IMPORT PendSVC ;20
IMPORT SysTickHandler ;21
IMPORT WWDG_IRQHandler ;22
IMPORT PVD_IRQHandler ;23
IMPORT TAMPER_IRQHandler ;24
IMPORT RTC_IRQHandler ;25
IMPORT FLASH_IRQHandler ;26
IMPORT RCC_IRQHandler ;27
IMPORT EXTI0_IRQHandler ;28
IMPORT EXTI1_IRQHandler ;29
IMPORT EXTI2_IRQHandler ;30
IMPORT EXTI3_IRQHandler ;31
IMPORT EXTI4_IRQHandler ;32
IMPORT DMA1_Channel1_IRQHandler ;33
IMPORT DMA1_Channel2_IRQHandler ;34
IMPORT DMA1_Channel3_IRQHandler ;35
IMPORT DMA1_Channel4_IRQHandler ;36
IMPORT DMA1_Channel5_IRQHandler ;37
IMPORT DMA1_Channel6_IRQHandler ;38
IMPORT DMA1_Channel7_IRQHandler ;39
IMPORT ADC1_2_IRQHandler ;40
IMPORT USB_HP_CAN_TX_IRQHandler ;41
IMPORT USB_LP_CAN_RX0_IRQHandler ;42
IMPORT CAN_RX1_IRQHandler ;43
IMPORT CAN_SCE_IRQHandler ;44
IMPORT EXTI9_5_IRQHandler ;45
IMPORT TIM1_BRK_IRQHandler ;46
IMPORT TIM1_UP_IRQHandler ;47
IMPORT TIM1_TRG_COM_IRQHandler ;48
IMPORT TIM1_CC_IRQHandler ;49
IMPORT TIM2_IRQHandler ;50
IMPORT TIM3_IRQHandler ;51
IMPORT TIM4_IRQHandler ;52
IMPORT I2C1_EV_IRQHandler ;53
IMPORT I2C1_ER_IRQHandler ;54
IMPORT I2C2_EV_IRQHandler ;55
IMPORT I2C2_ER_IRQHandler ;56
IMPORT SPI1_IRQHandler ;57
IMPORT SPI2_IRQHandler ;58
IMPORT USART1_IRQHandler ;59
IMPORT USART2_IRQHandler ;60
IMPORT USART3_IRQHandler ;61
IMPORT EXTI15_10_IRQHandler ;62
IMPORT RTCAlarm_IRQHandler ;63
IMPORT USBWakeUp_IRQHandler ;64
IMPORT TIM8_BRK_IRQHandler ;65
IMPORT TIM8_UP_IRQHandler ;66
IMPORT TIM8_TRG_COM_IRQHandler ;67
IMPORT TIM8_CC_IRQHandler ;68
IMPORT ADC3_IRQHandler ;69
IMPORT FSMC_IRQHandler ;70
IMPORT SDIO_IRQHandler ;71
IMPORT TIM5_IRQHandler ;72
IMPORT SPI3_IRQHandler ;73
IMPORT UART4_IRQHandler ;74
IMPORT UART5_IRQHandler ;75
IMPORT TIM6_IRQHandler ;76
IMPORT TIM7_IRQHandler ;77
IMPORT DMA2_Channel1_IRQHandler ;78
IMPORT DMA2_Channel2_IRQHandler ;79
IMPORT DMA2_Channel3_IRQHandler ;80
IMPORT DMA2_Channel4_5_IRQHandler ;81
AREA RESET, DATA, READONLY ;82
EXPORT __Vectors ;83
__Vectors ;84
DCD __initial_sp ;85
DCD Reset_Handler ;86
DCD NMIException ;87
DCD HardFaultException ;88
DCD MemManageException ;89
DCD BusFaultException ;90
DCD UsageFaultException ;91
DCD 0 ;92
DCD 0 ;93
DCD 0 ;94
DCD 0 ;95
DCD SVCHandler ;96
DCD DebugMonitor ;97
DCD 0 ;98
DCD PendSVC ;99
DCD SysTickHandler ;100
DCD WWDG_IRQHandler ;101
DCD PVD_IRQHandler ;102
DCD TAMPER_IRQHandler ;103
DCD RTC_IRQHandler ;104
DCD FLASH_IRQHandler ;105
DCD RCC_IRQHandler ;106
DCD EXTI0_IRQHandler ;107
DCD EXTI1_IRQHandler ;108
DCD EXTI2_IRQHandler ;109
DCD EXTI3_IRQHandler ;110
DCD EXTI4_IRQHandler ;111
DCD DMA1_Channel1_IRQHandler ;112
DCD DMA1_Channel2_IRQHandler ;113
DCD DMA1_Channel3_IRQHandler ;114
DCD DMA1_Channel4_IRQHandler ;115
DCD DMA1_Channel5_IRQHandler ;116
DCD DMA1_Channel6_IRQHandler ;117
DCD DMA1_Channel7_IRQHandler ;118
DCD ADC1_2_IRQHandler ;119
DCD USB_HP_CAN_TX_IRQHandler ;120
DCD USB_LP_CAN_RX0_IRQHandler ;121
DCD CAN_RX1_IRQHandler ;122
DCD CAN_SCE_IRQHandler ;123
DCD EXTI9_5_IRQHandler ;124
DCD TIM1_BRK_IRQHandler ;125
DCD TIM1_UP_IRQHandler ;126
DCD TIM1_TRG_COM_IRQHandler ;127
DCD TIM1_CC_IRQHandler ;128
DCD TIM2_IRQHandler ;129
DCD TIM3_IRQHandler ;130
DCD TIM4_IRQHandler ;131
DCD I2C1_EV_IRQHandler ;132
DCD I2C1_ER_IRQHandler ;133
DCD I2C2_EV_IRQHandler ;134
DCD I2C2_ER_IRQHandler ;135
DCD SPI1_IRQHandler ;136
DCD SPI2_IRQHandler ;137
DCD USART1_IRQHandler ;138
DCD USART2_IRQHandler ;139
DCD USART3_IRQHandler ;140
DCD EXTI15_10_IRQHandler ;141
DCD RTCAlarm_IRQHandler ;142
DCD USBWakeUp_IRQHandler ;143
DCD TIM8_BRK_IRQHandler ;144
DCD TIM8_UP_IRQHandler ;145
DCD TIM8_TRG_COM_IRQHandler ;146
DCD TIM8_CC_IRQHandler ;147
DCD ADC3_IRQHandler ;148
DCD FSMC_IRQHandler ;149
DCD SDIO_IRQHandler ;150
DCD TIM5_IRQHandler ;151
DCD SPI3_IRQHandler ;152
DCD UART4_IRQHandler ;153
DCD UART5_IRQHandler ;154
DCD TIM6_IRQHandler ;155
DCD TIM7_IRQHandler ;156
DCD DMA2_Channel1_IRQHandler ;157
DCD DMA2_Channel2_IRQHandler ;158
DCD DMA2_Channel3_IRQHandler ;159
DCD DMA2_Channel4_5_IRQHandler ;160
AREA |.text|, CODE, READONLY ;161
Reset_Handler PROC ;162
EXPORT Reset_Handler ;163
IF DATA_IN_ExtSRAM == 1 ;164
LDR R0,= 0x00000114 ;165
LDR R1,= 0x40021014 ;166
STR R0,[R1] ;167
LDR R0,= 0x000001E0 ;168
LDR R1,= 0x40021018 ;169
STR R0,[R1] ;170
LDR R0,= 0x44BB44BB ;171
LDR R1,= 0x40011400 ;172
STR R0,[R1] ;173
LDR R0,= 0xBBBBBBBB ;174
LDR R1,= 0x40011404 ;175
STR R0,[R1] ;176
LDR R0,= 0xB44444BB ;177
LDR R1,= 0x40011800 ;178
STR R0,[R1] ;179
LDR R0,= 0xBBBBBBBB ;180
LDR R1,= 0x40011804 ;181
STR R0,[R1] ;182
LDR R0,= 0x44BBBBBB ;183
LDR R1,= 0x40011C00 ;184
STR R0,[R1] ;185
LDR R0,= 0xBBBB4444 ;186
LDR R1,= 0x40011C04 ;187
STR R0,[R1] ;188
LDR R0,= 0x44BBBBBB ;189
LDR R1,= 0x40012000 ;190
STR R0,[R1] ;191
LDR R0,= 0x44444B44 ;192
LDR R1,= 0x40012004 ;193
STR R0,[R1] ;194
LDR R0,= 0x00001011 ;195
LDR R1,= 0xA0000010 ;196
STR R0,[R1] ;197
LDR R0,= 0x00000200 ;198
LDR R1,= 0xA0000014 ;199
STR R0,[R1] ;200
ENDIF ;201
IMPORT __main ;202
LDR R0, =__main ;203
BX R0 ;204
ENDP ;205
ALIGN ;206
IF :DEF:__MICROLIB ;207
EXPORT __initial_sp ;208
EXPORT __heap_base ;209
EXPORT __heap_limit ;210
ELSE ;211
IMPORT __use_two_region_memory ;212
EXPORT __user_initial_stackheap ;213
__user_initial_stackheap ;214
LDR R0, = Heap_Mem ;215
LDR R1, = (Stack_Mem + Stack_Size) ;216
LDR R2, = (Heap_Mem + Heap_Size) ;217
LDR R3, = Stack_Mem ;218
BX LR ;219
ALIGN ;220
ENDIF ;221
END ;222
ENDIF ;223
END ;224

如程序清單一,STM32的啟動代碼一共224行,使用了匯編語言編寫,這其中的主要原因下文將會給出交代。現在從第一行開始分析:
 第1行:定義是否使用外部SRAM,為1則使用,為0則表示不使用。此語行若用C語言表達則等價于:
define DATA_IN_ExtSRAM 0

 第2行:定義棧空間大小為0x00000400個字節,即1Kbyte。此語行亦等價于:
define Stack_Size 0x00000400

 第3行:偽指令AREA,表示
 第4行:開辟一段大小為Stack_Size的內存空間作為棧。
 第5行:標號__initial_sp,表示棧空間頂地址。
 第6行:定義堆空間大小為0x00000400個字節,也為1Kbyte。
 第7行:偽指令AREA,表示
 第8行:標號__heap_base,表示堆空間起始地址。
 第9行:開辟一段大小為Heap_Size的內存空間作為堆。
 第10行:標號__heap_limit,表示堆空間結束地址。
 第11行:告訴編譯器使用THUMB指令集。
 第12行:告訴編譯器以8字節對齊。
 第13—81行:IMPORT指令,指示后續符號是在外部文件定義的(類似C語言中的全局變量聲明),而下文可能會使用到這些符號。
 第82行:定義只讀數據段,實際上是在CODE區(假設STM32從FLASH啟動,則此中斷向量表起始地址即為0x8000000)
 第83行:將標號__Vectors聲明為全局標號,這樣外部文件就可以使用這個標號。
 第84行:標號__Vectors,表示中斷向量表入口地址。
 第85—160行:建立中斷向量表。
 第161行:
 第162行:復位中斷服務程序,PROC…ENDP結構表示程序的開始和結束。
 第163行:聲明復位中斷向量Reset_Handler為全局屬性,這樣外部文件就可以調用此復位中斷服務。
 第164行:IF…ENDIF為預編譯結構,判斷是否使用外部SRAM,在第1行中已定義為“不使用”。
 第165—201行:此部分代碼的作用是設置FSMC總線以支持SRAM,因不使用外部SRAM因此此部分代碼不會被編譯。
 第202行:聲明__main標號。
 第203—204行:跳轉__main地址執行。
 第207行:IF…ELSE…ENDIF結構,判斷是否使用DEF:__MICROLIB(此處為不使用)。
 第208—210行:若使用DEF:__MICROLIB,則將__initial_sp,__heap_base,__heap_limit亦即棧頂地址,堆始末地址賦予全局屬性,使外部程序可以使用。
 第212行:定義全局標號__use_two_region_memory。
 第213行:聲明全局標號__user_initial_stackheap,這樣外程序也可調用此標號。
 第214行:標號__user_initial_stackheap,表示用戶堆棧初始化程序入口。
 第215—218行:分別保存棧頂指針和棧大小,堆始地址和堆大小至R0,R1,R2,R3寄存器。
 第224行:程序完畢。
以上便是STM32的啟動代碼的完整解析,接下來對幾個小地方做解釋:
1、 AREA指令:偽指令,用于定義代碼段或數據段,后跟屬性標號。其中比較重要的一個標號為“READONLY”或者“READWRITE”,其中“READONLY”表示該段為只讀屬性,聯系到STM32的內部存儲介質,可知具有只讀屬性的段保存于FLASH區,即0x8000000地址后。而“READONLY”表示該段為“可讀寫”屬性,可知“可讀寫”段保存于SRAM區,即0x2000000地址后。由此可以從第3、7行代碼知道,堆棧段位于SRAM空間。從第82行可知,中斷向量表放置與FLASH區,而這也是整片啟動代碼中最先被放進FLASH區的數據。因此可以得到一條重要的信息:0x8000000地址存放的是棧頂地址__initial_sp,0x8000004地址存放的是復位中斷向量Reset_Handler(STM32使用32位總線,因此存儲空間為4字節對齊)。
2、 DCD指令:作用是開辟一段空間,其意義等價于C語言中的地址符“&”。因此從第84行開始建立的中斷向量表則類似于使用C語言定義了一個指針數組,其每一個成員都是一個函數指針,分別指向各個中斷服務函數。
3、 標號:前文多處使用了“標號”一詞。標號主要用于表示一片內存空間的某個位置,等價于C語言中的“地址”概念。地址僅僅表示存儲空間的一個位置,從C語言的角度來看,變量的地址,數組的地址或是函數的入口地址在本質上并無區別。
4、 第202行中的__main標號并不表示C程序中的main函數入口地址,因此第204行也并不是跳轉至main函數開始執行C程序。__main標號表示C/C++標準實時庫函數里的一個初始化子程序__main的入口地址。該程序的一個主要作用是初始化堆棧(對于程序清單一來說則是跳轉__user_initial_stackheap標號進行初始化堆棧的),并初始化映像文件,最后跳轉C程序中的main函數。這就解釋了為何所有的C程序必須有一個main函數作為程序的起點——因為這是由C/C++標準實時庫所規定的——并且不能更改,因為C/C++標準實時庫并不對外界開發源代碼。因此,實際上在用戶可見的前提下,程序在第204行后就跳轉至.c文件中的main函數,開始執行C程序了。
至此可以總結一下STM32的啟動文件和啟動過程。首先對棧和堆的大小進行定義,并在代碼區的起始處建立中斷向量表,其第一個表項是棧頂地址,第二個表項是復位中斷服務入口地址。然后在復位中斷服務程序中跳轉¬¬C/C++標準實時庫的__main函數,完成用戶堆棧等的初始化后,跳轉.c文件中的main函數開始執行C程序。假設STM32被設置為從內部FLASH啟動(這也是最常見的一種情況),中斷向量表起始地位為0x8000000,則棧頂地址存放于0x8000000處,而復位中斷服務入口地址存放于0x8000004處。當STM32遇到復位信號后,則從0x80000004處取出復位中斷服務入口地址,繼而執行復位中斷服務程序,然后跳轉__main函數,最后進入mian函數,來到C的世界。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 亚洲视频在线观看 | 久久久久国产 | 国产激情毛片 | jdav视频在线观看免费 | 日韩中文字幕视频 | 91麻豆精品一区二区三区 | 在线亚洲免费视频 | a级毛片免费高清视频 | 国产欧美一区二区精品久导航 | 国产999精品久久久久久 | 超碰97在线免费 | 成人国产精品 | 国产精品日韩欧美一区二区三区 | 孕妇一级毛片 | 日本电影韩国电影免费观看 | 午夜天堂精品久久久久 | 欧美在线视频观看 | 免费黄色片视频 | 欧美一级在线观看 | 国产精品国产成人国产三级 | 亚洲大片一区 | 91免费在线播放 | 91麻豆精品国产91久久久久久久久 | 91久久综合亚洲鲁鲁五月天 | 久精品久久 | 国内精品久久久久久 | 日本在线你懂的 | 久久久久成人精品 | 久草视 | 日日夜夜精品视频 | 久久天堂 | 日韩在线欧美 | 久久不射电影网 | 日韩在线中文 | 国产在线精品一区二区三区 | 97国产一区二区精品久久呦 | 国产精品 欧美精品 | 久久噜| 综合在线视频 | 国产精品视频久久久久久 | 日韩免费中文字幕 |