在介紹更多細(xì)節(jié)內(nèi)容之前,我不得不談?wù)勎覍?duì)USB調(diào)試方法的理解。USB通訊過程是一個(gè)動(dòng)態(tài)的過程,是不太好使用硬件仿真器來設(shè)斷點(diǎn)調(diào)試的,因?yàn)槊恳淮蜺SB的傳輸過程,都有時(shí)效要求,等待時(shí)間過長(zhǎng),通訊過程也就中止了。但也不排除可以巧妙地使用斷點(diǎn)仿真的方法進(jìn)行調(diào)試。但個(gè)人認(rèn)為,使用串口輔助編程過程,卻是一種經(jīng)濟(jì)有效的方法。所謂用串口輔助調(diào)試過程,也就是在固件代碼中加入類似于Printf的語句,向串口輸出一些信息。這些信息可以是幾個(gè)字符(如A、B、C),或是某個(gè)變量或寄存器的值。程序運(yùn)行到此處時(shí),便會(huì)輸出這些信息,借此,便可以知道:1、程序是否運(yùn)行到此處;2、運(yùn)行到此處時(shí)相應(yīng)變量或寄存器值。這不就是硬件仿真調(diào)試的功能么?如果想使用這種方式來調(diào)試,在硬件上必須增加一個(gè)RS232串口電平轉(zhuǎn)換芯片,而且所使用的MCU得要有串口,并且,一般要自己編寫Printf函數(shù)的實(shí)現(xiàn)方式。這個(gè)翻翻串口控制方面的書籍,很容易就可以搞定。
串口調(diào)試的方法,還可以推廣到其他的單片機(jī)應(yīng)用中,在簡(jiǎn)單系統(tǒng)中,它基本可以替代掉硬件仿真器,降低開發(fā)者的門檻和投資。在USB通訊過程中,有兩個(gè)階段,一是通過端點(diǎn)0完成對(duì)設(shè)備的配置,在此階段,把從USB端點(diǎn)得到的數(shù)據(jù)輸出到串口,就對(duì)通訊所處的階段一目了然了。一旦完成配置階段,Bus Hound便可以粉墨登場(chǎng)了,因?yàn)榇藭r(shí),Bus Hound中已經(jīng)可以看到設(shè)備了,看到設(shè)備后,便可以選擇設(shè)備,對(duì)主機(jī)與此設(shè)備間的通訊數(shù)據(jù)進(jìn)行分析和監(jiān)視。串口調(diào)試和Bus Hound這兩種手段配合使用,可以使USB通訊過程的調(diào)試更加容易。比如,剛開始時(shí),端點(diǎn)0的數(shù)據(jù)量本來就少,因此,使用串口調(diào)試比較方便。而對(duì)于Bulk端點(diǎn)的數(shù)據(jù)傳送過程,再使用串口就不太方便了,因?yàn)閿?shù)據(jù)量大,串口輸出的數(shù)據(jù)太多,延時(shí)會(huì)比較嚴(yán)重,影響USB通訊過程,所以改用BUS HOUND來監(jiān)視USB總線上的數(shù)據(jù)。這個(gè)時(shí)候很有趣的一件事情是,Bus Hound在PC機(jī)上,而串口實(shí)際上在單片機(jī)端。所以,利用這兩種手段,里應(yīng)外合,有助于我們確定一方發(fā)時(shí)另一方收的數(shù)據(jù)是否正確。比如,單片機(jī)上發(fā)出的一組數(shù),將其輸出到串口,然后看看Bus Hound上是否收到的是這些數(shù),如果正確,則說明硬件通訊過程沒有問題,如果不正確,則說明通訊的某一方有問題,進(jìn)一步可以定位此問題,排除之。正確的調(diào)試思路,將使調(diào)試過程事半功倍。比如,在調(diào)試端點(diǎn)0 的配置過程時(shí),可以先用Switch...Case語句建立對(duì)于端點(diǎn)0的數(shù)據(jù)的分支響應(yīng),對(duì)照標(biāo)準(zhǔn)請(qǐng)求的數(shù)據(jù)格式,可以得到什么情況下是Get Device Descriptor,什么時(shí)候是Get Configuration Descriptor,每個(gè)分支處理時(shí)對(duì)應(yīng)一個(gè)函數(shù),在這個(gè)函數(shù)里向串口標(biāo)志信息。這個(gè)工作完成以后,便一個(gè)一個(gè)地來處理請(qǐng)求,處理完一個(gè)后,主機(jī)會(huì)自動(dòng)進(jìn)入下一個(gè)階段,這時(shí),通過串口可以看到相應(yīng)的狀態(tài),按步就班地一個(gè)一個(gè)處理余下的請(qǐng)求,即可完成端點(diǎn)0的設(shè)備配置過程的固件程序的編寫。 對(duì)于Bulk端點(diǎn)也是一樣,先建立程序框架,然后再一個(gè)一個(gè)地處理請(qǐng)求。這種自上而下,逐步求精的思路并不稀奇,在USB調(diào)試過程中十分受用。最忌一上來就處理請(qǐng)求,不講求結(jié)構(gòu),不講求代碼的條理性,最后可能弄得自己都是一頭霧水
U盤固件編程之四:玩轉(zhuǎn)你的端點(diǎn)
接上面hewx,我來談?wù)劧它c(diǎn)的問題。前面提到過,端點(diǎn)是由USB設(shè)備端的接口芯片決定的。你選擇了什么樣的芯片,那么端點(diǎn)的配置情況屬性就已經(jīng)決定了,你只能使用將就這些特定的情況。這些端點(diǎn)的配置,具體要參考你所使用的接口芯片的芯片資料,比如說,端點(diǎn)0當(dāng)然都為控制端點(diǎn),其MaxPacketSize可能為8,16,32,64;端點(diǎn)1可能是Bulk-In端點(diǎn),2是Bulk-Out端點(diǎn),其字長(zhǎng)也有可能是8,16,32,64,但一般是64。其他端點(diǎn)可能有同步端點(diǎn),或者同一端點(diǎn)既可被配置成同步傳輸方式,也可以工作在Bulk傳輸方式下,等等,不一而足。USB協(xié)議精妙之處就在于枚舉過程。主機(jī)最初發(fā)過來的包,一定是8個(gè)字符長(zhǎng)的。所以,你的端點(diǎn)的MaxPacketSize至少必須是8,能滿足與主機(jī)之間最基本的通訊過程。對(duì)于主機(jī)的第一個(gè)請(qǐng)求Get Device Descriptor,你也只用回復(fù)8個(gè)字符就OK了,因?yàn)橹鳈C(jī)在第一次只對(duì)這8個(gè)字符感興趣,在后面逐漸的獲取描述符的過程中,主機(jī)逐漸得到設(shè)備使用那些端點(diǎn),每個(gè)端點(diǎn)的最大字長(zhǎng)(這些內(nèi)容在Endpoint Descriptor中,通過Configuration Descriptor提供)是多少,等等,總之,通過枚舉,主機(jī)便知道你的端點(diǎn)的情況了,以后就會(huì)用這些端點(diǎn)來與設(shè)備進(jìn)行通訊。對(duì)于Hewx的問題,我想是你在Endpoint Descriptor中沒有正確進(jìn)行端點(diǎn)的設(shè)置,因?yàn)椋绻M(jìn)行了正確的端點(diǎn)配置,主機(jī)是會(huì)自動(dòng)通過Bulk端點(diǎn)來發(fā)Inquiry命令的,而不會(huì)從你說的Endpoint1(16B)來發(fā)送這一信息。而且,主機(jī)會(huì)自動(dòng)對(duì)要發(fā)送的信息進(jìn)行分割,每次以不高于相應(yīng)端點(diǎn)的MaxPacketSize長(zhǎng)度來發(fā)送。除了描述符中要給出正確的端點(diǎn)描述符的描述,有些時(shí)候在芯片中也需要設(shè)備相應(yīng)的控制位,在決定你要使用哪些及如何使用這些端點(diǎn),這個(gè)也得根據(jù)具體的芯片資料來設(shè)置。
U盤固件編程之四:玩轉(zhuǎn)你的端點(diǎn)(增補(bǔ))
對(duì)于某種設(shè)備來說,需要使用到的端點(diǎn)是固定的。比如說,Mass Storage設(shè)備吧,就只需要用到一個(gè)Bulk-In端點(diǎn)和一個(gè)Bulk-Out端點(diǎn)。而不需要幾個(gè)此類端點(diǎn)。至于到底需要幾個(gè)端點(diǎn),完全需要根據(jù)有關(guān)協(xié)議中的說明進(jìn)行,描述符也據(jù)此進(jìn)行提供,而不是沒有根據(jù)地在描述符中提供許多端點(diǎn)。至于哪些端點(diǎn)可以做何種方式來使用,這也要看接口芯片的資料,比如,很可能,有的端點(diǎn)只能用作同步方式,那你就不要勉強(qiáng)將其用作批量方式,控制端點(diǎn)就只能用作控制傳輸方式,就不能為同步方式......搞清楚這個(gè)概念,在固件編程中才好正確地提供描述符。
評(píng)論