完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
各位老师,我在使用HID设备时候出现问题,请百忙之中指导,现象如下:
1.我的上位机是使用hidapi 库的,仅仅通过hid_read读取。通过上位机读取数据,无法读到上传数据 2.另外我直接使用CH9326的DEBUG程序打开该设备,试着读取,效果一样。还是无法读到数据。 3.先写使用hid_write写一帧数据,则可以读到一帧数据,再写则可以再读一帧数据。意思是只能写一帧才能读一帧。 问题如下:
* File Name : Main.c * Author : WCH * Version : V1.0 * Date : 2020/02/20 * Description : 模拟USB复合设备,键鼠,支持类命令 *******************************************************************************/ #include "CH58x_common.h" #define DevEP0SIZE 0x10 // 设备描述符 const UINT8 MyDevDescr[] = { 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, DevEP0SIZE, 0x3d, 0x41, 0x07, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; // 配置描述符 const UINT8 MyCfgDescr[] = { 0x09,0x02,0x29,0x00,0x01,0x01,0x04,0xA0,0x23, //配置描述符 0x09,0x04,0x00,0x00,0x02,0x03,0x00,0x00,0x05, //接口描述符 0x09,0x21,0x00,0x01,0x00,0x01,0x22,0x22,0x00, //HID类描述符 0x07,0x05,0x82,0x03,DevEP0SIZE,0x00,0x01, //端点描述符(全速间隔时间改成1ms) 0x07,0x05,0x02,0x03,DevEP0SIZE,0x00,0x01, //端点描述符 }; // 语言描述符 const UINT8 MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 }; // 厂家信息 const UINT8 MyManuInfo[] = { 0x0E, 0x03, 'X', 0, 'i', 0, 'n', 0, 'L', 0, 'i', 0, 'n', 0 }; // 产品信息 const UINT8 MyProdInfo[] = { 0x0C, 0x03, 'M', 0, 'a', 0, 'g', 0, 'i', 0, 'c', 0 }; /*HID类报表描述符*/ const UINT8 CfgDesc[] = { 0x06, 0x00,0xff, 0x09, 0x01, 0xa1, 0x01, //集合开始 0x09, 0x02, //Usage Page 用法 0x15, 0x00, //Logical Minimun 0x26, 0x00,0xff, //Logical Maximun 0x75, 0x08, //Report Size 0x95, DevEP0SIZE, //Report Counet 0x81, 0x06, //Input 0x09, 0x02, //Usage Page 用法 0x15, 0x00, //Logical Minimun 0x26, 0x00,0xff, //Logical Maximun 0x75, 0x08, //Report Size 0x95, DevEP0SIZE, //Report Counet 0x91, 0x06, //Output 0xC0 }; /**********************************************************/ UINT8 DevConfig, Ready; UINT8 SetupReqCode; UINT16 SetupReqLen; const UINT8 *pDescr; /*鼠标键盘数据*/ UINT8 HIDInOutData[DevEP0SIZE] = { 0 }; /******** 用户自定义分配端点RAM ****************************************/ __attribute__((aligned(4))) UINT8 EP0_Databuf[64 + 64 + 64]; //ep0(64)+ep4_out(64)+ep4_in(64) __attribute__((aligned(4))) UINT8 EP1_Databuf[64 + 64]; //ep1_out(64)+ep1_in(64) __attribute__((aligned(4))) UINT8 EP2_Databuf[64 + 64]; //ep2_out(64)+ep2_in(64) __attribute__((aligned(4))) UINT8 EP3_Databuf[64 + 64]; //ep3_out(64)+ep3_in(64) void USB_DevTransProcess( void ) { UINT8 len, chtype; UINT8 intflag, errflag = 0; intflag = R8_USB_INT_FG; if ( intflag & RB_UIF_TRANSFER ) { if ( ( R8_USB_INT_ST & MASK_UIS_TOKEN ) != MASK_UIS_TOKEN ) // 非空闲 { switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) ) // 分析操作令牌和端点号 { case UIS_TOKEN_IN : { switch ( SetupReqCode ) { case USB_GET_DESCRIPTOR : len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen; // 本次传输长度 memcpy( pEP0_DataBuf, pDescr, len ); /* 加载上传数据 */ SetupReqLen -= len; pDescr += len; R8_UEP0_T_LEN = len; R8_UEP0_CTRL ^= RB_UEP_T_TOG; // 翻转 break; case USB_SET_ADDRESS : R8_USB_DEV_AD = ( R8_USB_DEV_AD & RB_UDA_GP_BIT ) | SetupReqLen; R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; break; default : R8_UEP0_T_LEN = 0; // 状态阶段完成中断或者是强制上传0长度数据包结束控制传输 R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; break; } } break; case UIS_TOKEN_OUT : { //GPIOB_InverseBits(GPIO_Pin_19); len = R8_USB_RX_LEN; //if ( SetupReqCode == 0x09 ) { GPIOB_WriteBit(GPIO_Pin_19, pEP0_DataBuf[0]); } } break; case UIS_TOKEN_OUT | 1 : { if ( R8_USB_INT_ST & RB_UIS_TOG_OK ) { // 不同步的数据包将丢弃 len = R8_USB_RX_LEN; DevEP1_OUT_Deal( len ); } } break; case UIS_TOKEN_IN | 1 : R8_UEP1_CTRL = ( R8_UEP1_CTRL & ~MASK_UEP_T_RES ) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 2 : { if ( R8_USB_INT_ST & RB_UIS_TOG_OK ) { // 不同步的数据包将丢弃 len = R8_USB_RX_LEN; DevEP2_OUT_Deal( len ); } } break; case UIS_TOKEN_IN | 2 : //GPIOB_InverseBits(GPIO_Pin_19); // if ( !pEP2_IN_DataBuf[0] ) // { // GPIOB_SetBits(GPIO_Pin_19); // } // else // { // GPIOB_ResetBits(GPIO_Pin_19); // } GPIOB_WriteBit(GPIO_Pin_19, pEP2_OUT_DataBuf[1]); R8_UEP2_CTRL = ( R8_UEP2_CTRL & ~MASK_UEP_T_RES ) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 3 : { if ( R8_USB_INT_ST & RB_UIS_TOG_OK ) { // 不同步的数据包将丢弃 len = R8_USB_RX_LEN; DevEP3_OUT_Deal( len ); } } break; case UIS_TOKEN_IN | 3 : R8_UEP3_CTRL = ( R8_UEP3_CTRL & ~MASK_UEP_T_RES ) | UEP_T_RES_NAK; break; case UIS_TOKEN_OUT | 4 : { if ( R8_USB_INT_ST & RB_UIS_TOG_OK ) { R8_UEP4_CTRL ^= RB_UEP_R_TOG; len = R8_USB_RX_LEN; DevEP4_OUT_Deal( len ); } } break; case UIS_TOKEN_IN | 4 : R8_UEP4_CTRL ^= RB_UEP_T_TOG; R8_UEP4_CTRL = ( R8_UEP4_CTRL & ~MASK_UEP_T_RES ) | UEP_T_RES_NAK; break; default : break; } R8_USB_INT_FG = RB_UIF_TRANSFER; } if ( R8_USB_INT_ST & RB_UIS_SETUP_ACT ) // Setup包处理 { //GPIOB_InverseBits(GPIO_Pin_19); R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK; SetupReqLen = pSetupReqPak->wLength; SetupReqCode = pSetupReqPak->bRequest; chtype = pSetupReqPak->bRequestType; len = 0; errflag = 0; if ( ( pSetupReqPak->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD ) { switch ( SetupReqCode ) { case 0x0a : break; //这个一定要有 case 0x09 : break; default : errflag = 0xFF; } } else /* 标准请求 */ { switch ( SetupReqCode ) { case USB_GET_DESCRIPTOR : { switch ( ( ( pSetupReqPak->wValue ) >> 8 ) ) { case USB_DESCR_TYP_DEVICE : { pDescr = MyDevDescr; len = MyDevDescr[0]; } break; case USB_DESCR_TYP_CONFIG : { pDescr = MyCfgDescr; len = MyCfgDescr[2]; } break; case USB_DESCR_TYP_REPORT : { if ( ( ( pSetupReqPak->wIndex ) & 0xff ) == 0 ) //接口0报表描述符 { pDescr = CfgDesc; //数据准备上传 len = sizeof( CfgDesc ); } else len = 0xff; //本程序只有2个接口,这句话正常不可能执行 } break; case USB_DESCR_TYP_STRING : { switch ( ( pSetupReqPak->wValue ) & 0xff ) { case 1 : pDescr = MyManuInfo; len = MyManuInfo[0]; break; case 2 : pDescr = MyProdInfo; len = MyProdInfo[0]; break; case 0 : pDescr = MyLangDescr; len = MyLangDescr[0]; break; default : errflag = 0xFF; // 不支持的字符串描述符 break; } } break; default : errflag = 0xff; break; } if ( SetupReqLen > len ) SetupReqLen = len; //实际需上传总长度 len = ( SetupReqLen >= DevEP0SIZE ) ? DevEP0SIZE : SetupReqLen; memcpy( pEP0_DataBuf, pDescr, len ); pDescr += len; } break; case USB_SET_ADDRESS : SetupReqLen = ( pSetupReqPak->wValue ) & 0xff; break; case USB_GET_CONFIGURATION : pEP0_DataBuf[0] = DevConfig; if ( SetupReqLen > 1 ) SetupReqLen = 1; break; case USB_SET_CONFIGURATION : DevConfig = ( pSetupReqPak->wValue ) & 0xff; break; case USB_CLEAR_FEATURE : { if ( ( pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP ) // 端点 { switch ( ( pSetupReqPak->wIndex ) & 0xff ) { case 0x82 : R8_UEP2_CTRL = ( R8_UEP2_CTRL & ~( RB_UEP_T_TOG | MASK_UEP_T_RES ) ) | UEP_T_RES_NAK; break; case 0x02 : R8_UEP2_CTRL = ( R8_UEP2_CTRL & ~( RB_UEP_R_TOG | MASK_UEP_R_RES ) ) | UEP_R_RES_ACK; break; case 0x81 : R8_UEP1_CTRL = ( R8_UEP1_CTRL & ~( RB_UEP_T_TOG | MASK_UEP_T_RES ) ) | UEP_T_RES_NAK; break; case 0x01 : R8_UEP1_CTRL = ( R8_UEP1_CTRL & ~( RB_UEP_R_TOG | MASK_UEP_R_RES ) ) | UEP_R_RES_ACK; break; default : errflag = 0xFF; // 不支持的端点 break; } } else errflag = 0xFF; } break; case USB_GET_INTERFACE : pEP0_DataBuf[0] = 0x00; if ( SetupReqLen > 1 ) SetupReqLen = 1; break; case USB_GET_STATUS : pEP0_DataBuf[0] = 0x00; pEP0_DataBuf[1] = 0x00; if ( SetupReqLen > 2 ) SetupReqLen = 2; break; default : errflag = 0xff; break; } } if ( errflag == 0xff ) // 错误或不支持 { // SetupReqCode = 0xFF; R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL } else { if ( chtype & 0x80 ) // 上传 { len = ( SetupReqLen > DevEP0SIZE ) ? DevEP0SIZE : SetupReqLen; SetupReqLen -= len; } else len = 0; // 下传 R8_UEP0_T_LEN = len; R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 默认数据包是DATA1 } R8_USB_INT_FG = RB_UIF_TRANSFER; } } else if ( intflag & RB_UIF_BUS_RST ) { R8_USB_DEV_AD = 0; R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG; R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG; R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG; R8_USB_INT_FG = RB_UIF_BUS_RST; } else if ( intflag & RB_UIF_SUSPEND ) { if ( R8_USB_MIS_ST & RB_UMS_SUSPEND ) { ; } // 挂起 else { ; } // 唤醒 R8_USB_INT_FG = RB_UIF_SUSPEND; } else { R8_USB_INT_FG = intflag; } } void DebugInit( void ) { GPIOA_SetBits( GPIO_Pin_9 ); GPIOA_ModeCfg( GPIO_Pin_8, GPIO_ModeIN_PU ); GPIOA_ModeCfg( GPIO_Pin_9, GPIO_ModeOut_PP_5mA ); UART1_DefInit(); } int main() { SetSysClock( CLK_SOURCE_PLL_60MHz ); DebugInit(); printf( "startn" ); pEP0_RAM_Addr = EP0_Databuf; pEP1_RAM_Addr = EP1_Databuf; pEP2_RAM_Addr = EP2_Databuf; pEP3_RAM_Addr = EP3_Databuf; USB_DeviceInit(); PFIC_EnableIRQ( USB_IRQn ); GPIOB_ModeCfg(GPIO_Pin_19,GPIO_ModeOut_PP_20mA); GPIOB_ModeCfg(GPIO_Pin_19,GPIO_ModeOut_PP_20mA); GPIOB_ModeCfg(GPIO_Pin_18,GPIO_ModeOut_PP_20mA); mDelaymS(1000); while(1) { mDelaymS(100); DevEP2_OUT_Deal(32); } } void DevEP1_OUT_Deal( UINT8 l ) { /* 用户可自定义 */ UINT8 i; for ( i = 0; i < l; i++ ) { pEP1_IN_DataBuf = ~pEP1_OUT_DataBuf; } DevEP1_IN_Deal( l ); } void DevEP2_OUT_Deal( UINT8 l ) { /* 用户可自定义 */ UINT8 i; for ( i = 0; i < l; i++ ) { pEP2_IN_DataBuf = pEP2_OUT_DataBuf+1; } DevEP2_IN_Deal( l ); } void DevEP3_OUT_Deal( UINT8 l ) { /* 用户可自定义 */ UINT8 i; for ( i = 0; i < l; i++ ) { pEP3_IN_DataBuf = ~pEP3_OUT_DataBuf+2; } DevEP3_IN_Deal( l ); } void DevEP4_OUT_Deal( UINT8 l ) { /* 用户可自定义 */ UINT8 i; for ( i = 0; i < l; i++ ) { pEP4_IN_DataBuf = ~pEP4_OUT_DataBuf+3; } DevEP4_IN_Deal( l ); } __attribute__((interrupt("WCH-Interrupt-fast"))) __attribute__((section(".highcode"))) void USB_IRQHandler( void ) /* USB中断服务程序,使用寄存器组1 */ { USB_DevTransProcess(); } 目前进一步测试,发现,我只有通过hid_write写一部分数据进去之后,才能通过hid_read读一帧数据出来,如果不写则无法读出数据,我的USB初始化函数里面一个while循环在哪,发现LED是在闪烁。但是就是没有数据读出来。请教各位版主如何解决?我的目的很简单,就是实现一个HID设备,每隔20毫秒能向电脑传输一帧数据,大概有10来个字节左右。 void USB_Init() { pEP0_RAM_Addr = EP0_Databuf; pEP1_RAM_Addr = EP1_Databuf; pEP2_RAM_Addr = EP2_Databuf; pEP3_RAM_Addr = EP3_Databuf; USB_DeviceInit(); PFIC_EnableIRQ( USB_IRQn ); mDelaymS(1000); while(1) { mDelaymS(100); GPIOB_InverseBits(GPIO_Pin_18);//LED闪烁 for (int i = 0; i < 0x20; i++ ) { pEP2_IN_DataBuf = i*2; } DevEP2_IN_Deal( 0X20);//发送数据到端口2 } } 另外请教各位老师第三个问题:我在上位机使用hid_read读端口2数据时候,如下的程序段好像都没有被执行到,对应的LED没有发生闪烁,这是什么原因?我的理解是这是向PC机上传的中断,当PC发出hid_read命令时候,肯定会被执行到: case UIS_TOKEN_IN | 2 : GPIOB_InverseBits(GPIO_Pin_19); R8_UEP2_CTRL = ( R8_UEP2_CTRL & ~MASK_UEP_T_RES ) | UEP_T_RES_NAK; break; 当我在上位机执行hid_write命令,发现如下的程序段是执行的,因为对应的LED在闪烁。 case UIS_TOKEN_OUT | 2 : if ( R8_USB_INT_ST & RB_UIS_TOG_OK ) { // 不同步的数据包将丢弃 len = R8_USB_RX_LEN; //DevEP2_OUT_Deal( len ); for ( int i = 0; i < 64; i++ ) { pEP2_IN_DataBuf =0x33; } DevEP2_IN_Deal( len ); } GPIOB_InverseBits(GPIO_Pin_18); break; |
|
相关推荐
6个回答
|
|
DevEP4_IN_Deal( l ); 这句里面的 l 必须是64,也就是 上传数据必须是64个字节,我测试的时候,也发现了这个问题,发送字节要是不够64,上位机就收不到USB发来的数据
|
|
|
|
问题1:端点_OUT_Deal这个函数,是设备接收到主机发来的OUT包之后,对于OUT数据的处理,处理好后再通过IN方向的数据处理返回给主机;USB低速和全速传输中从机设备不能主动向主机PC上传数据。
问题2:可以修改IN方向端点2的描述符的最后一个字节,值改为20,即中断传输中,每隔20ms,主机发一个IN包给从机,从机设备收到PC发来的IN包,上传自定义数据。报表描述符中规定了上传数据的格式,DevEP0SIZE的值宏定义为了16,配合report size表示16个字节。这里中断使用端点2的话,报表描述符中DevEP0SIZE这个值可以不用通过宏定义,直接改成想要的字节数,最大为64。 |
|
|
|
感谢回复,关于问题1和2,我的理解:端点_OUT_Deal 这个函数就是将当前的数据提前准备好,等待上位机发命令下来就开始上传,当我发送了一个读的命令之后,相当于就是主机发送了一个IN的命令,那么准备好的数据就被上传到主机上了。因此理论上我应该得到数据的。
请问:我以上的描述中是哪个环节出了问题而导致我的数据没有被收到,也就是读失败了. |
|
|
|
我下载了附件中的程序,主函数复制于帖子中的主函数。
使用BUS HOUND抓包,能够抓到按程序设置并返回的IN数据。 此过程是否即是按6楼的说法进行的,OUT方向作为触发指令下达给从机设备,再设置数据后IN方向上传给主机。 |
|
|
|
是这样的,中断里面的确实说明了6楼的工作流程。
但是我在main 函数里面也一直在 循环调用 DevEP2_IN_Deal( 0X20);//发送数据到端口, 那么我在上位机中:不调用hid_write的情况下,一直调用hid_read,应该是可以得到数据的,但是事实上读取的时候没有返回数据。如何才能不调用hid_write 只调用hid_read能够返回数据呢?我现在将上传周期修改为20ms,仍然不能读取数据。 下面是下位机main函数中的while循环: while(1) { mDelaymS(100); GPIOB_InverseBits(GPIO_Pin_18);//LED闪烁 for (int i = 0; i < 0x20; i++ ) { pEP2_IN_DataBuf = i*2; } DevEP2_IN_Deal( 0X20);//发送数据到端口2 } } |
|
|
|
3楼中程序没有运行到IN方向case内,建议确定一下,调用hid_read,主机PC是否在端点2的IN方向向从机设备发送IN指令,指令是否下达到了单片机。建议在相应case内添加串口打印 PRINT("debug字符串注意最后加n换行"),由串口打印信息来debug。
当设置好中断函数后,每隔20ms主机会自动于端点2的IN方向管道,向从机设备发送IN指令。若要实现每20ms发送一段数据,收到这个IN指令前,要向pEP2_IN_DataBuf写好数据,而后调用 端点_IN_Deal()函数设置相应寄存器,即可在收到IN指令时发出去。 若收到IN指令前pEP2_IN_DataBuf内没有写数据,判断为设备没有准备好数据,会回NAK包。 |
|
|
|
只有小组成员才能发言,加入小组>>
230 浏览 1 评论
CH579M+RT-Thread,RTC从Sleep模式唤醒失败是什么原因?
2709 浏览 2 评论
2231 浏览 1 评论
735浏览 9评论
277浏览 7评论
请问一下CH573的PA9引脚用作TMR0功能可以做输入捕获用来进行红外解码吗?
1258浏览 7评论
BLE-Dongle与CH9141-A核心板进行双向透传,无法接收到串口数据怎么解决?
470浏览 7评论
CH582使用USB模拟HID设备,无法只读取数据是什么原因?
1077浏览 6评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-2 16:17 , Processed in 0.962805 second(s), Total 55, Slave 48 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191