lpc1768 IAP疑點全解釋

       本文檔基於平臺:LPC1768,開發環境:Keil4.10

                                                                                                                                                                                                   Time  :2013/8/6      

                                                                                                                                                                                                              Author:xj

                                                                                                                                                                                                              E-mail:[email protected]

IAP簡介:

       IAP爲在應用編程的簡稱,其作用是用戶自己的程序在運行過程中對用戶程序所在的部分區域進行燒寫,目的是爲了在產品發佈後可以方便地通過預留的通信口對產品中的程序進行更新升級

 

Lpc1768存儲器空間分配:

整體Flash佈局:     

地址範圍

地址說明

0x1000_0000 ~0x1000_7FFF

片上32K通用SRAM

0x2007_C000 ~0x2007_FFFF

片上16K以太網/USB靜態SRAM,可用作通用SRAM

0x2008_0000 ~0x2008_3FFF

片上16K以太網/USB靜態SRAM,可用作通用SRAM

0x1FFF_0000 ~0x1FFF_1FFF

片上 8K啓動代碼區

0x0000_0000 ~0x0007_FFFF

片上512K Flash存儲器

其他地址

APB、AHB等寄存器映射區

 

分散加載描述文件:

分散加載描述文件是arm連接器提供的可以將程序中的代碼段、數據段定位到flash中特定的物理地址的一種機制。通過此機制我們可以把給IAP程序和用戶程序分別分配一部分空間並制定各自的起始地址以保證IAP程序和用戶程序不會重疊。關於分散加載描述文件詳細文檔,請參考《RealView編譯工具----鏈接器參考指南》第三章,對於IAP涉及到的分散加載文件的知識,我們只需知道以下幾點。以本次IAP工程爲例,我們給IAP升級代碼留32K的空間(0x0000_0000~0x0000_7FFFF),剩餘的給用戶程序空間(即用戶程序從地址0x0000_8000開始)。對於IAP程序部分的分散加載文件不做修改,對於用戶程序部分修改如下:

我們僅僅對第5行和第6行做了修改,改動的地方做出了標註,其具體表示意思是:

 Line5:0x0000_8000表示加載域的起始地址,即放在flash0x0000_8000地址處開始放置,0x0008_0000表示代碼區、數據區的總共大小的最大值,程序文件超過此值將會報錯,這裏取默認值0x0008_0000即可。

Line6: 0x0000_8000表示執行域的起始地址,即程序從0x0000_8000地址處開始執行,0x0008_0000代表的意思參考上一行。

Line7:此行的作用是把中斷向量表定位在起始地址處(這裏是0x0000_8000).

要使用此分散加載描述文件,還需要將Target Opitions…->Linker下的Use Memory Layout from Target Dialog前的“√”去掉。

 

IAP函數的使用

   Iap函數是固化在Boot Rom中地址0x1FFF1FF1處的一個有傳入參數和返回參數的一個函數。對於不同的傳入參數,iap函數實現不同的功能。關於這些功能的詳細介紹,《LPC1768 user manual》32章第8節IAP commands一節中有詳細介紹,這裏不贅述。遠程升級中我們常用到的幾個iap命令是:讀器件標識號、準備寫操作扇區、擦除扇區、扇區查空、將RAM內容複製到Flash、比較<地址1><地址2><字節數>。

以準備寫操作扇區爲例說明iap函數的寫法。首先定義iap函數的入口地址:

1

#define  IAP_ENTER_ADR  0x1FFF1FF1/*IAP函數入口地址*/

接着聲明函數類型指針IAP_Entry:

1

void (*IAP_Entry)(uint32  paramin[ ],uint32  paramout[ ]) ;

初始化IAP函數指針使其指向IAP函數入口地址:

1

2

3

4

void  IAP_EntryInit(void)

{

   IAP_Entry  =( void(*)() )IAP_ENTER_ADR ;

}

由用戶手冊可知iap命令彙總如下圖:

Iap狀態碼彙總如下圖:

據此寫出IAP命令字和狀態碼宏定義如下:(PS:Command Code中的數字10表示十進制,如:Read part ID的命令字爲5410,表示其命令字爲十進制的54,見上圖)

準備寫操作扇區的命令解釋如下圖:

由上圖可知準備寫操作扇區需要三個參數,分別是Command code、Param0、Param1,返回狀態碼的可能取值爲CMD_SUCCESS、BUSY、INVALID_SECTOR。據此我們寫處準備寫操作扇區的命令函數如下:

1

2

3

4

5

6

7

8

9

uint32  PreSector(uint8  arg1,uint8  arg2)

{

    paramin[0] = IAP_SELECTOR ;             //設置命令字

    paramin[1] = arg1 ;                       //設置參數

    paramin[2] = arg2 ;

    (*IAP_Entry)(paramin, paramout) ;        //調用IAP服務程序

  

    Return (paramout[0]) ;                    // 返回狀態碼

}

其中paramin[]、paramout[]爲定義的uint32型全局數組。調用此函數時只需將起始扇區號傳給arg1,結束扇區號傳給arg2即可。其他命令的函數書寫於此大同小異。

這裏給出一個遠程升級的iap流程:讀取器件標識碼確定是當前芯片→確定待升級程序(用戶程序)佔用的起始扇區號與結束扇區號→準備需佔用扇區→擦除需佔用扇區→扇區查空確定需佔用扇區已成功擦除→執行將RAM複製到Flash命令將數據塊複製到Flash→執行比較命令校驗數據是否正確→如果正確執行下一數據塊的複製。

需要說明的一點是:在還行IAP命令的時候,需要關閉中斷以保證IAP命令的正確執行。幸運的是Cortex-M3提供了關閉/打開中斷的指令CPSID ICPSIE I,而且在core_cm3.h中也提供這樣的開關中斷的函數__enable_irq()__disable_irq(),需要的時候直接去調用就可以。

