日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Stm 32 IAP 在线 升级IAP 的 操作

發(fā)布時(shí)間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Stm 32 IAP 在线 升级IAP 的 操作 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

(擴(kuò)展-IAP主要用于產(chǎn)品出廠后應(yīng)用程序的更新作用,考慮到出廠時(shí)要先燒寫IAP ?再燒寫APP應(yīng)用程序要燒寫2次增加工人勞動(dòng)力基礎(chǔ)上寫了“STM32 IAP+APP ==>雙劍合一”鏈接稍后發(fā))

一、在進(jìn)入主題之前我們先了解一些必要的基礎(chǔ)知識(shí)----stm32系列芯片的種類和型號(hào)

startup_stm32f10x_cl.s 互聯(lián)型的器件,STM32F105xx,STM32F107xx
startup_stm32f10x_hd.s 大容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_hd_vl.s 大容量的STM32F100xx
startup_stm32f10x_ld.s 小容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_ld_vl.s 小容量的STM32F100xx
startup_stm32f10x_md.s 中容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_md_vl.s 中容量的STM32F100xx? (我項(xiàng)目中用的是此款芯片 stm32f100CB)
startup_stm32f10x_xl.s FLASH在512K到1024K字節(jié)的STM32F101xx,STM32F102xx,STM32F103xx (例如:像stm32f103re 這個(gè)型號(hào)的 芯片flash是512k 的, 啟動(dòng)文件用startup_stm32f10x_xl.s ?或者startup_stm32f10x_hd.s ?都可以;
cl:互聯(lián)型產(chǎn)品,stm32f105/107系列
vl:超值型產(chǎn)品,stm32f100系列
xl:超高密度產(chǎn)品,stm32f101/103系列
ld:低密度產(chǎn)品,FLASH小于64K
md:中等密度產(chǎn)品,FLASH=64 or 128
hd:高密度產(chǎn)品,FLASH大于128


二、在拿到ST公司官方的IAP 程序后 我們要思考幾點(diǎn):

? ? ? ? 1.ST 官方IAP是什么針對(duì)什么芯片型號(hào)的,我們要用的又是什么芯片型號(hào);

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

(我的資源里有官方IAP源碼:http://download.csdn.NET/detail/yx_l128125/6445811)

? ? ? ?

初略看了一下IAP源碼后,現(xiàn)在我們可以回答一下上面的2個(gè)問題了:

1.官網(wǎng)剛下載的IAP針對(duì)的是stm32f103c8芯片的,所以他的啟動(dòng)代碼文件選擇的是?startup_stm32f10x_md.s,而我的芯片是stm32f100cb,所以我的啟動(dòng)代碼文件選擇的是 ?startup_stm32f10x_md_lv.s?




? ? ? ? ? 2 .第二個(gè)問題就是今天我們要做詳細(xì)分析才能回答的問題了;

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

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

?B.在keil的options for ?targer 選項(xiàng)C/C++/PREPROMCESSOR symbols的Define欄里定義,把有關(guān)STM32F10X_MD的宏定義改成:STM32F10X_MD_VL

也可以在STM32F10X.H里用宏定義 [plain] view plaincopy
  • ??/*?Uncomment?the?line?below?according?to?the?target?STM32?device?used?in?your??
  • ???application???
  • ??*/??
  • ??
  • #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)???
  • ??/*?#define?STM32F10X_LD?*/????/*!<?STM32F10X_LD:?STM32?Low?density?devices?*/??
  • ??/*?#define?STM32F10X_LD_VL?*/?/*!<?STM32F10X_LD_VL:?STM32?Low?density?Value?Line?devices?*/????
  • ??/*?#define?STM32F10X_MD??*/??/*!<?STM32F10X_MD:?STM32?Medium?density?devices?*/??
  • ???#define?STM32F10X_MD_VL?????/*!<?STM32F10X_MD_VL:?STM32?Medium?density?Value?Line?devices?*/????
  • ??/*?#define?STM32F10X_HD?*/????/*!<?STM32F10X_HD:?STM32?High?density?devices?*/??
  • ??/*?#define?STM32F10X_HD_VL?*/?/*!<?STM32F10X_HD_VL:?STM32?High?density?value?line?devices?*/????
  • ??/*?#define?STM32F10X_XL?*/????/*!<?STM32F10X_XL:?STM32?XL-density?devices?*/??
  • ??/*?#define?STM32F10X_CL?*/????/*!<?STM32F10X_CL:?STM32?Connectivity?line?devices?*/??
  • #endif??
  • 上面代碼說的是如果沒有定義 STM32F10X_MD_VL, 則宏定義?STM32F10X_MD_VL

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

    [plain] view plaincopy
  • #if?!defined??HSE_VALUE??
  • ?#ifdef?STM32F10X_CL?????
  • ??#define?HSE_VALUE????((uint32_t)25000000)?//?Value?of?the?External?oscillator?in?Hz?<pre?name="code"?class="plain">?#else?</pre>??#define?HSE_VALUE????((uint32_t)8000000)?//Value?of?the?External?oscillator?in?Hz??#endif?/*?STM32F10X_CL?*/#endif?/*?HSE_VALUE?*/??

  • D.做系統(tǒng)主頻時(shí)鐘的更改

    system_stm32f10x.c的系統(tǒng)主頻率,依實(shí)際情況修改 ;我用的芯片主頻時(shí)鐘是24MHZ; [plain] view plaincopy
  • ??????
  • #if?defined?(STM32F10X_LD_VL)?||?(defined?STM32F10X_MD_VL)?||?(defined?STM32F10X_HD_VL)??
  • /*?#define?SYSCLK_FREQ_HSE????HSE_VALUE?*/??
  • ?#define?SYSCLK_FREQ_24MHz??24000000??
  • #else??
  • /*?#define?SYSCLK_FREQ_HSE????HSE_VALUE?*/??
  • ?#define?SYSCLK_FREQ_24MHz??24000000???
  • /*?#define?SYSCLK_FREQ_36MHz??36000000?*/??
  • /*?#define?SYSCLK_FREQ_48MHz??48000000?*/??
  • /*?#define?SYSCLK_FREQ_56MHz??56000000?*/??
  • /*#define?SYSCLK_FREQ_72MHz??72000000*/???
  • #endif??
  • E.下面是關(guān)鍵部分操作了,在說這部分操作前我們先來說一下內(nèi)存映射: 下圖在stm32f100芯片手冊(cè)的29頁,我們只截取關(guān)鍵部分

    從上圖我們看出幾個(gè)關(guān)鍵部分:

    1.內(nèi)部flash 是從0x0800 0000開始 到0x0801 FFFF ?結(jié)束, ? ?0x0801FFFF-0x0800 0000= 0x20000 =128k ? ?128也就是flash的大小;

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

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


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

    那么要就要設(shè)置編譯器keil 中的 ?options ?for target 的target選項(xiàng)中的 IROM1地址 為0x0800 0000 大小為 0x20000即128K;

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

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

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

    [plain] view plaincopy
  • /*******************************************************************************??
  • ??*?@函數(shù)名稱???main??
  • ??*?@函數(shù)說明???主函數(shù)??
  • ??*?@輸入?yún)?shù)???無??
  • ??*?@輸出參數(shù)???無??
  • ??*?@返回參數(shù)???無??
  • *******************************************************************************/??
  • int?main(void)??
  • {??
  • ????//Flash?解鎖??
  • ????FLASH_Unlock();??
  • ??
  • ????//配置PA15管腳??
  • ????KEY_Configuration()?;??
  • ????//配置串口1??
  • ????IAP_Init();??
  • ????//PA15是否為低電平??
  • ????if?(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)??==?0x00)??
  • ????{??
  • ??????????
  • ????????//執(zhí)行IAP驅(qū)動(dòng)程序更新Flash程序??
  • ??
  • ????????SerialPutString("\r\n======================================================================");??
  • ????????SerialPutString("\r\n=??????????????(C)?COPYRIGHT?2011?Lierda?????????????????????????????=");??
  • ????????SerialPutString("\r\n=????????????????????????????????????????????????????????????????????=");??
  • ????????SerialPutString("\r\n=?????In-Application?Programming?Application??(Version?1.0.0)????????=");??
  • ????????SerialPutString("\r\n=????????????????????????????????????????????????????????????????????=");??
  • ????????SerialPutString("\r\n=???????????????????????????????????By?wuguoyan??????????????????????=");??
  • ????????SerialPutString("\r\n======================================================================");??
  • ????????SerialPutString("\r\n\r\n");??
  • ????????Main_Menu?();??
  • ????}??
  • ????//否則執(zhí)行用戶程序??
  • ????else??
  • ????{??
  • ????????//判斷用處是否已經(jīng)下載了用戶程序,因?yàn)檎G闆r下此地址是棧地址??
  • ????????//若沒有這一句話,即使沒有下載程序也會(huì)進(jìn)入而導(dǎo)致跑飛。??
  • ????????if?(((*(__IO?uint32_t*)ApplicationAddress)?&?0x2FFE0000?)?==?0x20000000)??
  • ????????{??
  • ????????????SerialPutString("Execute?user?Program\r\n\n");??
  • ????????????//跳轉(zhuǎn)至用戶代碼??
  • ????????????JumpAddress?=?*(__IO?uint32_t*)?(ApplicationAddress?+?4);??
  • ????????????Jump_To_Application?=?(pFunction)?JumpAddress;??
  • ??
  • ????????????//初始化用戶程序的堆棧指針??
  • ????????????__set_MSP(*(__IO?uint32_t*)?ApplicationAddress);??
  • ????????????Jump_To_Application();??
  • ????????}??
  • ????????else??
  • ????????{??
  • ????????????SerialPutString("no?user?Program\r\n\n");??
  • ????????}??
  • ????}??

  • 這里重點(diǎn)說一下幾句經(jīng)典且非常重要的代碼:

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

    怎么理解呢? (1),在程序里#define ApplicationAddress ? ?0x8003000 ,*(__IO uint32_t*)ApplicationAddress) ?即取0x8003000開始到0x8003003 的4個(gè)字節(jié)的值, 因?yàn)槲覀兊膽?yīng)用程序APP中設(shè)置把?中斷向量表?放置在0x08003000 開始的位置;而中斷向量表里第一個(gè)放的就是棧頂?shù)刂返闹?/span>

    也就是說,這句話即通過判斷棧頂?shù)刂分凳欠裾_(是否在0x2000 0000 - 0x 2000 2000之間) 來判斷是否應(yīng)用程序已經(jīng)下載了,因?yàn)閼?yīng)用程序的啟動(dòng)文件剛開始就去初始化化棧空間,如果棧頂值對(duì)了,說應(yīng)用程已經(jīng)下載了啟動(dòng)文件的初始化也執(zhí)行了;



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

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

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

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

    [cpp] view plaincopy
  • pFunction???a1,a2,a3;??
  • ??
  • void??fun(void)??
  • {??
  • ????......??
  • }??
  • ??
  • a1?=?fun;??
  • 所以,Jump_To_Application = (pFunction) JumpAddress; ?此時(shí)Jump_To_Application指向了復(fù)位函數(shù)所在的地址;

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

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


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

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

    下文來自于:http://blog.sina.com.cn/s/blog_69bcf45201019djx.html

    解析?STM32?的啟動(dòng)過程

    解析STM32的啟動(dòng)過程

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

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

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

    相對(duì)于ARM上一代的主流ARM7/ARM9內(nèi)核架構(gòu),新一代Cortex內(nèi)核架構(gòu)的啟動(dòng)方式有了比較大的變化。ARM7/ARM9內(nèi)核的控制器在復(fù)位后,CPU會(huì)從存儲(chǔ)空間的絕對(duì)地址0x000000取出第一條指令執(zhí)行復(fù)位中斷服務(wù)程序的方式啟動(dòng),即固定了復(fù)位后的起始地址為0x000000PC = 0x000000)同時(shí)中斷向量表的位置并不是固定的。而Cortex-M3內(nèi)核則正好相反,有3種情況:
    1
    ?通過boot引腳設(shè)置可以將中斷向量表定位于SRAM區(qū),即起始地址為0x2000000,同時(shí)復(fù)位后PC指針位于0x2000000處;
    2
    ?通過boot引腳設(shè)置可以將中斷向量表定位于FLASH區(qū),即起始地址為0x8000000,同時(shí)復(fù)位后PC指針位于0x8000000處;
    3
    ?通過boot引腳設(shè)置可以將中斷向量表定位于內(nèi)置Bootloader區(qū),本文不對(duì)這種情況做論述;
    Cortex-M3內(nèi)核規(guī)定,起始地址必須存放堆頂指針,而第二個(gè)地址則必須存放復(fù)位中斷入口向量地址,這樣在Cortex-M3內(nèi)核復(fù)位后,會(huì)自動(dòng)從起始地址的下一個(gè)32位空間取出復(fù)位中斷入口向量,跳轉(zhuǎn)執(zhí)行復(fù)位中斷服務(wù)程序。對(duì)比ARM7/ARM9內(nèi)核,Cortex-M3內(nèi)核則是固定了中斷向量表的位置而起始地址是可變化的。
    有了上述準(zhǔn)備只是后,下面以STM322.02固件庫提供的啟動(dòng)文件stm32f10x_vector.s為模板,對(duì)STM32的啟動(dòng)過程做一個(gè)簡要而全面的解析。
    程序清單一:
    ;文件stm32f10x_vector.s,其中注釋為行號(hào)
    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的啟動(dòng)代碼一共224行,使用了匯編語言編寫,這其中的主要原因下文將會(huì)給出交代。現(xiàn)在從第一行開始分析:
    ??1行:定義是否使用外部SRAM,為1則使用,為0則表示不使用。此語行若用C語言表達(dá)則等價(jià)于:
    #define DATA_IN_ExtSRAM 0
    ??2行:定義棧空間大小為0x00000400個(gè)字節(jié),即1Kbyte。此語行亦等價(jià)于:
    #define Stack_Size 0x00000400
    ??3行:偽指令AREA,表示
    ??4行:開辟一段大小為Stack_Size的內(nèi)存空間作為棧。
    ??5行:標(biāo)號(hào)__initial_sp,表示棧空間頂?shù)刂贰?/span>
    ??6行:定義堆空間大小為0x00000400個(gè)字節(jié),也為1Kbyte
    ??7行:偽指令AREA,表示
    ??8行:標(biāo)號(hào)__heap_base,表示堆空間起始地址。
    ??9行:開辟一段大小為Heap_Size的內(nèi)存空間作為堆。
    ??10行:標(biāo)號(hào)__heap_limit,表示堆空間結(jié)束地址。
    ??11行:告訴編譯器使用THUMB指令集。
    ??12行:告訴編譯器以8字節(jié)對(duì)齊。
    ??1381行:IMPORT指令,指示后續(xù)符號(hào)是在外部文件定義的(類似C語言中的全局變量聲明),而下文可能會(huì)使用到這些符號(hào)。
    ??82行:定義只讀數(shù)據(jù)段,實(shí)際上是在CODE區(qū)(假設(shè)STM32FLASH啟動(dòng),則此中斷向量表起始地址即為0x8000000
    ??83行:將標(biāo)號(hào)__Vectors聲明為全局標(biāo)號(hào),這樣外部文件就可以使用這個(gè)標(biāo)號(hào)。
    ??84行:標(biāo)號(hào)__Vectors,表示中斷向量表入口地址。
    ??85160行:建立中斷向量表。
    ??161行:
    ??162行:復(fù)位中斷服務(wù)程序,PROCENDP結(jié)構(gòu)表示程序的開始和結(jié)束。
    ??163行:聲明復(fù)位中斷向量Reset_Handler為全局屬性,這樣外部文件就可以調(diào)用此復(fù)位中斷服務(wù)。
    ??164行:IFENDIF為預(yù)編譯結(jié)構(gòu),判斷是否使用外部SRAM,在第1行中已定義為不使用
    ??165201行:此部分代碼的作用是設(shè)置FSMC總線以支持SRAM,因不使用外部SRAM因此此部分代碼不會(huì)被編譯。
    ??202行:聲明__main標(biāo)號(hào)。
    ??203204行:跳轉(zhuǎn)__main地址執(zhí)行。
    ??207行:IFELSEENDIF結(jié)構(gòu),判斷是否使用DEF:__MICROLIB(此處為不使用)。
    ??208210行:若使用DEF:__MICROLIB,則將__initial_sp__heap_base__heap_limit亦即棧頂?shù)刂?#xff0c;堆始末地址賦予全局屬性,使外部程序可以使用。
    ??212行:定義全局標(biāo)號(hào)__use_two_region_memory
    ??213行:聲明全局標(biāo)號(hào)__user_initial_stackheap,這樣外程序也可調(diào)用此標(biāo)號(hào)。
    ??214行:標(biāo)號(hào)__user_initial_stackheap,表示用戶堆棧初始化程序入口。
    ??215218行:分別保存棧頂指針和棧大小,堆始地址和堆大小至R0R1R2R3寄存器。
    ??224行:程序完畢。
    以上便是STM32的啟動(dòng)代碼的完整解析,接下來對(duì)幾個(gè)小地方做解釋:
    1
    ?AREA指令:偽指令,用于定義代碼段或數(shù)據(jù)段,后跟屬性標(biāo)號(hào)。其中比較重要的一個(gè)標(biāo)號(hào)為READONLY或者READWRITE,其中READONLY表示該段為只讀屬性,聯(lián)系到STM32的內(nèi)部存儲(chǔ)介質(zhì),可知具有只讀屬性的段保存于FLASH區(qū),即0x8000000地址后。而READONLY表示該段為可讀寫屬性,可知可讀寫段保存于SRAM區(qū),即0x2000000地址后。由此可以從第37行代碼知道,堆棧段位于SRAM空間。從第82行可知,中斷向量表放置與FLASH區(qū),而這也是整片啟動(dòng)代碼中最先被放進(jìn)FLASH區(qū)的數(shù)據(jù)。因此可以得到一條重要的信息:0x8000000地址存放的是棧頂?shù)刂?/span>__initial_sp0x8000004地址存放的是復(fù)位中斷向量Reset_HandlerSTM32使用32位總線,因此存儲(chǔ)空間為4字節(jié)對(duì)齊)。
    2
    ?DCD指令:作用是開辟一段空間,其意義等價(jià)于C語言中的地址符&。因此從第84行開始建立的中斷向量表則類似于使用C語言定義了一個(gè)指針數(shù)組,其每一個(gè)成員都是一個(gè)函數(shù)指針,分別指向各個(gè)中斷服務(wù)函數(shù)。
    3
    ?標(biāo)號(hào):前文多處使用了標(biāo)號(hào)一詞。標(biāo)號(hào)主要用于表示一片內(nèi)存空間的某個(gè)位置,等價(jià)于C語言中的地址概念。地址僅僅表示存儲(chǔ)空間的一個(gè)位置,從C語言的角度來看,變量的地址,數(shù)組的地址或是函數(shù)的入口地址在本質(zhì)上并無區(qū)別。
    4
    ?202行中的__main標(biāo)號(hào)并不表示C程序中的main函數(shù)入口地址,因此第204行也并不是跳轉(zhuǎn)至main函數(shù)開始執(zhí)行C程序。__main標(biāo)號(hào)表示C/C++標(biāo)準(zhǔn)實(shí)時(shí)庫函數(shù)里的一個(gè)初始化子程序__main的入口地址。該程序的一個(gè)主要作用是初始化堆棧(對(duì)于程序清單一來說則是跳轉(zhuǎn)__user_initial_stackheap標(biāo)號(hào)進(jìn)行初始化堆棧的),并初始化映像文件,最后跳轉(zhuǎn)C程序中的main函數(shù)。這就解釋了為何所有的C程序必須有一個(gè)main函數(shù)作為程序的起點(diǎn)——因?yàn)檫@是由C/C++標(biāo)準(zhǔn)實(shí)時(shí)庫所規(guī)定的——并且不能更改,因?yàn)?/span>C/C++標(biāo)準(zhǔn)實(shí)時(shí)庫并不對(duì)外界開發(fā)源代碼。因此,實(shí)際上在用戶可見的前提下,程序在第204行后就跳轉(zhuǎn)至.c文件中的main函數(shù),開始執(zhí)行C程序了。
    至此可以總結(jié)一下STM32的啟動(dòng)文件和啟動(dòng)過程。首先對(duì)棧和堆的大小進(jìn)行定義,并在代碼區(qū)的起始處建立中斷向量表,其第一個(gè)表項(xiàng)是棧頂?shù)刂?#xff0c;第二個(gè)表項(xiàng)是復(fù)位中斷服務(wù)入口地址。然后在復(fù)位中斷服務(wù)程序中跳轉(zhuǎn)??C/C++標(biāo)準(zhǔn)實(shí)時(shí)庫的__main函數(shù),完成用戶堆棧等的初始化后,跳轉(zhuǎn).c文件中的main函數(shù)開始執(zhí)行C程序。假設(shè)STM32被設(shè)置為從內(nèi)部FLASH啟動(dòng)(這也是最常見的一種情況),中斷向量表起始地位為0x8000000,則棧頂?shù)刂反娣庞?/span>0x8000000處,而復(fù)位中斷服務(wù)入口地址存放于0x8000004處。當(dāng)STM32遇到復(fù)位信號(hào)后,則從0x80000004處取出復(fù)位中斷服務(wù)入口地址,繼而執(zhí)行復(fù)位中斷服務(wù)程序,然后跳轉(zhuǎn)__main函數(shù),最后進(jìn)入mian函數(shù),來到C的世界。

    總結(jié)

    以上是生活随笔為你收集整理的Stm 32 IAP 在线 升级IAP 的 操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。