(補充說明:現在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 主機不是關機,而是進入『待命』時,或是裝置移除時,
就會收到這個訊號~)都會發一個中斷給您的韌體,
此時,您的程式寫法就得如下所示:
;;--------------------------------------------------------------
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
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
;;
;; 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();
{
// 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來作充電器等!
謝謝各位的指教!
沒有留言:
張貼留言