📄 ch375host.c
字号:
// 接收成功,返回接收到的数据长度
if( status == USB_INT_SUCCESS )
{
status = CH375_ReadUSBData( buffer );// 读取接收到的数据
return( status ); // 返回数据长度( 0--64B )
}
// 接收错误处理
else
{
CH375_ClrStall6( ); // 接收设备端的端点错误
return( 0xFF ); // 返回操作失败
}
}
}
//=================================================================================================
//
//-------------------------------------------------------------------------------------------------
// 从设备端获取描述符
unsigned char CH375_GetDescription( unsigned char type )
{
xWriteCH375Cmd( CMD_GET_DESCR );
xWriteCH375Data( type ); // 描述符类型, 只支持1(设备)或者2(配置)
return( xQueryInterrupt( ) ); // 等待CH375操作完成
// 由于CH375 的控制传输缓冲区只有64个字节,所以当描述符的长度超过64 字节时,
// CH375将返回操作状态USB_INT_BUF_OVER,对于该USB 设备,单片机可以通过ISSUE_TOKEN 命令自行处理控制传输。
}
//-------------------------------------------------------------------------------------------------
// 设置设备端的USB地址
unsigned char CH375_SetAddress( unsigned char address )
{
unsigned char status;
xWriteCH375Cmd( CMD_SET_ADDRESS ); // 设置USB设备端的USB地址
xWriteCH375Data( address ); // 地址, 从1到127之间的任意值, 常用2到20
status = xQueryInterrupt( ); // 等待CH375操作完成
if( status == USB_INT_SUCCESS ) // 操作成功
{
xWriteCH375Cmd( CMD_SET_USB_ADDR ); // 设置USB主机端的USB地址
xWriteCH375Data( address ); // 当目标USB设备的地址成功修改后,应该同步修改主机端的USB地址
}
mDelaymS( 5 );
return( status );
}
//-------------------------------------------------------------------------------------------------
// 设置设备端的USB配置
unsigned char CH375_SetConfiguration( unsigned char configuration )
{
Endp6Mode = Endp7Mode = 0x80; // 复位USB数据同步标志
xWriteCH375Cmd( CMD_SET_CONFIG ); // 设置USB设备端的配置值
xWriteCH375Data( configuration ); // 此值取自USB设备的配置描述符中
return( xQueryInterrupt( ) ); // 等待CH375操作完成
}
//=================================================================================================
//=================================================================================================
// CH375初始化子程序
//=================================================================================================
//=================================================================================================
//
void CH375Init( void )
{
unsigned char i, k;
unsigned char Datum;
// CH375_PORT_INIT( ); // 使用通用I/O模块并口读写时序,进行初始化
// 测试CH375是否正常工作
for( k=100; k!=0; k-- )
{
xWriteCH375Cmd( CMD_CHECK_EXIST );// 测试CH375是否正常工作
i = 0x5A; xWriteCH375Data( i ); // 写入测试数据
i = ~i; // 返回数据应该是测试数据取反
Datum = xReadCH375Data( );
if( Datum != i ) // CH375不正常
{
for ( i=5; i!=0; i-- )
{
xWriteCH375Cmd( CMD_RESET_ALL ); // 多次重复发命令,执行硬件复位
}
mDelaymS( 50 ); // 延时50mS
}
else break;
}
if( k==0 )
{
mStopIfError( 0xFF ); // 如果错误则停止运行并显示错误状态
}
// 设置USB主机模式, 如果设备端是CH37X, 那么5和6均可
CH375_SetUSBMode( 6 );
// while( xQueryInterrupt( )!=USB_INT_CONNECT );// 等待USB设备连接上来
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
// 初始化USB设备,完成设备枚举
unsigned char CH375InitUSBDevice( void )
{
unsigned char address;
unsigned char status;
unsigned char length;
//-------------------------------------------
// USB规范中未要求在USB设备插入后必须复位该设备,但是计算机的WINDOWS总是这样做,
#ifdef USB_RESET_FIRST
CH375_SetUSBMode( 7 ); // 复位USB设备,CH375向USB信号线的D+和D-输出低电平
mDelaymS( 10 ); // 复位时间不少于1mS,建议为10mS
CH375_SetUSBMode( 6 );
mDelaymS( 100 );
while( xQueryInterrupt( )!=USB_INT_CONNECT );// 等待复位之后的USB设备端再次连接上来
mDelaymS( 200 );
#endif
//-------------------------------------------
// 获取设备描述符
status = CH375_GetDescription( 1 );
if( status == USB_INT_SUCCESS )
{
length = CH375_ReadUSBData( RECV_BUFFER ); // 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度
// 设备描述符错误
if( (length<18) || (p_dev_descr->bDescriptorType!=1) )
return( UNKNOWN_USB_DEVICE ); // 意外错误:描述符长度错误或者类型错误
if( p_dev_descr->bDeviceClass!=0 )
return( UNKNOWN_USB_DEVICE ); // 连接的USB设备不符合USB规范
status = CH375_SetAddress( 2 ); // 设置USB设备的USB地址 ????????????
if( status == USB_INT_SUCCESS )
{
status = CH375_GetDescription( 2 ); // 获取配置描述符
if( status == USB_INT_SUCCESS ) // 操作成功则读出描述符并分析
{
length = CH375_ReadUSBData( RECV_BUFFER ); // 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度
// 配置描述符错误
if( (p_cfg_descr->itf_descr.bInterfaceClass!=7) || (p_cfg_descr->itf_descr.bInterfaceSubClass!=1) )
return( UNKNOWN_USB_DEVICE );// 不符合USB规范
EndpOutAddr = EndpInAddr = 0;
address = p_cfg_descr->endp_descr[0].bEndpointAddress; // 第一个端点的地址
if( address & 0x80 ) EndpInAddr = address & 0x0F; // IN端点的地址
else // OUT端点
{
EndpOutAddr = address & 0x0F;
EndpOutSize = p_cfg_descr->endp_descr[0].wMaxPacketSize; // 数据接收端点的最大包长度
if( (EndpOutSize == 0) || (EndpOutSize > 64) ) EndpOutSize = 64;
}
// 接口有两个以上的端点
if( p_cfg_descr->itf_descr.bNumEndpoints >= 2 )
{
if( p_cfg_descr->endp_descr[1].bDescriptorType == 5 ) // 端点描述符
{
address = p_cfg_descr->endp_descr[1].bEndpointAddress; // 第二个端点的地址
if( address & 0x80 ) EndpInAddr = address & 0x0F; // IN端点
else // OUT端点
{
EndpOutAddr = address & 0x0F;
EndpOutSize = p_cfg_descr->endp_descr[1].wMaxPacketSize;
if( (EndpOutSize == 0) || (EndpOutSize > 64) ) EndpOutSize = 64;
}
}
}
if( p_cfg_descr->itf_descr.bInterfaceProtocol==1 ) EndpInAddr = 0; // 单向接口不需要IN端点
if( EndpOutAddr == 0 ) return( UNKNOWN_USB_DEVICE ); // 不符合USB规范
status = CH375_SetConfiguration( p_cfg_descr->cfg_descr.bConfigurationvalue ); // 加载USB配置值
if( status == USB_INT_SUCCESS )
{
// 如果单片机在USB设备忙时并无事可做,建议设置位7为1,使CH375在收到NAK时自动重试直到操作成功或者失败
// 如果希望单片机在USB设备忙时能够做其它事,那么应该设置位7为0,使CH375在收到NAK时不重试,
// 所以在下面的USB通讯过程中,如果USB设备正忙,issue_token等子程序将得到状态码USB_INT_RET_NAK
xWriteCH375Cmd( CMD_SET_RETRY ); // 设置USB事务操作的重试次数
xWriteCH375Data( 0x25 ); // 输入 0x25
xWriteCH375Data( 0xC5 ); // 位7为0则收到NAK时不重试
// 位7为1位6为0则收到NAK时无限重试 (CH375A)
// 位7为1位6为1则收到NAK时重试200mS, 位5~位0为超时后的重试次数 (CH375A)
}
}
}
}
return( status );
}
//=================================================================================================
// CH375 Host Procedure
//=================================================================================================
//
void CH375HostProcess( void )
{
unsigned char i;
unsigned char length;
i = xQueryInterrupt( ); // 查询中断状态
if( i == USB_INT_CONNECT ) // 检测到有设备连接
{
// UART0SendString( "USB设备连接\n" );
// 如果设备端是CH37X,那么以下步骤是可选的,
// 如果是其它USB芯片,那么需要执行以下步骤,并且要分析配置描述符的数据获得配置值以及端点号,并修改本程序中的端点号,
// USB规范中未要求在USB设备插入后必须复位该设备,但是计算机的WINDOWS总是这样做,所以有些USB设备也要求在插入后必须先复位才能工作
CH375_SetUSBMode( 7 ); // 复位USB设备,CH375向USB信号线的D+和D-输出低电平
// 如果单片机对CH375的INT#引脚采用中断方式而不是查询方式,那么应该在复制USB设备期间禁止CH375中断,在USB设备复位完成后清除CH375中断标志再允许中断
mDelaymS( 50 ); // Waiting ...
CH375_SetUSBMode( 6 ); // 结束复位
// 等待复位之后的设备端再次连接上来
while( 1 )
{
i = xQueryInterrupt( ); // 查询中断状态
if( i == USB_INT_CONNECT ) break;
}
// 有些USB设备要求延时数百毫秒后才能工作
mDelay( 100 );
// 初始化USB设备
for( i=5; i!=0; i-- )
{
if( CH375InitUSBDevice( ) != USB_INT_SUCCESS ) mStopIfError( 0xFF );
else break;
}
if( i == 0 ) mStopIfError( 0xFF );
// Processing
while( 1 )
{
ReceiveBuffer = RECV_BUFFER; // 接收缓冲区
length = CH375_HostReceive( ReceiveBuffer ); // 从设备端接收数据
if( length == 0xEF ) // 串口接收到数据
{
LED_OUT_ACT( ); // Enable LED!
receive( );
LED_OUT_INACT( ); // Disable LED!
ReceiveBuffer = RECV_BUFFER; // 接收缓冲区
length = RECV_LEN; // 刚接收到的数据长度
if( length !=0 ) CH375_HostSend( length, ReceiveBuffer ); // 将从串口接收到的数据发送到USB设备
else if( length == 0xFE ) break; // USB设备断开事件
else if( length != 0xFF )
{
ReceiveBuffer = RECV_BUFFER; // 接收缓冲区
while( length-- )
{
SendChar( *ReceiveBuffer ); // 将从USB设备接收到的数据发送到串口
ReceiveBuffer++;
}
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -