上个月客户那边提交了一个BUG,现象是我们写的DWC2(DesignWare OTG Controller 2.0)驱动在 USB Device 模式下工作的时候,不能识别VBUS的切断,而是在VBUS上没有电压的情况下,仍然能跟Host进行正常的USB通信。
调查了接近三个礼拜,终于被我找到了原因,只改了14行代码就搞定了。
先说结论:两个miss的复合作用导致这个BUG的产生。
1)GPIO上的USB_20_OTG_EN没有设成1。
2)DWC寄存器GUSBCFG上,BIT20『ulpiextvbusdrv』没有设成1。
解决的办法就简单了,当然是在初始化阶段把这个两个值都设成1。
先看图,下面这张是3300-EZK的模块说明图。
我们在基板在使用中,蓝色的线连接了一个继电器,控制继电器的就是GPIO管脚USB_20_OTG_EN。
红色和品红的两根,就是输入的VBUS。3300-EZK通过初始化的设置,来决定是使用VBUS还是EXTVBUS。
所以,当USB_20_OTG_EN=0时,整个3300-EZK是处于不供电状态的。
刚开始调查的时候,客户方面让我通过取间接读取寄存器的办法去取3300-EZK上的VBUS状态,取到的永远是0。
而且这种状态下,USB Device设成自供电完全是可以正常工作的。USB2.0线很简单,只有4根线:VBUS,D+,D-,GND。当我们设定成自供电的时候,只要D+D-能正常工作就好了,VBUS相当于被废掉了。
而我在实验的时候,另一块基板上也能取到VBUS的值,因为那块基板上的3300-EZK的VBUS没有连继电器,而是一直接着VCC呢!
DWC寄存器GUSBCFG上,BIT20『ulpiextvbusdrv』设置后,通过一系列的动作,控制的是3300-EZK的EXTVBUS。也就是内部供电还是外部供电的切换开关。
DataSheet上关于这个bit的描述是“This bit selects between internal or external supply to drive 5V on VBUS, in ULPI PHY.”,是正解。
但是描述中的“Host only.”这一句比较害人。我们第一次移植驱动的时候,看到Host only的字样就没有再去深究。其实在Linux代码里,能够看到这一位就是判断是否由外部供电用的。
在USB_20_OTG_EN=0时,单独设这一位没有任何反应。
之前的代码中一直没有设定这一位,所以我们的驱动就一直认为是自己供电的,也就是一直走着品红色的那根线,一直有电。
在调试的过程中,还有一个现象。当『ulpiextvbusdrv』单独设定的时候,不会接收Host发来的VBUS激活消息,与『hnpcap』、『srpcap』一起设下才可以。同时设下的现象是插线没有反应,其实是设成功了(因为要等外部供电)。但当时没意识到这一点,还以为这三个bit不能同时设。
事实是,只有三个bit同时设下,芯片才会处于OTG的A-Device状态,等待Host发来的激活信息,否则是B-Device状态,也就是自己供电的状态,Host直接就检知开始通信了。
最后说一下这次的一些心得。
代码是从Linux驱动抄过来的,Linux驱动中『ulpiextvbusdrv』是通过配置项来设定的,在移植的时候因为通信好用了就没再注意它。其实Linux默认的DeviceTree中,这一项是置1的。
物理设备3300-EZK确实是不用单独写驱动的,所有的设置都可以通过DWC的『gusbcfg』寄存器完成设置。
USB的peripheral模式,默认应该设成使用外部电源,或者在DeviceTree里做成可配置项。如果有特殊的descriptor,再改过来。
USB_20_OTG_EN,不应该放在不同基板的宏下面,而应该写成可配置项,放在DeviceTree当中。
我大学的时候也想玩单片机的,后来树莓派更适合我这种懒人,后来树莓派就没时间折腾
我只是工作的时候搞嵌入式,业余时间完全没有碰基板的兴趣。
昨天那状态,我以为你删库跑路了~
险些。
昨晚睡觉之前打开了一次,发现是诗经的内容。以为又出什么事情。。。
确实是出事情了啊。好在解决了。
老哥,你有了解的免费的VPS吗?可以给我推荐下吗?
我不擅长这个。我知道有个年付9美金的pzhost
我大学专业就是学的嵌入式,学的时候,就玩了51单片机、野火STM32开发板、还有下友善之臂ARM9的板子。
现在都改叫嵌入式专业了?我上学的时候还叫无线电或者电子信息。工作了好几年之后ARM才开始流行的。
专业名字是:电子信息工程技术
跟我那时候差不多。我就说没嵌入式这个专业嘛。
老哥,你现在是从事什么工作呢?我现在都转行了,嘻嘻
写驱动啊……
想起个问题,请教一下。
我一个U盘,经常拿来灌装系统,装过ubuntu,装过win10 装过黑苹果,突然有一天不识别了,用u盘工具恢复后只有winxp系统能用,win10下就提示不能识别什么标识的,用不了,这个有解没。
可能是烧坏了,只能认成USB1.1了。
2019年新年快乐!
牛逼,底层工程师,写驱动的都是扫地僧级别的。
写驱动的多了,扫地僧只有一个。
再说点个二极管响个蜂鸣器也叫驱动,会C语言的培训两个月都会写。
大神,请问一下,您用的DWC2内核是集成在哪个硬件平台下的?
Altera Cyclone V
大神,了解,再请问一下,Altera Cyclone V是跑VxWorks操作系统吗?移植Linux的DWC2驱动到VxWorks一个人力大概需要花费多长时间? 如果是移植到无操作系统的平台上需要多久? 麻烦告知一下。
对,是跑的VxWorks。DWC2的Host驱动VxWorks是有的,我们搞的是Device和OTC的驱动,花了大概14个人月。Device的大部分功能没问题,OTC还有功能没实现。
移植的最大问题是VxWorks提供的回调接口跟Linux的对不上号。
无操作系统的不了解。
大神,了解。还存在几个疑问。OTC是什么,不是很了解,OTG? 然后DWC2的官方synopsys有提供VxWorks的参考device驱动给你们吗? 我们现在也想移植DWC2 Linux的驱动,但我们会移植到无操作系统的裸机或者freeRTOS上,我们了解到Linux下的驱动是构建在Linux驱动和内核框架上的,所以使用了很多内核的库函数和数据结构体, 我们的裸机并没有Linux这么完善的驱动框架层,所以目前评估移植存在比较大的难度。也不知到有没有人做过DWC2的裸机驱动。不知道大神您对此有什么建议或想法?
对,写错了,OTG。
Host驱动是VxWorks的人写的,Device一直在它的支持列表里,但没实现。
像USB这种比较复杂的驱动,Linux把它分成了上层和下层(VxWorks也是这么干的)。上层负责USB协议的共通逻辑,留了很多上层到下层回调函数接口。上层驱动一般都不用改。下层驱动真正跟硬件寄存器打交道,把上层的回调给实装了,把中断处理明白了,这个驱动算写完。
裸机驱动想读写寄存器是很简单的,我们的硬件开发商就是裸机测芯片好不好用。但是协议的部分(上层)就很复杂,要自己处理很多状态。其实我觉得DWC2这么常见的芯片,应该能找到现成的裸机驱动。
大神,了解。我之前表述的可能有点问题。USB一般是分了好几层,我们这边需要验证的裸机驱动可能不止是读写寄存器,而是基本实现usb的功能,比如作为HOST读写u盘,或者作为device虚拟u盘之类的。所以其实我们这边的裸机驱动是指整个USB功能(包括底层驱动和上层设备类枚举实现之类的)。相当于是不跑OS,跑while(1)之类的主流程,去实现USB功能。 我个人是觉得直接参考Linux的DWC2代码移植到裸机上实现USB完整功能是比较复杂的。不知您那边的建议如何?
我们的裸板程序实现了读写,但是完全没有协议的部分。我觉得两部分都应该有现成的代码,可以抄。不好找的部分是host的具体设备的驱动。USB2.0协议很复杂的,想自己写太容易漏了。
大神,了解。方便分享一下你的裸板读写程序吗? host具体设备的驱动我这边能找到相关示例。 方便留个邮箱联系吗?我的邮箱地址648037365@qq.com 感谢。
不能。有保密协议。而且在专网上无法拷贝。
OK.我们这边大概了解啦。USB2.0协议确实很复杂。感谢大神您抽空帮忙解惑交流。以后有机会再沟通合作啦。