?? ch375driver-1.c
字號:
#include <string.h>
#include <stdio.h>
#include <intrins.h>
#include <reg51.h>
#define u8 unsigned char
#define u16 unsigned int
/*USB設備命令---------------------------------------------------------------------------------------*/
#define CMD_WR_USB_DATA7 0x2B /* 向USB 主機端點的輸出緩沖區寫入數據塊 */
#define CMD_RESET_ALL 0x05 /* 執行硬件復位 */
#define CMD_ISSUE_TOKEN 0x4F /* 產生中斷,發出令牌,執行事務 */
#define CMD_CLR_STALL 0x41 /* 產生中斷,清除端點錯誤 */
#define CMD_ABORT_NAK 0x17 /* 放棄當前NAK 的重試 */
#define CMD_READ_USB_DATA 0x27 /* 從當前USB 中斷的端點緩沖區讀取數據塊 */
#define CMD_CHECK_EXIST 0x06 /* 測試工作狀態 */
#define CMD_SET_ENDP6 0x1C /* 設置USB主機端點的接收器 */
#define CMD_SET_ENDP7 0x1D /* 設置USB主機端點的發送器 */
#define CMD_SET_RETRY 0x0B /* 設置USB 事務操作的重試次數 */
#define CMD_SET_CONFIG 0x49 /* 產生中斷,控制傳輸:設置USB 配置 */
#define CMD_SET_USB_MODE 0x15 /* 設置USB 工作模式 */
#define CMD_SET_ADDRESS 0x45 /* 產生中斷,控制傳輸:設置USB 地址 */
#define CMD_SET_USB_ADDR 0x13 /* 設置USB 地址,沒有返回值 */
#define CMD_GET_DESCR 0x46 /* 產生中斷,獲取描述符 */
#define CMD_GET_STATUS 0x22 /* 獲取中斷狀態并取消請求 */
/*-------------------------------------------------------------------------------------------------*/
/*如果命令的輸出數據是操作狀態*/
#define CMD_RET_SUCCESS 0x51 /* 操作成功 */
#define DEF_USB_PID_OUT 0x01 /* CH375 支持的USB 令牌PID,執行OUT 事務,發送數據 */
#define DEF_USB_PID_IN 0x01 /* CH375 支持的USB 令牌PID,執行IN 事務,接收數據 */
#define SET_USB_MODE_6 0x06 /* 模式代碼為06H 時切換到已啟用的USB 主機方式,自動產生SOF 包 */
#define SET_USB_MODE_7 0x07 /* 模式代碼為07H 時切換到已啟用的USB 主機方式,復位USB 總線 */
/*USB 主機方式的常用中斷狀態*/
#define USB_INT_SUCCESS 0x14 /* USB 事務或者傳輸操作成功 */
#define USB_INT_CONNECT 0x15 /* 檢測到USB 設備連接事件 */
#define USB_INT_DISCONNECT 0x16 /* 檢測到USB 設備斷開事件 */
#define USB_INT_BUF_OVER 0x17 /* USB 傳輸的數據有誤或者數據太多緩沖區溢出 */
#define USB_INT_DISK_READ 0x1D /* USB 存儲設備讀操作,請求數據讀出 */
#define USB_INT_DISK_WRITE 0x1E /* USB 存儲設備寫操作,請求數據寫入 */
#define USB_INT_DISK_ERR 0x1F /* USB 存儲設備操作失敗 */
#define A0_WRITE_CMD 1
#define A0_READ_WRITE_DATA 0
#define DELAY_START_value 1 /* 根據單片機的時鐘選擇延時初值 */
#define UNKNOWN_USB_DEVICE 0xF1
#define USB_INT_RET_NAK 0x2A /* 00101010B,返回NAK */
typedef struct _USB_DEVICE_DESCRIPTOR
{
u8 bLength;
u8 bDescriptorType;
unsigned short bcdUSB;
u8 bDeviceClass;
u8 bDeviceSubClass;
u8 bDeviceProtocol;
u8 bMaxPacketSize0;
unsigned short idVendor;
unsigned short idProduct;
unsigned short bcdDevice;
u8 iManufacturer;
u8 iProduct;
u8 iSerialNumber;
u8 bNumConfigurations;
} USB_DEV_DESCR, *PUSB_DEV_DESCR;
typedef struct _USB_CONFIG_DESCRIPTOR
{
u8 bLength;
u8 bDescriptorType;
unsigned short wTotalLength;
u8 bNumInterfaces;
u8 bConfigurationvalue;
u8 iConfiguration;
u8 bmAttributes;
u8 MaxPower;
} USB_CFG_DESCR, *PUSB_CFG_DESCR;
typedef struct _USB_INTERF_DESCRIPTOR
{
u8 bLength;
u8 bDescriptorType;
u8 bInterfaceNumber;
u8 bAlternateSetting;
u8 bNumEndpoints;
u8 bInterfaceClass;
u8 bInterfaceSubClass;
u8 bInterfaceProtocol;
u8 iInterface;
} USB_ITF_DESCR, *PUSB_ITF_DESCR;
typedef struct _USB_ENDPOINT_DESCRIPTOR
{
u8 bLength;
u8 bDescriptorType;
u8 bEndpointAddress;
u8 bmAttributes;
unsigned short wMaxPacketSize;
u8 bInterval;
} USB_ENDP_DESCR, *PUSB_ENDP_DESCR;
typedef struct _USB_CONFIG_DESCRIPTOR_LONG
{
USB_CFG_DESCR cfg_descr;
USB_ITF_DESCR itf_descr;
USB_ENDP_DESCR endp_descr[4];
} USB_CFG_DESCR_LONG, *PUSB_CFG_DESCR_LONG;
#define CH375_MAX_DATA_LEN 64
u8 RECV_LEN; /* 剛接收到的數據的長度 */
u8 idata RECV_BUFFER[ CH375_MAX_DATA_LEN ]; /* 數據緩沖區,用于保存接收到的下傳數據,長度為0到64字節 */
u8 idata *cmd_buf;
u8 idata *ret_buf;
#define p_dev_descr ((PUSB_DEV_DESCR)RECV_BUFFER)
#define p_cfg_descr ((PUSB_CFG_DESCR_LONG)RECV_BUFFER)
u8 endp_out_addr; /* USB數據接收端點的端點地址 */
u8 endp_out_size; /* USB數據接收端點的端點尺寸 */
u8 endp_in_addr; /* USB狀態發送端點的端點地址,為0則只支持單向接口 */
u8 endp6_mode, endp7_mode;
/*
接線圖-----單片機------USB------
P1.0 D0
P1.1 D1
P1.2 D2
P1.3 D3
P1.4 D4
P1.5 D5
P1.6 D6
P1.7 D7
P3.7 A0
P3.5 RD
P3.4 WR
CS 接地
P3.2(int0) int
*/
#define CH375_DATA_PORT P1 /* CH375端口的I/O地址 */
sbit CH375_CMD_DAT = P3^7; /* CH375地址線輸入A0,A0=1時寫命令,A0=0時讀寫數據 */
sbit CH375_RD = P3^5; /* CH375讀選通輸入,低電平有效 */
sbit CH375_WR = P3^4; /* CH375寫選通輸入,低電平有效 */
sbit led = P3^3; /* 指示燈 */
sbit CH375_INT = P3^2; /* CH375中斷請求輸出,低電平有效 */
void Delay2us(void);
void Delay50ms(void);
void Delay1s(void);
void FlashLED(void);
void ToggleReceive(void);
void ToggleSend(void);
void Ch375Init( void );
void ComInit(void);
void SendChar(u8 buff);
void Ch375WriteCommand( u8 cmd );
void Ch375WriteData( u8 dat );
void SetUsbMode( u8 mode );
void WriteUsbData( u8 len, u8 *buf );
void HostSend( u8 len, u8 *buf );
u8 ClearStall6( void);
u8 ClearStall7( void);
u8 Ch375ReadData(void);
u8 WaitInterrupt(void);
u8 InitUsbDevice(void);
u8 HostReceive( u8 *buf );
u8 GetDescr( u8 type );
u8 SetAddress( u8 addr );
u8 SetConfig( u8 cfg );
u8 IssueToken( u8 endp_and_pid );
u8 ReadUsbData( u8 *buf );
//void SendChars( u8 *buff );
/*-------------------------------------------------------------------------------*/
void Delay2us(void)
{
u8 i;
for ( i=DELAY_START_value*2+1; i!=0; i-- );
}
void Delay50ms(void)
{
u8 i, j;
for( i=100; i!=0; i-- )
for( j=250; j!=0; j-- );
}
void Delay1s(void)
{
u8 i,j,k;
for( i=10; i!=0; i-- )
for( j=200; j!=0; j-- )
for( k=250; k!=0; k-- );
}
void FlashLED(void)
{
u8 i;
for( i=10; i>0; i-- )
{
led=!led;
Delay1s();
}
}
/*-------------------------------------------------------------------------------*/
/* 與CH372/CH375有關的基本I/O操作 */
/* 向CH375的命令端口寫入命令,周期不小于4uS,如果單片機較快則延時 */
void Ch375WriteCommand( u8 cmd )
{
_nop_();
_nop_();
CH375_CMD_DAT = A0_WRITE_CMD; /* 命令 */
CH375_DATA_PORT = cmd;
CH375_RD = 1;
CH375_WR = 0;
_nop_();
_nop_();
CH375_WR = 1;
CH375_CMD_DAT = A0_READ_WRITE_DATA;
CH375_DATA_PORT = 0xFF;
}
/* 向CH375的數據端口寫入數據,周期不小于1.5uS,如果單片機較快則延時 */
void Ch375WriteData( u8 dat )
{
_nop_();
CH375_CMD_DAT = A0_READ_WRITE_DATA; /* 數據 */
CH375_DATA_PORT = dat;
CH375_RD = 1;
CH375_WR = 0;
_nop_();
CH375_WR = 1;
CH375_DATA_PORT = 0xFF;
}
/* 從CH375的數據端口讀出數據,周期不小于1.5uS,如果單片機較快則延時 */
u8 Ch375ReadData(void)
{
u8 rev_data;
CH375_DATA_PORT = 0xFF;
CH375_CMD_DAT = A0_READ_WRITE_DATA; /* 數據 */
CH375_WR = 1;
CH375_RD = 0;
_nop_();
rev_data = CH375_DATA_PORT;
CH375_RD = 1;
return( rev_data );
}
/* 主機端等待操作完成, 返回操作狀態 */
u8 WaitInterrupt(void)
{
CH375_INT = 1;
while( CH375_INT ) /* 查詢等待CH375操作完成中斷(INT#低電平) */
{
if( RI==1 ) /* 串口接收到數據 */
{
Ch375WriteCommand( (u8)(CMD_ABORT_NAK) ); /* 放棄當前操作 */
return( 0xEF );
}
}
Ch375WriteCommand( CMD_GET_STATUS ); /* 產生操作完成中斷, 獲取中斷狀態 */
return( Ch375ReadData() );
}
/* 設置CH37X的工作模式 */
void SetUsbMode( u8 mode )
{
u8 i;
Ch375WriteCommand( CMD_SET_USB_MODE );
Ch375WriteData( mode );
endp6_mode = endp7_mode = 0x80; /* 主機端復位USB數據同步標志 */
for( i=100; i!=0; i-- ) /* 等待設置模式操作完成,不超過30uS */
{
if( Ch375ReadData() == CMD_RET_SUCCESS )
return; /* 成功 */
}
while(1)
{
FlashLED(); /* CH375出錯 */
}
}
/************************************************************************************
數據同步
USB的數據同步通過切換DATA0和DATA1實現: 在設備端, USB設備可以自動切換;
在主機端, 必須由SET_ENDP6和SET_ENDP7命令控制CH375切換DATA0與DATA1.
主機端的程序處理方法是為設備端的各個端點分別提供一個全局變量,
初始值均為DATA0, 每執行一次成功事務后取反, 每執行一次失敗事務后將其復位為DATA1
*************************************************************************************/
void ToggleReceive(void) /* 主機接收成功后,切換DATA0和DATA1實現數據同步 */
{
Ch375WriteCommand( CMD_SET_ENDP6 );
Ch375WriteData( endp6_mode );
endp6_mode^=0x40;
Delay2us();
}
void ToggleSend(void) /* 主機發送成功后,切換DATA0和DATA1實現數據同步 */
{
Ch375WriteCommand( CMD_SET_ENDP7 );
Ch375WriteData( endp7_mode );
endp7_mode^=0x40;
Delay2us();
}
u8 ClearStall6(void) /* 主機接收失敗后,復位設備端的數據同步到DATA0 */
{
Ch375WriteCommand( CMD_CLR_STALL );
Ch375WriteData( 0x80 ); /* 對于OUT端點,有效地址是01H~0FH,對于IN端點,有效地址是81H~8FH */
endp6_mode=0x80;
return( WaitInterrupt() );
}
u8 ClearStall7(void) /* 主機發送失敗后,復位設備端的數據同步到DATA0 */
{
Ch375WriteCommand( CMD_CLR_STALL );
Ch375WriteData( 0x80 ); /* 對于OUT端點,有效地址是01H~0FH,對于IN端點,有效地址是81H~8FH */
endp7_mode=0x80;
return( WaitInterrupt() );
}
/* 數據讀寫, 單片機讀寫CH375芯片中的數據緩沖區 */
u8 ReadUsbData( u8 *buf ) /* 從CH37X讀出數據塊 */
{
u8 len, length;
Ch375WriteCommand( CMD_READ_USB_DATA ); /* 從CH375的端點緩沖區讀取接收到的數據 */
len = Ch375ReadData(); /* 后續數據長度 */
length=len;
while( len-- )
{
*buf = Ch375ReadData();
buf++;
}
return( length );
}
/* 向CH37X寫入數據塊 */
void WriteUsbData( u8 len, u8 *buf )
{
Ch375WriteCommand( CMD_WR_USB_DATA7 ); /* 向CH375的端點緩沖區寫入準備發送的數據 */
Ch375WriteData( len ); /* 后續數據長度, len不能大于64 */
while( len-- )
{
Ch375WriteData( *buf );
buf++;
}
}
/* 主機操作 */
u8 IssueToken( u8 endp_and_pid ) /* 執行USB事務 */
{
u8 status;
/* 執行完成后, 將產生中斷通知單片機, 如果是USB_INT_SUCCESS就說明操作成功 */
Ch375WriteCommand( CMD_ISSUE_TOKEN );
Ch375WriteData( endp_and_pid ); /* 高4位目的端點號, 低4位令牌PID */
status = WaitInterrupt(); /* 等待CH375操作完成 */
return( status );
}
void HostSend( u8 len, u8 *buf ) /* 主機發送 */
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -