找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 6766|回復(fù): 1
收起左側(cè)

通過LST和HEX文件分析CortexM3的復(fù)位啟動(dòng)過程

[復(fù)制鏈接]
ID:104497 發(fā)表于 2016-4-27 21:21 | 顯示全部樓層 |閱讀模式
      從匯編編程的角度上看,STM32從復(fù)位到主程序的過程要比MCS稍顯復(fù)雜,一個(gè)比較主要的原因是CortexM3用很多偽指令來描述啟動(dòng)過程,會(huì)讓我這樣的菜鳥感到云遮霧罩。
      說到底,CortexM3也好,MCS51也罷,啟動(dòng)過程都是大同小異的,無非是PC指針初始化,執(zhí)行完用戶的復(fù)位程序之后取出主程序地址,跳到主程序上。
      對(duì)于MCS51來說,這個(gè)過程非常好理解:
                    ORG        0000H
                    LJMP        Reset
                    ORG        0003H
                    ;配置各個(gè)中斷服務(wù)程序的入口
                      ………………
                    ORG        0100H
Reset:
                     ………………
                   ;初始化及主程序段
     51單片機(jī)復(fù)位,PC=0000H指向首地址,取指令和操作數(shù),轉(zhuǎn)0100H執(zhí)行初始化及主程序,先定義堆棧指針SP,然后再干別的。
      這個(gè)過程說明MCS51程序存儲(chǔ)器是這樣分區(qū)的:
復(fù)位入口        0000H-0002H。放置越過中斷向量程序段,直達(dá)主程序段的跳轉(zhuǎn)指令。
中斷向量        0003H-00BBH。放置中斷服務(wù)程序向量。有些增強(qiáng)型51單片機(jī)的中斷向量已經(jīng)用到了00BBH。
復(fù)位程序        從最后一個(gè)中斷向量操作數(shù)之后的地址開始。通常是先配置堆棧指針SP。
主程序段        主程序代碼區(qū)。
      但對(duì)于CortexM3來說,它的復(fù)位過程有點(diǎn)兒特殊:如果BOOT0配置成從FLASH區(qū)啟動(dòng),那首先是PC=0x08000000,先把這個(gè)地址開始的4個(gè)字節(jié)數(shù)值賦值給主棧指針MSP,然后再把0x08000004開始的4個(gè)字節(jié)賦值給PC,轉(zhuǎn)到復(fù)位程序。
      實(shí)際上,復(fù)位時(shí)PC=0x00000000,但BOOT0=0時(shí),0x00000000會(huì)被映射到0x08000000上,所以說PC是從0x08000000開始也是可以的。
      CortexM3程序存儲(chǔ)器分區(qū)是如下:
MSP賦值        0x08000000—0x08000003。當(dāng)PC指向這個(gè)數(shù)據(jù)塊時(shí),4字節(jié)數(shù)自動(dòng)賦值給MSP。
復(fù)位入口        0x08000004—0x08000007。4個(gè)字節(jié),放置復(fù)位程序的入口地址。
中斷向量        在0x08000007之后,每個(gè)向量的入口地址可以定義。每個(gè)中斷向量地址可以浮動(dòng)。
復(fù)位程序        從最后一個(gè)中斷向量操作數(shù)之后的地址開始。
主程序段        主程序代碼區(qū)。
      歸結(jié)起來,兩者跳轉(zhuǎn)的方式有所不同,MCS51是通過入口放置指令,而CortexM3則是通過入口處放置地址來實(shí)現(xiàn)跳轉(zhuǎn)。
      為了深入探究一下CortexM3的復(fù)位機(jī)制,我編一個(gè)簡(jiǎn)單的程序,力圖通過HEX和LST文件理清脈絡(luò)。
環(huán)境如下:
IDE:Keil 4.12
硬件:STM32F103VCT6,BOOT0=0
程序:匯編語言

LST程序如下:
(1)        初始化程序Initialization.LST
00000000 20005000    MSP_Top  EQU  0x20005000
00000000                                          THUMB
00000000                                          AREA     Reset, Data, ReadOnly
00000000                                          EXPORT   __Vectors
00000000                                          EXPORT   __Vectors_End
00000000                                          EXPORT   __Vectors_Size
00000000                      __Vectors
00000000 20005000                         DCD     MSP_Top
00000004 00000000                         DCD     Reset_Handler
00000008 00 00 00
               00 00 00
               00 00                                  SPACE            0x8
00000010                     __Vectors_End
00000010 00000010                         __Vectors_Size      EQU   __Vectors_End - __Vectors
00000010                                         AREA     |.text|, Code, Readonly
00000000                     Reset_Handler        PROC
00000000                                         EXPORT   Reset_Handler           [WEAK]
00000000                                         IMPORT   Main
00000000 4800                                LDR      R0,=Main
00000002 4700                                BX       R0
00000004                                         ENDP
00000004                                         ALIGN
00000004                                         END
      主棧配置到SRAM區(qū)0x20005000,暫時(shí)未定義主棧大小。暫時(shí)未定義其它中斷向量。
(2)        主程序Main.LST
                                     INCLUDE  Stm32F103REG.h
00000000                     Main     PROC
00000000                                        EXPORT    Main
00000000 4801                               LDR       R0,=RCC_CR
00000002 6801                               LDR       R1,[R0]
00000004 E7FE                               B         Main
00000006                                        ENDP
00000006                                        END
      Stm32F103REG.h是自行編制的寄存器定義程序。
