[求助]CH374枚举HUB

[font=Arial][size=4]各位好!有个问题想请教各位大虾: 现在有个项目是要用单片机+CH374通过HUB完成对外设的数据传输。程序是照着抄的,但是枚举一个USB鼠标(低速)时,可以得到正确的设备描述符;枚举 HUB 时,则老是有问题,数据时常不定时的出错,以下是 HUB 返回的描述符: 0x12 0x01 0x44 0x42 0x09 0x00 0x06 0x44 0xE3 0x55 0x18 0x86 0x41 0x09 0x38 0x39 0x00 0x01 而正确的描述符应该是: 12 01 00 02 09 00 00 40 e3 05 08 06 01 09 00 01 00 01 虽然每次的错误都不一定一样,但是基本上这几个字节都是不正确的。 HUB 的硬件部分是正确的,可以正常使用;而 CH374 与单片机的通信是正常的(单片机向374写数据后读出正确)。 另外,在枚举过程中有个意外的情况:我第一次由CH374向设备发出设备描述符请求,建立过程返回正确,但数据过程(即要求设备返回描述符)则出现了一次的NAK,要再进行一次数据过程才能返回描述符(虽然后来证明得到的数据有误)。 请各位大虾指教,谢谢! [/size][/font]

请问下你使用的单片机是什么?和CH374的硬件接口是什么?是否可以把三个读写子函数贴出来看下?按照你给出的数据来看,应该是三个读写子函数在时序上面有点问题。


[font=Arial][size=3] 谢谢回复。单片机就是 stc 的51,接的是30MHz的晶振(之前接过24MHz的晶振效果也一样),通过并口与 374 通信,A8、CS与普通IO口连接,INT连接 51 的INT口。 CH374工作应该是正常的,枚举鼠标返回的描述符正确。当然鼠标为低速设备,接的 HUB 为高速设备。

