阅读:3972回复:19
老问题:D12的枚举,有很多问的帖子,可是我没发现有一篇帖子把它讨论清楚的。无奈,我叹!!!
关于用51+D12进行USB开发的人很多,所以问关于D12枚举或中断的人也很多,偶是其中之一。我用51+D12做一个数据采集系统,现在被USB部分捆住一周毫无进展,实在无奈,想请教各位:
我的问题是: 1.USB设备跟主机连接后,goodlinkLED指示灯会闪烁三次,之后就无反应,在电脑“设备管理器”中会出现Unknow Device。我知道这是设备枚举不成功的原因,我想问用什么工具或者怎样来调试设备在连接到主机上设备的枚举过程? 2.当设备连接到主机,GoodlinkLED灯闪完之后,我测试D12的/INT脚电瓶状态,有时候一直为低,这样造成程序一直在USB中断服务程序中跑,出不来,但是我不知道为什么/INT的脚位有时候一直为低(但有时灯闪完之后是高电位)???程序中每次进USB中断都是先读了中断寄存器,然后再读了最后结果处理寄存器的!!!! 我把程序贴出来,供大家讨论指教。真的希望走过这段路的有经验的朋友能把这个问题讲清楚,特别是实际调试中的经验。向所有准备给予此问题解答的DX们致谢! #include <stdio.h> #include <string.h> #include "Epphal.h" #include "d12ci.h" #include "mainloop.h" #include "USB100.h" EPPFLAGS bEPPflags; IO_REQUEST idata ioRequest; unsigned char ioSize, ioCount; unsigned long ClockTicks = 0; /* ISR static vars */ unsigned char idata GenEpBuf[EP1_PACKET_SIZE]; unsigned char idata EpBuf[EP2_PACKET_SIZE]; unsigned char idata MainEpBuf[64];//????? extern BOOL bNoRAM; extern CONTROL_XFER ControlData; /******************************************************************************** 函数声明 *********************************************************************************/ void fn_usb_isr(void); void bus_reset(void); void ep0_txdone(void); void ep0_rxdone(void); void ep1_txdone(void); void ep1_rxdone(void); void main_txdone(void); void main_rxdone(void); void dma_eot(void); /******************************************************************************** 函数定义 *********************************************************************************/ void timer_isr(void) interrupt 1//被修饰为中断函数,中断向量表对应T0中断源 { //DISABLE; ET0=0; ClockTicks++; TR0=0; TH0=TH_50MS; TL0=TL_50MS; TR0=1; bEPPflags.bits.timer = 1; ET0=1; //ENABLE; } void usb_isr(void) interrupt 0//被修饰为中断函数,中断向量表对应外部中断0中断源 { DISABLE; /* D12_RESET=0; TR1=0; TF1=0; TL0=TL_3MS; TH0=TH_3MS; TR1=1; while(TF1==0); D12_RESET=1; */ fn_usb_isr(); //test------------------- CPL2; //-------------- ENABLE; } void fn_usb_isr(void) { unsigned int i_st; bEPPflags.bits.in_isr = 1; //set isr_flag i_st = D12_ReadInterruptRegister(); //根据中断标志位判断引起中断的原因,进行相应的中断处理 if(i_st != 0) { if(i_st & D12_INT_BUSRESET) //is BusReset? { bus_reset(); bEPPflags.bits.bus_reset = 1; } if(i_st & D12_INT_EOT) //DMA end of transmit? { dma_eot(); } if(i_st & D12_INT_SUSPENDCHANGE)//is suspend? { bEPPflags.bits.suspend = 1; } if(i_st & D12_INT_ENDP0IN) //is endpoint0 in? { ep0_txdone(); } if(i_st & D12_INT_ENDP0OUT) //is endpoint0 out? { ep0_rxdone(); } if(i_st & D12_INT_ENDP1IN) //is endpoint1 in? { ep1_txdone(); } if(i_st & D12_INT_ENDP1OUT) //is endpoint1 out? { ep1_rxdone(); } if(i_st & D12_INT_ENDP2IN) //is endpoint2 in? { main_txdone(); } if(i_st & D12_INT_ENDP2OUT) //is endpoint2 out? { main_rxdone(); } } bEPPflags.bits.in_isr = 0; //clear isr_flag } void bus_reset(void) { } void dma_eot(void) { } //-----------------------------Control Out Handler---------------------------------------------- /*控制端点0既可能接收SETUP packet也可能接收OUT packet,所以读最终结果状态寄存器的目的,一是为了 清中断,二是为了判断是那一种令牌包。*/ void ep0_rxdone(void) { unsigned char ep_last, i; ep_last = D12_ReadLastTransactionStatus(0); // Clear interrupt flag if (ep_last & D12_SETUPPACKET)//判断是否是一个setup packet? { ControlData.wLength = 0; ControlData.wCount = 0; //判断端点是否满,如是,则取出 if( D12_ReadEndpoint(0, sizeof(ControlData.DeviceRequest), (unsigned char *)(&(ControlData.DeviceRequest))) != sizeof(DEVICE_REQUEST) ) { D12_SetEndpointStatus(0, 1); D12_SetEndpointStatus(1, 1);//判断在SETUP阶段出错,端点0挂起--->这里将向host返回一个stall????? bEPPflags.bits.control_state = USB_IDLE; return; } ControlData.DeviceRequest.wValue = SWAP(ControlData.DeviceRequest.wValue); ControlData.DeviceRequest.wIndex = SWAP(ControlData.DeviceRequest.wIndex); ControlData.DeviceRequest.wLength = SWAP(ControlData.DeviceRequest.wLength); // Acknowledge setup here to unlock in/out endp //向控制输出端点发送应答建立命令以重新使能下一个建立阶段 D12_AcknowledgeEndpoint(0); D12_AcknowledgeEndpoint(1); ControlData.wLength = ControlData.DeviceRequest.wLength; ControlData.wCount = 0; //需要证实控制传输是控制读还是写 //如果控制传输是一个控制读类型那就是说器件需要在下一个数据阶段向 //主机发回数据包.MCU需要设置一个标志以指示USB 设备现在正处于传输 //模式即准备在主机发送请求时发送数据 if (ControlData.DeviceRequest.bmRequestType & (unsigned char)USB_ENDPOINT_DIRECTION_MASK) { bEPPflags.bits.setup_packet = 1; //控制读 bEPPflags.bits.control_state = USB_IDLE; /* get command !!!此处bEPPflags.bits.control_state不能置为USB_TRANSMIT*/ } //如果是写 else { if (ControlData.DeviceRequest.wLength == 0) { bEPPflags.bits.setup_packet = 1; //无数据控制写 bEPPflags.bits.control_state = USB_IDLE; /* set command */ } else { if(ControlData.DeviceRequest.wLength > MAX_CONTROLDATA_SIZE) { bEPPflags.bits.control_state = USB_IDLE; D12_SetEndpointStatus(0, 1); D12_SetEndpointStatus(1, 1); //stall control endpoints } else { //带数据控制写 bEPPflags.bits.control_state = USB_RECEIVE; /* set command with OUT token */ } } // set command with data } // else set command } // if setup packet else if (bEPPflags.bits.control_state == USB_RECEIVE) { i = D12_ReadEndpoint(0, EP0_PACKET_SIZE, ControlData.dataBuffer + ControlData.wCount); ControlData.wCount += i; if( i != EP0_PACKET_SIZE || ControlData.wCount >= ControlData.wLength) { bEPPflags.bits.setup_packet = 1;//数据接收完 bEPPflags.bits.control_state = USB_IDLE; } } else { bEPPflags.bits.control_state = USB_IDLE; } } //---------------------------------Control In Handler------------------------------------- void ep0_txdone(void) { short i = ControlData.wLength - ControlData.wCount; D12_ReadLastTransactionStatus(1); // Clear interrupt flag if (bEPPflags.bits.control_state != USB_TRANSMIT) { return; } //------------------------- if( i >= EP0_PACKET_SIZE) { D12_WriteEndpoint(1, EP0_PACKET_SIZE, ControlData.pData + ControlData.wCount); ControlData.wCount += EP0_PACKET_SIZE; bEPPflags.bits.control_state = USB_TRANSMIT; } else if( i != 0) { D12_WriteEndpoint(1, i, ControlData.pData + ControlData.wCount); ControlData.wCount += i; bEPPflags.bits.control_state = USB_IDLE; } else if (i == 0) { D12_WriteEndpoint(1, 0, 0); // Send zero packet at the end ??? bEPPflags.bits.control_state = USB_IDLE; } } //---------------------------------- void ep1_txdone(void) { D12_ReadLastTransactionStatus(3); /* Clear interrupt flag */ } void ep1_rxdone(void) { unsigned char len; D12_ReadLastTransactionStatus(2); /* Clear interrupt flag */ len = D12_ReadEndpoint(2, sizeof(GenEpBuf), GenEpBuf); if(len != 0) bEPPflags.bits.ep1_rxdone = 1; } //--------------------------------- void main_txdone(void) { unsigned char len; D12_ReadLastTransactionStatus(5); /* Clear interrupt flag */ len = ioSize - ioCount; if(len == 0) { if(bEPPflags.bits.dma_state == DMA_PENDING) { bEPPflags.bits.setup_dma ++; } else { bEPPflags.bits.dma_state = DMA_IDLE; } } else { if(len > 64) { len = 64; } if(bNoRAM) { len = D12_WriteEndpoint(5, len, EpBuf + ioCount); } else { len = D12_WriteEndpoint(5, len, MainEpBuf + ioCount); } ioCount += len; } } void main_rxdone(void) { unsigned char len; D12_ReadLastTransactionStatus(4); /* Clear interrupt flag */ if(bNoRAM) { len = D12_ReadEndpoint(4, 64, EpBuf + ioCount); } else { len = D12_ReadEndpoint(4, 64, MainEpBuf + ioCount); } ioCount += len; if(bNoRAM) { len = D12_ReadEndpoint(4, 64, EpBuf + ioCount); } else { len = D12_ReadEndpoint(4, 64, MainEpBuf + ioCount); } ioCount += len; if(ioCount >= ioSize) { if(bEPPflags.bits.dma_state == DMA_PENDING) { bEPPflags.bits.setup_dma ++; } else { bEPPflags.bits.dma_state = DMA_IDLE; } } } |
|
沙发#
发布于:2004-02-13 10:37
用USB协议分析仪抓下数据就知道问题在那里啦!!!
|
|
板凳#
发布于:2004-02-13 10:45
因为系统枚举USB设备的时间很短,一段时间内如果不成功就说发现一个无法识别的设备。所以,我没有想到好的办法去调试单片机的程序。
我的做法是,把D12的数据线和控制线连接到一台电脑的LPT口,用电脑的LPT口模拟单片机,去操作D12,把从D12读到的东西和写到D12的东西都纪录下来,然后再回过头来查看,这样就可以弄清楚枚举过程中究竟发生了什么。 都弄懂之后,你就把电脑上的软件的程序翻译成单片机的程序就可以了。 其实,没有必要大家都重复设计USB,可以购买现成的USB模块,实现USB通讯。 |
|
|
地板#
发布于:2004-02-13 15:45
我也遇到过了,不过现在已经解决,有几个地方要修改的
不知道你用的是哪个版本的固件和驱动 |
|
|
地下室#
发布于:2004-02-13 15:55
主循环函数呢,其中的RECONNECT()修改一下
|
|
|
5楼#
发布于:2004-02-13 16:39
呵呵,,,等你全部做完之后你就会发现,其实这里有好多帖子已经把它讨论的很明白了,,,,,,
其实枚举就是送几个描述符,,,另外建议你尽量提高单片机的速度,,, |
|
6楼#
发布于:2004-05-12 22:30
主机对USB设备的识别过程叫做枚举,一个完整的Windows对USB设备枚举的过程为(以本系统为例,其它设备可能稍微有些不同):
1) Get Device Descriptor。主机的第一个命令要求得到设备描述符,此SETUP包为8个字节数据(80,06,00,01,00,00,40,00),其具体含义请参考表5-1和5-2。“40”表示返回数据长度最大为40H个字节。实际上,只返回一个包,即数组DEV_DESC[ ]中的前8个字节,用于说明设备的描述符的真实长度和设备的类型。 2) Set Address。接着是设置设备地址处理事件,主机发送一个含有指定地址的数据包(00,05,02,00,00,00,00,00),在主机只有一个USB设备的时候,这个地址一般会是2,最大地址127,USB协议中可以连接127个设备。设置地址事件处理结束后,设备进入地址状态,主机以后会在新的指定地址处访问设备。 3) Get Device Descriptor。主机再次发送请求得到设备描述符的数据包(80,06,00,01,00,00,12,00),与上次不同的是,要求的数据的长度是实际的数据长度。因为D12设备每次只能发送16个字节,因此它会分两次完成此要求(“12”指12H,十进制值为18)。 4) Get Configuration Descriptor。接着主机要求得到设备的配置描述符(80,06,00,02,00,00,09,00),包中数据“09”指定设备发送9个字节,这正是设备配置描述符的长度。 5) 读取全部Configuration Descriptor。接着主机要求得到设备全部的配置描述符、接口描述符和节点描述符(80,06,00,02,00,00,FF,00),由于主机不知道设备描述符的真实长度,因此它要求得到256个字节,实际上本系统中的D12发送46个字节就完成了此任务。 6) 如果以上步骤都正确,主机将找到新设备,提示安装驱动程序;否则找到未知设备,不可用。 如果驱动程序安装成功,主机会再次以描述符的实际长度要求设备重新发送设备描述符和配置描述符;接着主机发送设置设备配置SETUP包,设备处理此事件,将允许所有节点进入工作状态;最后主机请求得到设备和接口的配置,如果设备成功应答,枚举过程结束。此后D12状态灯应该一直亮。 |
|
|
7楼#
发布于:2004-05-15 10:29
为什么我只收到3个Get Device Descriptor 请求,就挂起改变中断了了?
还进不了IN中断,不是在IN里送描述符吗?? 希望能给我指点迷津! 先谢过了!! |
|
8楼#
发布于:2004-05-15 10:31
没有向主机回应,
或者没有向主机发送描述符。 |
|
9楼#
发布于:2004-10-28 22:43
这个帖长,我在跟哈。如果灯已经闪了,就应该与RECONNECT()无关。多半是描述符不对。
|
|
10楼#
发布于:2004-10-29 09:47
我开发了一个U盘,但是向U盘中拷贝文件时很慢!不知道为什麽!
各位老大有相关经验的请帮我一下,告诉我什麽原因! |
|
11楼#
发布于:2004-12-14 17:29
我也有同样的问题,可否交流。qq:343056590
|
|
|
12楼#
发布于:2004-12-14 19:58
呵呵, 我也没仔细看程序,不够我说两句。首先你就应该把采集部分的程序去掉,就单调试d12的枚主, 调试中用断点看看你的中断到底跑到哪了,另外软件不一定有问题,我也出现楼主类似的情况,调了一个星期的软件,没用,最后发现硬件ale引脚虚焊,焊接好后就成功了,也就是地址锁存不对,读不出正确的中断,也就清不了中断寄存器,也就一直为低。所以你得仔细看看硬件有没有问题。
|
|
13楼#
发布于:2004-12-15 09:37
TO lujunql兄,你用的是什么USB芯片啊?可以交流哈。
|
|
14楼#
发布于:2005-07-27 22:33
老问题:D12的枚举,
我的也是这样的毛病,还么解决,应该怎么找出毛病所在啊 |
|
15楼#
发布于:2005-07-28 09:00
Re:老问题:D12的枚举
我也是,有中断,就是得不到EP0中断,晕啊!该怎么办? |
|
16楼#
发布于:2007-06-29 09:21
硬件问题
|
|
|
17楼#
发布于:2007-06-29 10:33
我也是呀,能收到pc的80 06 00 01 00 00 40 00
pc就是收不到我传送的描述符 |
|
18楼#
发布于:2007-08-30 16:02
受教
|
|
19楼#
发布于:2007-11-12 21:27
我和iam200的问题一样
我用的是net2272的芯片 |
|