2019年9月25日 星期三

Hinet 網頁系列 --- USB DIY 系列 (一) USB Q&A (四)

(補充說明:現在USB   的規格已經發展到 3.0 了,有關硬體的新規範,還是要查一下規格書。

本篇文章事以前我自己搞過的經驗,有時候,還是會拿出來簡單的測試驗證一下,

這一種文章說明,就比較偏實務面的操作,比較不像一般"速成"開箱文的東西。就算是

原廠的範例程式也很少會去做這方面的說明或提供範例,這就得完全看系統開發者自己本身的

經驗與功力了。但個人覺得這不只是在USB 這方面的觀念而已,而是在於許多系統產品開發上

都應該建立的基本態度與原則問題。)


Q: 在什麼情況之下會使用suspend state ?
 
A: 關於USB Suspend 這一類的問題是有點牽涉到USB 硬體觀念的東西,

因為許多人作USB 的東西,一開始都會浸淫在韌體與通訊協定上,

就很容易忘了這一類的問題。也搞不太清楚這部分要做什麼?!

關於 Suspend 有關的名詞有:

Suspend : 不會翻譯,就是要讓USB裝置處於『待命』狀態。

在『待命』狀態下,USB Host 不會對您再發任何 Protocol 的東西,

包括SOF !既然稱為『待命』,就是要隨時會回   到原來狀態。
-----
Resume : 就是『喚醒』,什麼『喚醒』?

就是叫USB 裝置從『待命』再回到原來狀態。
----
Remote Wake-Up : 也是『喚醒』!那他跟 Resume 有什麼不一樣?!

Resume 是由PC Host 主機叫醒 USB device 的;

而Wake-Up 是由 USB Device 叫醒 PC Host 主機的。


    前面兩個主控權,當然是在PC Host 囉,但是,Wake-Up 卻必須在

USB device 裝置插入主機時,在Device configuration 時,就必須宣告,

然後主機才會支援。以簡單的規格的通訊協定來說,就是這麼一回事。

    但是在硬體上,就有額外一層意義了。USB 規格規定:所有的USB Device 

裝置都必須支援Suspend 規格(什麼是支援Suspend ?

就是在韌體上,USB Controller 也必須接受到Suspend 訊息,就是中斷的意思啊

~待會兒我就用韌體說明!),而且在進入 Suspend 時,整個USB Device耗電

必須低於 500uA 。您一定覺得,這個規格很簡單?!

哈~哈~ 我們就簡單推算一下吧:

因為若您的USB 裝置是高速裝置的話,您的 D+ 會Pull-high 1.5K ,

然後因為經由南橋一個內阻到GND,所以,會有一個約 220uA 的基本耗電。

又因為 USB 供電是5.0 VDC,您還是需要一棵整流IC將 5VDC 轉成3.3VDC。

一般這種IC都屬於Linear regulator 型的,他的基本內耗也都是100 uA 級的,

以前我用過類似立錡科技的Switch 型的如9262 ~

結果是:他本身耗34uA+Feedback 5uA+ CE 那根控制線約 12 uA 所以是 51uA ~

 因為又要拿來偵測USB插入狀態,所以,又用掉一根 Pull-high pin ~ 

約50uA 就是  100 uA + 基本220uA= 320 uA 了。

當然,您若要支援 Remote wake-up 的話,您還是用一根 I/O 來當 

Push-button也會有額外的耗電了。所以,您當然是不可能點LED燈號了。

 所以在電路設計上就要小心了。有沒有看過電影『阿波羅十一號』?!

您就會有那種感覺了就是了。
       
 那在韌體上要如何處理呢?!就以我  USB ROM Emulator 來說明吧:

    一般USB Controller 硬體設計上,收到 USB Bus 上Suspend 訊號時,

(譬如PC 主機不是關機,而是進入『待命』時,或是裝置移除時,

就會收到這個訊號~)都會發一個中斷給您的韌體,

此時,您的程式寫法就得如下所示:

_Suspend6816: ;; b7:R51, b6:Reversed, b5:6803, b4:Low Speed,                    ;; b3:PLL Clock, b2:PLL, b1:6802, b0:M2
;;--------------------------------------------------------------
        USBPowerOff

        ;; 所有的I/O 都必須切到最省電方向!

        CLRP2 USBDevCtl ;; disable suspend/resume timer(detect suspend/resume event in USB bus)
;---------------------------------------------------------------
        REG_WR SCR, #00000001b ;; M2
        orl A, #00100011b ;; M2,6802,6803
        movx @DPTR, A
        orl A, #00110011b ;; M2,6802,6803,LS
        movx @DPTR, A
        orl A, #00111111b ;; M2,6802,6803,LS,PLL
        movx @DPTR, A
        mov C, MD6Init_ ;;
        mov A.6, C
        orl A, #10111111b ;; M2,6802,6803,LS,PLL,51
        movx @DPTR, A
        ;;<---------- 程式停在此處!   
        ;;
        ;; into Suspend mode wait USB K State or WakeUp Low -> High
        ;; Now Power <= 2.5 mA
        ;;
        ;; REG_WR SCR, #00110011b ;; PLL Enable
        anl A, #00110011b
        movx @DPTR, A
        ;;
        ;; Wait PLL stabe
        ;;
        mov R0, #2 ;; Delay 2*400uS=800uS
