const UINT8C SetupGetDevDescr[] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 }; // 獲取設備描述符 const UINT8C SetupGetCfgDescr[] = { 0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00 }; // 獲取配置描述符 const UINT8C SetupSetUsbAddr[] = { 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 設置USB地址 const UINT8C SetupSetUsbConfig[] = { 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 設置USB配置 UINT8 UsbDevEndpSize = DEFAULT_ENDP0_SIZE; /* USB設備的端點0的最大包尺寸 */ UINT8 FlagDeviceStatus; /* 當前USB設備狀態(tài),通常用于中斷方式的全局變量,本程序中未使用 */ // CH374傳輸事務,輸入目的端點地址/PID令牌/同步標志,返回同CH375,NAK不重試,超時/出錯重試 UINT8 HostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog ); // CH374傳輸事務,輸入目的端點地址/PID令牌/同步標志/以mS為單位的NAK重試總時間(0xFFFF無限重試),返回同CH375,NAK重試,超時出錯重試 UINT8 WaitHostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog, UINT16 timeout ); UINT8 HostCtrlTransfer374( PUINT8 ReqBuf, PUINT8 DatBuf, PUINT8 RetLen ); // 執(zhí)行控制傳輸,ReqBuf指向8字節(jié)請求碼,DatBuf為收發(fā)緩沖區(qū) // 如果需要接收和發(fā)送數(shù)據(jù),那么DatBuf需指向有效緩沖區(qū)用于存放后續(xù)數(shù)據(jù),實際成功收發(fā)的總長度保存在ReqLen指向的字節(jié)變量中 // 查詢當前是否存在USB設備 //BOOL Query374DeviceIn( void ); #define Query374DeviceIn( ) ( ( Read374Byte( REG_HUB_SETUP ) & BIT_HUB0_ATTACH ) ? TRUE : FALSE )
// 查詢當前的USB設備是全速還是低速, 返回TRUE為全速 //BOOL Query374DevFullSpeed( void ); #define Query374DevFullSpeed( ) ( ( Read374Byte( REG_SYS_INFO ) & BIT_INFO_USB_DP ) ? TRUE : FALSE )
void HostDetectInterrupt( void ); // 處理USB設備插拔事件中斷 void SetHostUsbAddr( UINT8 addr ); // 設置USB主機當前操作的USB設備地址 void HostSetBusFree( void ); // USB總線空閑 void HostSetBusReset( void ); // USB總線復位 void HostSetFullSpeed( void ); // 設定全速USB設備運行環(huán)境 void HostSetLowSpeed( void ); // 設定低速USB設備運行環(huán)境 void Init374Host( void ); // 初始化USB主機 UINT8 GetDeviceDescr( PUINT8 buf ); // 獲取設備描述符 UINT8 GetConfigDescr( PUINT8 buf ); // 獲取配置描述符 UINT8 SetUsbAddress( UINT8 addr ); // 設置USB設備地址 UINT8 SetUsbConfig( UINT8 cfg ); // 設置USB設備配置
// CH374傳輸事務,輸入目的端點地址/PID令牌/同步標志,返回同CH375,NAK不重試,超時/出錯重試 UINT8 HostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog ) { // 本子程序著重于易理解,而在實際應用中,為了提供運行速度,應該對本子程序代碼進行優(yōu)化 UINT8 retry; UINT8 s, r, u; for ( retry = 0; retry < 3; 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 ); // 取消暫停 s = Wait374Interrupt( ); if ( s == ERR_USB_UNKNOWN ) return( s ); // 中斷超時,可能是硬件異常 s = Read374Byte( REG_INTER_FLAG ); // 獲取中斷狀態(tài) if ( s & BIT_IF_DEV_DETECT ) { // USB設備插拔事件 delay_us( 250 ); // 等待傳輸完成 Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_TRANSFER ); // 清中斷標志 if ( s & BIT_IF_DEV_ATTACH ) { // USB設備連接事件 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 ) { // 傳輸完成 Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER ); // 清中斷標志 s = Read374Byte( REG_USB_STATUS ); // USB狀態(tài) r = s & BIT_STAT_DEV_RESP; // USB設備應答狀態(tài) switch ( pid ) { case DEF_USB_PID_SETUP: case DEF_USB_PID_OUT: if ( r == DEF_USB_PID_ACK ) return( USB_INT_SUCCESS ); else if ( r == DEF_USB_PID_STALL || r == DEF_USB_PID_NAK ) return( r | 0x20 ); else if ( ! M_IS_HOST_TIMEOUT( s ) ) return( r | 0x20 ); // 不是超時/出錯,意外應答 break; case DEF_USB_PID_IN: if ( M_IS_HOST_IN_DATA( s ) ) { // DEF_USB_PID_DATA0 or DEF_USB_PID_DATA1 if ( s & BIT_STAT_TOG_MATCH ) return( USB_INT_SUCCESS ); // 不同步則需丟棄后重試 } else if ( r == DEF_USB_PID_STALL || r == DEF_USB_PID_NAK ) return( r | 0x20 ); else if ( ! M_IS_HOST_TIMEOUT( s ) ) return( r | 0x20 ); // 不是超時/出錯,意外應答 break; default: return( ERR_USB_UNKNOWN ); // 不可能的情況 break; } } else { // 其它中斷,不應該發(fā)生的情況 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 ) { for ( i = 0; i < 200; i ++ ) { s = HostTransact374( endp_addr, pid, tog ); if ( s != ( DEF_USB_PID_NAK | 0x20 ) || timeout == 0 ) return( s ); delay_us( 20 ); //50 } if ( timeout < 0xFFFF ) timeout --; } }
UINT8 HostCtrlTransfer374( PUINT8 ReqBuf, PUINT8 DatBuf, PUINT8 RetLen ) // 執(zhí)行控制傳輸,ReqBuf指向8字節(jié)請求碼,DatBuf為收發(fā)緩沖區(qū) // 如果需要接收和發(fā)送數(shù)據(jù),那么DatBuf需指向有效緩沖區(qū)用于存放后續(xù)數(shù)據(jù),實際成功收發(fā)的總長度保存在ReqLen指向的字節(jié)變量中 { UINT8 s, len, count, total; BOOL tog; Write374Block( RAM_HOST_TRAN, 8, ReqBuf ); Write374Byte( REG_USB_LENGTH, 8 ); delay_us( 100 );///////////////////////////////// s = WaitHostTransact374( 0, DEF_USB_PID_SETUP, FALSE, 200 ); // SETUP階段,200mS超時///////////////////// if ( s == USB_INT_SUCCESS ) { // SETUP成功 tog = TRUE; // 默認DATA1,默認無數(shù)據(jù)故狀態(tài)階段為IN if ((*( ReqBuf + 3 )) == 0x22 ) { total = *( ReqBuf + 6 ) - 0x40; } else { total = *( ReqBuf + 6 ); } if ( total && DatBuf ) { // 需要收發(fā)數(shù)據(jù) len = total; if ( *ReqBuf & 0x80 ) { // 收 while ( len ) { delay_us( 100 );///////////////////// s = WaitHostTransact374( 0, DEF_USB_PID_IN, tog, 200 ); // IN數(shù)據(jù) //////////////// if ( s != USB_INT_SUCCESS ) break; count = Read374Byte( REG_USB_LENGTH ); Read374Block( RAM_HOST_RECV, count, DatBuf ); DatBuf += count; if ( count <= len ) len -= count; else len