这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 嵌入式开发» MCU» Get Over It —— 我碰到的USB设备连接问题

共17条 1/2 1 2 跳转至

Get Over It —— 我碰到的USB设备连接问题

助工
2009-10-25 16:08:38 打赏
发现问题
前一阵在学习ARM,到淘宝上买了一块很便宜的AT91SAM7S开发板。这块板子的设计是同ATMEL官方的AT91SAM7S-EK兼容的,因此在AT91SAM7S-EK上能跑的ATMEL例程都可以直接拿来用。由于AT91SAM7S系列的一大特色就是带有USB接口,因此我便迫不及待地想试验一下USB究竟有多么神奇。 在AT91SAM7S-EK Software Package找了个最简单的USB例程usb-device-core-project,用J-link下到板子里去,一运行,Windows竟然提示检测到无法识别的USB设备,没有出现令人期待的新硬件安装向导。多次拔插依然如故。在调试串口里看到了这些信息:

初步分析
因为用的是ATMEL官方例程,我暂时还不敢怀疑程序会出错。莫非是我的板子的问题?为了搞个究竟,我打算先研究一下源程序再说。 在main.c中查找,发现不断输出错误信息的函数是static void ISR_Vbus(const Pin*pPin)。这个函数是一个中断服务程序,内容也很简单,就是检测一下引脚pinVbus上的电压,如果是1,则调用USBD_Connect(),把引脚pinPullUp置为0;否则调用USBD_Disconnect(),把引脚pinPullUp置为1。这个中断服务函数是在函数static void VBus_Configure(void)中配置的。每当pinVbus引脚上的电压发生变化时,就会引起这个PIO中断。 //------------------------------------------------------------------- /// Handles interrupts coming from PIO controllers. //------------------------------------------------------------------- static voidISR_Vbus ( constPin *pPin ) { // Check current level on VBus if (PIO_Get (&pinVbus )) {TRACE_INFO ("VBUS conn\n\r" );USBD_Connect (); //PIO_Clear(&pinPullUp); } else {TRACE_INFO ("VBUS discon\n\r" );USBD_Disconnect (); //PIO_Set(&pinPullUp); } } 上图调试串口输出的结果表明, ISR_Vbus这个中断一直在不断地被调用,而且pinVBUS引脚上的电压也在不断地高低变化。为了搞清楚问题的原因,我尝试在函数ISR_Vbus的入口处下断点。当板子插入USB接口时,程序被断了下来,继续单步运行,程序输出VBUS conn。继续全速运行,Windows竟然提示发现新硬件了,板子工作正常。但是如果删除断点全速运行,板子工作就又会不正常,真是一件奇怪的事情。
初步解决

仔细思考一下,单步运行程序和全速运行程序到底有什么区别呢?代码完全一样,但是,单步运行程序的时候在两句代码间会有延迟。由此推测程序中可能需要加入延时。联想到按键去抖动的原理,即检测到电平变化后需要等待一段时间再检测一次以排除干扰,我尝试在PIO_Get(&pinVbus)前加一小段延时,程序变成这样: //------------------------------------------------------------------- // Software wait loop -- suspends all tasks! //------------------------------------------------------------------- voiddelay ( intwait_time ) { volatile unsigned int i ; for (i =0 ;i <wait_time * ( BOARD_MCK / 10000 ) ;i ++ ) { ;;; } }
//------------------------------------------------------------------- /// Handles interrupts coming from PIO controllers. //------------------------------------------------------------------- static voidISR_Vbus( constPin *pPin) { // Check current level on VBus
delay(1);// Wait a moment if(PIO_Get(&pinVbus)){ TRACE_INFO("VBUS conn\n\r"); USBD_Connect(); //PIO_Clear(&pinPullUp);} else{ TRACE_INFO("VBUS discon\n\r"); USBD_Disconnect(); //PIO_Set(&pinPullUp);} } 再次下载运行,一切正常。

深入分析
最后再来看一下板子上pinVbus(即PA13,图中VBUS_DET)和pinPullUp(即PA16,图中USB_DP_PUP)引脚究竟是怎样连接的,彻底搞清其中原理。原理图如下所示,很简单。当板子插到USB接口中后,VBUS处会从电阻处分压到高电平,此时会触发pinVbus的PIO中断。系统检测到中断后,调用ISR_Vbus函数,将USB_DP_PUP置为低电平。此时N型MOS管Q1的Vgs>导通电压,管子导通,进而导致P型MOS管Q2的栅极接低电平,Q2也导通。这样D+数据线就通过1.5K电阻接到VCC,建立了USB连接。若设备从USB总线中移除(VBUS=0)或者将USB_DP_UP置为高电平,都会使Q1、Q2截止,断开了1.5K上拉电阻。
从电路中可以看到,pinVbus是直接连接到VBUS的,若VBUS的电平发生变化,就会产生PIO中断。在刚刚插入USB接口的那一瞬间,VBUS电平不稳定,会不断触发中断(这和按键的抖动有些类似),由此引发USB_DP_PUP引脚上的电压也不断改变。后来VBUS虽然稳定了,但是USB_DP_PUP引脚上不断改变的电压已经通过某种耦合(这可能与PCB的设计相关)使VBUS_DET处的电压产生震荡,再次引发中断,在中断处理程序中又会改变USB_DP_PUP引脚上的电压,从而使电路产生了自激震荡,无法正常工作。

经验总结 也许在你用的板子上没有出现类似的问题,但是我的这次经历表明,在中断程序中不加延时直接检测VBUS上的电压是有风险的。你可能会遇到USB有时工作正常,有时工作不正常的现象,这时就需要看看是否有上面的问题。特别是我们一般都比较信赖官方的例程,往往会不加修改的直接借用,因此那个有风险的ISR_Vbus函数可能正在被许多系统使用着。 另外,如果在调试过程中单步运行程序工作正常,而全速运行则工作不正常,这很可能是说明程序的时序上出现了问题。尝试加入一些延时(特别在检测一些易产生电平抖动的器件的电压时),也许就能解决问题。这可以算得上是一个调试的技巧。这是我从这次经历中总结出的另一个经验。

多谢sjdai指出文中不严谨之处!现已改正!若仍有问题还请大家多多指教!



关键词: 碰到 设备 连接 问题 运行 程序 中断 电压

高工
2009-10-25 18:38:32 打赏
2楼
很好,赞一个!

院士
2009-10-27 08:51:03 打赏
3楼
需要这样的案例

菜鸟
2009-10-28 09:18:44 打赏
4楼

狂赞


院士
2009-10-28 09:27:27 打赏
5楼
看楼主的ID,莫非是Vicor公司的?
张先生?

victorzhang

助工
2009-10-28 13:51:42 打赏
6楼
呵呵,楼上猜错了,victor只是我在网络上使用的英文名字而已

院士
2009-10-28 15:56:08 打赏
7楼
看错了,是羽毛球拍的品牌啊~~

呵呵

工程师
2009-10-28 21:12:22 打赏
8楼

很精彩


菜鸟
2009-10-31 15:01:53 打赏
9楼
路过支持一下。

工程师
2009-11-03 23:35:34 打赏
10楼

呵呵,不错顶一个!


共17条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]