新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 基于IAP和Keil MDK的遠(yuǎn)程升級設(shè)計(jì)

基于IAP和Keil MDK的遠(yuǎn)程升級設(shè)計(jì)

作者: 時(shí)間:2016-12-19 來源:網(wǎng)絡(luò) 收藏

  寫在前面:三個(gè)周之前,我突然想寫一個(gè)遠(yuǎn)程升級的程序。那個(gè)時(shí)候我只是大概知道的意思是在應(yīng)用編程,但怎么編,我還一無所知。我給自己定下一個(gè)個(gè)階段目標(biāo),從最基礎(chǔ)的代碼一點(diǎn)點(diǎn)寫起,解決一個(gè)又一個(gè)的問題。三個(gè)周之后,我用自己設(shè)計(jì)的方法實(shí)驗(yàn)了50多次,無一例升級失敗。

本文引用地址:http://www.butianyuan.cn/article/201612/341760.htm

  三個(gè)周來,遇到了很多的不解、困惑,甚至是想放棄,但我現(xiàn)在想說的是:很多未知的困難會擋在我們面前,我們會感覺毫無頭緒甚至覺得毫無出路忍不住要放棄,但多堅(jiān)持一下,那些困難不但能煙消云散還能帶給我們進(jìn)步。

  本設(shè)計(jì)是基于LPC2114和 MDK(V4.10),但所有支持的處理器都可借鑒本方案,重要的是思想,而不是用什么。

  0 引言

  在應(yīng)用編程()技術(shù)為系統(tǒng)在線升級和遠(yuǎn)程升級提供了良好的解決方案,也為數(shù)據(jù)存儲和現(xiàn)場固件的升級都帶來了極大的靈活性。通??衫眯酒拇锌诮拥接?jì)算機(jī)的RS232口、通過現(xiàn)有的Internet或、無線網(wǎng)絡(luò)或者其他通信方式很方便地實(shí)現(xiàn)在線以及遠(yuǎn)程升級和維護(hù)。

  本文以NXP的LPC2114 ARM微處理器為平臺,以 MDK為開發(fā)工具,闡述IAP的原理、Flash的劃分、分散加載機(jī)制、中斷重映射以及在線升級的實(shí)現(xiàn)方案及其優(yōu)化。本方案使用多種校驗(yàn)技術(shù),最大限度的保障傳輸數(shù)據(jù)的正確性;使用bootloader機(jī)制,即使因意外事件(斷電,編程Flash失敗等)造成升級失敗后,程序也能返回到升級前的狀態(tài)。

  1 LPC2114的Flash規(guī)劃

  1.1 扇區(qū)描述

  LPC2114共有128KB片內(nèi)Flash,共分為16個(gè)扇區(qū),分別為0扇區(qū)~15扇區(qū),每個(gè)扇區(qū)為8KB存儲空間。其中第15扇區(qū)出廠時(shí)被固化為Boot Block區(qū),控制復(fù)位后的初始化操作,并提供實(shí)現(xiàn)Flash 編程的方法。所以用戶可用的Flash空間只有120KB。IAP程序固化于Boot Block中,IAP操作是以扇區(qū)為單位,并占用片內(nèi)RAM的高32字節(jié)。下表列出LPC2114器件所包含的扇區(qū)數(shù)和存儲器地址.

  表1.1 LPC2114 Flash 器件中的扇區(qū)

image

  1.2 Flash的扇區(qū)劃分

  本設(shè)計(jì)將Flash劃分為四個(gè)區(qū),扇區(qū)0存放跳轉(zhuǎn)程序和升級引導(dǎo)程序(Bootloader)。分站上電后執(zhí)行跳轉(zhuǎn)程序,跳轉(zhuǎn)到用戶程序處。用戶程序運(yùn)行過程中,如果接收到升級指令,會從用戶程序跳轉(zhuǎn)到引導(dǎo)程序區(qū)(Bootloader),接收新程序數(shù)據(jù)包,完成Flash編程并跳轉(zhuǎn)到新程序區(qū)執(zhí)行程序。扇區(qū)1~扇區(qū)7為程序存儲低區(qū);扇區(qū)8~扇區(qū)13為程序存儲高區(qū);扇區(qū)14存放當(dāng)前程序運(yùn)行區(qū)域標(biāo)志,如果當(dāng)前程序運(yùn)行在高區(qū),該標(biāo)志區(qū)的最低四個(gè)字節(jié)為0x00010000,如果當(dāng)前程序運(yùn)行在低區(qū),該標(biāo)志區(qū)的最低四個(gè)字節(jié)為0x00008000。

  2 IAP的原理與軟件設(shè)計(jì)

  2.1 IAP的原理

  IAP函數(shù)是固化在微處理器內(nèi)部flash上的一些函數(shù)代碼,最終的用戶程序可以直接通過調(diào)用這些函數(shù)來對內(nèi)部flash進(jìn)行擦除和編程操作。LPC2114微處理器的內(nèi)部flash有一個(gè)塊稱為Boot Block,位于flash的頂端,可供調(diào)用的IAP函數(shù)就位于該塊中。上電后Boot Block被映射到內(nèi)部地址空間的頂端,同樣IAP函數(shù)人口地址也被映射到地址0x7ffffff0處。用戶可通過跳轉(zhuǎn)到該地址來調(diào)用相應(yīng)的lAP函數(shù)。

  2.2 IAP 命令

  對于在應(yīng)用編程來說,應(yīng)當(dāng)通過寄存器r0 中的字指針指向存儲器(RAM)包含的命令代碼和參數(shù)來調(diào)用IAP 程序。IAP 命令的結(jié)果返回到寄存器r1 所指向的返回表。用戶可通過傳遞寄存器r0 和r1 中的相同指針重用命令表來得到結(jié)果。參數(shù)表應(yīng)當(dāng)大到足夠保存所有的結(jié)果以防結(jié)果的數(shù)目大于參數(shù)的數(shù)目。參數(shù)傳遞見圖2-1。參數(shù)和結(jié)果的數(shù)目根據(jù)IAP命令而有所不同。參數(shù)的最大數(shù)目為5,由“將RAM 內(nèi)容復(fù)制到Flash”命令傳遞。結(jié)果的最大數(shù)目為2,由“扇區(qū)查空”命令返回。命令處理程序在接收到一個(gè)未定義的命令時(shí)發(fā)送狀態(tài)代碼INVALID_COMMAND。IAP 程序是thumb 代碼,位于地址0x7FFFFFF0。

    

