2017年11月18日 星期六

USB DIY--自學計畫 (N+2) --- USB HID BootLoader

雖然這是一篇不知道要稱為 USB DIY--自學計畫 (N+1) 幾了?

這也是原本就應該要交代的一篇USB DIY 技術內容,但一直沒時間整理寫下來。

也隨著MCU與韌體技術發展,也不知道這個東西對大家來說:還有沒有那個參考價值?

以現在MCU技術來說:除了一般Flash 燒錄技術外,對許多老MCU 架構來說:在硬體上

也都未必能支援所謂智能升級,因為這又牽扯到MCU 本身有沒有支援 BootLoader,

尤其是要藉由USB 介面來做韌體更新工作,這是一個非常重要的事,因為東西賣出去之後,

哪天你都不知道會碰到甚麼奇怪的技術支援,甚至有些技術支援還牽涉到韌體必須更新

這件事,總不能全部回收吧?要做到對客戶來說:無痛升級,船過水無痕。那原本釋出的

韌體程式就必須支援智能升級功能。尤其是像有些USB 介面工具的東西,那就需要了。

這篇文章的內容是依照我之前所開發的可程式化CDI 的下載傳輸線產品所整理的。

所以這是一個實際有販售的產品經驗,大家大可放心技術文章是否有實務經驗問題。


主控 USB MCU 為 Silicon Labs 的C8501F321 。當然還是八位元的8051 。

就是符合我說的:老 MCU ,原本就沒有 FLASH ,更沒有所謂智能升級的 BootLoader架構。

所以一切就得靠許多小技巧才能完成USB 智能升級功能。

幾個關鍵字先提一下: 8051、USB、Keil C 及 Visual C ++ (MFC)。

首先要注意的是:雖然是寫 BootLoader 程式,但最好是連應用程式一起發展,這樣子

在 IDE開發環境裡會比較容易維護,不用一下子搞不清楚改了哪一段Code 然後又搞不清楚

另一支相關程式沒改到:

(在這篇文章中,如果覺得圖形不意看清楚,就麻煩自行點選放大一下,不好意思了!)


至於如何在 Keil C IDE 環境裡如何維護這樣子的選項功能?不好意思,這也都是要自己

摸出來的,教了你也不一定下一次會自己設定,還是得用心去體會一下。


不同的環境設定會自動切換不同的編譯組譯程式組。還是一樣要自己下功夫。

接下來就是要事先規劃要使用多少程式記憶體來當作 BootLoader 空間?那就得看你自己

對於 BootlLoader 功能就作到甚麼程度?對不起,一般 UART 的Bootloader 我沒做過,

不知道,但對於USB 的 Bootloader 我是預留了 0x0000 ~0x13FF 。所以這樣子的話,

就得在所謂的 Startup.A51 中設定,(當然IDE 環境也有對應的設定!)

然後呢?那就得教程式說:那到底是要跑在一般應用程式裡呢?還是所謂的 BootLoader 呢?

簡單來說:就是要隨時任意的能控制程式到底是跑在一般應用程式呢?還是 Bootloader ?

當然啊~這些韌體程式最重要的還是你自己的應用程式,Bootloader 也只不過偶爾跑一次

而已。但我們在程式架構規劃還是希望把 Bootloader 擺在0x0000 最前面一段,因為它是

不應該會隨時長大的程式:

我們是在程式一跑起來時。(就是 STARTUP.A51) 中利用 2F.7 這個 BIT 值來讓Bootloader 

程式來判斷:Bootloader 的 Startup 程式為:USB_BL_STARTUP.A51。2F.7=1。

一般應用程式的Startup 程式為:USB_STARTUP.A51。2F.7=0。




一般來說,上電的 Hardware Reset 之後,都是應該跑在Bootloader 裡,沒辦法,這是 8051

先天架構上的問題,所以當Bootloader 跑進主程式 Main.C 之後,就會判斷程式控制權

要不要交給一般程式:



以上這段程式有兩個重點:

一個是C8051F321 特有的功能,就是程式可以藉由 Register 來判斷程式 Reset 是來自於哪一

種 reset :軟體 Reset ?或是硬體 Reset ?這兩個也是 C8051F321 特有的功能。只是它的硬體

reset 是利用產生 Flash Read/write Error 來產生的。

另一個就是一個系統應用的觀念:在系統ISP (智能升級)中有可能會發生不可以預期的斷電

或其他因素造成程式燒錄不正常,此時連 Bootloader 都不能死。所以這段程式的第二個就是

檢查燒錄最後填入的 Signature 來檢查,上回燒錄有沒有發生問題。

所以當系統要求進入燒錄過程:就是外部燒錄程式要求應用程式產生軟體Reset ,讓

bootloader 接手系統。否則就跑一般應用程式就可以了。




以上兩張圖就是說明不同的主程式在切換系統程式模式的部分,其實這都是透過PC 端的USB

應用程式可以輕易控制的。

----
至於,Bootloader 在支援應用程式介面時,要用多複雜的命令組?其實也不用太複雜,

我簡單列一 下:



無非就是清除,寫入及要求系統Reset  而已。至於要不要強化保證資料傳輸的正確性,

那也可以加入 CRC 檢查機制。至於那個 WriteValidation 就是我之前講的最後寫入檢查碼,

以確認整個燒錄動作完成。
---
對USB HID介面來說:就不要搞得太複雜,這一點我是覺得對USB 這一種傳輸介面來說

真的就簡單多了。不過這邊還是要強調一點:要注意的是不管哪一支程式,USB 最基礎基本

的 USB Enumeration 的宣告:Device Descriptor 一定是要一致的。免得在系統更新後,

還牽動作系統的重新安裝驅動程式。(你不要以為USB HID 還需要甚麼驅動程式?其實,

對作業系統來說,不同的USB Device Descriptor,它就認定是不同的裝置)

所以我們就用兩個簡單專屬的 Report ID 來分別負責 Interrupt IN 及 Interrupt OUT 就可以了。


這樣子就可以了。

所以接下來就可以在PC端寫相關的應用程式了:


所以我們就可以在不同的 Report ID 下定義不同的命令組,來完成我們所需要的ISP 功能。

而所對應的就是標準不同的 Interrupt IN 及 Interrupt OUT pipe 應用副程式:




所以我們就可以很容易地透過這些命令來操控韌體程式的許多動作:包括切換不同的模式:

Bootloader 或是 一般應用程式:下圖是一般應用程式模式:


 而下圖則是在Bootloader 模式下等待程式更新模式:


當然啊,這只是一個簡單的測試應用程式。你也可以把這些程式功能包含到真正產品

軟體中,去完成所謂的韌體程式自動更新工作。
---
好了~你以為這樣子就講完了?喔~不是的。其實在兩種韌體程式中最麻煩的不是一般

程式而已,最討厭的就是中斷程式的處理,因為 8051 是有固定的中斷向量表。

而這些中斷向量表又全部被你集中寫在 Bootloader 中了,未來你在系統發展中,可以

隨時會調整中斷副程式,會造成中斷程式忽長忽短的。那要怎麼安排這些中斷向量表呢?

這一部分就有一點小技巧了:那就是把所有中斷向量表全部導到應用程式端去:也就是

超過 0x1400 之後:



但是重點是 USB 中斷要特別處理,因為我們就是利用USB 中斷來完成程式更新的,所以

一部分USB 程式更新程式要留在Bootloader 這一段以內。

所以在 Keil C 編譯後的規劃來看:


上圖就是BootLoader 的中斷向量表,全跑到 0x1400 之後了。就留下一部分的USB 中斷。

而下圖則是一般應用程式的中斷向量表,完全接手Bootloader 轉過來的中段向量位置。


當然啊~在應用程式裡也未必會把所有中斷向量表全用上,所以我們才會看到一般在韌體

程式規劃中的中斷向量表。如果這兩張圖不清楚的話,則下圖比較圖最清楚說明:


----
好了,算是簡單的交代一下如何利用 USB HID 介面來完成系統更新工作。

我說過了,新一代的MCU 幾乎都會支援ISP 智能升級功能,只是使用介面不盡相同。

許多工作原廠都會想辦法提供一些標準的參考程式供你參考。

但很不幸的是:有些是場老架構的MCU 一來本來就沒有統一的ISP 介面,二來也有可能

不太想在支援這些老MCU 市場應用,所以寫這一篇文章,也算是對過去慢慢累積N 年

的USB DIY 文章做一個最後一塊版圖的完成工作。

---
其實我自己這幾年很少接觸這些傳統MCU 應用市場了,也很少也會花很多時間去研究

這些程式架構的東西,一來年紀大了,多的時間都是陪退休的賈老師或是看一些比較

輕鬆一點的書籍:像是歷史史書之類的。二來,現在在工作上也完全跳脫純電子應用領域

也是邊學邊指導新一代年輕人接手一些系統研究與發展工作。

您說:會不會覺得可惜?不會啊~我覺得這是更有意義的事。因為我們畢竟都會慢慢老去。

能真正在完全掌握的東西真的很有限了。至於過去自己所累積的許多不管是硬體或軟體的

東西,就這樣子慢慢流失,會不會覺得感傷?那又怎樣?

真的。連我自己現在所接觸的系統應用MCU 都已經不是 八位元MCU 了,而是非常冷門

的 32 位元車用MCU。所以我都很懷疑:未來幾年還有多少八位元的MCU 還會出現我身

邊?那幹嘛還要死抱著不放呢?所以我才想趕快整理這些文章內容。

只是不好意思地是:真的把時間拖得太久了,如果緩不濟急的沒幫上各位的需求的話,

也只能說聲抱歉了。

或許改天可以用不同的職場經驗來告訴大家許多不同的屬於工程師一生的精采的歷練。

連我自己都覺得很幸運的有這樣神奇的際遇。

改天再跟各位報告了。先暫時保留一下。

謝謝各位在USB DIY 這一塊領域的批評與指教。





8 則留言:

  1. 這也是我正在做的.只是不會寫PC.後來就找到手機APP也有USB HID,沒想到就可以用。被手機APP救到一把。另外也找到node.js也可以用。但C也不用太担心(之前排名大退化),後面webAssemble就要起來。C也可以寫網頁應用(包括3D game)。

    回覆刪除
    回覆
    1. 很棒喔!或許改天也可以看到你的經驗分享。

      不過,我自己卻不禁暗自淚潸潸...果然看到移動裝置取代傳統PC應用了。

      所以我才說:這樣子的技術分享的時效性也會備受挑戰的。

      沒關係,我說了:我們老人家也只能如此。看到世代交替也是一件可以欣慰的事啊。

      謝謝你小小的經驗分享。

      刪除
  2. USB是Intel主推,當PC是主流時,可以保有霸主地位。但現在電腦的主角是NB及手機。NB上還有USB,但NB的厚度也是被連接頭給限制了。反而是手機在創新規格,現在USB新一代已是手機廠在主導。而NB未來也有被手機廠商給主導規格。今年手機皆使用USB typeC,我想這是最後一代了。再來的手機應是連孔也沒有。
    時代的前進,腳步越來越快!

    回覆刪除
    回覆
    1. 簡單一句話:PC 時代已經過去了,PC (應該也包括NB)已經成為一種成熟產品。

      已經不太需要還要投入太多技術研發資源了,就像我在車用電子領域的道理是一樣的。

      很多車廠都已經發表說:20xx年不再開發汽油引擎(不代表不生產喔),只是因為在許多技術

      領域來看是:投入研發與產出的CP 值不高了。

      我想USB也是如此。甚至有些硬體規格也是如此這般,你可能投入要投入很龐大的研發經費,

      結果所能得到的效果是有限的,譬如USB 2.0 到3.0 其實所能創造的平易近人的使用環境

      絕對沒有早期2.0 那麼簡單。是的~3.0 比較快,但應用領域可能是龐大的資料傳輸,

      畢竟市場肯定是比較小,所能攤提的研發成本有限,結果惡性循環的造成使用成本高。

      大家喜歡追求技術,挑戰極限,但並不代表那是一個可以讓大家都可以接受的市場。

      我想這是許多工程師要思考的問題。

      刪除
  3. 請問版主是在EL公司嗎
    這個USB還有在研究?

    回覆刪除
    回覆
    1. 謝謝你的關心。我目前不在EL 了。

      至於USB 的東西,沒有所謂的研究,就是一直在用,因為這已經是很成熟的東西。

      只要有需要我都隨時拿出來用,譬如隨便搞個治具或 Tools 的東西。

      有時在浩瀚的網路世界裡找,還不如自己做一個比較快。您說不是嗎?

      刪除

    2. 真的就如chamber大哥所說的,
      有時要找個工(治)具或tools,
      都會覺的不大順手或不大順自已的想法,
      為了遷就工具,
      花費的時間還真的是不少,
      所以最近也在練習MFC與usb相關連結,
      也把自已在這一個領域比較不足的地方稍微補強。

      刪除
    3. 喔~沒關係,如果有哪邊我可以幫上忙的,也不用客氣。

      我說了:我們老人家能做也不多,能多幫幫後進者比較重要吧。

      刪除