在我阅读CH341A的PDF文档时,着实高兴了一阵子,因为觉得CH341A的使用太简单了,比菲利浦的PDIUSBD12简单得多(此前我一直用这个芯片做USB类产品),至少可以免写驱动,而且价格还很便宜。国内IC厂商能做出这样的产品,值得鼓励。于是上淘宝购了几片CH341A着手进行测试。
测试的第一天晚上,使用的是CH341A的EPP1.7模式,无论如何发数据,我的设备都不理。因为我的设备端有CRC16校验,数据出错就不予理睬,所以可以肯定是数据出错了。于是使用CH341EppWriteData,每次只发一个字节,通讯成功,然而这个速度真吃不消,大约100Bytes/s。为什么多个字节一起发就不行呢?研究了一下EPP1.7的PDF,发现我的程序时序没错,而可能是CH341A的EPP1.7模式,并不等待nWAIT拉高就自行结束EPP周期,所以数据象流水般发送,我们的程序无法同步:前面的数据并未接收,后面的数据就覆盖了它!这么说来,CH341A的EPP1.7可能是个貌似的EPP1.7,与标准的EPP1.7文档中的可能不一样。WCH的文档并没说明,我只是根据测试现象猜测。
第二天,采用CH341A的EPP1.9模式。我之所以不太乐意用EPP1.9,因为EPP1.9对WAIT信号很敏感,若数据写入之后的10ms内,WAIT不被外设拉低,则置位超时标志,强制结束EPP周期,而且需要人为清除超时标志,才能启动下一个EPP周期,所以对于响应不够快的设备,EPP1.9并不适合。因为我的设备是多任务的,通讯任务的优先级较低,50ms内都可能没时间去处理通讯中断。结果发现CH341A的EPP1.9竟然又是个貌似的EPP1.9,根本没有10ms时限控制。这一下歪打正着,恰好我就是不需要这个超时控制的!于是修改了程序的时序:设备初始化拉低CH341A的WAIT引脚 -> CH341A的DS引脚从高跳低的下降沿触发通讯中断->设备接收数据,然后拉高CH341A的WAIT引脚5us,通知CH341A结束当前EPP周期 -> 设备拉低CH341A的WAIT引脚,通知CH341A启动下一EPP周期。经过这样的时序匹配,CH341A才真正和我的设备通讯起来,速率可达220k/s左右。关于这点,WCH的文挡也没有说明,我是万不得已才采用EPP1.9模式试试,才发现没这个10ms时限控制!
可见,WCH的文档不够详细严密,否则就不要走这个弯路。大体上,我们对于EPP1.7和EPP1.9的了解,来自英文的标准文档。所以个人认为,与标准有所不同的地方,应着重在文档中申明。
但是,还是高兴得太早!众所周知,USB总线携带的数据包,带有CRC16校验。所以当数据发送到CH341A时,理论上应该是准确无误的,而CH341A在PCB上,与PCB上的CPU的距离不到1cm,完全就是CPU一个片外扩展器件,若这么短的距离内通讯,还出错的话,那CPU和片外所有的器件通讯,都要出错,所以出错应该在USB传输层。但我发现CH341A发送到CPU的数据还是很多错的。为了验证这个问题,我在设备的PCB上加了个指示灯,每检测到一个数据包的CRC16校验码错误,就闪烁一次指示灯。结果我所看到的情况是指示灯不停地闪(我的数据量一般在几M字节以上,发送几十字节几k字节可能观察不到)!USB传输层的错误,我们还能有什么办法?芯片对我们而言是黑盒子的,驱动和应用层API也对我们是黑盒子。但办法总还是有的:对要发送的数据,先自己封包,把封好的包使用CH341EppWriteData发出去,设备端再检测包的正确性,错了通知应用程序重发。我的包是这样封的:握手的同步字符(2字节(我使用0xAA+0x55作为同步字符)) + 包号(2字节) + 数据流长度 1字节 + 数据流(最多255字节) + CRC16(2字节)。一次连续通讯最多65535个包,每包最多255字节,一次连续通讯可发16M数据,一般的应用可说足够了!经过这样处理后,CH341A终于和我们的设备可准确无误地通讯。准确到什么程度呢?即使正在通讯时,我把USB电缆不断地拔出、插入,人为破坏其通讯,99%的情况下还能正确完成通讯。我使用Bus hound总线监控软件,可以清楚地看到错包重发的现象,很爽。看到这里,觉得问题是不是应该解决了?可是——
还是有一个问题:CH341A频繁随机断线问题!CH341A断线之后,必须拔出USB电缆再插入,才能重新连接上。前面说过,我改进的通讯机制,已经不怕通讯时拔出电缆再插入电缆。问题是,很多设备是工作于无人值守的情况下,不可能专门安排个人去监视设备的通讯。这个问题的解决办法其实并不复杂:控制CH341A的Reset In引脚。但目前的CH341A不够方便,因为它没有一个引脚通知CPU说它断线了,只能判断多久没有通讯事件发生,确定是否是断线了,这会造成失误。PDIUSBD12有个重连功能,当断线发生时,GoodLink会熄灭,根据GoodLink的电平高低,就能知道是否断线,这点非常适合无人值守的设备!若CH341A能内置断线重连功能,它的应用范围就宽了不少。目前,它只适合于一般性应用,比方在无人值守的工业控制产品方面,根本就无法用。
应该说,CH341A在数据量不大时,通讯还是蛮可靠的,我测试了数据量在10k以下时的通讯质量,很少会出错。仅这点,做做下载线等一般性应用就很方便。但是,在数据量较大时,不经过应用层的严密处理,就几乎没法用。
CH341A的应用,简单不?
现在遗留两个问题: 1、开机不管插不插带CH341A的设备,都弹出找到新硬件向导! 2、频繁随机断线的问题。虽然可控制CH341A的RESET引脚重连,但毕竟如何知道断线了呢?