從bootloader到UsrApp的跳轉:

這裏我們把引導cpu進入用戶代碼區的程序稱作bootloader,把用戶實際實現相應功能的程序稱作UsrApp,它們是一個完整的程序,下文提到的bootloader、UsrApp均指這些。

bootloader到UsrApp的跳轉需要熟知兩方面的知識:一個是中斷向量表的重映射,另一個是一段完整的程序的入口是如何定義的。

中斷向量表重映射:

在LPC1768中,位於地址0xE000_ED08處有一個向量表偏移寄存器VTOR,通過修改此寄存器可以設定向量表基址位於Code區或是RAM區以及向量表的基址偏移域,以此達到中斷向量表重映射的目的。比如我們的UsrApp起始地址爲0x8000;爲使UsrApp在發生中斷行爲時不會產生錯誤或異常,我們可以通過以下代碼段將中斷向量表重映射到地址0x8000處Code區。

1

SCB->VTOR = USR_APP_START_ADDR &0x1FFFFF80;

SCB->VTOR由core_cm3.c提供,對應向量表偏移寄存器地址0xE000_ED08。USR_APP_START_ADDR爲用戶代碼區的起始地址,和數值0x1FFFFF80按位與是保證寄存器的保留位爲0和向量表基址位於Code區。此寄存器的詳細說明請參考《cortex-M3技術參考手冊》第八章第二節的NVIC寄存器描述或《LPC17XX User manual》英文版34.4.3.5章節。,此處不再貼出。對於用戶程序,在bootloader中的向量表偏移設置並不起作用,需要在用戶程序中重新設置向量表偏移寄存器。原因是CM3器件進入main()函數即要求調用SystemInit(void)進行系統初始化,系統初始化的時候將向量表偏移寄存器清零了,所以需要在調用SystemInit()之後重新設置向量表偏移寄存器。有網文稱對於應用了OS的用戶程序需要這樣做,其實對於開啓了中斷的的用戶程序都需要這樣,你的簡單的IAP測試程序之所以在沒有這樣做的情況下通過了測試,是因爲你的用戶程序測試代碼中並沒有用到中斷。

 

一個完整鏡像的程序入口:

       對於在flash中存儲的一個完整的程序代碼,其起始部分應該爲向量表,向量表的內容格式固定如下表(參考《cortex-M3權威指南》7.3節)

上電後的向量表:

由表可知,對於起始存儲地址爲0的一段完整程序,其首地址處存放的是MSP的初始值,偏移4字節的地址處存放的是PC指針的初始值,我們要運行這段完整的程序,只需將這段完整程序的SP、PC初始值賦給SP和PC寄存器即可,具體實現的函數如下:

1

2

3

4

5

__asm void boot_jump(uint32 address)

{

   LDR  SP, [R0]

LDR  PC ,[R0, #4]

}

對於此函數的解釋:__asm是MDK的編譯器提供的嵌入彙編的指令(RealView C編譯器3.0以上版本提供)。函數體中兩行彙編代碼的功能分別爲:

LDR  SP, [R0]:把R0中的值作爲地址,將此地址中的值賦給SP

LDR  PC ,[R0, #4]:把R0中的值加4作爲地址,將此地址中的值賦給SP

這裏涉及到一個問題,r0中的值是什麼?我們根據ATPCS(ARM-THUMBprocedure call standard)可知,對於參數少於等於4的函數,參數是通過R0~R3傳遞的,第一個參數放在R0中,依次類推。所以這裏的R0存放的正式UsrApp的起始地址,回過頭再看前面的兩行彙編代碼,它們做的事正是將UsrApp的SP、PC初始值賦給相應寄存器,達到開始運行UsrApp的目的。

 

UsrApp的燒寫:

因爲在片內flash的起始地址處燒寫的是我們的iap處理程序,用戶程序的起始地址不是0x0000_0000,在通過keil用jlink下載程序的時候,還需做一個設置。在Option for Target→Debug→Settings→Flash Download中,設置下載程序時的起始地址爲用戶程序的起始地址。如本例中用戶程序的起始地址是0x0000_8000,我們設置下載程序的起始地址爲0x0000_8000,如下圖。如果不這麼做的話,通過jlink下載程序的時候會從地址0x0000_0000開始擦除。

 

遺留的問題:

疑問1:《lpc1768 user manual》34.4.3.5章節指出中斷向量表偏移寄存器的向量表基址偏移域爲[28:8]位,爲什麼將偏移量實際賦值給此寄存器的時候沒有做’<<8’的處理而是直接賦值過來?PS:《Cortex-M3技術參考手冊》第8章的表8-15指出中斷向量偏移寄存器的向量表基址偏移域爲[28:7]

疑問2:手冊中指出使用iap的時候RAM頂部32字節空出,這該怎麼理解?iap佔用ram頂端32字節,即使我不去刻意留出也不影響iap使用這32字節的空間,我能想到的唯一解釋是編譯器可能會把程序中的全局變量放到ram頂端32字節區域進而調用iap函數會引起全局變量被修改,是這樣麼?

  如果你讀到了這裏並且你知道這些答案,敬請告知解惑。E-mail:[email protected]

參考過的文獻:

《arm彙編指令集》--------網文

《arm啓動代碼的探究-鄭遠超》

《arm體系結構與編程》------杜春雷(PS:重點第11章)

《map文件認識初步》-------網文

《彙編器指南》------RealviewMDK

《鏈接器指南》------RealviewMDK

《中斷向量表重映射與複製》------網文

《cortex-m3技術參考手冊》

 

發佈了11 篇原創文章 · 獲贊 19 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章