在我閱讀CH341A的PDF文檔時(shí),著實(shí)高興了一陣子,因?yàn)橛X(jué)得CH341A的使用太簡(jiǎn)單了,比菲利浦的PDIUSBD12簡(jiǎn)單得多(此前我一直用這個(gè)芯片做USB類產(chǎn)品),至少可以免寫驅(qū)動(dòng),而且價(jià)格還很便宜。國(guó)內(nèi)IC廠商能做出這樣的產(chǎn)品,值得鼓勵(lì)。于是上淘寶購(gòu)了幾片CH341A著手進(jìn)行測(cè)試。
測(cè)試的第一天晚上,使用的是CH341A的EPP1.7模式,無(wú)論如何發(fā)數(shù)據(jù),我的設(shè)備都不理。因?yàn)槲业脑O(shè)備端有CRC16校驗(yàn),數(shù)據(jù)出錯(cuò)就不予理睬,所以可以肯定是數(shù)據(jù)出錯(cuò)了。于是使用CH341EppWriteData,每次只發(fā)一個(gè)字節(jié),通訊成功,然而這個(gè)速度真吃不消,大約100Bytes/s。為什么多個(gè)字節(jié)一起發(fā)就不行呢?研究了一下EPP1.7的PDF,發(fā)現(xiàn)我的程序時(shí)序沒(méi)錯(cuò),而可能是CH341A的EPP1.7模式,并不等待nWAIT拉高就自行結(jié)束EPP周期,所以數(shù)據(jù)象流水般發(fā)送,我們的程序無(wú)法同步:前面的數(shù)據(jù)并未接收,后面的數(shù)據(jù)就覆蓋了它!這么說(shuō)來(lái),CH341A的EPP1.7可能是個(gè)貌似的EPP1.7,與標(biāo)準(zhǔn)的EPP1.7文檔中的可能不一樣。WCH的文檔并沒(méi)說(shuō)明,我只是根據(jù)測(cè)試現(xiàn)象猜測(cè)。
第二天,采用CH341A的EPP1.9模式。我之所以不太樂(lè)意用EPP1.9,因?yàn)镋PP1.9對(duì)WAIT信號(hào)很敏感,若數(shù)據(jù)寫入之后的10ms內(nèi),WAIT不被外設(shè)拉低,則置位超時(shí)標(biāo)志,強(qiáng)制結(jié)束EPP周期,而且需要人為清除超時(shí)標(biāo)志,才能啟動(dòng)下一個(gè)EPP周期,所以對(duì)于響應(yīng)不夠快的設(shè)備,EPP1.9并不適合。因?yàn)槲业脑O(shè)備是多任務(wù)的,通訊任務(wù)的優(yōu)先級(jí)較低,50ms內(nèi)都可能沒(méi)時(shí)間去處理通訊中斷。結(jié)果發(fā)現(xiàn)CH341A的EPP1.9竟然又是個(gè)貌似的EPP1.9,根本沒(méi)有10ms時(shí)限控制。這一下歪打正著,恰好我就是不需要這個(gè)超時(shí)控制的!于是修改了程序的時(shí)序:設(shè)備初始化拉低CH341A的WAIT引腳 -> CH341A的DS引腳從高跳低的下降沿觸發(fā)通訊中斷->設(shè)備接收數(shù)據(jù),然后拉高CH341A的WAIT引腳5us,通知CH341A結(jié)束當(dāng)前EPP周期 -> 設(shè)備拉低CH341A的WAIT引腳,通知CH341A啟動(dòng)下一EPP周期。經(jīng)過(guò)這樣的時(shí)序匹配,CH341A才真正和我的設(shè)備通訊起來(lái),速率可達(dá)220k/s左右。關(guān)于這點(diǎn),WCH的文擋也沒(méi)有說(shuō)明,我是萬(wàn)不得已才采用EPP1.9模式試試,才發(fā)現(xiàn)沒(méi)這個(gè)10ms時(shí)限控制!
可見(jiàn),WCH的文檔不夠詳細(xì)嚴(yán)密,否則就不要走這個(gè)彎路。大體上,我們對(duì)于EPP1.7和EPP1.9的了解,來(lái)自英文的標(biāo)準(zhǔn)文檔。所以個(gè)人認(rèn)為,與標(biāo)準(zhǔn)有所不同的地方,應(yīng)著重在文檔中申明。
但是,還是高興得太早!眾所周知,USB總線攜帶的數(shù)據(jù)包,帶有CRC16校驗(yàn)。所以當(dāng)數(shù)據(jù)發(fā)送到CH341A時(shí),理論上應(yīng)該是準(zhǔn)確無(wú)誤的,而CH341A在PCB上,與PCB上的CPU的距離不到1cm,完全就是CPU一個(gè)片外擴(kuò)展器件,若這么短的距離內(nèi)通訊,還出錯(cuò)的話,那CPU和片外所有的器件通訊,都要出錯(cuò),所以出錯(cuò)應(yīng)該在USB傳輸層。但我發(fā)現(xiàn)CH341A發(fā)送到CPU的數(shù)據(jù)還是很多錯(cuò)的。為了驗(yàn)證這個(gè)問(wèn)題,我在設(shè)備的PCB上加了個(gè)指示燈,每檢測(cè)到一個(gè)數(shù)據(jù)包的CRC16校驗(yàn)碼錯(cuò)誤,就閃爍一次指示燈。結(jié)果我所看到的情況是指示燈不停地閃(我的數(shù)據(jù)量一般在幾M字節(jié)以上,發(fā)送幾十字節(jié)幾k字節(jié)可能觀察不到)!USB傳輸層的錯(cuò)誤,我們還能有什么辦法?芯片對(duì)我們而言是黑盒子的,驅(qū)動(dòng)和應(yīng)用層API也對(duì)我們是黑盒子。但辦法總還是有的:對(duì)要發(fā)送的數(shù)據(jù),先自己封包,把封好的包使用CH341EppWriteData發(fā)出去,設(shè)備端再檢測(cè)包的正確性,錯(cuò)了通知應(yīng)用程序重發(fā)。我的包是這樣封的:握手的同步字符(2字節(jié)(我使用0xAA+0x55作為同步字符)) + 包號(hào)(2字節(jié)) + 數(shù)據(jù)流長(zhǎng)度 1字節(jié) + 數(shù)據(jù)流(最多255字節(jié)) + CRC16(2字節(jié))。一次連續(xù)通訊最多65535個(gè)包,每包最多255字節(jié),一次連續(xù)通訊可發(fā)16M數(shù)據(jù),一般的應(yīng)用可說(shuō)足夠了!經(jīng)過(guò)這樣處理后,CH341A終于和我們的設(shè)備可準(zhǔn)確無(wú)誤地通訊。準(zhǔn)確到什么程度呢?即使正在通訊時(shí),我把USB電纜不斷地拔出、插入,人為破壞其通訊,99%的情況下還能正確完成通訊。我使用Bus hound總線監(jiān)控軟件,可以清楚地看到錯(cuò)包重發(fā)的現(xiàn)象,很爽??吹竭@里,覺(jué)得問(wèn)題是不是應(yīng)該解決了?可是——
還是有一個(gè)問(wèn)題:CH341A頻繁隨機(jī)斷線問(wèn)題!CH341A斷線之后,必須拔出USB電纜再插入,才能重新連接上。前面說(shuō)過(guò),我改進(jìn)的通訊機(jī)制,已經(jīng)不怕通訊時(shí)拔出電纜再插入電纜。問(wèn)題是,很多設(shè)備是工作于無(wú)人值守的情況下,不可能專門安排個(gè)人去監(jiān)視設(shè)備的通訊。這個(gè)問(wèn)題的解決辦法其實(shí)并不復(fù)雜:控制CH341A的Reset In引腳。但目前的CH341A不夠方便,因?yàn)樗鼪](méi)有一個(gè)引腳通知CPU說(shuō)它斷線了,只能判斷多久沒(méi)有通訊事件發(fā)生,確定是否是斷線了,這會(huì)造成失誤。PDIUSBD12有個(gè)重連功能,當(dāng)斷線發(fā)生時(shí),GoodLink會(huì)熄滅,根據(jù)GoodLink的電平高低,就能知道是否斷線,這點(diǎn)非常適合無(wú)人值守的設(shè)備!若CH341A能內(nèi)置斷線重連功能,它的應(yīng)用范圍就寬了不少。目前,它只適合于一般性應(yīng)用,比方在無(wú)人值守的工業(yè)控制產(chǎn)品方面,根本就無(wú)法用。
應(yīng)該說(shuō),CH341A在數(shù)據(jù)量不大時(shí),通訊還是蠻可靠的,我測(cè)試了數(shù)據(jù)量在10k以下時(shí)的通訊質(zhì)量,很少會(huì)出錯(cuò)。僅這點(diǎn),做做下載線等一般性應(yīng)用就很方便。但是,在數(shù)據(jù)量較大時(shí),不經(jīng)過(guò)應(yīng)用層的嚴(yán)密處理,就幾乎沒(méi)法用。
CH341A的應(yīng)用,簡(jiǎn)單不?
現(xiàn)在遺留兩個(gè)問(wèn)題: 1、開(kāi)機(jī)不管插不插帶CH341A的設(shè)備,都彈出找到新硬件向?qū)В? 2、頻繁隨機(jī)斷線的問(wèn)題。雖然可控制CH341A的RESET引腳重連,但畢竟如何知道斷線了呢?