SysSuspend029:
        mov R1, #238 ;; Delay 400uS
        djnz R1, $
        djnz R0, SysSuspend029

        ;; REG_WR SCR, #00100011b ;; High Speed
        anl A, #00100011b
        movx @DPTR, A
        anl A, #00000001b
        movx @DPTR, A
        clr A
        movx @DPTR, A
SysWakeUp:

        REG_RD ASR
        jnb WakeupInit_, SysSuspend030
        cpl A.7
SysSuspend030:
        jnb A.7, SysSuspend050

        USB_K_State
        mov R0, #4 ;; Delay 4*50uS=200uS
SysSuspend040:
        mov R1, #238 ;; Delay 50uS
        djnz R1, $
        djnz R0, SysSuspend040

SysSuspend050:
        USBNormal

        REG_RD USBDevCtl ;; suspend/resume timer(detect suspend/resume event in USB bus)
        setb A.2
        movx @DPTR, A

        ret

 
        這段程式,沒什麼意思,只有兩個重點:第一:收到Suspend 後要利用韌體,

把硬體上的耗電切成最省電方式,(I/O 盡量不要有Output 狀態!)

然後,就是把USB  Controller 內部會耗電的部分也一併關掉~

諸如:記憶體啊~PLL啦~等等:重要的是:連8051自己都得關掉!!

哈~哈~所以,程式就停在原點~當硬體收到 Resume 時,自然就會往下跑~

所以,有些人程式寫不好,就會一覺不醒了。

哈~哈~或許,每一家USB Controller 的設計都不一樣,但是,奇怪的是:

我玩過兩家的最法都是一樣的~因為大家設計 USB Controller 都沒把握

可以作到很省電,所以乾脆讓 8051 直接停下來最省電~

(其實,8051 是很耗電的~這點大家都知道!)不信的話:

看另一個程式:

void USB_Intr_Suspend_Process() USING_1
{
        // printf("sleep\n");
        _G_USB_Setup_Interrupt1 = 0; // Clear flag for Enable LCD_Reset Controller
        LCD_Reset();
        _G_USB_Setup_Interrupt1 = 1; // restore the flag for USB status !
        DbgP15=0;//turn off DAC OP Power
        DbgP16=1;//A LED OFF MP3 Mode
        DbgP17=1;//B LED OFF DVR Mode
        TIMER0_Stop();
        XBYTE[0x25d0] |= 0x80; //Enable interrupt for Resume
        CPUIO_PushState();

        USB_Suspend_Process();   

        XBYTE[0x2050]|=0x04; // Enable Wake-Up !

        XBYTE[0x2003] = 0x01; //Suspend        
///程式也是停在這裡!!哈~哈~
        //----------------------------------------------------
        //wakeup
        XBYTE[0x2003] = 0x00; // Suspend Normal
        XBYTE[0x2010] = 0x1e; //Close 48MHz Clk
        CPUIO_PopState();
        XBYTE[0x2050]&=0xfb; // Enable GPIO.2(Wakeup)
        // XBYTE[0x2050]&=0xbf; // Disable GPIO Intr.
        XBYTE[0x2048]=0x00; // Clear GPIO intr Event
        XBYTE[0x2040]&=0xbf; // Clear GPIO intr Event
        XBYTE[0x25d0] = 0x37; //Disable interrupt for Resume/Enable Supsend Intr
        //----------------------------
        DbgP15=0;//turn on DAC OP Power
        Charge_Pin=1;

        XBYTE[0x2010] |= 0x01; //DSP Wakeup
...
        至於Resume 這個中斷~有些USB Controller 也會提供,但是好像用到的機會不多,

因為就如同上述的程式所示~程式都自己醒來,執行Resume 程式了~

還要進入  Resume 中斷要做什麼?!

        其實,當您完成一個 USB Device 之後,您自己可以用一個電表量一下,

您USB 裝置有沒有達到USB的規格。還有 讓主機進入 待命狀態,然後,

在鍵盤上隨便按個鍵,把主機叫醒,看您的USB Device 醒不醒得過來?!

很好玩喔~這是需要一點調教功力的。作不好,還得改硬體電路的。
  
      當然,這部分還有許多值得討論的空間,改天我在用一些實際範例,

拍一些照片來說明的。譬如:您的USB Device 是 Self-Power 呢?

還是 Bus-Power ?!還可利用USB POWER來作充電器等!
        
謝謝各位的指教!

沒有留言:

張貼留言