我用CH374T(3.3V)工作在设备模式,可一插入电脑后,只检测到有总线复位,挂起及换醒的中断,但就没有传输中断,所以就提交不到Descriptors,电脑无法得知此设备。请问是什么问题呢?
PC提示找到新硬件了吗?你是如何判断产生总线复位,挂起及换醒的中断的?可能是你没有正确的初始化!把你的程序贴出来看看!
PC找到无法适别的硬件。我是简单通过LED灯后指示发生什么中断的。以下的部分初始化程序,基本上与DEMO的一样。 /* CH374初始化子程序 */ void CH374DeviceInit( void ) { //if (Read374Byte(REG_SYS_INFO) & 1) RLED = 0; Write374Byte( REG_USB_SETUP, 0x00 ); Write374Byte( REG_USB_ADDR, 0x00 ); Write374Byte( REG_USB_ENDP0, M_SET_EP0_TRAN_NAK( 0 ) ); Write374Byte( REG_USB_ENDP1, M_SET_EP1_TRAN_NAK( 0 ) ); Write374Byte( REG_USB_ENDP2, M_SET_EP2_TRAN_NAK( 0 ) ); Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); // 清所有中断标志 Write374Byte( REG_INTER_EN, BIT_IE_TRANSFER | BIT_IE_BUS_RESET | BIT_IE_USB_SUSPEND ); // 允许传输完成中断和USB总线复位中断以及USB总线挂起中断,芯片唤醒完成中断 Write374Byte( REG_SYS_CTRL, BIT_CTRL_OE_POLAR | BIT_CTRL_USB_POWER); // 对于CH374T或者UEN引脚悬空的CH374S必须置BIT_CTRL_OE_POLAR为1 Write374Byte( REG_USB_SETUP, BIT_SETP_TRANS_EN ); // 启动USB设备 /* 下面启用USB中断,CH374的INT#引脚可以连接到单片机的中断引脚,中断为低电平有效或者下降沿有效, 如果不使用中断,那么也可以用查询方式,由单片机程序查询CH374的INT#引脚为低电平 */ IT0 = 0; /* 置外部信号为低电平触发 */ IE0 = 0; /* 清中断标志 */ EX0 = 1; /* 允许CH374中断,假定CH374的INT#引脚连接到单片机的INT0 */ }
void ch374intr() interrupt 0 {
u8 cnt, SetupReq, SetupLen; u8 dat, cmd; u8 *pDescr; //u8 *buf; USB_DATA_PKT udp;
#define int_status dat /* 节约一个变量存储单元 */ /* IE0 = 0; 清中断标志,与单片机硬件有关,对应于INT0中断 */ int_status = Read374Byte( REG_INTER_FLAG ); // 获取中断状态 if ( int_status & BIT_IF_BUS_RESET ) { // USB总线复位 Write374Byte( REG_USB_ADDR, 0x00 ); // 清USB设备地址 Write374Byte( REG_USB_ENDP0, M_SET_EP0_TRAN_NAK( 0 ) ); Write374Byte( REG_USB_ENDP1, M_SET_EP1_TRAN_NAK( 0 ) ); Write374Byte( REG_USB_ENDP2, M_SET_EP2_TRAN_NAK( 0 ) ); Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_BUS_RESET ); // 清中断标志 } else if ( int_status & BIT_IF_TRANSFER ) { /* transfer complete */ int_status = Read374Byte( REG_USB_STATUS ); /* get usb status*/ //RLED = 0; switch( int_status & BIT_STAT_PID_ENDP ) { // USB设备中断状态 case USB_INT_EP2_OUT: { // bulk endpoint out if ( int_status & BIT_STAT_TOG_MATCH ) { // 仅同步包 cnt = Read374Byte( REG_USB_LENGTH ); Read374Block( RAM_ENDP2_RECV, cnt, (u8 *)&udp.down ); if ( cnt == 0 ) { /* 长度为0,没有数据,在某些应用中也可以将长度0定义为一种特殊命令 */ Write374Byte( REG_USB_ENDP2, M_SET_EP2_TRAN_NAK( Read374Byte( REG_USB_ENDP2 ) ) ); /* 同步触发位不变,设置USB端点2的IN正忙,返回NAK */ RLED = 0; return; } if ( udp.down.mCommand != (u8)( ~ udp.down.mCommandNot ) ) /* 命令包反码校验通过,否则放弃该下传包 */ { RLED = 0; return; } if ( udp.down.mCommand == USB_CMD_SET_LED ) { RLED = (bit)udp.down.mBuffer[0]; GLED = (bit)(udp.down.mBuffer[0] >> 1); } else if ( udp.down.mCommand == USB_CMD_GET_STATUS ) { cmd = udp.down.mBuffer[0]; udp.up.hadr = ~cmd; udp.up.mLength = 1; udp.up.mBuffer[0] = 0xaa; //buf = (u8 *)&udp.up; cnt = 3; } else if ( udp.down.mCommand == USB_CMD_GET_DATA ) { pvdata = udp.up.mBuffer; vcnt = get_video(pvdata); udp.up.hadr = 0xaa; udp.up.mLength = sizeof(*pvdata); //buf = (u8 *)&udp.up; cnt = udp.up.mLength + 2; } else if ( udp.down.mCommand == USB_CMD_GET_REG ) { cmd = udp.down.mCommand; udp.up.hadr = cmd; udp.up.mLength = 1; udp.up.mBuffer[0] = get_reg(udp.down.mBuffer[0]); //buf = (u8 *)&udp.up; cnt = 3; } else if ( udp.down.mCommand == USB_CMD_SET_REG ) { set_reg(udp.down.mBuffer[0], udp.down.mBuffer[1]); dat = get_reg(udp.down.mBuffer[0]); cmd = udp.down.mCommand; udp.up.hadr = cmd; udp.up.mLength = 1; udp.up.mBuffer[0] = dat; //buf = (u8 *)&udp.up; cnt = 3; } else if ( udp.down.mCommand == USB_CMD_TEST_RINTV ) { TL0 = 0; TH0 = 0; cntt = 0; rintvl = 1; cmd = udp.down.mCommand; udp.up.hadr = TH0; //buf = (u8 *)&udp.up; cnt = 1; } //cnt = pudp->up.mLength + (UINT8)( & ( (USB_UP_PKT *)0 ) -> mBuffer ); Write374Byte( REG_USB_LENGTH, cnt ); Write374Block( RAM_ENDP1_TRAN, cnt, (u8 *)&udp.up ); Write374Byte( REG_USB_ENDP2, Read374Byte( REG_USB_ENDP2 ) ^ BIT_EP2_RECV_TOG); Write374Byte( REG_USB_ENDP1, M_SET_EP1_TRAN_ACK( Read374Byte( REG_USB_ENDP1 ), cnt )); } //end of if ( int_status & BIT_STAT_TOG_MATCH ) break; } case USB_INT_EP2_IN: { // 批量端点上传成功,未处理 Write374Byte( REG_USB_ENDP2, M_SET_EP2_TRAN_NAK( Read374Byte( REG_USB_ENDP2 ) ) ^ BIT_EP2_TRAN_TOG ); // Write374Index( REG_USB_ENDP2 ); // 对于并口连接可以用本行及下面一行代替上一行的程序,减少写一次index的时间,提高效率 // Write374Data( M_SET_EP2_TRAN_NAK( Read374Data0( ) ) ^ BIT_EP2_TRAN_TOG ); break; } case USB_INT_EP1_IN: { // 中断端点上传成功,未处理 Write374Byte( REG_USB_ENDP1, M_SET_EP1_TRAN_NAK( Read374Byte( REG_USB_ENDP1 ) ) ^ BIT_EP1_TRAN_TOG ); break; } case USB_INT_EP0_SETUP: { USB_SETUP_REQ SetupReqBuf; cnt = Read374Byte( REG_USB_LENGTH ); RLED = 0; if ( cnt == sizeof( USB_SETUP_REQ ) ) { Read374Block( RAM_ENDP0_RECV, cnt, (u8 *)&SetupReqBuf ); SetupLen = SetupReqBuf.wLengthL; if ( SetupReqBuf.wLengthH || SetupLen > 0x7F ) SetupLen = 0x7F; // 限制总长度 cnt = 0; // 默认为成功并且上传0长度 if ( ( SetupReqBuf.bType & DEF_USB_REQ_TYPE ) != DEF_USB_REQ_STAND ) { /* 只支持标准请求 */ cnt = 0xFF; // 操作失败 } else { // 标准请求 SetupReq = SetupReqBuf.bReq; // 请求码 switch( SetupReq ) { case DEF_USB_GET_DESCR: switch( SetupReqBuf.wValueH ) { case 1: pDescr = (u8 *)( &MyDevDescr[0] ); cnt = sizeof( MyDevDescr ); break; case 2: pDescr = (u8 *)( &MyCfgDescr[0] ); cnt = sizeof( MyCfgDescr ); break; case 3: switch( SetupReqBuf.wValueL ) { case 1: pDescr = (u8 *)( &MyManuInfo[0] ); cnt = sizeof( MyManuInfo ); break; case 2: pDescr = (u8 *)( &MyProdInfo[0] ); cnt = sizeof( MyProdInfo ); break; case 0: pDescr = (u8 *)( &MyLangDescr[0] ); cnt = sizeof( MyLangDescr ); break; default: cnt = 0xFF; // 操作失败 break; } break; default: cnt = 0xFF; // 操作失败 break; } if ( SetupLen > cnt ) SetupLen = cnt; // 限制总长度 cnt = SetupLen >= RAM_ENDP0_SIZE ? RAM_ENDP0_SIZE : SetupLen; // 本次传输长度 Write374Block( RAM_ENDP0_TRAN, cnt, pDescr ); /* 加载上传数据 */ SetupLen -= cnt; pDescr += cnt; break; case DEF_USB_SET_ADDRESS: SetupLen = SetupReqBuf.wValueL; // 暂存USB设备地址 break; case DEF_USB_GET_CONFIG: Write374Byte( RAM_ENDP0_TRAN, UsbConfig ); if ( SetupLen >= 1 ) cnt = 1; break; case DEF_USB_SET_CONFIG: UsbConfig = SetupReqBuf.wValueL; break; case DEF_USB_CLR_FEATURE: if ( ( SetupReqBuf.bType & 0x1F ) == 0x02 ) { // 不是端点不支持 switch( SetupReqBuf.wIndexL ) { case 0x82: Write374Byte( REG_USB_ENDP2, M_SET_EP2_TRAN_NAK( Read374Byte( REG_USB_ENDP2 ) ) ); break; case 0x02: Write374Byte( REG_USB_ENDP2, M_SET_EP2_TRAN_ACK( Read374Byte( REG_USB_ENDP2 ) ) ); break; case 0x81: Write374Byte(
(1)Write374Byte( REG_USB_SETUP, BIT_SETP_TRANS_EN ); // 启动USB设备,你并没有启用上拉电阻,计算机根本不会检测到设备插入,374也不会产生任何中断,不知道你所说的总线复位,唤醒中断是如何获得的。 (2)中断程序里面不允许“return”,否则程序会跑飞 (3)建议先用示例程序,熟悉374的操作流程后,再根据自己的需要进行修改。
硬件电路的+U脚已有上拉,CH374内部还需再拉高吗? 总线复位,唤醒中断确实是检测得到,我是在相应的中断标志检测入口处加LED的显示,那就很容易知道那个中断发生了。
不是内部需要上拉是外部不需要上拉,我们374芯片内部有上拉 正确的方式应该是: Write374Byte( REG_USB_SETUP, BIT_SETP_TRANS_EN | BIT_SETP_PULLUP_EN ); // 启动USB设备
但就一直没检测到传输中断标志。我之前是用CH372B的,因为它不支持等时传输,所以我不得不换用CH374T的。
你仔细检查下在产生只检测到有总线复位,挂起及换醒的中断之后,你有没有去清中断寄存器,如果不清的话就会出现你说的上面的现象,不断的出现复位,挂起及唤醒中断。
很郁闷啊!我用DEMO示例程序的从模式部分还是不行,就是检测不到有传输中断标志!中断寄存器都清过了,初始化时写入的寄存器再读回也是正确的。一插入电脑后,先来一个总线复位中断,再来几会挂起及换醒的中断之后,就提示是无法适别的设备。怎么也没有传输中断这个发生,程序就没法提交Descriptors。怎么回这样的呢?为什么插入电脑后CH374T产生不了传输中断呢?难道IC坏了?
(1)DEMO示例程序肯定不会有问题。 (2)可能是你程序中某些地方没处理好,方便的话,你把整个程序结构整理一下,便于我们分析,打包上传。我们来测试一下。
问题解决了!是硬件的问题。原来我是用CH372B的,配的是12MHz晶振,后来因为要支持等时传输就直接换用CH374T,却不知道要用24MHz晶振。直是傻傻的错误! 但之后又发现一个奇怪的现象,DEMO示例程序中的Read374Block函数竟然编译出死循环! void Read374Block( u8 mAddr, u8 mLen, u8 *mBuf ) /* 从指定起始地址读出数据块 */ { Write374Index( mAddr ); while ( mLen -- ) *mBuf++ = Read374Data( ); }
我在这附上了图片,R5就是保存着mLen的值,但只是做递减就不对R5做判断。真奇怪的现象,请问是什么原因呢?