读写函数是照抄的,如下: /* CH374传输事务,输入目的端点地址/PID令牌/同步标志,返回同CH375,NAK不重试,超时/出错重试 */ UINT8 HostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog ) { // 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化 UINT8 i, retry; UINT8 s=1, r, u; for ( retry = 0; retry < 3; retry ++ ) { print("retry number in HostTranact374() is ",retry); Write374Byte( REG_USB_H_PID, M_MK_HOST_PID_ENDP( pid, endp_addr ) ); // 指定令牌PID和目的端点号 // Write374Byte( REG_USB_H_CTRL, BIT_HOST_START | ( tog ? ( BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : 0x00 ) ); // 设置同步标志并启动传输 Write374Byte( REG_USB_H_CTRL, ( tog ? ( BIT_HOST_START | BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : BIT_HOST_START ) ); // 设置同步标志并启动传输 // Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE ); // 取消暂停 // mDelayuS( 200 ); s = Wait374Interrupt( ); for(i=0;i<18;i++) print("this value is ",Read374Byte(RAM_HOST_RECV+i)); if(s==0) send_str("in transfer: interrupt occurs.\r\n"); if ( s == ERR_USB_UNKNOWN ) { send_str("in transfer: unknown error.\r\n"); return( s ); // 中断超时,可能是硬件异常 } s = Read374Byte( REG_INTER_FLAG ); // 获取中断状态 print("REG_INTER_FLAG = ",s); /* if ( s & BIT_IF_DEV_DETECT ) { // USB设备插拔事件 send_str("in transfer: device detected.\r\n"); delay_us( 200 ); // 等待传输完成 Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_TRANSFER ); // 清中断标志 if ( s & BIT_IF_DEV_ATTACH ) { // USB设备连接事件 send_str("in transfer: device attached.\r\n"); u = Read374Byte( REG_USB_SETUP ); if ( s & BIT_IF_USB_DX_IN ) { // 速度匹配,不需要切换速度 if ( u & BIT_SETP_USB_SPEED ) return( USB_INT_CONNECT_LS ); // 低速USB设备 return( USB_INT_CONNECT ); // 全速USB设备 } else { // 速度失配,需要切换速度 if ( u & BIT_SETP_USB_SPEED ) return( USB_INT_CONNECT ); // 全速USB设备 return( USB_INT_CONNECT_LS ); // 低速USB设备 } } else return( USB_INT_DISCONNECT ); // USB设备断开事件 } else*/ if ( s & BIT_IF_TRANSFER ) { // 传输完成 send_str("in transfer: transfer complete.\r\n"); Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER ); // 清中断标志 s = Read374Byte( REG_USB_STATUS ); // USB状态 print("REG_USB_STATUS = ",s); r = s & BIT_STAT_DEV_RESP; // USB设备应答状态 switch ( pid ) { case DEF_USB_PID_SETUP: case DEF_USB_PID_OUT:

send_str("setup or out event.\r\n"); if ( r == DEF_USB_PID_ACK ) return( USB_INT_SUCCESS ); else if ( r == DEF_USB_PID_STALL || r == DEF_USB_PID_NAK ) { send_str("status is STALL or NAK.\r\n"); return( r | 0x20 ); } else if ( ! M_IS_HOST_TIMEOUT( s ) ) { send_str("status is unknown error.\r\n"); return( r | 0x20 ); // 不是超时/出错,意外应答 } break;

case DEF_USB_PID_IN:

send_str("in event.\r\n"); if ( M_IS_HOST_IN_DATA( s ) ) { // DEF_USB_PID_DATA0 or DEF_USB_PID_DATA1 if ( s & BIT_STAT_TOG_MATCH ) { send_str("status is tog matched.\r\n"); return( USB_INT_SUCCESS ); // 不同步则需丢弃后重试 } } else if ( r == DEF_USB_PID_STALL || r == DEF_USB_PID_NAK ) { send_str("status is STALL or NAK.\r\n"); for(i=0;i<18;i++) print("this value is ",Read374Byte(RAM_HOST_RECV+i)); return( r | 0x20 ); } else if ( ! M_IS_HOST_TIMEOUT( s ) ) { send_str("status is unknown error.\r\n"); return( r | 0x20 ); // 不是超时/出错,意外应答 } break;

default: return( ERR_USB_UNKNOWN ); // 不可能的情况 break; } } else { // 其它中断,不应该发生的情况 delay_us( 200 ); // 等待传输完成 Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); /* 清中断标志 */ if ( retry ) return( ERR_USB_UNKNOWN ); // 不是第一次检测到则返回错误 } } return( 0x20 ); // 应答超时 }

/* CH374传输事务,输入目的端点地址/PID令牌/同步标志/以mS为单位的NAK重试总时间(0xFFFF无限重试),返回同CH375,NAK重试,超时出错重试 */ UINT8 WaitHostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog, UINT16 timeout ) { UINT8 i, s; while ( 1 ) { send_str("try WaitHostTransact() for 40 times.\r\n"); for ( i = 0; i < 40; i ++ ) { s = HostTransact374( endp_addr, pid, tog ); if ( s != ( DEF_USB_PID_NAK | 0x20 ) || timeout == 0 ) { return( s ); } send_str("retry in WaitHostTransact374() NAK or timeout.\r\n"); delay_us( 20 ); } if ( timeout < 0xFFFF ) timeout --; else send_str("time out in WaitHostTransact374().\r\n"); } }

/* 执行控制传输,ReqBuf指向8字节请求码,DatBuf为收发缓冲区 */ UINT8 HostCtrlTransfer374( PUINT8 ReqBuf, PUINT8 DatBuf, PUINT8 RetLen ) // 如果需要接收和发送数据,那么DatBuf需指向有效缓冲区用于存放后续数据,实际成功收发的总长度保存在ReqLen指向的字节变量中 { UINT8 s, len, count, total, i; BOOL tog; Write374Block( RAM_HOST_TRAN, RequestNum, ReqBuf ); //write command to CH374 that ask for describtor Write374Byte( REG_USB_LENGTH, RequestNum ); //and the length number of sending package delay_us( 100 ); send_str(" start setup transfer.\r\n"); s = WaitHostTransact374( 0, DEF_USB_PID_SETUP, FALSE, 200 ); // SETUP阶段,20uS延时重试200次超时 if ( s == USB_INT_SUCCESS ) // SETUP成功 { send_str(" setup success.\r\n"); tog = TRUE; // 默认DATA1,默认无数据故状态阶段为IN if((*(ReqBuf+3))==0x22) { total=*( ReqBuf + 6 )-0x40; } else { send_str("length of data equals Buf[6].\r\n"); total = *( ReqBuf + 6 ); } if ( total && DatBuf ) // 需要收数据 { len = total; if ( *ReqBuf & 0x80 ) // 收 { send_str("get data from device.\r\n"); while ( len ) { send_str(" start to read.\r\n"); delay_us( 100 ); Write374Byte(RAM_HOST_RECV+0,0); Write374Byte(RAM_HOST_RECV+1,1); Write374Byte(RAM_HOST_RECV+2,2); Write374Byte(RAM_HOST_RECV+3,3); Write374Byte(RAM_HOST_RECV+4,4); Write374Byte(RAM_HOST_RECV+5,5); Write374Byte(RAM_HOST_RECV+6,6); Write374Byte(RAM_HOST_RECV+7,7); i = Read374Byte(RAM_HOST_RECV+0); print("the third byte is ",i); i = Read374Byte(RAM_HOST_RECV+1); print("the forth byte is ",i); i = Read374Byte(RAM_HOST_RECV+2); print("the sixth byte is ",i); i = Read374Byte(RAM_HOST_RECV+3); print("the third byte is ",i); i = Read374Byte(RAM_HOST_RECV+4); print("the forth byte is ",i); i = Read374Byte(RAM_HOST_RECV+5); print("the sixth byte is ",i); i = Read374Byte(RAM_HOST_RECV+6); print("the third byte is ",i); i = Read374Byte(RAM_HOST_RECV+7); print("the forth byte is ",i); s = WaitHostTransact374( 0, DEF_USB_PID_IN, tog, 200 ); // IN数据 if ( s != USB_INT_SUCCESS ) break; count = Read374Byte( REG_USB_LENGTH ); print("read count is ",count); //Read374Block( RAM_HOST_RECV, count, DatBuf ); i = Read374Byte(RAM_HOST_RECV+3); print("the third byte is ",i); i = Read374Byte(RAM_HOST_RECV+3); print("the third byte is ",i); i = Read374Byte(RAM_HOST_RECV+3); print("the third byte is ",i); i = Read374Byte(RAM_HOST_RECV+3); print("the third byte is ",i); i = Read


[font=Arial][size=4]这个帖子的排版有点问题,谢谢大虾的回复。 再问,在 HostTransact374()这个函数中,说要进行优化,请问应该做怎么样的优化呢?请稍微给点提示。 谢谢! [/size][/font]


上面的程序没什么问题,但是我需要看下你的三个读写子函数,写索引,写数据,读数据三个函数。


[font=Arial][size=3]你指的是以下这一系列宏和函数么? // P2.0 A0 // P2.1 CS# 如果并口上只有CH374,那么CS#可以直接接低电平,强制片选 */ UINT8XV CH374_IDX_PORT _at_ 0x0FDFF; /* 假定CH374索引端口的I/O地址 */ UINT8XV CH374_DAT_PORT _at_ 0x0FCFF; /* 假定CH374数据端口的I/O地址 */

#define Write374Index( a ) { CH374_IDX_PORT = a; } /* 向索引端口写入索引地址 */ #define Write374Data( d ) { CH374_DAT_PORT = d; } /* 向数据端口写入数据,索引地址自动加1 */ #define Read374Data( ) ( CH374_DAT_PORT ) /* 从数据端口读出数据,索引地址自动加1 */ #define Read374Data0( ) ( CH374_IDX_PORT ) /* 从索引端口读出数据,索引地址不变,适用于[读出->修改->写回]操作 */ UINT8 Read374Byte( UINT8 mAddr ) /* 从指定寄存器读取数据 */ { Write374Index( mAddr ); return( Read374Data( ) ); } void Write374Byte( UINT8 mAddr, UINT8 mData ) /* 向指定寄存器写入数据 */ { Write374Index( mAddr ); Write374Data( mData ); } 另外,查询函数如下: // 查询CH374中断(INT#低电平) BOOL Query374Interrupt( void ) { #ifdef CH374_INT_WIRE send_str("................................\r\n"); return( CH374_INT_WIRE ? FALSE : TRUE ); /* 如果连接了CH374的中断引脚则直接查询中断引脚 */ #else return( Read374Byte( REG_INTER_FLAG ) & BIT_IF_INTER_FLAG ? TRUE : FALSE ); /* 如果未连接CH374的中断引脚则查询中断标志寄存器 */ #endif }

// 等待CH374中断(INT#低电平),超时则返回ERR_USB_UNKNOWN UINT8 Wait374Interrupt( void ) { UINT16 i; for ( i = 0; i < 10000; i ++ ) { // 计数防止超时 if ( Query374Interrupt( ) ) return( 0 ); } return( ERR_USB_UNKNOWN ); // 不应该发生的情况 } [/size][/font]


你把这2个函数按照我写的程序修改下:

void Read374Block( UINT8 mAddr, UINT8 mLen, PUINT8 mBuf ) /* 从指定起始地址读出数据块 */ { while ( mLen -- ){ Write374Index( mAddr ); *mBuf++ = Read374Data( ); mAddr++; } }

void Write374Block( UINT8 mAddr, UINT8 mLen, PUINT8 mBuf ) /* 向指定起始地址写入数据块 */ { while ( mLen -- ){ Write374Index( mAddr ); mAddr++; Write374Data( *mBuf++ ); } }


[font=Arial][size=3]你好,谢谢你的耐心回复。 已经把之前的程序修改了,并去掉了一些多余的判断,数据仍然出现问题: the device descriptor is 0x12 0x01 0x44 0x42 0x09 0x00 0x02 0x40 0xE3 0x85 0x1A 0x86 0x01 0x09 0x28 0x39 0x00 0x01 另外用该程序枚举鼠标仍然正确。这里还有个现象: 我在获得中断信号后,对 374 进行读动作,反复读取描述符其中的某个字节,比如第4个字节,返回的数据一直为“0x42”,我的推测是:可能 HUB 返回数据到 374 的RAM_HOST_RECV 中,数据已经是有问题的了(HUB 芯片是GL850A,2.0协议,并可以正常连接电脑工作)。 不知大虾有什么看法。 [/size][/font]


按照HUB的设计应该不会出现你说的现象。因为即使是设备描述符,2.0和1.1基本上是一样的。估计还是在读取数据上面有问题。那你枚举U盘有这个问题吗?


[font=Arial][size=3]向U盘发出获取设备描述符命令,得到的数据为: the device descriptor is 0x12 0x01 0xA8 0x06 0x00 0x04 0x02 0x40 0x51 0x49 0x36 0x96 0x00 0x02 0x29 0x32 0x03 0x01 但是我也不知道正确的描述符应该是多少啊,用 Bus Hound 在电脑看U盘连接数据,竟然没有获取描述符的申请,真奇怪。 请问,是否有 51+374 连接 Hub 成功的实例啊?应该有吧,可以下载么?要不我再试试。这次我什么都不改,就用提供的例子来试。是否硬件要求为 51 接24MHz的晶振?还有什么其他的么? 谢谢! [/size][/font]


你发一份E-MAIL到我邮箱,我给你发份例子


[font=Arial][size=3]你好,邮件已发,题目是“求助 CH374 枚举 HUB”。 [/size][/font]


[font=Arial][size=3]不好意思,到现在才看到,邮箱竟然把邮件认到**邮件里了,真是诡异。 请问,硬件条件呢?晶振是24MHz的么?还有其他的么? 我今晚才有时间试,现在比较忙,嘿嘿,还是谢谢了。 [/size][/font]


24M是可以工作的。其他没什么,你需要拿串口来跟踪下程序运行。


[font=Arial][size=3]大虾你好,谢谢你的回复。我今天看了程序,发现其关联关系比较混乱。 我已经将头文件:HAL.H包含,也在工程中加入了以前下载的 HAL_BASE.C 和 PARA_HW.C。但是 CH374的头文件呢? 我加入了 CH374INC.H,报编译出错,关于 HUB 的寄存器 REG_HUB_SETUP 没有定义,就又下了一个 CH374HFC.H,包含编译了又报一些类型没有定义,增加完类型定义后又报 multiple public definition 的错误。 请问是否可以发个比较完整的程序,因为我还不知道另外还有什么我没修补好的奇怪错误。 谢谢!关于此问题我将全程回复。 [/size][/font]


已经将工程做好E-MAIL给你。有什么问题可以进行E-MAIL进行联系。


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