[求助]ch375host读usb设备描述符怪事

按照网站例子用get_descr(2获取配置描述符可以得出一串正确的完整的配置描述符(包括接口、端点等描述符信息)。但用一下语句读配置描述符本身(不包括接口、端点),rd_usb_data函数读出后续数据长度是8不是9,但读完长度后,读数据时第一字节(按协议来说应该是配置描述符的长度)却是9。语句如下:

endp7_mode=0x80; toggle_send(); wr_usb_data(8,get_ctg_des);//get_ctg_des,0x80,0x06,0x00,0x02,0x00,0x00,9,0 status=issue_token(( 0 << 4 ) | DEF_USB_PID_SETUP); if(status==USB_INT_SUCCESS)/* SETUP阶段操作成功 */ { endp6_mode=0xc0; toggle_recv(); } else return(0); status=issue_token(( 0 << 4 ) | DEF_USB_PID_IN); if(status==USB_INT_SUCCESS)/* DATA阶段操作成功 */ rd_usb_data(RECV_BUFFER); [Emot]13[/Emot]

其实是这样的,获取描述符是以控制传输通过端点0来获取的,端点0最大为8个字节,而你想获取的配置描述符为9个字节,这样其实就需要两次传输才能将9个字节获取上来。


按照这个例子,你应该读取2次才能读完,也就是说控制端点的端点大小为8字节,一次最多传输8字节的数据,所以,你读取到的数据长度为9的话,那么,你应该读取2次之后(第一次为8字节,第2次为1字节)就能读取完数据


能不能提供一个51控制375host的外置固件程序呢?


请参考以下程序: unsigned char get_descr_ex() { unsigned char descr_len; unsigned char *p=data_buf; endp7_mode=0x80; toggle_send(); wr_usb_data(8,Request.Req_buf); issue_token(( 0 << 4 ) | DEF_USB_PID_SETUP);status=wait_interrupt(); if(status==USB_INT_SUCCESS)/* SETUP阶段操作成功 */ { endp6_mode=0xc0; toggle_recv(); } else return(0); issue_token(( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS)/* DATA阶段操作成功 */ { if(flag_config_2)descr_len=data_buf[2]-rd_usb_data(data_buf); else descr_len=data_buf[0]-rd_usb_data(data_buf); while(descr_len>0) { toggle_recv(); p+=0x08; issue_token(( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) /* DATA阶段操作成功 */ descr_len-=rd_usb_data(p); else return(0); } } else return(0); endp7_mode=0xc0; toggle_send(); wr_usb_data(0,Request.Req_buf); issue_token(( 0 << 4 ) | DEF_USB_PID_OUT);status=wait_interrupt(); if(status==USB_INT_SUCCESS)/* 状态阶段操作成功 */ return(1); else return(0); } void get() /* 获取配置描述符 */ { unsigned short i;

Request.Req.bmRequestType=0x80; Request.Req.bRequest=0x06; Request.Req.wValue=0x0002; Request.Req.wIndex=0x0000; Request.Req.wLength=0x0900; if(get_descr_ex()==1) { for(i=0;i!=buffer[0];i++) printf("%02x ",(unsigned int)buffer[i]); printf("\n");

} else printf("get config descr failed\n"); printf("config 2\n"); if(buffer[2]>0x09) {flag_config_1=1; Request.Req.bmRequestType=0x80; Request.Req.bRequest=0x06; Request.Req.wValue=0x0002; Request.Req.wIndex=0x0000; Request.Req.wLength=0x0000|((unsigned int)buffer[2]<<8); if(get_descr_ex()==1) { for(i=0;i!=buffer[2];i++) printf("%02x ",(unsigned int)buffer[i]); printf("\n"); flag_config_1=0; } else printf("get device descr again failed\n"); }


再读一次是成功了,不过疑问又来了,读一次端点0,难度就一定要返回8个字节,就不可以是一个字节?通过修改descr_len也不行吗?


不是这个意思,在USB协议里面,你发下去的控制传输的命令里面,最后2个字节是你需要获取的描述符的长度,如果获取的描述符的长度是小于实际上传的长度的话(也就是上面的程序),那么,就直接返回你要取的描述符的长度,如果实际的描述符的长度是小于你要获取的长度的话,那么,就传输实际描述符的长度,实际描述符的长度,对于设备描述符的长度是开始的第一个字节,配置描述符是描述符的第3个字节。你如果想获取一个字节的描述符也可以啊,直接在你发送控制传输的命令里面将获取描述符的长度改为01就可以了(80 06 00 02 00 00 01 00)。但是实际的描述符的长度还是实际存在一定的长度,只不过你没有去获取完。


endp7_mode=0x80; toggle_send(); wr_usb_data(8,get_ctg_des); //读配置描述符,0x80,0x06,0x00,0x02,0x00,0x00,0x09,0x00 status=issue_token(( 0 << 4 ) | DEF_USB_PID_SETUP); if(status==USB_INT_SUCCESS)/* SETUP阶段操作成功 */ { endp6_mode=0xc0; toggle_recv(); } else return(0); status=issue_token(( 0 << 4 ) | DEF_USB_PID_IN); if(status==USB_INT_SUCCESS)/* DATA阶段操作成功 */ rd_usb_data(RECV_BUFFER); get_ctg_des[6]=0x01; toggle_recv(); status=issue_token(( 0 << 4 ) | DEF_USB_PID_IN); if(status==USB_INT_SUCCESS)/* DATA阶段操作成功 */ rd_usb_data(RECV_BUFFER); 我修改了长度值成1,但第二次读出还是8个字节,虽然这8个字节是前8个字节的后续


你看一下get_ctg_des[6]里面的数据,发出来看一下!!


0x80,0x06,0x00,0x02,0x00,0x00,0x01,0x00


归根到底还是对usb协议不熟悉,各位能不能提供一份usb中文协议呢?,网上搜到的都是同一版本,里面3个压缩包,第一个打不开。能找到一份完整的就最好了,谢谢各位的帮助


按照你写的程序,第一个发送获取长度为1字节的描述符的话,那么,在发送SETUP包的时候,操作成功,在发送IN包的时候,应该也是成功,这个时候读取数据的时候,数据长度为1,在发送IN的时候,就不应该有中断,你应该及时的发送状态包,让设备给你返回成功


终于知道原因了,第一次获取是0x80,0x06,0x00,0x02,0x00,0x00,0xff,0x00,所以读了ff个字节,第2次0x80,0x06,0x00,0x02,0x00,0x00,0x01,0x00,虽然第二次将长度改成1,但还是将前一次命令读的都读出来了。我将第一次长度改了9,之后就正常了,谢谢各位耐心指导


还有一个问题就是你们提供的内置固件的程序在调用toggle_recv和toggle_send之前没有给endp6_mode和endp7_mode赋初值,那么第一次调用这两个函数时endp6_mode和endp7_mode是等于0的,再调用就成了0x40了。不知道理解对没有.但看pdf的介绍只说过0x80和0xc0这两个值,没有0和0x40这两个值。应该怎样理解这两个变量呢? void toggle_recv(void) /* 主机接收成功后,切换DATA0和DATA1实现数据同步 */ { CH375_WR_CMD_PORT( CMD_SET_ENDP6 ); CH375_WR_DAT_PORT( endp6_mode ); endp6_mode^=0x40; delay2us(); }

void toggle_send(void) /* 主机发送成功后,切换DATA0和DATA1实现数据同步 */ { CH375_WR_CMD_PORT( CMD_SET_ENDP7 ); CH375_WR_DAT_PORT( endp7_mode ); endp7_mode^=0x40; delay2us(); }


endp6_mode 肯定是有初值的,按照我们提供的例子程序,应该是: void toggle_recv( BOOL1 tog ) { /* 主机接收同步控制:0=DATA0,1=DATA1 */ CH375_WR_CMD_PORT( CMD_SET_ENDP6 ); CH375_WR_DAT_PORT( tog ? 0xC0 : 0x80 ); delay2us(); }

void toggle_send( BOOL1 tog ) { /* 主机发送同步控制:0=DATA0,1=DATA1 */ CH375_WR_CMD_PORT( CMD_SET_ENDP7 ); CH375_WR_DAT_PORT( tog ? 0xC0 : 0x80 ); delay2us(); }


同步控制到底是在什么情况下需要做的呢,如何操作呢,375的pdf没有详细说


只有登录才能回复,可以选择微信账号登录