2019年10月31日 星期四

Hinet 網頁系列 --- USB DIY 系列(十四)---USB DIY 講座 (十二)實作範例 USB ISP

(補充說明:這一篇是我當初在 Hinet 連載 USB 文章的最後一篇了,後來就轉到部落格,

以另一種方式來寫了,剛好這一篇當初也有留下當時撰寫的日期,那時我還在八核心MCU

的技術團隊裡---雖然其實那時公司才五六個人而已。但是過了這幾年,這種東西滿街都是

了:USB ISP,就連你是原廠的燒錄工具也淪為滿街的便宜貨了。當年後來沒有繼續搞

看來是對的。當這種東西最後成了這種市場情況,怎麼看都看不出誰是贏家?當然你會覺得

那些賣USB MCU 的最好了。但他們畢竟是原廠,本來賣MCU 是他們的本業,這一點小玩意

市場,也不算甚麼吧?

今天也剛好是十月份的最後一天,日子也過得很快,轉眼之間,也過了十幾年了。坦白講,

這十幾年來 USB在這方面的系統應用技術也沒有改變很多,雖然已經有很多原來 8bits 市場

轉換成 32bits 的,但這些USB的基礎應用都沒多大改變。而且就以這類的USB tools 應用來說

更是幾乎一統天下了。這的確是在PC 周邊應用發展來說,是一大成就,不管你是否願不願意?

或是有沒有機會搞這一類的技術?我想多多少少在這個領域行業裡,這應該還是可以在維持

一段不少的日子吧。那我的期望呢?

在這過去一段很長的日子,我都幾乎使用 8 bits USB MCU 來搞這些東西,接下來有空

我應該也會拿個  32 bits USB MCU 來玩玩吧?我是有稍微研究了一下,說真的~其實

許多類似USB 系統應用來說:我還真的看不出換  32 bits MCU 有甚麼特別的地方?

8 bits USB MCU 一顆已經降至 US$ 0.8 以下了。 32 bits 還沒有看到這個價錢。

或許,學個 32 bits USB MCU 只是成就系統應用的完整性之外,大概也沒有多大的

技術意義?也許各位看官有更好的建議,可以提出討論吧。謝謝。

)


>>>>>>++++++++++++++++++
------------------------------------------------------------------------------------------------------------------
(2006/11/01) 前言:這個東西自從版主架設網頁時。就說要作,卻就一直被其他事情給

耽擱了,不過,說真的~作這種東西就像版主作 USB ROM Emulator 一樣,只是圖個好玩

與一種拿來『交際應酬』的真的要靠技術賺錢的,唯有走在技術的領導地位才有

機會,像玩那個FPPATM  -才是一塊完全沒被開發的處女地。他所潛藏的無限空間才是

技術創造商機的無窮動能。就像說版主常言:若技術開發只不過想一些Cost Down 或

想複製別人成功的模式,來開創事業,我想這種結果:大家也都可以預見得到的結果了。

        FPPATM  -帶給版主的想法是:他不是要去取代市面上的單晶片:Such as 8051 或MicroChip 

的PIC 。他是自己去創造出一塊屬於多核心應用市場的。因為這個觀念是領導廠商Intel 

所帶出來的。當您發現您在玩一塊或創造一塊人們完全無法想像或全然不解的領域時,

就猶如當然哥倫布發現新大陸一般,誰會料到那片土地發展成全球霸權國家?!

        所以,寫寫這幾篇USB ISP的東西是要教導一些年輕學子,像這些顯而易見或垂首可得

的東西,您只要在技術領域裡磨個幾年都不難。要傳達給各位的是是當您完成這些

稀疏平常的東西之外,您要拿什麼東西給老外看,才能贏得別人對您的讚賞?

因為地球是平的了!您未來的競爭不在侷限在島內或一個地區而已

這是版主在進入FPPATM  -領域後接觸到日韓美等國家客戶之後,深深的體會到:

作技術也可以昂首闊步的走在國外街上的
        
也把這份心得與成果分享給各位。至於,這一系列的東西,大家就多少加減當作大家

交朋友的交際應酬的『等路』(台語,禮物之意)。
----------------------------------------------------------------------------------------------
        首先,當然說明一下:版主作這個USP ISP的規劃與想法:就是利用USB 單晶片控制器

來寫個簡單的燒錄器,又不想搞得太複雜,只要簡單容易上手就好。所以,就選定常見

的8051 與 PIC系列,這個其中的方式就是最好是Serial interface ,這一部份 PIC 還好

(不過他有個缺點,就是要12 VDC ,USB 只有5VDC)。而8051 呢?剛好 Atmel 推出

所謂ISP (In-System-Programmable) 的89Sxx 系列產品,所以就把這兩個東西當作目標。
       
 而手上的 USB 單晶片控制器來作這個東西野蠻合適的,而且韌體也可隨時更新,

對於功能的驗證與產品開發偵錯野蠻方便的,就開始著手進行了:
        
先看整個系統規劃圖:

有幾個重點先說明一下:

1. 對於PIC 系列來說:比較討厭的是需要一組 12VDC 的電源,不過,拜台灣目前一些

類比IC公司一堆,所以,解決方案還蠻好找的,體積也不大。

2.一般IC 對於燒錄電壓都多多少少有一點必須要留意的,所以,我們也利用我這顆USB

 單晶片控制器的 A/D 來隨時量測燒錄電壓,其中當然就包括利用USB (5VDC)升壓後

的12 VDC 了。

3. 一般這種 Serial interface 所用的I/O 都不多,所以,可以直接利用USB 單晶片控制器上

的GPIO 即可。

4. 當然還需要不乏LED燈號顯示啊~或電源切換開關啊~都可以利用其他可控制的  I/O 

來控制。

5. 當然,要作Parallel Interface 的也可以啊,只是這一次的應用就不先考慮了。

我想在硬體部分,都還算蠻簡單的啊~這一部份在一般網路上教大家作ISP Cable 的網站

都有公布。這也用不著版主來教。

            接下來就直接看PCB的結果:


放得夠大了吧,這下大家可以好好研究了,沒有任何一IC有任何隱藏的東西

(喔~放心好了,背面沒東西了!)。至於,圖中那條跳線,唉~人非聖賢,孰能無過呢?

PCB 板子回來驗證後,結果還是錯了一條線。已經不錯了啦。

(有沒有看到PCB的月份,6月耶~放到都快要『生菇』了!唉~嘻~嘻!)

        至於如何ISP 一般的IC 呢?就看另一片板子:


您不要問我為何在 PIC 方面只選用這幾顆型號?!因為我就用過這幾顆而已吧,

而且這幾顆手上也剛好有Sample ,版主也是作來玩玩的,又不一定要拿來賣您們的喔。

對不對?!

        所以,一般使用就把上下兩片組合起來就可以了:


咦~有沒有覺得那個盒子很面熟?嘻嘻~版主是借用 Altera 的那個USB Blaster II 的

盒子囉。這一部份就要感謝一下友晶科技的友情贊助,有興趣玩 Altera 的 FPGA 的話,

也可以到友晶科技的網站看看囉。
-------------------------------------------------------------------------------------------------------------------------------
        硬體部分,我想大概不會難倒太多人,比較辛苦的是軟體部分,因為一般網路提供硬體

的資訊也很多,但軟體部分的比較可憐了,往往只給的執行檔就放牛吃草了。

又偏偏不是USB 介面,又不知該如何著手Debug ?而又往往USB的東西又很難上手。

如果,看過版主所公布的USB DIY的內容的話,就應該瞭解這一部份,其實野蠻簡單的,

如果您還覺得很難看得懂的話?那就代表您對版主之前的USB DIY 內容不夠用心研讀,

可能還要多努力一下。

        我們就稍微說明一下軟體的開發技巧:當然就沿用版主所常用的USB Driver ,

不過,要注意的是,為了避免跟其他相同USB Controller 發生驅動程式衝突問題,

比較建議用不同的GUID ,這樣子就可以避開這個問題了:
...
DEFINE_GUID(GUID_CLASS_GT680X_SCANNER,
//0xa7e7beb7, 0x8099, 0x11d2, 0xbe, 0xbb, 0x0, 0x80, 0xc8, 0x93, 0x8c, 0x65);
//DEFINE_GUID(GUID_CLASS_I82930_BULK,
0xce25239c, 0x6ed5, 0x4895, 0x94, 0x6d, 0x82, 0xc0, 0x38, 0xe4, 0x15, 0xcc); //ChamberPlus
//0x89bb4816, 0x3e22, 0x4979, 0x8b, 0x14, 0x5, 0x38, 0xfd, 0xa9, 0x68, 0x7d); // Romter
//0x6bdd1fc6, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x0, 0x2b, 0xe2, 0x09, 0x2f);
//#endif

    以上是節錄於軟體程式中的GUID 定義檔。當然啊~不同的驅動程式就有不同的GUID,

這部分是跟著驅動程式產生時,一起產生的喔。所以,您若要用Cypress 的解決方案的話,

最好也要有屬於自己的GUID,否則,您要套用別人的驅動程式時,不要出了門才有一天

發現:您的親生父親(Cypress)在外面也生了一大堆孿生兄弟一大堆。到時候,您的

應用程式跟您的孿生兄弟幹架時,您都不知如何是好啊?!

---- 本是同根生,相煎何太急啊?!

        注意喔~版主這裡所說的GUID 跟一般的PID/VID 是不一樣的喔,不要搞錯了,

還來問版主,到時版主還要數落您一下:老師在講您都沒在聽啊~沒有聽!沒有聽!...

 接下來,就是要給這個產品一個PID/VID 囉。這部分是要寫在Boot Code 裡,

然後燒在Boot Code 裡的(一般就是24Cxx 那一系列的)。之後當裝置插入USB 之後,

您就可以看到:

   不錯,有前途,您已經成功一半了。

    接下來就要開始動手同時上層的應用程式底層的USB 單晶片控制器韌體

(一般就是8051 啊),當然,這個時候最好一個人同時間寫會比較快,否則,一些介面

或命令,光溝通來,溝通去的就大家就不用作了,更何況是這種屬DIY的小東西呢!

        所以.....時光飛逝(不要笑~版主是很嚴肅滴!)~只要短短一兩天內,您就很快可以

完成這樣一支美美(或水水)的應用程式了:


當然這裡面有幾個重點要跟各位解密一下:因為這種韌體程式不會一開始就作得很

完美的,因為大家一開始都是一樣的沒經驗,USB 單晶片控制器的韌體也不可能一次

就OK 完善的。所以大家可以在我的上層應用程式的右下角偷偷的留一個介面: 

UpdateFW 就是拿來隨時更新USB 單晶片控制器韌體 的。這個就是版主說的:最好,

這些程式都是一個人寫的比較快。不會!?那就慢慢『盧』了吧!當您最後驗證完之後,

Relaese 給客戶時,再把他拿掉就可以了。不過,這時要記住您最後版本的Checksum 時,

這樣子就不會搞亂您的韌體了,這是一種版控(版本控制)的觀念。

       這個階段的最後我來交代一下韌體介面與USB介面使用上的技巧。若看不太懂或領悟力

不夠的話,那就還是老話一句:多多用功唸書!!
        
重點一:像做這種Tool 的東西。有百分之九十幾都是利用USB Control Token 完成的

只有很少部分用到Bulk Transfer token  (甚至您不用我也沒意見!)。所以不要太在乎速度

問題。因為所有的ISP動作都是交給USB 單晶片控制器韌體作的。所以,我上面的架構圖裡

就是利用我USB 單晶片控制器內的那一部份16KBytes 的SRAM 。應該對ISP 4K/8K/16KBytes 

綽綽有餘吧!當然,超過也沒問題,只是韌體會比較複雜一點而已。

        像Atmel ISP這種介面,也有他自己的 Instruction Format ,這部分當然是交由USB 單晶片

控制器韌體來處理,這一部份就完全是USB Control Token 完成的,那怕是只讀一個Lock Bit

也是

而我們上層應用程式就倒不一定要跟著他定義走,像我的作法如下:

            ATmel 89S51 Programmable Enable : AC/53 - - ; 而我上層命令為0x8D ! 反正 我自己USB 

單晶片控制器韌體 看得懂就好了。

         重點二:記住一點:那怕是只是用USB Control Token 這慢的介面,他還是遠遠超過 ISP 

介面中的SPI(Serial peripheral Interface)的速度,所以,不要下同一個命令去讀資料

譬如讀Target IC 的Signatures Bytes。因為您一個 Setup-Out-Null In (Command)再加一個

Setup-In-Null Out (Read Data) 最慢也是6mSec ,而且您還有可能打亂USB Contrller 正在處理

的SPI 介面。版主的意思是說:先下一個命令讓USB 單晶片控制器 去處理SPI 介面。

等一會兒再用另一個Setup Token 去讀 data 。這樣子,就可以完全確保USB 介面命令中斷

不會去干擾SPI介面(因為這個介面可能是用8051 I/O 去造出來的!)。

而且,也可以正確的讀到您所要的資料。這個重要觀念:在您作USB 轉 I2C 時,

也是一樣適用的。所以,在上圖應用範例中:版主就是利用這樣子的觀念去完成那個

ChipID 命令(其實就是 Signature Bytes Read 命令執行):

Virual C++ 程式碼:

BOOL CUSBAISPDlg::OnButtonSignature()
{
        // TODO: Add your control notification handler code here
        m_ICSignature= false;
        //----
        m_MessageBlanking=false; //clear blinking string show

        if(!USB_DEVICE_INITIALIZE())
        {
            m_MessageBlanking=true; //clear blinking string show
            BlinkShowString="Check USB Device or Cable...";
            return false;
        }

        m_MessageString.SetTextColor(LIGHTBLUE);
        m_MessageString.SetWindowText("Read Chip Signature...");
        m_TimerMessageUpdate = TRUE;
        //---
        CString BulkInStr;
        char BulkInRaw[5];
        //---
        hDEV = open_dev();
        if(hDEV!=INVALID_HANDLE_VALUE)
        {
            //---- Check RESET STATUS ----
            UINT GPIODR=USB_DEVICE_READ_GPIO();
            CButton *LocalRST;
            LocalRST = (CButton*) GetDlgItem(IDC_CHECK_RESETHOLD);
            if(!(GPIODR&0x80)){
                USB_DEVICE_RESETCOMMAND(1);
                LocalRST->SetCheck(TRUE);
            }
            //---- End of Check RESET STATUS ----
            int i;

            for(i=0;i<8;i++) STICommandString[i]=0x00; // reset the parameters
            STICommandString[0]=0x89; // Read ISP ID Test Command
            STICommandString[1]=0x01; //
            USB_DEVICE_SEND_STI_COMMAND(STICommandString);


            for(i=0;i<8;i++) STICommandString[i]=0x00; // reset the parameters
            STICommandString[0]=0x25; // Read ISP ID Test Command
            STICommandString[1]=0x01; //
            USB_DEVICE_SEND_STI_COMMAND(STICommandString);



            for(i=2;i<0x05;i++)
            {
                char ShwBulkIn[3]="00";
                ATMELSignature[i-2] = iobuffer[i];
                _itoa(iobuffer[i], BulkInRaw,16);
                if(strlen(BulkInRaw)!=2)
                {
                    strcpy(ShwBulkIn+1,strupr(BulkInRaw));
                }
                else
                    strcpy(ShwBulkIn,strupr(BulkInRaw));
                    BulkInStr += (CString)ShwBulkIn;
            }  
            //
            m_ChipSignature.SetWindowText(BulkInStr);
            //---
            //----- Parse the IC ---
            m_ICSignature= true;
            if(ATMELSignature[0]==0x1E && ATMELSignature[1]==0x51 && ATMELSignature[2]==0x06){
                Ini_CHIPCODE = 0x00;
                Ini_CHIPSIZE = 0x1000;
            }else if(ATMELSignature[0]==0x1E && ATMELSignature[1]==0x52 && ATMELSignature[2]==0x06){
                Ini_CHIPCODE = 0x01;
                Ini_CHIPSIZE = 0x2000;
            }else if(ATMELSignature[0]==0x1E && ATMELSignature[1]==0x53 && ATMELSignature[2]==0x06){
                Ini_CHIPCODE = 0x3000;
            }else{
                Ini_CHIPCODE = 0x00;
                Ini_CHIPSIZE = 0x1000;
                m_ICSignature= false;
            }
            m_SelectChip.SetCurSel(Ini_CHIPCODE);
            //----
            CloseHandle(hDEV);
            hDEV=INVALID_HANDLE_VALUE;
            return m_ICSignature;
        }else
        return false;
}

         所以,我們很快的就可以完成ISP的第一個重要命令:讀Target Chip 的ID 值了!

我們再看實際的波形:


我們就很明顯可以讀到 Atmel 89S51 回給我們的 Signature Bytes 值了。

    那當我們這個環節打通之後,那剩下的那一些功能就輕而易舉了。那您覺得,利用USB

介面來作Tool 簡不簡單啊?!
------------------------------------------------------------------------------------------------------------------

   (結語) 說真的,版主深深的體會到 USB 的東西是不可能再帶給版主有多大的激情與

成就感的。也不知道最終要完成這樣的東西是有何種意義?!或許,真的只是剩下那一點

功德無量的默默的善行吧。下一回也不知未來何年何時才有空寫下一集?所以,

趁下一次還沒出國前,趕快補這麼一篇文章,再給版主的網頁再衝一衝人氣指數。

           但也別忘了多多給一點掌聲與鼓勵。

            

沒有留言:

張貼留言