最近,在研究F28035平臺下采用CAN總線的方式更新Flash的方法。取得了一些進展,現介紹一下具體的實現思路。
這里所說的BootLoader并不是芯片自帶的Boot ROM,而是經過Boot ROM引導,通過Flash方式啟動后,執行C語言環境下的MCU程序,也稱為二次BootLoader。BootLoader需要配合PC端上位機使用,所以本文也涉及到了PC端上位機的開發。
下面的內容從四個方面介紹:
1)BootLoader程序實現的功能
2)F28035系列芯片的啟動流程
3)MCU中BootLoader實現的方式
4)C#開發PC端上位機
硬件:
TI的C2000平臺下的F28035開發板(帶CAN2.0總線收發功能)
CAN盒:周立功USBCAN-2E-U
下載仿真器:XDS100V3
軟件:
CCS10.3.1
Visual Studio 2022
操作系統:
WIN10 IoT 企業版 LTCS(21H2)
一、BootLoader實現的功能
將MCU中的程序代碼根據功能,可以劃分成兩個部分:
1)BootLoader(以下用BL代指)
2)Appilication(以下用app代指)
這兩部分代碼的關系如下圖所示:
如上圖,當MCU上電后,通過復位向量的跳轉,進入Boot ROM,通過Boot ROM的引導,選擇Flash方式啟動,然后執行FlashA扇區中的BootLoader程序,BL通過CAN總線接收app的源代碼,并寫入到指定的MCU內部Flash扇區(比如C-H扇區),然后對app代碼進行校驗,確保接收的app源代碼正確后,通過復位看門狗,重新啟動MCU。MCU重啟后,再經過復位向量--BootROM--BL--app這樣的步驟,最終將MCU的軟硬件的資源交給app,app來完成用戶要求的功能。
Flash存儲區域經過這樣劃分,保證了BL與app的隔離。app可以獨立于BL進行開發,只要在app的CMD文件中將FlashA扇區空閑出來,不用就行,并不需要更改其它的地址空間中的內容。而且app也可以不用BL加載,直接通過TI官方的下載器,下載到MCU,app代碼也能正常工作,增加了BL使用的可選擇性。
至于CMD文件如何編寫、如何從BL跳到app的入口等等,這些技術細節,會在后面詳細闡述。
總結一下BL寫入Flash的具體步驟:
1)先將BL編譯完成的.out文件通過下載器(如XDS100V3)下載到MCU中,成功后,MCU關電。
2)連接好CAN盒,啟動C#編寫的上位機程序,選擇好對應的要寫入MCU的app程序(.out)文件,此時上位機開始嘗試主動與MCU通訊,通過CAN發送握手信號。
3)MCU上電,接收到上位機發送的握手信號后,上位機和MCU開始通訊,MCU接收完整的app代碼文件,并寫入Flash指定扇區。
4)app代碼校驗成功后,MCU通過復位看門狗,使MCU重啟。
5)MCU重啟后,首先進入BL,當MCU在指定時間內沒有接收到上位機發出的握手信號時,BL會將程序指針指向app的入口地址。然后app程序開始執行。
6)當app沒有被成功寫入時,則始終停留在BL程序中。
二、F28035的啟動流程
理解MCU上電后的啟動流程,對于開發BootLoader來說是非常重要的。對于C2000系列的MCU來說,啟動流程基本一致,只是個別的跳轉地址不一致。這些不一樣的地方需要查找對應型號的MCU手冊來確定。下面就以F28035芯片為例來說明:
F28035 MCU內存映射如下:
可看到此表格的最下端(地址:0x3F FFC0至0x3F FFFF),是上電啟動后CPU的中斷向量表(Vector)。當MCU上電后,首先將程序指針,指向此區域的0x3F FFC0處。此過程是固化在MCU硬件中的,不可改變。在0x3F FFC0處只能放下兩個字節(16Bit)數據,功能就是讓程序指針指向Boot ROM區域的InitBoot函數(0x3F F4B0)。下圖是Boot ROM區域的放大:
注意根據不同型號的MCU,InitBoot函數(0x3F F4B0)地址也是不同的,具體是多少要查找手冊,幸運的是這個跳轉也是硬件自動完成的,不需要干預。
從上圖中,可以看到紅框中的區域就是Boot ROM了。這個區域是固化(只讀)在內存中的,用戶不能寫入數據。從Boot ROM內部的功能劃分來看,主要實現以下幾部分功能:
1)Boot ROM版本和Boot ROM校驗
2)Flash API庫:我們需要的Flash擦除與寫入函數就在此庫中。
3)Boot引導函數:包括InitBoot函數和其它的功能函數。
4)定點型的數學函數:如sin、cos等。
5)定點型的數學表格。
最重要的就是2)和3)這兩項。
Flash API庫里包含著一些Flash相關的操作函數,如擦除、寫入、數據校驗等功能。在BL代碼中Flash操作需要的函數都在這里能夠找到。當然,也可以在編譯BL代碼時,從芯片外部引入TI官方提供的專門FlashAPI庫,但是這樣就增加了BL的代碼體積。最好就是用這個包含在Boot ROM中的FlashAPI。如果要用BootROM中的FlashAPI,需要將一個符號庫引入到BL的工程文件夾中。
當程序指針指向InitBoot函數,就開始依次執行下面的功能:
上圖中SelectBootMode()函數做了簡化,具體技術細節請參見手冊。
_c_int00()在跳轉到程序入口之前完成了以下的工作
1) 定義系統棧.stack,并初始化棧指針,配置相關寄存器
2) 初始化全局變量(.cinit)
3) 若使用C++,還會完成全局對象構造(.pinit)
4) 調用main函數運行C程序
5) 當main函數return時,調用exit函數
注意:_c_int00()是在rts2800_ml.lib庫中。當修改程序代碼后,再編譯時,程序的入口地址就可能和上次的不一樣。到此,MCU就完成了從上電到C程序執行的全過程。
BL與app各自編譯后的入口地址是不一樣的。
因為BL的程序代碼先下載到MCU中,app的代碼通過BL的CAN總線,下載到MCU的Flash扇區里,所以程序指針先指向BL的_c_int00(),執行BL的代碼,然后BL再將程序指針指向app的_c_int00(),建立app的C語言環境。即app的內存分配方式會完全覆蓋BL的內存分配方式,所以app和BL這兩個工程的CMD編寫中,除了各自代碼存放的Flash扇區要隔離開以外,象RAMM0、1和RAML0-3分配的方式可以完全不一樣,最終app的內存分配也會覆蓋BL的內存分配,所以app通過BL下載到指定Flash后能正常運行,而此后BL代碼將不能再執行,除非MCU重新上電或讓app將程序指針指向BL的入口地址。(待續)