?? hub.c
字號(hào):
/* CH374芯片 應(yīng)用層 V1.0 */
/* USB主機(jī),初始化和枚舉當(dāng)前連接的USB設(shè)備,支持多個(gè)USB-HUB級(jí)聯(lián) */
#include <stdio.h>
#include <string.h>
#include "..\HAL.H" // 以MCS51為例,其它單片機(jī)需修改HAL*硬件抽象層的幾個(gè)文件
#include "..\HAL_BASE.C" // 基本子程序及中斷查詢子程序
/* 硬件接口層,以下連接方式任選一種 */
#include "..\PARA_HW.C" /* 硬件標(biāo)準(zhǔn)8位并口 */
//#include "..\PARA_SW.C" /* 軟件I/O模擬8位并口 */
//#include "..\SPI_HW.C" /* 硬件標(biāo)準(zhǔn)4線SPI串口 */
//#include "..\SPI_SW.C" /* 軟件I/O模擬4線SPI串口 */
//#include "..\SPI3_SW.C" /* 軟件I/O模擬3線SPI串口,SDO和SDI合用一個(gè)引腳 */
#include "HUB.H"
// 獲取設(shè)備描述符
const UINT8C SetupGetDevDescr[] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 };
// 獲取配置描述符
const UINT8C SetupGetCfgDescr[] = { 0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00 };
// 設(shè)置USB地址
const UINT8C SetupSetUsbAddr[] = { 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
// 設(shè)置USB配置
const UINT8C SetupSetUsbConfig[] = { 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
UINT8 UsbDevEndpSize = DEFAULT_ENDP0_SIZE; /* USB設(shè)備的端點(diǎn)0的最大包尺寸 */
UINT8 FlagDeviceStatus; /* 當(dāng)前USB設(shè)備狀態(tài),通常用于中斷方式的全局變量,本程序中未使用 */
UINT8 idata bHUBendp ; // 集線器的中斷端點(diǎn)
UINT8 idata bNumPort ; // 集線器上的端口數(shù)量
UINT8 idata buf[64]; // 內(nèi)部數(shù)據(jù)組
UINT8 idata bPORTchange , bInterval, bConfig, bMine;
UINT8 idata bChange;
UINT8 idata bAddr;
UINT16 idata mm,kk;
UINT8 idata bHubNum, bDevNum;
//UINT8 xdata xbuf[1778]={ 0 }; // 外部數(shù)據(jù)組
UINT8 xdata xbuf[700]={ 0 }; // 外部數(shù)據(jù)組
#define p_HUB_Descr ((PHUBDescr)buf) // 指向HUB描述符的指針
#define p_Dev_Addr ((PNUM)xbuf) // 指向設(shè)備屬性的指針
// CH374傳輸事務(wù),輸入目的端點(diǎn)地址/PID令牌/同步標(biāo)志,返回同CH375,NAK不重試,超時(shí)/出錯(cuò)重試
UINT8 HostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog );
// CH374傳輸事務(wù),輸入目的端點(diǎn)地址/PID令牌/同步標(biāo)志/以mS為單位的NAK重試總時(shí)間(0xFFFF無限重試),返回同CH375,NAK重試,超時(shí)出錯(cuò)重試
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ù),實(shí)際成功收發(fā)的總長度保存在ReqLen指向的字節(jié)變量中
// 查詢當(dāng)前是否存在USB設(shè)備
//BOOL Query374DeviceIn( void );
#define Query374DeviceIn( ) ( ( Read374Byte( REG_INTER_FLAG ) & BIT_IF_DEV_ATTACH ) ? TRUE : FALSE )
// 查詢當(dāng)前的USB設(shè)備是全速還是低速, 返回TRUE為全速
//BOOL Query374DevFullSpeed( void );
#define Query374DevFullSpeed( ) ( ( Read374Byte( REG_SYS_INFO ) & BIT_INFO_USB_DP ) ? TRUE : FALSE )
void HostDetectInterrupt( void ); // 處理USB設(shè)備插拔事件中斷
void SetHostUsbAddr( UINT8 addr ); // 設(shè)置USB主機(jī)當(dāng)前操作的USB設(shè)備地址
void HostSetBusFree( void ); // USB總線空閑
void HostSetBusReset( void ); // USB總線復(fù)位
void HostSetFullSpeed( void ); // 設(shè)定全速USB設(shè)備運(yùn)行環(huán)境
void HostSetLowSpeed( void ); // 設(shè)定低速USB設(shè)備運(yùn)行環(huán)境
void Init374Host( void ); // 初始化USB主機(jī)
UINT8 GetDeviceDescr( PUINT8 buf ); // 獲取設(shè)備描述符
UINT8 GetConfigDescr( PUINT8 buf ); // 獲取配置描述符
UINT8 SetUsbAddress( UINT8 addr ); // 設(shè)置USB設(shè)備地址
UINT8 SetUsbConfig( UINT8 cfg ); // 設(shè)置USB設(shè)備配置
// CH374傳輸事務(wù),輸入目的端點(diǎn)地址/PID令牌/同步標(biāo)志,返回同CH375,NAK不重試,超時(shí)/出錯(cuò)重試
UINT8 HostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog )
{ // 本子程序著重于易理解,而在實(shí)際應(yīng)用中,為了提供運(yùn)行速度,應(yīng)該對(duì)本子程序代碼進(jìn)行優(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和目的端點(diǎn)號(hào)
// Write374Byte( REG_USB_H_CTRL, BIT_HOST_START | ( tog ? ( BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : 0x00 ) ); // 設(shè)置同步標(biāo)志并啟動(dòng)傳輸
Write374Byte( REG_USB_H_CTRL, ( tog ? ( BIT_HOST_START | BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : BIT_HOST_START ) ); // 設(shè)置同步標(biāo)志并啟動(dòng)傳輸
// Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE ); // 取消暫停
s = Wait374Interrupt( );
if ( s == ERR_USB_UNKNOWN ) return( s ); // 中斷超時(shí),可能是硬件異常
s = Read374Byte( REG_INTER_FLAG ); // 獲取中斷狀態(tài)
if ( s & BIT_IF_DEV_DETECT ) { // USB設(shè)備插拔事件
mDelayuS( 200 ); // 等待傳輸完成
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_TRANSFER ); // 清中斷標(biāo)志
if ( s & BIT_IF_DEV_ATTACH ) { // USB設(shè)備連接事件
u = Read374Byte( REG_USB_SETUP );
if ( s & BIT_IF_USB_DX_IN ) { // 速度匹配,不需要切換速度
if ( u & BIT_SETP_USB_SPEED ) return( USB_INT_CONNECT_LS ); // 低速USB設(shè)備
return( USB_INT_CONNECT ); // 全速USB設(shè)備
}
else { // 速度失配,需要切換速度
if ( u & BIT_SETP_USB_SPEED ) return( USB_INT_CONNECT ); // 全速USB設(shè)備
return( USB_INT_CONNECT_LS ); // 低速USB設(shè)備
}
}
else return( USB_INT_DISCONNECT ); // USB設(shè)備斷開事件
}
else if ( s & BIT_IF_TRANSFER ) { // 傳輸完成
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER ); // 清中斷標(biāo)志
s = Read374Byte( REG_USB_STATUS ); // USB狀態(tài)
r = s & BIT_STAT_DEV_RESP; // USB設(shè)備應(yīng)答狀態(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 ); // 不是超時(shí)/出錯(cuò),意外應(yīng)答
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 ); // 不是超時(shí)/出錯(cuò),意外應(yīng)答
break;
default:
return( ERR_USB_UNKNOWN ); // 不可能的情況
break;
}
}
else { // 其它中斷,不應(yīng)該發(fā)生的情況
mDelayuS( 200 ); // 等待傳輸完成
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); /* 清中斷標(biāo)志 */
if ( retry ) return( ERR_USB_UNKNOWN ); /* 不是第一次檢測到則返回錯(cuò)誤 */
}
}
return( 0x20 ); // 應(yīng)答超時(shí)
}
// CH374傳輸事務(wù),輸入目的端點(diǎn)地址/PID令牌/同步標(biāo)志/以mS為單位的NAK重試總時(shí)間(0xFFFF無限重試),返回同CH375,NAK重試,超時(shí)出錯(cuò)重試
UINT8 WaitHostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog, UINT16 timeout )
{
UINT8 i, s;
while ( 1 ) {
for ( i = 0; i < 40; i ++ ) {
s = HostTransact374( endp_addr, pid, tog );
if ( s != ( DEF_USB_PID_NAK | 0x20 ) || timeout == 0 ) return( s );
mDelayuS( 20 );
}
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ù),實(shí)際成功收發(fā)的總長度保存在ReqLen指向的字節(jié)變量中
{
UINT8 s, len, count, total;
BOOL tog;
Write374Block( RAM_HOST_TRAN, 8, ReqBuf );
Write374Byte( REG_USB_LENGTH, 8 );
mDelayuS( 200 );
s = WaitHostTransact374( 0, DEF_USB_PID_SETUP, FALSE, 200 ); // SETUP階段,200mS超時(shí)
if ( s == USB_INT_SUCCESS ) { // SETUP成功
tog = TRUE; // 默認(rèn)DATA1,默認(rèn)無數(shù)據(jù)故狀態(tài)階段為IN
total = *( ReqBuf + 6 );
if ( total && DatBuf ) { // 需要收發(fā)數(shù)據(jù)
len = total;
if ( *ReqBuf & 0x80 ) { // 收
while ( len ) {
mDelayuS( 200 );
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 = 0;
if ( count & ( UsbDevEndpSize - 1 ) ) break; // 短包
tog = tog ? FALSE : TRUE;
}
tog = FALSE; // 狀態(tài)階段為OUT
}
else { // 發(fā)
while ( len ) {
mDelayuS( 200 );
count = len >= UsbDevEndpSize ? UsbDevEndpSize : len;
Write374Block( RAM_HOST_TRAN, count, DatBuf );
Write374Byte( REG_USB_LENGTH, count );
s = WaitHostTransact374( 0, DEF_USB_PID_OUT, tog, 200 ); // OUT數(shù)據(jù)
if ( s != USB_INT_SUCCESS ) break;
DatBuf += count;
len -= count;
tog = tog ? FALSE : TRUE;
}
tog = TRUE; // 狀態(tài)階段為IN
}
total -= len; // 減去剩余長度得實(shí)際傳輸長度
}
if ( s == USB_INT_SUCCESS ) { // 數(shù)據(jù)階段成功
Write374Byte( REG_USB_LENGTH, 0 );
mDelayuS( 200 );
s = WaitHostTransact374( 0, ( tog ? DEF_USB_PID_IN : DEF_USB_PID_OUT ), TRUE, 200 ); // STATUS階段
if ( tog && s == USB_INT_SUCCESS ) { // 檢查IN狀態(tài)返回?cái)?shù)據(jù)長度
if ( Read374Byte( REG_USB_LENGTH ) ) s = USB_INT_BUF_OVER; // 狀態(tài)階段錯(cuò)誤
}
}
}
if ( RetLen ) *RetLen = total; // 實(shí)際成功收發(fā)的總長度
return( s );
}
// 查詢當(dāng)前是否存在USB設(shè)備
//BOOL Query374DeviceIn( void )
//#define Query374DeviceIn( ) ( ( Read374Byte( REG_INTER_FLAG ) & BIT_IF_DEV_ATTACH ) ? TRUE : FALSE )
// 查詢當(dāng)前的USB設(shè)備是全速還是低速, 返回TRUE為全速
//BOOL Query374DevFullSpeed( void )
//#define Query374DevFullSpeed( ) ( ( Read374Byte( REG_SYS_INFO ) & BIT_INFO_USB_DP ) ? TRUE : FALSE )
void HostDetectInterrupt( void ) // 處理USB設(shè)備插拔事件中斷
{
UINT8 s, u;
s = Read374Byte( REG_INTER_FLAG ); // 獲取中斷狀態(tài)
if ( s & BIT_IF_DEV_DETECT ) { // USB設(shè)備插拔事件
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT ); // 清中斷標(biāo)志
if ( s & BIT_IF_DEV_ATTACH ) { // USB設(shè)備連接事件
u = Read374Byte( REG_USB_SETUP );
if ( s & BIT_IF_USB_DX_IN ) { // 速度匹配,不需要切換速度
if ( u & BIT_SETP_USB_SPEED ) FlagDeviceStatus = USB_INT_CONNECT_LS; // 低速USB設(shè)備
else FlagDeviceStatus = USB_INT_CONNECT; // 全速USB設(shè)備
}
else { // 速度失配,需要切換速度
if ( u & BIT_SETP_USB_SPEED ) FlagDeviceStatus = USB_INT_CONNECT; // 全速USB設(shè)備
else FlagDeviceStatus = USB_INT_CONNECT_LS; // 低速USB設(shè)備
}
}
else FlagDeviceStatus = USB_INT_DISCONNECT; // USB設(shè)備斷開事件
}
else { // 意外的中斷
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER | BIT_IF_USB_SUSPEND | BIT_IF_WAKE_UP ); // 清中斷標(biāo)志
}
}
void SetHostUsbAddr( UINT8 addr ) // 設(shè)置USB主機(jī)當(dāng)前操作的USB設(shè)備地址
{
Write374Byte( REG_USB_ADDR, addr );
}
void HostSetBusFree( void ) // USB總線空閑
{
// Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_FREE( Read374Byte( REG_USB_SETUP ) ) ); // USB總線空閑
Write374Byte( REG_USB_SETUP, BIT_SETP_HOST_MODE ); // USB總線復(fù)位
Write374Byte( REG_USB_SETUP, BIT_SETP_HOST_MODE | BIT_SETP_AUTO_SOF ); // USB總線復(fù)位,允許SOF
}
void HostSetBusReset( void ) // USB總線復(fù)位
{
UsbDevEndpSize = DEFAULT_ENDP0_SIZE; /* USB設(shè)備的端點(diǎn)0的最大包尺寸 */
SetHostUsbAddr( 0x00 );
Write374Byte( REG_USB_H_CTRL, 0x00 );
// Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_RESET( Read374Byte( REG_USB_SETUP ) & ~ BIT_SETP_AUTO_SOF ) ); // USB總線復(fù)位
Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_RESET( BIT_SETP_HOST_MODE ) ); // USB總線復(fù)位
mDelaymS( 20 ); // USB總線復(fù)位期間
// Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_FREE( Read374Byte( REG_USB_SETUP ) ) ); // USB總線空閑
HostSetBusFree( ); // USB總線空閑
mDelaymS( 1 );
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_USB_SUSPEND ); // 清中斷標(biāo)志
}
void HostSetFullSpeed( void ) // 設(shè)定全速USB設(shè)備運(yùn)行環(huán)境
{
Write374Byte( REG_USB_SETUP, Read374Byte( REG_USB_SETUP ) & ~ BIT_SETP_USB_SPEED | BIT_SETP_AUTO_SOF ); // 全速且發(fā)SOF
mDelaymS( 1 );
}
void HostSetLowSpeed( void ) // 設(shè)定低速USB設(shè)備運(yùn)行環(huán)境
{
Write374Byte( REG_USB_SETUP, Read374Byte( REG_USB_SETUP ) | BIT_SETP_USB_SPEED | BIT_SETP_AUTO_SOF ); // 低速且發(fā)SOF
mDelaymS( 1 );
}
void Init374Host( void ) // 初始化USB主機(jī)
{
Write374Byte( REG_USB_SETUP, 0x00 );
SetHostUsbAddr( 0x00 );
Write374Byte( REG_USB_H_CTRL, 0x00 );
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); // 清所有中斷標(biāo)志
// Write374Byte( REG_INTER_EN, BIT_IE_TRANSFER ); // 允許傳輸完成中斷,因?yàn)楸境绦蚴褂貌樵兎绞綑z測USB設(shè)備插拔,所以無需USB設(shè)備檢測中斷
Write374Byte( REG_INTER_EN, BIT_IE_TRANSFER | BIT_IE_DEV_DETECT ); // 允許傳輸完成中斷和USB設(shè)備檢測中斷
Write374Byte( REG_SYS_CTRL, BIT_CTRL_OE_POLAR ); // 對(duì)于CH374T或者UEN引腳懸空的CH374S必須置BIT_CTRL_OE_POLAR為1
HostSetBusFree( ); // USB總線空閑
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -