1. 程式人生 > >CRC校驗原理及STM32 IAP線上升級程式

CRC校驗原理及STM32 IAP線上升級程式

CRC校驗原理:

什麼是CRC校驗?

CRC即迴圈冗餘校驗碼:是資料通訊領域中最常用的一種查錯校驗碼,其特徵是資訊欄位和校驗欄位的長度可以任意選定。迴圈冗餘檢查(CRC)是一種資料傳輸檢錯功能,對資料進行多項式計算,並將得到的結果附在幀的後面,接收裝置也執行類似的演算法,以保證資料傳輸的正確性和完整性。

CRC校驗原理:

其根本思想就是先在要傳送的幀後面附加一個數(這個就是用來校驗的校驗碼,但要注意,這裡的數也是二進位制序列的,下同),生成一個新幀傳送給接收端。當然,這個附加的數不是隨意的,它要使所生成的新幀能與傳送端和接收端共同選定的某個特定數整除(注意,這裡不是直接採用二進位制除法,而是採用一種稱之為“模2除法

”)。到達接收端後,再把接收到的新幀除以(同樣採用“模2除法”)這個選定的除數。因為在傳送端傳送資料幀之前就已通過附加一個數,做了“去餘”處理(也就已經能整除了),所以結果應該是沒有餘數。如果有餘數,則表明該幀在傳輸過程中出現了差錯。

模2除法:

模2除法與算術除法類似,但每一位除的結果不影響其它位,即不向上一位借位,所以實際上就是異或。在迴圈冗餘校驗碼(CRC)的計算中有應用到模2除法。如:

CRC校驗步驟:

CRC校驗中有兩個關鍵點,一是預先確定一個傳送送端和接收端都用來作為除數的二進位制位元串(或多項式),可以隨機選擇,也可以使用國際標準,但是最高位和最低位必須為1;二是把原始幀與上面計算出的除數進行模2除法運算,計算出CRC碼。

具體步驟:

1. 選擇合適的除數

2. 看選定除數的二進位制位數,然後再要傳送的資料幀上面加上這個位數-1位的0,然後用新生成的幀以模2除法的方式除上面的除數,得到的餘數就是該幀的CRC校驗碼。注意,餘數的位數一定只比除數位數少一位,也就是CRC校驗碼位數比除數位數少一位,如果前面位是0也不能省略。

3. 將計算出來的CRC校驗碼附加在原資料幀後面,構建成一個新的資料幀進行傳送;最後接收端在以模2除法方式除以前面選擇的除數,如果沒有餘數,則說明資料幀在傳輸的過程中沒有出錯。

CRC校驗碼計算示例:

現假設選擇的CRC生成多項式為G(X) = X4 + X3 + 1,要求出二進位制序列10110011的CRC校驗碼。下面是具體的計算過程:

①將多項式轉化為二進位制序列,由G(X) = X4 + X3 + 1可知二進位制一種有五位,第4位、第三位和第零位分別為1,則序列為11001

②多項式的位數位5,則在資料幀的後面加上5-1位0,資料幀變為101100110000,然後使用模2除法除以除數11001,得到餘數。

③將計算出來的CRC校驗碼新增在原始幀的後面,真正的資料幀為101100110100,再把這個資料幀傳送到接收端。

④接收端收到資料幀後,用上面選定的除數,用模2除法除去,驗證餘數是否為0,如果為0,則說明資料幀沒有出錯。

STM32 IAP線上升級步驟:

首先談談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點的寫法。

一般的我們可以:

將  flash  分成四個區域   地址區域由低到高  
最低地址的
1號區域放bootloader程式  的地址區間
2號區域flash放一個存放操作標誌數的區間
3號區域app1的地址區間
4號區域app2的地址區間

每回主控上電或者復位
  先去讀取2號區域的數值  
     假設如果區域2 的 flash的標誌數讀回來是
         1跳轉執行3號區域app1的程式               執行app1的時候如果檢測到升級操作指示
                   寫2號區域flash標誌數4  軟後軟體復位微控制器
               沒有升級指示  正常執行app1
         2跳轉執行4號區域app2的程式
               執行app2的時候如果檢測到升級操作指示
                   寫2號區域flash標誌數3  軟後軟體復位微控制器
               沒有升級指示  正常執行app2
         3執行bootloader升級app1區域
                 刷寫完程式以後並校驗該程式區域
                     如果校驗正確   寫區域2flash的標誌數為 1 軟後軟體復位微控制器
                     如果校驗錯誤   寫區域2flash的標誌數為 2 軟後軟體復位微控制器
         4執行bootloader升級app2區域
                刷寫完程式以後並校驗該程式區域
                     如果校驗正確   寫區域2flash的標誌數為 2 軟後軟體復位微控制器
                     如果校驗錯誤   寫區域2flash的標誌數為 1 軟後軟體復位微控制器

以上就是我的升級思路
但是這裡要考慮到程式執行錯誤的情況   就是硬體錯誤  跑飛
我都會在有可能出現錯誤時掉進的while裡
寫一段軟體復位程式
這段錯誤處理程式可以這麼寫
先讀取  區域2flash的標誌數
看看現在執行出錯的app是哪個區域的
如果是區域3的app1那麼就把區域2的flash標誌數寫為2  然後軟體復位  這樣復位以後執行的就是app2了
如果是區域4的app2那麼就把區域2的flash標誌數寫為1  然後軟體復位  這樣復位以後執行的就是app1了