clip_image005

  圖2-1 IAP的參數(shù)傳遞

  表2-1描述了IAP的命令。

  表2-1 IAP 命令匯總

  IAP命令命令代碼描述

  準(zhǔn)備編程扇區(qū)50該命令必須在執(zhí)行“將 RAM 內(nèi)容復(fù)制到Flash”或“擦除扇區(qū)”命令之前執(zhí)行。這兩個(gè)命令的成功執(zhí)行會導(dǎo)致相關(guān)的扇區(qū)再次被保護(hù)。該命令不能用于boot 扇區(qū)。要準(zhǔn)備單個(gè)扇區(qū),可將起始和結(jié)束扇區(qū)號設(shè)置為相同值。

  將RAM內(nèi)容復(fù)制到Flash51該命令用于編程 Flash 存儲器。受影響的扇區(qū)應(yīng)當(dāng)先通過調(diào)用“準(zhǔn)備寫操作的扇區(qū)”命令準(zhǔn)備。當(dāng)成功執(zhí)行復(fù)制命令后,扇區(qū)將自動受到保護(hù)。該命令不能寫boot 扇區(qū)。

  擦除扇區(qū)52該命令用于擦除片內(nèi) Flash 存儲器的一個(gè)或多個(gè)扇區(qū)。boot 扇區(qū)不能由該命令擦除。要擦除單個(gè)扇區(qū)可將起始和結(jié)束扇區(qū)號設(shè)定為相同值。

  扇區(qū)查空53該命令用于對片內(nèi) Flash 存儲器的一個(gè)或多個(gè)扇區(qū)進(jìn)行查空。要查空單個(gè)扇區(qū)可將起始和結(jié)束扇區(qū)號設(shè)定為相同值。

  讀器件ID54該命令用于讀取器件的 ID 號。

  讀Boot版本55該命令用于讀取 boot 代碼版本號。

  IAP比較56該命令用來比較兩個(gè)地址單元的存儲器內(nèi)容。當(dāng)源或目標(biāo)地址包含從地址0 開始的前64字節(jié)中的任意一個(gè)時(shí),比較的結(jié)果不一定正確。前64字節(jié)重新映射到Flash boot 扇區(qū)。

  2.3 IAP 編程函數(shù)接口

  IAP 功能可用下面的C 代碼來調(diào)用。

  定義 IAP 程序的入口地址。由于IAP 地址的第0 位是1,因此,當(dāng)程序計(jì)數(shù)器轉(zhuǎn)移到該地址時(shí)會引起Thumb 指令集的變化。

  #define IAP_LOCATION 0x7ffffff1

  定義數(shù)據(jù)結(jié)構(gòu)或指針,將IAP 命令表和結(jié)果表傳遞給IAP 函數(shù)

  unsigned long command[5];

  unsigned long result[2];

  定義函數(shù)類型指針,函數(shù)包含2 個(gè)參數(shù),無返回值。注意:IAP 將函數(shù)結(jié)果和R1 中的表格基址一同返回。

  typedef void (*IAP) (unsigned int [ ] , unsigned int [ ]);

  IAP iap_entry;

  設(shè)置函數(shù)指針

  iap_entry=(IAP) IAP_LOCATION;

  使用下面的語句來調(diào)用IAP。

  iap_entry (command , result);

  Flash 存儲器在寫或擦除操作過程中不可被訪問。執(zhí)行Flash 寫/擦除操作的IAP 命令

  使用片內(nèi)RAM 頂端的32 個(gè)字節(jié)空間。如果應(yīng)用程序中允許IAP 編程,那么用戶程序不應(yīng)

  使用該空間。

  3 LPC2114升級實(shí)現(xiàn)過程

  由于在升級程序軟件設(shè)計(jì)中,分散加載機(jī)制、中斷向量的重映射、軟中斷等的實(shí)現(xiàn)還與所使用的編譯器緊密相關(guān),因此,本文結(jié)合 MDK(V4.10)編譯工具,來詳細(xì)闡述升級程序的實(shí)現(xiàn)過程。

  3.1 總體思路

  分站上電后,首先運(yùn)行位于Flash 0x000~0x3FF中的跳轉(zhuǎn)程序。跳轉(zhuǎn)程序會讀取位于14扇區(qū)的當(dāng)前程序運(yùn)行標(biāo)志,如果該扇區(qū)的最低四個(gè)字節(jié)為0x00010000,表示當(dāng)前程序運(yùn)行在高區(qū),跳轉(zhuǎn)程序會跳轉(zhuǎn)到Flash的0x00010000處執(zhí)行用戶程序;如果該標(biāo)志區(qū)的最低四個(gè)字節(jié)為0x00008000,表示當(dāng)前程序運(yùn)行在低區(qū),跳轉(zhuǎn)程序會跳轉(zhuǎn)到Flash的0x00002000處執(zhí)行用戶程序。用戶程序正常執(zhí)行后,會按照設(shè)計(jì)進(jìn)行正常的程序采集、數(shù)據(jù)處理傳送。當(dāng)接收到升級命令后,用戶程序會跳轉(zhuǎn)到Flash的0x00000400處的Bootloader處進(jìn)行升級的一些操作。當(dāng)升級成功后,Bootloader程序更新當(dāng)前程序運(yùn)行區(qū)標(biāo)志,程序跳轉(zhuǎn)到新程序處運(yùn)行,如果升級不成功,返回升級前的程序。

  流程圖如下所示:

clip_image006

  3.2 跳轉(zhuǎn)程序的設(shè)計(jì)

  跳轉(zhuǎn)程序是分站上電后最先運(yùn)行的程序,根據(jù)當(dāng)前程序運(yùn)行區(qū)標(biāo)志,跳轉(zhuǎn)到相應(yīng)的用戶程序區(qū)執(zhí)行。本段程序占用Flash的最低1K字節(jié)空間,與Bootloader同在第0扇區(qū)。

  跳轉(zhuǎn)程序的啟動代碼僅初始化堆棧,不使用PLL和存儲加速功能。代碼1描述了跳轉(zhuǎn)程序的主要啟動代碼。

  ; Enter User Mode and set its Stack Pointer

  MSR CPSR_c, #Mode_USR

  MOV SP, R0

  SUB SL, SP, #USR_Stack_Size

  ; Enter the C code

  IMPORT __main

  LDR R0, =__main

  BX R0

  代碼1:跳轉(zhuǎn)程序啟動代碼

  當(dāng)跳轉(zhuǎn)程序確定要跳轉(zhuǎn)到高區(qū)用戶程序或者低區(qū)用戶程序后,使用函數(shù)指針跳轉(zhuǎn)到0x00010000處(高區(qū)用戶函數(shù)入口地址)或0x00002000處(低區(qū)用戶函數(shù)入口地址)。

  定義函數(shù)指針:

  void (*UserProgram)() ;

  指定入口地址:

  UserProgram = (void (*)()) (0x00010000);

  UserProgram = (void (*)()) (0x00002000);

  實(shí)現(xiàn)跳轉(zhuǎn):

  (*UserProgram)() ;

  要將用戶代碼精確定位到Flash的0x00010000處(高區(qū)用戶函數(shù)入口地址)或0x00002000處(低區(qū)用戶函數(shù)入口地址),需要使用編譯器的分散加載機(jī)制,將在Bootloader中詳細(xì)描述實(shí)現(xiàn)過程。

  另外,跳轉(zhuǎn)程序還在燒錄代碼的同時(shí)初始化當(dāng)前程序運(yùn)行區(qū)標(biāo)志,即對Flash的0x0001C000地址處寫入0x00008000,表示當(dāng)前用戶程序在低區(qū)。主要使用了編譯器的__at關(guān)鍵字:精確定位變量。需要注意的是,使用該關(guān)鍵字必須包含頭文件absacc.h。

  const uint32 x __at(0x0001C000)=0x00008000; //初始化用戶程序標(biāo)志區(qū),默認(rèn)運(yùn)行低區(qū)

  3.3 升級程序Bootloader的設(shè)計(jì)

  升級程序的好壞,在很大程度上取決于Bootloader設(shè)計(jì)的好壞。

  一個(gè)優(yōu)秀的IAP升級Bootloader,必須做好升級中出現(xiàn)故障等異常的處理。保證系統(tǒng)不會崩潰,即使升級失敗,也能返回升級前的程序。

  ? 有升級指令,進(jìn)行初始化工作(串口、定時(shí)器、看門狗)

  ? 接收升級數(shù)據(jù)包,檢測幀頭、長度、幀號、數(shù)據(jù)區(qū)校驗(yàn),最大程度的保證升級數(shù)據(jù)的完整性、正確性。

  ? 實(shí)時(shí)檢測接收狀態(tài),10 S內(nèi)沒有接收到數(shù)據(jù)或接收到的數(shù)據(jù)包都是錯(cuò)的,則退出升級,返回原程序。

  ? 接收的數(shù)據(jù)按照512字節(jié)一組寫入Flash,寫入后再讀出與原數(shù)據(jù)進(jìn)行對比校驗(yàn),校

  驗(yàn)成功后,本次編程Flash成功。允許連續(xù)3次編程Flash,三次都不成功,退出升級程序,執(zhí)行原程序。

  ? 升級成功后,更新當(dāng)前程序運(yùn)行區(qū)標(biāo)志,跳轉(zhuǎn)到新程序,同時(shí)原程序保存。

  本設(shè)計(jì)的Bootload位于Flash的0x400開始的扇區(qū)0存儲區(qū)內(nèi),使用分散加載機(jī)制,將程序的入口地址定位到0x00000400處。當(dāng)用戶程序接收到升級指令后,就會使用函數(shù)指針跳轉(zhuǎn)到這個(gè)入口處。

  3.3.1 使用IAP

  圖3-1 描述了使用IAP編程Flash所必須的步驟。

clip_image007

  3.3.1.1 定義系統(tǒng)參數(shù)

  在使用IAP前,需要定義一些系統(tǒng)參數(shù),比如系統(tǒng)時(shí)鐘、IAP中斷入口、輸入輸出緩存。

  #define IAP_CLK 11059200UL

  #define IAP_LOCATION 0x7FFFFFF1

  typedef void(*IAP)(uint32 [],uint32 []); //定義函數(shù)類型指針

  IAP iap_entry=(IAP)IAP_LOCATION; //設(shè)置函數(shù)指針

  unsigned long command[5] = {0,0,0,0,0};

  unsigned long result[2]= {0,0};

  代碼3-1:定義系統(tǒng)參數(shù)


上一頁 1 2 3 下一頁

關(guān)鍵詞: IAP Keil

評論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