?
USB固件編程可以用以下語句來精練地進行描述:
Device的固件編程,要搞定的是那幾個端點。端點多少和配置情況受所用的Device芯片決定,具體可以看芯片資料。芯片一般提供一個中斷信號,與單片機接口時,只要端點接受到數據,或發送數據成功后,便后產生中斷,在固件里面,只要對些中斷進行響應即可。當Device接收到數據時,對這些數據進行分析處理(端點0遵守標準的數據格式,其他端點受端點類型的不同,有不同的數據格式),一般來說,這些數據是主機對設備發出的請求,設備只要響應主機的這些請求即可。Device芯片發送完數據后也會產生中斷,這個中斷信號告訴與之接口的單片機,可以繼續發送后續的數據。USB固件,好比一個有“妻管炎”的男人,而主機,則好是一個女管家。一般來說,主機讓干啥就干啥,所以,USB固件程序的結構一般是基于中斷處理的。平時,主程序做完必要的初始化工作后,就什么事也不做了,等待USB中斷的產生,中斷產生后,根據中斷狀態對相應的端點讀取數據,或是向相應的端點發送數據。這一點是USB通訊協議的主-從模式先天決定的。但讓人不可思議的是,這還有點象是母系氏族時期,因為,一個USB總線上,只能有一個主機,可以有多個設備,整個USB總線上通訊的協議和處理,發起與中止,基本上是主機控制的。因此,固件編程中,只要滿足了主機的要求,就萬事大吉了,可以確保自己的氏族中的應有地位
U盤固件編程之二:固件編程的幾個主要部分
在整個U盤固件中,程序從功能模塊上分成兩個部分:USB協議的處理和對Flash的讀寫.USB協議的處理又分成兩個方面.
一是端點0的配置過程.所有USB設備在插入USB端口時,主機都通過地址0與設備的端口0進行通訊。在這個過程中,主機發出一系列得到描述符的請求,通過這些請求,主機得到所有感興趣的設備的描述符,從而知道設備的情況,然后通過Set Address為設備設置一個唯一的地址,配置過程完成以后,主機就通過為設備所設定的地址與設備通訊,而不再是使用默認地址0.配置地址后,可能還要獲取一次描述符,然后設置配置(Set Configuration),之后便完成了對新插入USB總線的設備的配置過程。
二是其他端點的數據通訊過程。在配置階段中,主機已經知道了設備的端點的使用情況,以后,便可以通過這些端點來進行特定傳輸方式的通訊了。對于U盤來說,有兩種傳輸方式,BULK ONLY和CBI方式,一般使用Bulk Only較多。這種傳輸方式要使用特定的Bulk端點,然后還要為其選擇一種命令集。比如UFI或SCSI,因為Bulk端點的數據沒有特定的數據格式,因此,需要使用某種命令集,來約定所傳數據的格式。對于U盤固件編程來講,就是要處理BULK端點的各種數據通訊。除了對各個相關的端點的USB協議的處理,剩下的就是FLASH的讀寫問題。這里存在兩個層面的問題。
一是解決Flash讀寫的問題,就是說你使用的Flash,先要實現成功的讀寫和擦除,這部分內容,是比較成熟的,一般都使用三星公司出的K9FXX08系列的,有16M(2808),32M(5608),64M(1208),138M(1G08)。它們的封裝一致,只需要軟件編程中稍做修改,便可以進行適應于另一種容量的存儲器。
第二個層面的問題,就是在U盤通訊過程中的問題了。NAND型的Flash有個特點,不可隨機存取,擦除操作一次對16K的內容進行。所以,在U盤響應過程中,不可避免要對數據進行緩存。如果你的U盤方案中有較寬裕的RAM(超過16K),這個問題變得簡單,只需要開一個16K的數組,把數據存到這16K中,最后再寫入Flash即可。否則,在緩沖上面是要花一些功夫的。最基本的思路是用Flash的另外一個Block做緩沖空間。但這種方式會引發下列問題:1、速度;2、Flash的那個用來做緩存的塊將比別的塊使用頻度大幅上升,磨損最嚴重,最先壞,這影響整個Flash的壽命。在實際處理中,引入了一系列的折中方案,比如,對Write命令所寫的Block號進行判斷,如果是整個的數據Block,則直接擦除原有內容,將數據寫入。再如,對于非整個Block的數據進行緩沖,而對于整個Block的讀寫,不緩沖直接寫入。再就是對于前面文件分配表、目錄項所在的Block進行緩沖,等等。經過這些處理,可以盡可能地提高Write的速度。
U盤固件編程之三:合理的USB通訊調試方法和思路是成功的關鍵
在介紹更多細節內容之前,我不得不談談我對USB調試方法的理解。USB通訊過程是一個動態的過程,是不太好使用硬件仿真器來設斷點調試的,因為每一次USB的傳輸過程,都有時效要求,等待時間過長,通訊過程也就中止了。但也不排除可以巧妙地使用斷點仿真的方法進行調試。但個人認為,使用串口輔助編程過程,卻是一種經濟有效的方法。所謂用串口輔助調試過程,也就是在固件代碼中加入類似于Printf的語句,向串口輸出一些信息。這些信息可以是幾個字符(如A、B、C),或是某個變量或寄存器的值。程序運行到此處時,便會輸出這些信息,借此,便可以知道:1、程序是否運行到此處;2、運行到此處時相應變量或寄存器值。這不就是硬件仿真調試的功能么?如果想使用這種方式來調試,在硬件上必須增加一個RS232串口電平轉換芯片,而且所使用的MCU得要有串口,并且,一般要自己編寫Printf函數的實現方式。這個翻翻串口控制方面的書籍,很容易就可以搞定。
串口調試的方法,還可以推廣到其他的單片機應用中,在簡單系統中,它基本可以替代掉硬件仿真器,降低開發者的門檻和投資。在USB通訊過程中,有兩個階段,一是通過端點0完成對設備的配置,在此階段,把從USB端點得到的數據輸出到串口,就對通訊所處的階段一目了然了。一旦完成配置階段,Bus Hound便可以粉墨登場了,因為此時,Bus Hound中已經可以看到設備了,看到設備后,便可以選擇設備,對主機與此設備間的通訊數據進行分析和監視。串口調試和Bus Hound這兩種手段配合使用,可以使USB通訊過程的調試更加容易。比如,剛開始時,端點0的數據量本來就少,因此,使用串口調試比較方便。而對于Bulk端點的數據傳送過程,再使用串口就不太方便了,因為數據量大,串口輸出的數據太多,延時會比較嚴重,影響USB通訊過程,所以改用BUS HOUND來監視USB總線上的數據。這個時候很有趣的一件事情是,Bus Hound在PC機上,而串口實際上在單片機端。所以,利用這兩種手段,里應外合,有助于我們確定一方發時另一方收的數據是否正確。比如,單片機上發出的一組數,將其輸出到串口,然后看看Bus Hound上是否收到的是這些數,如果正確,則說明硬件通訊過程沒有問題,如果不正確,則說明通訊的某一方有問題,進一步可以定位此問題,排除之。正確的調試思路,將使調試過程事半功倍。比如,在調試端點0 的配置過程時,可以先用Switch...Case語句建立對于端點0的數據的分支響應,對照標準請求的數據格式,可以得到什么情況下是Get Device Descriptor,什么時候是Get Configuration Descriptor,每個分支處理時對應一個函數,在這個函數里向串口標志信息。這個工作完成以后,便一個一個地來處理請求,處理完一個后,主機會自動進入下一個階段,這時,通過串口可以看到相應的狀態,按步就班地一個一個處理余下的請求,即可完成端點0的設備配置過程的固件程序的編寫。 對于Bulk端點也是一樣,先建立程序框架,然后再一個一個地處理請求。這種自上而下,逐步求精的思路并不稀奇,在USB調試過程中十分受用。最忌一上來就處理請求,不講求結構,不講求代碼的條理性,最后可能弄得自己都是一頭霧水
U盤固件編程之四:玩轉你的端點
接上面hewx,我來談談端點的問題。前面提到過,端點是由USB設備端的接口芯片決定的。你選擇了什么樣的芯片,那么端點的配置情況屬性就已經決定了,你只能使用將就這些特定的情況。這些端點的配置,具體要參考你所使用的接口芯片的芯片資料,比如說,端點0當然都為控制端點,其MaxPacketSize可能為8,16,32,64;端點1可能是Bulk-In端點,2是Bulk-Out端點,其字長也有可能是8,16,32,64,但一般是64。其他端點可能有同步端點,或者同一端點既可被配置成同步傳輸方式,也可以工作在Bulk傳輸方式下,等等,不一而足。USB協議精妙之處就在于枚舉過程。主機最初發過來的包,一定是8個字符長的。所以,你的端點的MaxPacketSize至少必須是8,能滿足與主機之間最基本的通訊過程。對于主機的第一個請求Get Device Descriptor,你也只用回復8個字符就OK了,因為主機在第一次只對這8個字符感興趣,在后面逐漸的獲取描述符的過程中,主機逐漸得到設備使用那些端點,每個端點的最大字長(這些內容在Endpoint Descriptor中,通過Configuration Descriptor提供)是多少,等等,總之,通過枚舉,主機便知道你的端點的情況了,以后就會用這些端點來與設備進行通訊。對于Hewx的問題,我想是你在Endpoint Descriptor中沒有正確進行端點的設置,因為,如果進行了正確的端點配置,主機是會自動通過Bulk端點來發Inquiry命令的,而不會從你說的Endpoint1(16B)來發送這一信息。而且,主機會自動對要發送的信息進行分割,每次以不高于相應端點的MaxPacketSize長度來發送。除了描述符中要給出正確的端點描述符的描述,有些時候在芯片中也需要設備相應的控制位,在決定你要使用哪些及如何使用這些端點,這個也得根據具體的芯片資料來設置。
U盤固件編程之四:玩轉你的端點(增補)
對于某種設備來說,需要使用到的端點是固定的。比如說,Mass Storage設備吧,就只需要用到一個Bulk-In端點和一個Bulk-Out端點。而不需要幾個此類端點。至于到底需要幾個端點,完全需要根據有關協議中的說明進行,描述符也據此進行提供,而不是沒有根據地在描述符中提供許多端點。至于哪些端點可以做何種方式來使用,這也要看接口芯片的資料,比如,很可能,有的端點只能用作同步方式,那你就不要勉強將其用作批量方式,控制端點就只能用作控制傳輸方式,就不能為同步方式......搞清楚這個概念,在固件編程中才好正確地提供描述符。
評論
查看更多