1. 程式人生 > >stm32線上升級

stm32線上升級



不需要拆機就能對產品進行韌體升級是很多人想要的效果,不僅方便而且節省精力和成本。那麼如何完成這項工作呢?接下來所介紹的Bootloader就可以完成這項工作,通過Bootloader載入程式完成韌體的升級。下面來淺析STM32Bootloader設計。

首先談談stm32的ISP和IAP區別和聯絡。 ISP(In-System Programming)在系統可程式設計,指電路板上的空白器件可以程式設計寫入終端使用者程式碼, 而不需要從電路板上取下器件,已經程式設計的器件也可以用ISP方式擦除或再程式設計。IAP(In-Application Programming) 指MCU可以在系統中獲取新程式碼並對自己重新程式設計,即可用程式來改變程式。ISP和IAP技術是未來儀器儀表的發展方向。   1  ISP和IAP的工作原理

  ISP的實現相對要簡單一些,一般通用做法是內部的儲存器可以由上位機的軟體通過串列埠來進行改寫。對於微控制器來講可以通過SPI或其它的序列介面接收上位機傳來的資料並寫入儲存器中。所以即使我們將晶片焊接在電路板上,只要留出和上位機介面的這個串列埠,就可以實現晶片內部儲存器的改寫,而無須再取下晶片。
  IAP的實現相對要複雜一些,在實現IAP功能時, 微控制器內部一定要有兩塊儲存區,一般一塊被稱為BOOT區,另外一塊被稱為儲存區。微控制器上電執行在BOOT區,如果有外部改寫程式的條件滿足,則對儲存區的程式進行改寫操作。如果外部改寫程式的條件不滿足,程式指標跳到儲存區,開始執行放在儲存區的程式,這樣便實現了IAP功能。
  2 ISP和IAP的優點

  ISP技術的優勢是不需要程式設計器就可以進行微控制器的實驗和開發,微控制器晶片可以直接焊接到電路板上,除錯結束即成成品,免去了除錯時由於頻繁地插入取出晶片對晶片和電路板帶來的不便。
  IAP技術是從結構上將Flash儲存器對映為兩個儲存體,當執行一個儲存體上的使用者程式時,可對另一個儲存體重新程式設計,之後將程式從一個儲存體轉向另一個。
  ISP的實現一般需要很少的外部電路輔助實現, 而IAP的實現更加靈活,通常可利用微控制器的序列口接到計算機的RS232口,通過專門設計的韌體程式來程式設計內部儲存器,可以通過現有的INTERNET或其它通訊方式很方便地實現遠端升級和維護。 IAP的編寫流程 設計思想
        由Bootloader負責檢測SD卡中是否有韌體更新所需的BIN檔案。如果檢測到所需要的BIN檔案,則開始複製檔案更新韌體。更新結束後跳轉到指定的地址開始執行最新的程式。   知識要點   STM32內部FLASH的起始地址為0X08000000,Bootloader程式檔案就從此地址開始寫入,存放APP程式的首地址設定在緊跟Bootloader之後。當程式開始執行時,首先執行的是Bootloader程式,此時Bootloader檢測SD卡中的BIN檔案並將其複製到APP區域使韌體得以更新,韌體更新結束後還需要跳轉到APP程式開始執行新的程式,完成這最後這一步要了解Cortex-M3的中斷向量表:
  程式啟動後,將首先從“中斷向量表”取出復位中斷向量執行復位中斷程式完成啟動,當復位中斷程式執行完成後才跳轉到main函式。由此可見,在最後一步的設計中需要根據存放APP程式的起始地址以及中斷向量表來設定棧頂地址,並獲取復位中斷地址跳轉到復位中斷程式。接下來開始分析程式設計步驟。   Bootloader程式設計   1.確定存放APP程式的首地址   #define FLASH_APP_ADDR 0x08010000 //應用程式起始地址(存放在FLASH)上一句程式碼中是0X08010000可以看出,留給Bootloader程式的儲存空間大小為64K。存放APP程式的起始地址為0X08010000。   2.Bootloader檢測是否有BIN檔案   gCheckFat = f_open(&FP_Struct,"/APP/LIKLON.BIN",FA_READ);//判讀gCheckFat確定上面的程式碼是檢測是否存在liklon.bin這個檔案存在,其中liklon.bin檔案就是韌體升級所需要的BIN檔案。   3.複製檔案到指定地址   上一步中如果gCheckFat為0則表示存在所需BIN檔案,則可以執行這一步。f_read (&FP_Struct,ReadAppBuffer,512,(UINT *)&ReadNum); //讀取512個位元組將512個位元組轉換為256個16位的資料存放在ChangeBuffer陣列中,準備寫入FLASH。FlashWrite(FLASH_APP_ADDR + i * 512,ChangeBuffer,256); //向指定地址寫入讀出資料向APP程式區寫入512個位元組的資料。按照這樣讀取寫入,就可以完成對APP程式區的更新。 4.跳轉到新程式執行   更新完程式後就需要跳轉到新程式開始執行,具體實現看下面程式碼:   typedef void (*iapfun)(void); //定義一個函式型別的引數
  iapfun jump2app;
  __asm void MSR_MSP(u32 addr) //設定堆疊指標
  {
        MSR MSP, r0
        BX r14
  }
  //跳轉到應用程式段
  //appxaddr:使用者程式碼起始地址.
  void iap_load_app(u32 appxaddr)
  {
        if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //檢查棧頂地址是否合法.
        {
              jump2app = (iapfun)*(vu32*)(appxaddr+4);//使用者程式碼區第二個字為程式開始地址(復位地址),此處檢視中斷向量表可知
              MSR_MSP(*(vu32*)appxaddr);//初始化APP堆疊指標(使用者程式碼區的第一個字用於存放棧頂地址)
              jump2app(); //跳轉到APP,執行復位中斷程式
        }
  }
  APP程式設計注意   1.編譯軟體需要做出設定:
  在Bootloader程式中已經指定了APP程式儲存的起始地址為0x08010000,所以在APP程式設計時需要將編譯軟體這裡做出設定,修改起始地址和大小。   2.修改system_stm32f10x.c檔案
  同樣是針對於APP的起始地址改變而修改這裡的偏移量,如上圖所示。   文中只是簡單的介紹了關於Bootloader程式的設計,作為拋磚引玉,大家可以繼續深入,新增資料校驗和程式加密等。 ///////////////////////////////////////////////////////////////////////////////////跳轉函式具體說明 1、函式原型: void Jump_Address(void) { if (((*(volatile u32*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) { test = (*(volatile u32*)ApplicationAddress); JumpAddress = *(volatile u32*) (ApplicationAddress + 4); Jump_To_Application = (pFunction) JumpAddress; __set_MSP(*(volatile u32*) ApplicationAddress);                 Jump_To_Application(); } } 2、if (((*(volatile u32*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)分析: ApplicationAddress存放的是使用者程式Flash的首地址,(*(volatile u32*)ApplicationAddress)的意思是取使用者程式首地址裡面的資料,這個資料就是使用者程式碼的堆疊地址,堆疊地址指向RAM,而RAM的起始地址是0x20000000,因此上面的判斷語句執行:判斷使用者程式碼的堆疊地址是否落在:0x20000000~0x2001ffff區間中,這個區間的大小為128K,筆者查閱STM32各型號的RAM大小,目前RAM最大的容量可以做到192K+4K,時鐘頻率為168MHZ。一般情況下,我們使用的晶片較多的落在<128K RAM的區間,因此上面的判斷語句是沒有太大問題的。
3、經過2的分析,test儲存的就是堆疊地址(並且是應用程式堆疊的棧頂地址),檢視STM32的向量表,可以知道:棧頂地址 + 4 存放的是復位地址,因此JumpAddress存放的是復位地址。
4、呼叫__set_MSP函式後,將把使用者程式碼的棧頂地址設為棧頂指標
5、Jump_To_Application();的意思就是設定PC指標為復位地址。
CORTEX-M3上電後後檢測BOOT引腳的電平來決定PC的位置。例:BOOT設定為FLASH啟動,啟動後CPU會先取兩個地址:一個是棧頂地址,另一個是復位地址。因此才有了第4、第5點的寫法。