CH375做为设备方式,使用外部固件方式,上电后通过USB线和PC连通,通过bus hound只拦截到集线器类的命令,PC都没有给CH375设备发出Get_descriptor,这是什么原因??? 我首先复位CH375,然后Set_Usb_mode(DEV_Ext_Firmware),这时就会有0x07的usb总线复位状态中断,然后就没有中断发生了。PC说未知设备。 怎么会连第一个Get_descriptor都不出现???? 改为内部固件方式时,PC会发出Get_descriptor,能够正确枚举。
(1)外置固件,需要用户处理所有的中断,复位中断是如何处理的?接收复位中断后,要解锁 (2)CH372EVT.ZIP中\PUB\XFIRM\C\下有完整C语言示例
有unlock_usb,PC还是不发送Get_descriptor。 Bus Hound 5.04 capture on Windows XP Service Pack 2. Complements of www.perisoft.net
Device - Device ID (followed by the endpoint for USB devices) (21) USB Root Hub (24) Unknown Device Phase - Phase Type CTL USB control transfer IN Data in transfer Data - Hex dump of the data transferred Descr - Description of the phase Cmd... - Position in the captured data
Device Phase Data Description Cmd.Phase.Ofs(rep) ------ ----- ------------------------ ---------------- ------------------ 21 IN 1.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 2.1.0(2) 21.0 IN 00 01 01 00 .... 2.2.0 21.0 CTL 23 01 10 00 01 00 00 00 CLEAR FEATURE 4.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 5.1.0 21.0 IN 00 01 00 00 .... 5.2.0 21.0 CTL a3 00 00 00 02 00 04 00 GET STATUS 6.1.0 21.0 IN 00 01 00 00 .... 6.2.0 21 IN 7.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 8.1.0(2) 21.0 IN 01 01 01 00 .... 8.2.0 21.0 CTL 23 01 10 00 01 00 00 00 CLEAR FEATURE 10.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 11.1.0(2) 21.0 IN 01 01 00 00 .... 11.2.0 21.0 CTL 23 03 04 00 01 00 00 00 SET FEATURE 13.1.0 21 IN 14.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 15.1.0 21.0 IN 03 01 10 00 .... 15.2.0 21.0 CTL 23 01 14 00 01 00 00 00 CLEAR FEATURE 16.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 17.1.0(3) 21.0 IN 03 01 00 00 .... 17.2.0 21.0 CTL 23 03 04 00 01 00 00 00 SET FEATURE 19.1.0(2) 21 IN 20.1.0(2) 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 21.1.0(2) 21.0 IN 03 01 10 00 .... 21.2.0 21.0 CTL 23 01 14 00 01 00 00 00 CLEAR FEATURE 22.1.0(2) 21.0 CTL 23 01 01 00 01 00 00 00 CLEAR FEATURE 28.1.0 21.0 CTL a3 00 00 00 02 00 04 00 GET STATUS 29.1.0 21.0 IN 00 01 00 00 .... 29.2.0 21 IN 30.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 31.1.0(2) 21.0 IN 00 01 01 00 .... 31.2.0 21.0 CTL 23 01 10 00 01 00 00 00 CLEAR FEATURE 33.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 34.1.0 21.0 IN 00 01 00 00 .... 34.2.0 21.0 CTL a3 00 00 00 02 00 04 00 GET STATUS 35.1.0 21.0 IN 00 01 00 00 .... 35.2.0 21 IN 36.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 37.1.0(2) 21.0 IN 01 01 01 00 .... 37.2.0 21.0 CTL 23 01 10 00 01 00 00 00 CLEAR FEATURE 39.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 40.1.0(2) 21.0 IN 01 01 00 00 .... 40.2.0 21.0 CTL 23 03 04 00 01 00 00 00 SET FEATURE 42.1.0 21 IN 43.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 44.1.0 21.0 IN 03 01 10 00 .... 44.2.0 21.0 CTL 23 01 14 00 01 00 00 00 CLEAR FEATURE 45.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 46.1.0(3) 21.0 IN 03 01 00 00 .... 46.2.0 21.0 CTL 23 03 04 00 01 00 00 00 SET FEATURE 48.1.0(2) 21 IN 49.1.0(2) 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 50.1.0(2) 21.0 IN 03 01 10 00 .... 50.2.0 21.0 CTL 23 01 14 00 01 00 00 00 CLEAR FEATURE 51.1.0(2) 21.0 CTL 23 01 01 00 01 00 00 00 CLEAR FEATURE 57.1.0 21.0 CTL a3 00 00 00 02 00 04 00 GET STATUS 58.1.0 21.0 IN 00 01 00 00 .... 58.2.0 21 IN 59.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 60.1.0(2) 21.0 IN 00 01 01 00 .... 60.2.0 21.0 CTL 23 01 10 00 01 00 00 00 CLEAR FEATURE 62.1.0 21.0 CTL a3 00 00 00 01 00 04 00 GET STATUS 63.1.0 21.0 IN 00 01 00 00 .... 63.2.0 21.0 CTL a3 00 00 00 02 00 04 00 GET STATUS 64.1.0 21.0 IN 00 01 00 00 .... 64.2.0 都是集线器的命令。
应该还是程序上的原因,不妨贴出来看看
首先一个就是在你程序一上来需要延时50MS以上,然后设置模式1,这个时候主机就会发送相应的请求下来.
好的,下面是代码。CH375_init是正常的,set_usb_mode函数也是好的,HOST_MODE方式我使用过。 hid_usb_status_handler( )由外部中断1处理函数调用。 main() { res = CH375_init(); CH375_set_ext_slave_mode(); while(P1_1==0); //检测usb线接通,上电 InitInt1(1); }
unsigned char CH375_init( ) { unsigned char i; unsigned char ver;
/* test the ch375 */ for (i=5; i!=0; i--) { CH375_write_cmd(CMD_CHECK_EXIST); CH375_write_data(0x55); ver = CH375_read_data(); // isnt version, assign to ver for test only if ( ver== 0xaa ) { break; } CH375_write_cmd(CMD_RESET_ALL); delay_nms(50); } if(i==0) return 0xff; CH375_write_cmd(CMD_GET_IC_VER); ver = CH375_read_data(); return(ver&~0x80); }
unsigned char CH375_set_usb_mode(unsigned char mode) { CH375_write_cmd(CMD_SET_USB_MODE); delay_1us(); CH375_write_data(mode); delay_nus(40); /* wait operate successfully, less than 20us */ if( CH375_read_data()==CMD_RET_SUCCESS) return 0; else return 0xff; }
uint8 CH375_set_ext_slave_mode() reentrant { return CH375_set_usb_mode(DEVICE_ACTIVE_EXT_FIRMWARE); }
typedef struct _tagEP_STATE { unsigned char ep0_in_busy : 1; unsigned char ep0_in_mutex : 1; unsigned char ep1_in_busy : 1; unsigned char ep1_in_mutex : 1; unsigned char ep2_in_busy : 1; unsigned char ep2_in_mutex : 1; unsigned char * ep0_in_ptr; unsigned char ep0_in_len; unsigned char xdata * ep1_in_ptr; unsigned char ep1_in_len; unsigned char xdata * ep2_in_ptr; unsigned char ep2_in_len; } EP_STATE, * PEP_STATE;
unsigned char enum_state; unsigned char remote_wakeup; unsigned char hid_protocol; unsigned char hid_idle;
SETUP setup; EP_STATE ep_state; uint8 configure_value; unsigned char setup_echo[2]; unsigned char hid_report_data[8];
/* In user code, check device is avalibe and idle using while(ep_state.epx_in_mutex==1); == device has no buffer assigned to transfer. while(ep_state.epx_in_busy==1); == device has no data left in tx buffer. then set ep_state.epx_in_mutex = 1; assign ep_state.epx_in_ptr and ep_state.epx_in_len to fire transfer. */ void usb_transmit(unsigned char no) reentrant { if(no==3 && ep_state.ep0_in_len && ep_state.ep0_in_ptr) { ep_state.ep0_in_busy = 1; if(ep_state.ep0_in_len>8) { CH375_write_usb_data(3, ep_state.ep0_in_ptr, 8); ep_state.ep0_in_ptr += 8; ep_state.ep0_in_len -= 8; } else { CH375_write_usb_data(3, ep_state.ep0_in_ptr, ep_state.ep0_in_len); ep_state.ep0_in_ptr = NULL; ep_state.ep0_in_len = 0; ep_state.ep0_in_mutex = 0; } } else if(no==5 && ep_state.ep1_in_len && ep_state.ep1_in_ptr) { ep_state.ep1_in_busy = 1; if(ep_state.ep1_in_len>8) { CH375_write_usb_data(no, ep_state.ep1_in_ptr, 8); ep_state.ep1_in_ptr += 8; ep_state.ep1_in_len -= 8; } else { CH375_write_usb_data(no, ep_state.ep1_in_ptr, ep_state.ep1_in_len); ep_state.ep1_in_ptr = NULL; ep_state.ep1_in_len = 0; ep_state.ep1_in_mutex = 0; } } else if(no==7 && ep_state.ep2_in_len && ep_state.ep2_in_ptr) { ep_state.ep2_in_busy = 1; if(ep_state.ep2_in_len>64) { CH375_write_usb_data(no, ep_state.ep2_in_ptr, 64); ep_state.ep2_in_ptr += 64; ep_state.ep2_in_len -= 64; } else { CH375_write_usb_data(no, ep_state.ep2_in_ptr, ep_state.ep2_in_len); ep_state.ep2_in_ptr = NULL; ep_state.ep2_in_len = 0; ep_state.ep2_in_mutex = 0; } } else return;
}
void hid_usb_status_handler( ) reentrant { uint8 status, len, req_type, usb_addr; uint8 bDescriptor; uint8 bIndexofwValue;
status = CH375_get_status();
switch(status) { case(USB_INT_EP0_SETUP): { SBUF = '1'; len=CH375_read_usb_data((uint8 xdata * )&setup, 8); if( len != 8 ) { CH375_set_endp(3, ENDP_STALL); break; } setup.wValue = ENDIANADJ(setup.wValue); setup.wIndex = ENDIANADJ(setup.wIndex); setup.wLength = ENDIANADJ(setup.wLength); req_type = setup.bmRequestType & USB_REQUEST_TYPE_MASK; switch(req_type) { SBUF = '2'; case(USB_STANDARD_REQUEST): //setup standard request { //一些请求只有在USB设备处于特定状态时有效,本实现没有实现状态检测,由USB主控制器保证 //具体请求的有效状态参考相关资料 SBUF = '3'; switch(setup.bRequest) { SBUF = '4'; //本请求只有USB设备处于地址状态和配置状态时才有效 case(DEF_USB_GET_STATUS): { if(setup.bmRequestType & USB_RECIPIENT_MASK == USB_RECIPIENT_DEVICE) { setup_echo[0]=3; // support self-powered and remote wake up setup_echo[1]=0; CH375_write_usb_data(3, setup_echo, 2); } else if(setup.bmRequestType & USB_RECIPIENT_MASK == USB_RECIPIENT_INTERFACE) { setup_echo[0]=0; //应该检测接口的有效性,同样由USB主控制器保证 setup_echo[1]=0; CH375_write_usb_data(3, setup_echo, 2); } else //(ep0.setup.bmRequestType & USB_RECIPIENT_MASK == USB_RECIPIENT_ENDPOINT) { setup_echo[0]=0; // not stoped setup_echo[1]=0; //应该检测端点的有效性,同样由USB主控制器保证 CH375_write_usb_data(3, setup_echo, 2); } break; } //本请求只有USB设备处于地址状态和配置状态时才有效 case(DEF_USB_CLR_FEATURE): { if( (setup.bmRequestType & USB_RECIPIENT_MASK == USB_RECIPIENT_ENDPOINT) && setup.wValue == USB_FEATURE_ENDPOINT_STALL ) { if(setup.wIndex==0x01) { CH375_set_endp(4, 0x80); CH375_write_usb_data(3, NULL, 0); } else if(setup.wIndex==0x81) { CH375_set_endp(5, 0x8E); CH375_write_usb_data(3, NULL, 0); } else if(setup.wIndex==0x02) { CH375_set_endp(6, 0x80); //清除端点2下传 CH375_write_usb_data(3, NULL, 0); } else if(setup.wIndex==0x82) { CH375_set_endp(7, 0x8E); //发命令清除端点 CH375_write_usb_data(3, NULL, 0); } else { CH375_set_endp(3, ENDP_STALL); } } else if( (setup.bmRequestType & USB_RECIPIENT_MASK == USB_RECIPIENT_DEVICE) && setup.wValue == USB_FEATURE_REMOTE_WAKEUP) { remote_wakeup = 0; //清0远程唤醒标志 CH375_write_usb_data(3, NULL, 0); //返回一个空的数据表示执行完毕 } else { CH375_set_endp(3, ENDP_STALL); } break; } case(DEF_USB_SET_FEATURE): { CH375_set_endp(3, ENDP_STALL); break; } //地址的设定应该根据不同的设备状态,本实现不做检测,直接设定,正确性由USB主控制器保证 case(DEF_USB_SET_ADDRESS): { usb_addr=(uint8)setup.wValue; CH375_write_usb_data(3, NULL, 0); CH375_set_usb_addr(usb_addr); break; } case(DEF_USB_GET_DESCR): { bDescriptor = MSB(setup.wValue); //读取请求的描述符类型 if(setup.bmRequestType & USB_RECIPIENT_MASK == USB_RECIPIENT_DEVICE) { switch(bDescriptor) { case(USB_DEVICE_DESCRIPTOR): { while(ep_state.ep0_in_mutex==1); while(ep_state.ep0_in_busy==1); ep_state.ep0_in_mutex = 1; ep_state.ep0_in_ptr = device_descriptor; ep_state.ep0_in_len = sizeof(DEVICE_DESCRIPTOR_STRUCT); usb_transmit(3); break; } case(USB_CONFIGURATION_DESCRIPTOR): { if (setup.wLength > ENDIANADJ(((pUSB_DESCRIPTOR_STRUCT)config_descriptor)->configuration_descriptor.wTotalLength)) setup.wLength = ENDIANADJ(((pUSB_DESCRIPTOR_STRUCT)config_descriptor)->configuration_descriptor.wTotalLength);
贴出来程序没有层次感了。 一执行了Set_usb_mode(EXT_SLAVE),就有中断产生,返回0x07。以后就再也没有中断了。PC上显示的未知设备。
main()函数后面有个while(1);是我没有贴出来
(1)CH375_read_data()中若是用CMD_RD_USB_DATA读取数据,则不需要再调用CH375_unlock_usb()解锁,那么解锁函数位置错误。 (2)建议先用我们的外置固件示例程序调试,理解整个流程后再移植,同时也便于我们分析。
噢 好的,我再修改一下试试。不过我发现问题在于hid_usb_handler可以进入,但是switch语句无法进入。直接调用软件仿真,会出现胡乱跳转,会执行两个平行的case,可能是编译器将一个case的语句优化掉了,然后又进入另一个case。
向EP0_IN管道里只写ACK,就是写0个字节,会不会引起EP0_IN中断?为什么我的程序写ACK总是会引起EP0——IN中断?而你们的代码的ACK我却没有发现会引起中断?到底是怎么回事?
会的,释放一下缓冲区就可以了.
折腾了一周,自己写的HID设备的代码,终于能够正常枚举了,CH375还真是够古怪的,搞一次从设备外部固件方式的开发,简直就是下一次地狱。还好,终于摸到CH375的脉门了。感觉文档提供的信息太笼统了。
你好,我现在也在做设备方式的外部固件的程序,也出现了问题,你能把你的程序发给我,借我看一看吗?谢谢
我们有个CH375通过外部固件模式模拟鼠标键盘的例子,可以参考: /bbs/View.asp?S=101&I=19463
使用CH375的外部固件模式时,单片机接收到0x0c中断,EP0成功setup后,使用CH375的RD_USB_DATA命令时,每读取完一个字节后,需解锁一次
如:
ch375_write_cmd(0x28);
ch375_read_byte(&data);
ch375_write_cmd(0x23);
for(i=0;i<8;i++)
{
ch375_read_byte(buf+i);
ch375_write_cmd(0x23);
}
使用以上代码,可以读取到主机发送的8字节数据80 06 00 01 00 00 40 00