<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 基于IAP和Keil MDK的遠程升級設計

基于IAP和Keil MDK的遠程升級設計

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

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

本文引用地址:http://dyxdggzs.com/article/201612/341760.htm

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

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

  0 引言

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

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

  1 LPC2114的Flash規劃

  1.1 扇區描述

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

  表1.1 LPC2114 Flash 器件中的扇區

image

  1.2 Flash的扇區劃分

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

  2 IAP的原理與軟件設計

  2.1 IAP的原理

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

  2.2 IAP 命令

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

    

clip_image005

  圖2-1 IAP的參數傳遞

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

  表2-1 IAP 命令匯總

  IAP命令命令代碼描述

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

  將RAM內容復制到Flash51該命令用于編程 Flash 存儲器。受影響的扇區應當先通過(guò)調用“準備寫(xiě)操作的扇區”命令準備。當成功執行復制命令后,扇區將自動(dòng)受到保護。該命令不能寫(xiě)boot 扇區。

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

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

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

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

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

  2.3 IAP 編程函數接口

  IAP 功能可用下面的C 代碼來(lái)調用。

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

  #define IAP_LOCATION 0x7ffffff1

  定義數據結構或指針,將IAP 命令表和結果表傳遞給IAP 函數

  unsigned long command[5];

  unsigned long result[2];

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

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

  IAP iap_entry;

  設置函數指針

  iap_entry=(IAP) IAP_LOCATION;

  使用下面的語(yǔ)句來(lái)調用IAP。

  iap_entry (command , result);

  Flash 存儲器在寫(xiě)或擦除操作過(guò)程中不可被訪(fǎng)問(wèn)。執行Flash 寫(xiě)/擦除操作的IAP 命令

  使用片內RAM 頂端的32 個(gè)字節空間。如果應用程序中允許IAP 編程,那么用戶(hù)程序不應

  使用該空間。

  3 LPC2114升級實(shí)現過(guò)程

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

  3.1 總體思路

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

  流程圖如下所示:

clip_image006

  3.2 跳轉程序的設計

  跳轉程序是分站上電后最先運行的程序,根據當前程序運行區標志,跳轉到相應的用戶(hù)程序區執行。本段程序占用Flash的最低1K字節空間,與Bootloader同在第0扇區。

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

  ; 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:跳轉程序啟動(dòng)代碼

  當跳轉程序確定要跳轉到高區用戶(hù)程序或者低區用戶(hù)程序后,使用函數指針跳轉到0x00010000處(高區用戶(hù)函數入口地址)或0x00002000處(低區用戶(hù)函數入口地址)。

  定義函數指針:

  void (*UserProgram)() ;

  指定入口地址:

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

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

  實(shí)現跳轉:

  (*UserProgram)() ;

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

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

  const uint32 x __at(0x0001C000)=0x00008000; //初始化用戶(hù)程序標志區,默認運行低區

  3.3 升級程序Bootloader的設計

  升級程序的好壞,在很大程度上取決于Bootloader設計的好壞。

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

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

  ? 接收升級數據包,檢測幀頭、長(cháng)度、幀號、數據區校驗,最大程度的保證升級數據的完整性、正確性。

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

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

  驗成功后,本次編程Flash成功。允許連續3次編程Flash,三次都不成功,退出升級程序,執行原程序。

  ? 升級成功后,更新當前程序運行區標志,跳轉到新程序,同時(shí)原程序保存。

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

  3.3.1 使用IAP

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

clip_image007

  3.3.1.1 定義系統參數

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

  #define IAP_CLK 11059200UL

  #define IAP_LOCATION 0x7FFFFFF1

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

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

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

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

  代碼3-1:定義系統參數


上一頁(yè) 1 2 3 下一頁(yè)

關(guān)鍵詞: IAP Keil

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>