⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch375driver-1.c

📁 usb接口芯片Ch375驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -