2018年10月14日 星期日

USB DIY--自學計畫_USB新平台(二)

上回有討論關於 Silicon Labs 新版USB MCU 的探討USB DIY--自學計畫_USB新平台(一)

這也不是甚麼新鮮玩意兒,也只不過我本身認為在系統開發經驗中,會經常碰到

使用PC 來做為許多產品開發的系統驗證或是一些分析工作。而USB 一直是我的首選。

並不是我不想用一般 USB 轉RS232 的東西。有時我是認為可以用一顆MCU 就可以解決

的事,我為什麼還是用兩顆呢?更何況USB HID (Vendor HID) 很方便啊,

沒有甚麼不妥之處。其實用RS232 還要花很多時間去定義通訊協定,

還要擔心資料錯誤或一大堆有的沒有的。而USB 的基本架構就已經由硬體幫你

處理掉許多煩人的通訊協定與資料偵測問題。由這一篇文章中我們就可以看到:

有時候只要硬體稍微支援你系統一下,就可以省下你許多寶貴的時間,這也不代表說:

你就英雄無用武之處,而是讓你多一點時間專注在你專業的系統開發工作上。



在一般會利用PC 來做為系統輔助工具平台時,最重要的事就是要能支援所謂的智能升級

工作,因為你永遠不知道當你第一代產品釋出到市場上時,未來會不會碰到奇怪的

疑難雜症?或是有沒有可能系統本身功能的擴充性?這些需要能簡單的提供客戶端的

韌體更新升級功能。就連科技產品世界品牌第一的蘋果手機 iPhone 也都有提供這樣子的

雲端服務,那就更不用說,我們常常在研發時間壓力下所釋出的韌體程式是否會不會

出問題啊?所以這是當我們在一探討完USB MCU 之後,所要馬上面臨碰到的問題了。

8051 MCU 本身架構並沒有支援這樣子的功能,所以這些功能往往就得要考驗著

系統工程師的能耐了。早期MCU 很少有所謂的 Flash Memory,所以也不用想這件事,

當市場上開始出現所謂的系統智能升級之後,這樣的系統需求就算是一般基本功能

需求了。早期比較常見的還是UART (串口通訊)介面為主,但坦白講智能升級在系統本身

也是存在一定的風險,而且有時也會造成串口介面資源的不足。所以如果MCU 本身

若已經支援USB 介面的話,那就更顯得簡單輕鬆了。

但 8051 的架構有所謂的智能升級功能,也常常就是會占用原本一部分的程式記憶體,

所以如何有效或縮小這方面的負擔,就成了各家 8051 廠商的重要課題。用硬體直接

做掉不是不行,但有時候硬體的設計就是沒有韌體系統的彈性與自由度,相對風險也

較少,所以一般的MCU 硬體設計工程師們也不會給自己添麻煩的用硬體做掉,還是會

保留給系統的韌體工程師們發揮的。

 以前關於USB MCU 如何在標準的8051 的基本架構做到所謂的韌體系統智能升級,

我在去年已經有整理一篇了:USB DIY--自學計畫 (N+2) --- USB HID BootLoader

前一代的8051 的智能升級功能在硬體本身,嚴格說:他只有提供一個簡單的 Software Reset

的機制與相關暫存器,可以讓我們能夠簡單地透過純軟體的方式幫助軟體程式完成韌體

更新工作。下圖就是前一代的做法:他直接用保留 MCU 前段程式記憶體的空間當成

系統韌體升級的 Bootloader。 

至於要保留多少?那就看每個人的需求。但這一種做法就是得變動 8051 的中斷向量表,

把真正的系統應用端的韌體程式的中斷向量表重新導到後面去:



這樣子的作法當然就是會造成系統進入中斷時的時間性問題(Latency),也往往會造成

一些韌體程式空間的浪費。尤其現在因為變種的 8051 所支援的周邊功能越來越多:

譬如 SPI/I2C或是A/D 、多組UART 等等。這些也都會提供中斷功能,這也使得

中斷向量表的不斷的擴充,所以光是保留給中斷向量表的程式碼就非常可觀了。

當然最重要的是:這樣子的系統的確是會造成許多人在開發上的不便,畢竟這樣子的

作法不是很正統,對許多對MCU 沒有深入了解的系統工程師是會造成一些困擾。

所以在新版的MCU 架構(硬體方面),原廠就提供了一個比較簡單也能保留系統彈性的

設計方式:
其實說起來很簡單:就是在硬體設計上只保留一個 BootLoader 程式的進入點:0xFBC0

然後整個 Bootloader 程式還是會占用一部分的程式記憶體,只不過它已經把他挪到地址

靠近 0x3FFF 附近了。(它還是以512Bytes page 為一個基本單位)

這樣子簡單的說:就是可以讓你不用占用原來程式記憶體一開始的位置,這樣子也自然

不會挪動到原本的中斷向量表。而啟動進入 Bootloader 的方式也很簡單,就只有以下

三種方式:這些方法不管是  UART 或USB 的 Bootloader 都是一樣的。



但坦白講:這三種方法也不是硬體設計的方法,而是在進入 Bootloader 的程式執行點時,

由Bootloader 的 Startup.A51 程式來判斷的,所以:如果你覺得這些方法不適合你用,

那你也可以修改這部分程式,這就是我之前所提到的:原始的MCU 硬體設計工程師保留

給我們系統開發工程師的一些彈性作法。 這些原始程式碼原廠是有直接提供在其所附的

Simplicity Studio 開發環境中。大家可以直接找出來研究一下。

不過,我可以肯定的跟你說:他這一版的範例程式,絕對跟舊版MCU 的作法是完全不同

的工程師做的。因為原廠所提供的範例程式,只有提供 MCU 端的範例程式原始碼。

但PC 端的工具程式他只有給一個簡單的 Python 的原始碼。他也只能在 DOS Prompt 中

以命令列的方式執行。Python ?對我這個老人家來說:肯定是無字天書。

我家裡是有 Python 的書,但那不是我念的書,那是我兒子的書,但我想我應該不會想去

學的,而且我兒子應該也不會教我,也不會幫我解釋這個程式的原始碼。所以我也只能

透過:USB 分析儀來看他程式的執行過程,然後自己再用 VC++ 在寫一個程式吧。

這也是我在這一範例中花最多時間的部分。

結果就可以直接看以下影片:---



-----


---
原廠的這一支 Bootloader 並沒有跟任何的系統應用程式綁在一起,嚴格說:它只是一支預燒

在MCU 裡面的一支協助你用軟體燒錄程式碼的韌體程式,而非是真正的"智能升級程式"。

這部分還需要跟真正的USB 系統應用程式結合再一起才有用的。

另外影片中我拿來燒錄的範例程式也是原廠所提供的 efm8_rainbow_Blink的程式碼。

而PC 的範例程式是我用USB DIY--自學計畫 (N+2) --- USB HID BootLoader

中的程式繼續修改而來的。所以看起來應該是可以了。
----
最後我還是稍微 Highlight 一下其他比較值得關注的技術相關問題。

第一:基本上,它Bootloader 在處理USB 通訊協定部分,捨棄了中斷方式,全部以 polling

          方式來處理,這一點還是要考驗一下你對於USB 韌體程式的功力。這樣子的做法

          的確會比較節省一下程式碼大小。不過也是佔用了 1.5 KBytes ( 3 Pages)。

第二:USB Bootloader 程式還是可以通過 Chapter 9 的規範測試,只是不支援 Suspend/Resume

         的功能,這一點也是。這個 Suspend/Resume 本來就是成雙成對的命令組合。當然在此

        韌體程式執行過程中,應該沒有人還會讓系統進入Suspend/Resume 的作業流程中吧。

第三:USB 還是走標準的 Vendor HID 標準規範,只用一個 interrupt IN Token。Output 方向

         還是用Endpoint 0 的 SetReport 方式處理,但在命令的通訊協定中,回復命令執行結果

        就是用 Endpoint 1 的  Interrupt IN Token。這一點很重要,待會兒會以圖片說明。

第四:燒錄的驗證檢查是採用MCU 本身所附的 CRC 檢查機制,原廠在MCU 的使用手冊中

        也有提供CRC 硬體設計中等效的  C 語言程式碼,這一部分可以直接移植到PC 端程式

        中就可以了,這也就是為什麼新一代的MCU 還都把 CRC 的演算功能加進去,這對這

         一類的系統應用是蠻好用的。

第五:對於原廠所提供的燒錄程式碼的效能與程式語法,的確有比較好的程式效率,

       這應該就是寫軟體工程師的傑作,是值得參考的一個範例。

----
最後這裡要補充說明的就是關於第三點的問題點。

在USB 的 vendor HID 的應用中,其實也是常常用這一種用 Endpoint 0 的 Setup Token 下命令

,然後用 Endpoint 1 的 Interrupt IN Token 來回覆命令的執行結果。所以這時往往就是在這

兩個 Endpoint 0 與 Endpoint 1 之間來來去去,這也都是正常的使用情形。要不然,這時

Endpoint 1 要拿來做甚麼?又不用鍵盤滑鼠老是要一直回鍵盤滑鼠的狀態。

但是,很討厭的是:在PC 端的應用程式,這兩個關於USB 底層驅動程式來說,就是不同

的做法,尤其是 Endpoint 1 的Interrupt IN Token。因為PC 端的程式,作業系統又不可能就

如同我們MCU 端的作法,就在那邊傻傻地一直等啊。所以微軟的作業系統就會建議你用

所謂的 Multi-thread (多執行緒,大陸稱為"线程")的方式來處理 Endpoint 1的 Interrupt IN Token

,那這樣子你就得要留意一下這兩者之間的先後順序問題。因為你有可能一不小心就會

誤放接下來的USB 命令組,這在一般程式執行時不容易察覺,因為看起來似乎很合理,

程式也不會發出錯誤訊息,尤其是 Multi-thread 的程式是超難 Debug 的。(公認的)

以下就是我們從USB 分析儀中看到的結果:



上圖就是一種很簡單的 Set Report 的命令組,下到MCU 系統端之後,MCU 系統端會

利用Endpoint 1的 Interrupt IN Token 回覆你系統執行的結果。結果你PC 端的程式也不容易

在Endpoint 0 與 Endpoint 1 之間可以同步檢查一下,結果你主程式就直接再下另一組

Set Report 的命令組。其實這在USB 的通訊息協定中沒有任何不對的地方。但在PC 端

可能會造成系統的一些問題。這一點真的要多留意一點。

所以:這還真的得如我這一種MCU 系統韌體程式與PC 端通訊協定程式一起搞的人才

有辦法在短時間內很快地抓到問題點。或許也可以間接地回答上一篇文章中,讀者留言

所表達的意思。

------
最後,還是一個系統經驗分享,搞這一種USB 燒錄程式的系統問題時,有許多老闆或是

工程師常常會爭論的問題是:為什麼我們家的MCU 燒錄速度老是怎麼那慢的問題?

老闆天天逼工程師,因為客訴啊。但系統工程師常常會把問題再推給IC 設計者,

然後 IC 設計者又會把問題推給 IC 製造商所提供的 IP 問題。然後把問題搞得很大,

一副要所有相關廠商的相關工程師全部叫來,Call 個 Meeting。結果呢?搞了老半天

就只改善個5% 或10% 。然後大家兩手一攤,不知道了囉。

每次遇到這個問題,我總是先考問一下系統工程師:你到底有沒有看到問題癥結點啊?

工程師就是一副:我真的也不知道啊。因為我不可能可以看到所有的通訊協定與每個

命令的執行結果啊。

蛤?這是甚麼理由啊?連最後系統的終極目標結果,你都不知道,那你到底上班在幹甚麼?

反正事情只要往外一推,有誰能真正的點出問題癥結點?老闆你又不可能自己下來

同時解讀MCU 的PC 端的程式啊。所以就打一場迷糊仗啊。我跟你說:這是我常常

遇到的真實場景。一點也都不意外。

所以你真的不要以為你甚麼都不學,然後甚麼都可以往外推,當你碰到天外有天,

人外有人時,你就知道"事情大條了囉"。

這算是一個簡單的笑話結語。

(未完待續)


沒有留言:

張貼留言