上述程序編譯之后打開工程HEX文件和兩個(gè)程序段的LST文件并整理一下,刪除一些不重要的數(shù)據(jù),結(jié)果如下:
(3)工程HEX文件
:020000040800F2
:100000000050002011000008000000000000000067
:10001000004800471900000801480168FCE700009B
:04002000001002408A
:0400000508000019D6
:00000001FF
看起來有些亂七八糟,整理一下。

數(shù)據(jù)長(zhǎng)度    地址偏移   數(shù)據(jù)類型                    數(shù)據(jù)塊                                                                 校驗(yàn)和
1byte          2bytes      1byte                          n bytes                                                                1byte
02              00 00         04                08 00                                                                                 F2
10                  00 00            00                00 50 00 20 11 00 00 08 00 00 00 00 00 00 00 00             67
10                  00 10            00                00 48 00 47 19 00 00 08 01 48 01 68 FC E7 00 00             9B
04                  00 20            00                00 10 02 40                                                                          8A
04                  00 00            05                08 00 00 19                                                                          D6
00                  00 00            01                                                                                                          FF

     數(shù)據(jù)長(zhǎng)度好理解,是說本行中數(shù)據(jù)塊有幾個(gè)字節(jié)。
     地址偏移是指當(dāng)前行第一個(gè)數(shù)據(jù)相對(duì)于基址的位置。
     查了一下資料,數(shù)據(jù)類型可分為5種類型:
00=這一行的數(shù)據(jù)塊里全是數(shù)據(jù);
01=HEX文件結(jié)束符,所在行數(shù)據(jù)塊為空;
02=數(shù)據(jù)塊里的數(shù)據(jù)是擴(kuò)展段地址;
03=數(shù)據(jù)塊里的數(shù)據(jù)是段地址;
04=數(shù)據(jù)塊里的數(shù)據(jù)是線性地址高位;
05=數(shù)據(jù)塊里的數(shù)據(jù)是線性地址。
      看起來,數(shù)據(jù)類型可分為三大類:數(shù)據(jù)類(00)、地址類(02~05)和編譯標(biāo)識(shí)類(01)

      第一行數(shù)據(jù)類型為04,說明后面的0800和地址偏移0000構(gòu)成了一個(gè)基址0x08000000,這是STM32F103 FLASH區(qū)的首址,后序行的數(shù)據(jù)存儲(chǔ)地址都可以根據(jù)這個(gè)基址加偏移量計(jì)算出來。
      第二行數(shù)據(jù)類型為00,偏移量為0000,也就是說,數(shù)據(jù)塊的第一個(gè)00被存放在地址0x08000000中,這就是單片機(jī)復(fù)位時(shí)從FLASH區(qū)啟動(dòng)的首址。
      按照前面的說明,首址之后的4個(gè)字節(jié)應(yīng)當(dāng)是準(zhǔn)備賦給MSP的值,也就是程序指定的0x20005000,可現(xiàn)在卻是00 50 00 20,看了半天恍然大悟,突然想起CortexM3數(shù)據(jù)格式是所謂的小端模式Little-endian,所以這4個(gè)字節(jié)的32位數(shù)據(jù)得按字節(jié)倒過來讀成20 00 50 00。但當(dāng)數(shù)據(jù)類型為地址類時(shí),數(shù)據(jù)塊數(shù)據(jù)就可以正著讀了,哈哈。
      00 50 00 20之后又是一個(gè)地址,倒過來是08 00 00 11,這就是復(fù)位程序入口地址。其后的數(shù)據(jù)是8個(gè)字節(jié)的00,這就是SPACE 0x8的功勞了。 按照流程,復(fù)位地址賦值給PC之后會(huì)從地址0x08000011開始運(yùn)行,0x08000011單元的數(shù)據(jù)是48,對(duì)照一下Initialization.LST,對(duì)應(yīng)的是它的第一條可執(zhí)行語句'LDR  R0,=Main',只不過這條指令的代碼48 00也存儲(chǔ)成了小端模式。
      以此類推,逐一閱讀后面的數(shù)據(jù),過程就出來了,Main的段地址是第三行的那個(gè)大紅圈里的數(shù)據(jù)0x08000019,從它以后就是Main的指令代碼了。但這里有一個(gè)問題,Main.LST表明‘B  Main’指令的代碼是E7 FE,可HEX里卻是E7 FC,這又是怎么回事兒呢?不知道哪位前輩能告訴我。
     還有一個(gè)問題:從0x08000020開始的數(shù)據(jù)明顯是RCC_CR的地址,它怎么會(huì)出現(xiàn)在這兒呢?

      用匯編寫STM32程序是苦中有樂,有人說我這是自找麻煩,但我不這么認(rèn)為。與使用固件庫編程相比,無論是面向寄存器編程還是直接用匯編,編程難度都要大很多,但是,程序透明度也比前者大得多,絕對(duì)不會(huì)出現(xiàn)神龍見首不見尾的感覺,尤其是對(duì)于我這種不太會(huì)C語言的硬件工程師就更是如此。


評(píng)分

參與人數(shù) 2黑幣 +60 收起 理由
51黑ele + 10 很給力!
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:115111 發(fā)表于 2016-4-27 23:05 | 顯示全部樓層
好文章啊結(jié)合51單片機(jī)談stm32單片機(jī)的啟動(dòng)過程,讓我們這些51的學(xué)習(xí)者也能進(jìn)入stm32的世界,期待樓主的更多文章
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表