各位老师,我在使用HID设备时候出现问题,请百忙之中指导,现象如下:
1.我的上位机是使用hidapi 库的,仅仅通过hid_read读取。通过上位机读取数据,无法读到上传数据
2.另外我直接使用CH9326的DEBUG程序打开该设备,试着读取,效果一样。还是无法读到数据。
3.先写使用hid_write写一帧数据,则可以读到一帧数据,再写则可以再读一帧数据。意思是只能写一帧才能读一帧。
问题如下:
- 我的理解是我的main函数的while循环里面包含语句DevEP2_OUT_Deal(16);就是向PC机器上传数据,为什么无法读取。
- 我只需要实现每20ms向PC上上传一帧20个字节左右的自定义数据,如何实现?
- 我的回复帖是新的问题,请不吝指导。
附件是对应的ch582下位机程序和上位机测试代码
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.c
* Author : WCH
* Version : V1.0
* Date : 2020/02/20
* Descrip
tion : 模拟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;