#include "./Public/CH554.H"
#include "./Public/Debug.H"
#include <stdio.h>
#include <string.h>
#define THIS_ENDP0_SIZE DEFAULT_ENDP0_SIZE
UINT8X Ep0Buffer[THIS_ENDP0_SIZE] _at_ 0x0000; //端点0 OUT&IN缓冲区,必须是偶地址
UINT8X Ep2Buffer[2*MAX_PACKET_SIZE] _at_ 0x0008; //端点2 IN&OUT缓冲区,必须是偶地址
UINT8X Ep1Buffer[MAX_PACKET_SIZE] _at_ 0x00a0;
UINT8 SetupReq,SetupLen,Ready,Count,FLAG,UsbConfig;
PUINT8 pDescr; //USB配置标志
USB_SETUP_REQ SetupReqBuf; //暂存Setup包
UINT8 num = 0;
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
sbit Ep2InKey = P1^5; //K1按键
#pragma NOAREGS
/*设备描述符*/
UINT8C DevDesc[18]={0x12,0x01,0x10,0x01,0xff,0x00,0x02,0x08, //设备描述符
0x86,0x1a,0x23,0x55,0x04,0x03,0x00,0x00,
0x00,0x01};
UINT8C CfgDesc[39]={0x09,0x02,0x27,0x00,0x01,0x01,0x00,0x80,0xf0, //配置描述符,接口描述符,端点描述符
0x09,0x04,0x00,0x00,0x03,0xff,0x01,0x02,0x00,
0x07,0x05,0x82,0x02,0x20,0x00,0x00, //批量上传端点
0x07,0x05,0x02,0x02,0x20,0x00,0x00, //批量下传端点
0x07,0x05,0x81,0x03,0x08,0x00,0x01}; //中断上传端点
UINT8C DataBuf[26]={0x30,0x00,0xc3,0x00,0xff,0xec,0x9f,0xec,0xff,0xec,0xdf,0xec,
0xdf,0xec,0xdf,0xec,0x9f,0xec,0x9f,0xec,0x9f,0xec,0x9f,0xec,
0xff,0xec};
/*字符串描述符 略*/
// unsigned char code LangDes[]={0x04,0x03,0x09,0x04}; //语言描述符
// unsigned char code SerDes[]={
// 0x28,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x49,0x00,0x43,0x00,0x42,
// 0x00,0x43,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00
// }; //字符串描述符
UINT8X UserEp2Buf[64]; //用户数据定义
/*******************************************************************************
* Function Name : Enp2BlukIn()
* Description : USB设备模式端点2的批量上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Enp2BlukIn( )
{
memcpy( Ep2Buffer+MAX_PACKET_SIZE, UserEp2Buf, sizeof(UserEp2Buf)); //加载上传数据
UEP2_T_LEN = THIS_ENDP0_SIZE; //上传最大包长度
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
while(UEP2_CTRL&UEP_T_RES_ACK); //等待传输完成
}
/*******************************************************************************
* Function Name : DeviceInterrupt()
* Description : CH559USB中断处理函数
*******************************************************************************/
void DeviceInterrupt( void ) interrupt INT_NO_USB using 1 //USB中断服务程序,使用寄存器组1
{
UINT8 len,i;
if(UIF_TRANSFER) //USB传输完成标志
{
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
{
case UIS_TOKEN_IN | 2: //endpoint 2# 端点批量上传
UEP2_T_LEN = 0; //预使用发送长度一定要清空
// UEP1_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
break;
case UIS_TOKEN_OUT | 2: //endpoint 2# 端点批量下传
if ( U_TOG_OK ) // 不同步的数据包将丢弃
{
len = USB_RX_LEN; //接收数据长度,数据从Ep2Buffer首地址开始存放
for ( i = 0; i < len; i ++ )
{
Ep2Buffer[MAX_PACKET_SIZE+i] = Ep2Buffer[i]; // OUT数据取反到IN由计算机验证
}
UEP2_T_LEN = len;
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; // 允许上传
}
break;
case UIS_TOKEN_SETUP | 0: //SETUP事务
len = USB_RX_LEN;
if(len == (sizeof(USB_SETUP_REQ)))
{
SetupLen = UsbSetupBuf->wLengthL;
if(UsbSetupBuf->wLengthH || SetupLen > 0x7F )
{
SetupLen = 0x7F; // 限制总长度
}
len = 0; // 默认为成功并且上传0长度
SetupReq = UsbSetupBuf->bRequest;
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )/*HID类命令*/
{
switch( SetupReq )
{
case 0xC0:
pDescr = &DataBuf[num];
len = 2;
if(num<24)
{
num += 2;
}
else
{
num = 24;
}
break;
case 0x40:
len = 9; //保证状态阶段,这里只要比8大,且不等于0xff即可
break;
default:
len = 0xFF; /*命令不支持*/
break;
}
if ( SetupLen > len )
{
SetupLen = len; //限制总长度
}
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;//本次传输长度
memcpy(Ep0Buffer,pDescr,len); //加载上传数据
SetupLen -= len;
pDescr += len;
}
else //标准请求
{
switch(SetupReq) //请求码
{
case USB_GET_DESCRIPTOR:
switch(UsbSetupBuf->wValueH)
{
case 1: //设备描述符
pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(DevDesc);
break;
case 2: //配置描述符
pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(CfgDesc);
break;
default:
len = 0xff; //不支持的命令或者出错
break;
}
if ( SetupLen > len )
{
SetupLen = len; //限制总长度
}
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;//本次传输长度
memcpy(Ep0Buffer,pDescr,len); //加载上传数据
SetupLen -= len;
pDescr += len;
break;
case USB_SET_ADDRESS:
SetupLen = UsbSetupBuf->wValueL; //暂存USB设备地址
break;
case USB_GET_CONFIGURATION:
Ep0Buffer[0] = UsbConfig;
if ( SetupLen >= 1 )
{
len = 1;
}
break;
case USB_SET_CONFIGURATION:
UsbConfig = UsbSetupBuf->wValueL;
break;
case 0x0A:
break;
case USB_CLEAR_FEATURE: //Clear Feature
if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
{
switch( UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
default:
len = 0xFF; // 不支持的端点
break;
}
}
else
{
len = 0xFF; // 不是端点不支持
}
break;
case USB_SET_FEATURE: /* Set Feature */
if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x00 ) /* 设置设备 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
{
if( CfgDesc[ 7 ] & 0x20 )
{
/* 设置唤醒使能标志 */
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x02 ) /* 设置端点 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
{
switch( ( ( UINT16 )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
break;
default:
len = 0xFF; /* 操作失败 */
break;
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
break;
case USB_GET_STATUS:
Ep0Buffer[0] = 0x00;
Ep0Buffer[1] = 0x00;
if ( SetupLen >= 2 )
{
len = 2;
}
else
{
len = SetupLen;
}
break;
default:
len = 0xff; //操作失败
break;
}
}
}
else
{
len = 0xff; //包长度错误
}
if(len == 0xff)
{
SetupReq = 0xFF;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
}
else if(len <= THIS_ENDP0_SIZE) //上传数据或者状态阶段返回0长度包
{
UEP0_T_LEN = len;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
}
else
{
UEP0_T_LEN = 0; //虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
}
break;
case UIS_TOKEN_IN | 0: //endpoint0 IN
switch(SetupReq)
{
case USB_GET_DESCRIPTOR:
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; //本次传输长度
memcpy( Ep0Buffer, pDescr, len ); //加载上传数据
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
break;
case USB_SET_ADDRESS:
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT | 0: // endpoint0 OUT
len = USB_RX_LEN;
if(SetupReq == 0x09)
{
if(Ep0Buffer[0])
{
printf("Light on Num Lock LED!\n");
}
else if(Ep0Buffer[0] == 0)
{
printf("Light off Num Lock LED!\n");
}
}
UEP0_T_LEN = 0; //虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA0,返回应答ACK
break;
default:
break;
}
UIF_TRANSFER = 0; //写0清空中断
}
if(UIF_BUS_RST) //设备模式USB总线复位中断
{
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
USB_DEV_AD = 0x00;
UIF_SUSPEND = 0;
UIF_TRANSFER = 0;
UIF_BUS_RST = 0; //清中断标志
}
if (UIF_SUSPEND) //USB总线挂起/唤醒完成
{
UIF_SUSPEND = 0;
if ( USB_MIS_ST & bUMS_SUSPEND ) //挂起
{
#ifdef DE_PRINTF
printf( "zz" ); //睡眠状态
#endif
while ( XBUS_AUX & bUART0_TX )
{
; //等待发送完成
}
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO; //USB或者RXD0有信号时可被唤醒
PCON |= PD; //睡眠
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
}
else { //意外的中断,不可能发生的情况
USB_INT_FG = 0xFF; //清中断标志
// printf("UnknownInt N");
}
}
/*******************************************************************************
* Function Name : USBDeviceCfg()
* Description : USB设备模式配置
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USBDeviceCfg()
{
USB_CTRL = 0x00; //清空USB控制寄存器
USB_CTRL &= ~bUC_HOST_MODE; //该位为选择设备模式
USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; //USB设备和内部上拉使能,在中断期间中断标志未清除前自动返回NAK
USB_DEV_AD = 0x00; //设备地址初始化
// USB_CTRL |= bUC_LOW_SPEED;
// UDEV_CTRL |= bUD_LOW_SPEED; //选择低速1.5M模式
USB_CTRL &= ~bUC_LOW_SPEED;
UDEV_CTRL &= ~bUD_LOW_SPEED; //选择全速12M模式,默认方式
UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
UDEV_CTRL |= bUD_PORT_EN; //使能物理端口
}
/*******************************************************************************
* Function Name : USBDeviceEndPointCfg()
* Description : USB设备模式端点配置,模拟兼容HID设备,除了端点0的控制传输,还包括端点2批量上下传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USBDeviceEndPointCfg()
{
UEP1_DMA = Ep1Buffer; //端点1 发送数据传输地址
UEP2_DMA = Ep2Buffer; //端点2 IN数据传输地址
UEP2_3_MOD = 0xCC; //端点2/3 单缓冲收发使能
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; //端点2自动翻转同步标志位,IN事务返回NAK,OUT返回ACK
UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点1自动翻转同步标志位,IN事务返回NAK
UEP0_DMA = Ep0Buffer; //端点0数据传输地址
UEP4_1_MOD = 0X40; //端点1上传缓冲区;端点0单64字节收发缓冲区
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //手动翻转,OUT事务返回ACK,IN事务返回NAK
}
/*******************************************************************************
* Function Name : USBDeviceIntCfg()
* Description : USB设备模式中断初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USBDeviceIntCfg()
{
USB_INT_EN |= bUIE_SUSPEND; //使能设备挂起中断
USB_INT_EN |= bUIE_TRANSFER; //使能USB传输完成中断
USB_INT_EN |= bUIE_BUS_RST; //使能设备模式USB总线复位中断
USB_INT_FG |= 0x1F; //清中断标志
IE_USB = 1; //使能USB中断
EA = 1; //允许单片机中断
}
main()
{
UINT8 i;
CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //修改主频等待内部晶振稳定,必加
mInitSTDIO( ); //串口0初始化
#ifdef DE_PRINTF
printf("start ...\n");
#endif
USBDeviceCfg();
USBDeviceEndPointCfg(); //端点配置
USBDeviceIntCfg(); //中断初始化
UEP0_T_LEN = 0;
UEP1_T_LEN = 0; //预使用发送长度一定要清空
UEP2_T_LEN = 0; //预使用发送长度一定要清空
while(1)
{
}
}
上面是官网下载的,CH559模拟CH340 USB转串口的参考程序。我改成CH552是可以识别出CH341A,但是没看懂发送和接收应该如何调用。main()中也没有调用发送和接收。另外,如果想要发送64byte以上数据,应该如何操作。求指点。对沁恒的USB了解不够,刚接触。以前有用过STM32F103C8T6的USB,但是是用库实现的,对USB的详细过程理解得不透。
|
|