2013年12月21日 星期六

USB HID Class BootLoader DIY (二)--- 簡介


這是繼續上一篇: USB HID Class BootLoader DIY (一)--- 前言

的內容,這中間雖然寫一篇引起很大迴響的文章,但我們還是回頭把該交代的

事情給做完吧。有時聽別人講故事很容易,真的要您做,就未必也能做出一篇

精彩的人生故事啊。

----

如何要利用USB 的HID 做到Bootloader  ISP?! 在前一篇文章中有提到原廠的一篇

Application Note :

 http://www.silabs.com/Support%20Documents/TechnicalDocs/AN200.pdf

他裡面有許多基本觀念,我就不再重複描述了。我就直接利用HID Class 的

方式直接給他實現化。

原廠也有一份HID 的參考範例程式,不是公布在一般網站上。Google 不到。

我是透過Agent 管道拿到的,所以我也沒辦法從我這裡提供這一支範例程式。

有興趣者可以去接洽您的Agent 。不過呢?以我自己跑過這一支程式,

說真的~也不好用、也有問題。我就說明如下。

---
 基本上,要做到可以ISP 更新韌體程式,在您的目標MCU 身上一定要提供

相關的介面...不管是硬體的作法?還是韌體的作法,這包括USB 或是UART。

主要就是要透過PC 端的應用程式來完成。當然啊...為了避免更新失敗造成

"永久的傷害"--- 就是非得要回收全部更新程式不可。在這一塊的Bootloader

與PC 端就要有一定程度的通訊協定來保證資料完整性。...當然這樣子的

通訊協定就非USB 莫屬了...因為USB 在硬體上相對UART 來說:真的比較嚴謹。

出錯的機會比較少。

以下這一張圖就是簡單說明在這樣子的 Firmware Based ISP 架構下的ROM 配置:

基本上:他一定是同時存在兩支可以獨立運行的F/W : Bootloader 與Application F/W。

但MCU 一次也只能跑其中一支,沒辦法同時跑兩支韌體,他又不是多核心嘛!


當然啦...以前我就有強烈的懷疑過原廠的 3E00 以後不能用?這一個Page 應該是

硬體燒錄程式C2 介面的程式碼。不過,他一定用硬體做的...方法很簡單,

我是覺得也沒必要去研究他,因為只要您搞過像 JTAG 這個東西應該就知道。

至於我們自己要用Firmware 來完成 ISP 的Bootloader ,那您自己本身就要懂一點

MCU 的基本架構與運行的基本原理。譬如:像8051 這麼老的MCU ,當初也沒過

他有一天要支持Bootloader...所以我們也只能從現有的架構去找出方法。

原則上8051 一開機就是從 0x0000 跑起。所以Bootloader 就得一定從 0x0000 擺起。

如上圖所示。而您真正未來要Update 的Firmware Code 就得另外從 0x1?00 擺起。

至於0x1?00 要用多少?就看您自己的程式功力。

之前我在USB DIY 講座(七)-- USB Controller 提到的那一棵USB Controller ,

我們是用了 2KBytes 來當Bootloader,他可以 2KBytes 做到是因為他有部分是

用硬體上支援,而且是用組合語言寫的...Code 小小的是合理的。原廠提供的

HID Bootloader 約4~5 KBytes。也差不多啦。不過~原廠這一支範例程式只有

教您如何寫一支Bootloader。卻沒有教您如何同時讓Bootloader 與Application

同時存在。這樣子一來,您的USB Firmware 產品就無法一次生產,您就得先

用別的方法先把Bootloader 先預先燒錄在MCU 上,再利用Bootloader 來燒錄

您真正的Application F/W。當然啊~他也沒教您如何讓MCU 從Application F/W

再跳回Bootloader 狀態。就是我上圖所示的兩條紅線箭頭如何應用自如的切換在

兩支韌體之間。下圖就是原廠所附的PC 端應用程式:


看到沒~他只有Exit Bootloader Mode...然後當然就是進入Application F/W Mode

而當您重新開機後,當然就一定得要進入Application F/W Mode (您的標準應用程式)。

那下回如何再進入Bootloader 呢?!原廠範例沒交代。量產後真的碰到要ISP 怎麼辦?

當然在上述的那一篇Application Note有提到可以利用 I/O 來切換,但如果一般

USB 產品都是包裝好好的~難道您還要留一個ISP 啟動開關?很奇怪吧。

-----
所以我就自行稍微改寫一下韌體與PC 端程式:加入一個檢查機制,讓我上層的

PC 應用軟體知道我的MCU 是跑在Bootloader ?還是Application Mode 下。

然後下面那一個Exit Bootloader Mode 就會自動的在這兩者之間切換。


原廠的範例中是利用寫一個指令Access 到他的0x3FFF ,他就自動產生 Flash Error Reset。

就會跳進剛ISP 燒錄好的Application mode。而我們在Application Mode 裡呢?

就利用USB HID Command 方式讓MCU 產生一個Software Reset 。(此MCU 有支援 !)

當然啊~因為MCU 一上電,還是從Bootloader 先跑,檢查完Reset  機制後才決定

留在Bootloader mode 呢?還是 Application mode。

---
所以一般我們要準備這一種支援ISP 功能的MCU目的就是擔心改天量產出貨後

有需要重新更新韌體程式,但這一種現象也不是我們一開始出貨時就想碰到的,

最好的方式還是把產品一次搞定,而既然要留這樣子的介面功能,

就一開始把兩個同時搞定。所以在您的IDE 開發平台上就要同時支援這

兩組 Firmware 。讓您的開發平台可以很容易的同時維護這兩支Firmware :

下圖就是我整理的開發平台,這是利用Keil C 的開發平台。


我們可以看到有一個USBHID_ISPBOOT 是用來維護Bootloader 的;而另一支

USBHID_APP 就是拿來開發正常的韌體程式的。

很重要的一點是:USB 的基本宣告是最好Bootloader 與 Application 兩者韌體程式

是一樣的,否則客人會發現這一個奇怪的動作....雖然用HID 已經不需要驅動程式了。

所以這一點就說明了USB HID 真的比另一種USB Bulk 方法好一點。

----

至於為什麼8051 可以從原來Bootloader 0x0000 的位置跳到0x1?00 的執行位置?

最重要的還是在於中斷向量表的重新導向,這一種方法很早就有人這樣子做了,

我如果記得沒錯的話,以前林老師在寫國內第一本關於8051 書時,他當初也

有出了一塊 Flag51 的版子,他用的方法就是把要學習的8051 程式碼導到 0x8000 

的位置。只不過,那時候林老師是用組合語言的方法,對現在許多學生來說

可能有點太難理解了,現在像Keil C 這樣子的開發平台來說:就很容易可以幫

您處理:



其中唯一比較要留意的地方就是:USB 的中斷向量位置。要分成兩組。

因為您的Bootloader 要用這個USB 中斷,您的Application F/W 也要用,

所以就得要靠一個flag :2F.7 (7FH) 。來區別判斷。但因為一般

8051 Reset Boot 起來時,都會做clear RAM (memory) 的動作,所以

Default 2F.7 (7FH) 這個值都會是零。所以Default 就是Bootloader mode。 
------------

也就是因為要同時支援 Bootloader 與Application 的USB 介面,所以USB 的

Device Description 也要同時支援兩組,當然最好就是宣告一致。這也是這

一支Bootloader 程式會稍微大一點的原因。因為USB 的Device Description

是這一支Bootloader 最大的副程式。當然如果真的要再縮小Bootloader ,

我想應該還是可以的~只是真的要多一點心思來挑戰,不只要縮小,而且

每一次縮減Bootloader Code 都要以一個Page (512 Bytes)為單位才有意義。

否則,Bootloader 要拿Flash 來Erase 與Write 也不方便。

-----
整理寫這一種程式最大的成就就是:只要您寫對就是對的,不太可能您搞錯

想法或作法還可以矇到可以成功。因為一棵MCU 能真正Boot 起來跑程式

還是有一定的嚴謹性的,可不能隨隨便便就可以讓您 ISP 的。

如果您真的搞得懂這樣子的流程與作法的話,不管您是用USB Bulk 方法或是

HID 。甚至要用UART ~應該原理是一樣的啦。

---
-----
---

備註:

1. 原本要挑戰真正"無縫" 接軌的ISP 功能:就是當您Update 成功韌體時,

USB 可以不用再執行一次Plug and play (就是Device Enumeration),但沒有成功。

因為在這一棵USB MCU 中,他的USB Register 在Reset 之下硬體會把那個

Pull-high 電阻放開...所以一定會造成USB Un-plug 的現象。但我認為要做到

"無縫" 接軌的ISP 功能應該也是可以。因為您可以發現原廠的USB Debug

Tools 在Keil IDE 環境與原廠燒錄應用程式兩者之間,他是會自動更新韌體的。

但我從USB 分析儀看到的是:原廠沒有Reset MCU ,他的作法應該只是

更新部分韌體而已...這個韌體是在一個特定的ROM Address 區域裡。

這一種ISP 方法也行,只是真的一開始您就得要好好的規劃您的韌體程式架構。

要做到也不難。

       只是因為您真的可以完成我這一篇USB HID 的 Bootloader ISP 其實就算

reset  Plug-and-play ,有啥關係嗎?這不就是人家要用USB HID 的目的嗎?

因為他就是要做到自動 Plug-and play。

------ 當然最後我也懶了啦,您看人家我同學鮭魚不就是適時的發揮他應有的

專長,趕快賺錢比較實際吧。

>>>>
2. 原廠的PC 端的應用程式是利用兩組Report ID 來完成Get Report 與Set report

的功能,而這兩個Report ID 也就是拿來做為Bootloader ISP 專用的Report ID。

Set report 沒啥問題。但很不幸的是他的Get report 是用Multi-thread 寫的。

這一部份原廠的程式是有錯誤的地方,會造成燒錄失敗。--- 我以前講過:

您要用Multi-thread 來處理USB 介面要小心。因為這兩個東西Performance

跑起來誰也不輸誰,結果就是錯的。錯的地方是:當Set report 寫(燒錄)

一段Flash 之後,會馬上利用Multi-thread 來Get Report 讀取燒錄CRC 檢查碼。

因為Multi-thread 彷彿就是多核心多工器在處理USB 介面。他的另一隻

Set Report 無法跟他是同步的!當然程式中有靠一個Flag 來檢查。只是

真的兩者誰也不輸誰...搶效能之下,您會發現這一個Flag 擋的位置不對,

會造成那支Set report 副程式在檢查flag 之後會讀到上一回Write flash 的

CRC 值...發生CRC Check 失敗。只要您有留意到,就可以很快的修正掉。

還是老話一句:Multi-thread 來處理USB 介面,還是要多小心一點。



沒有留言:

張貼留言