📄 ch374_hid.c
字号:
/* CH374芯片 应用层 V1.0 */
/* USB主机,初始化和枚举当前连接的USB设备 */
#include <stdio.h>
#include <string.h>
#include "HAL.H" // 以MCS51为例,其它单片机需修改HAL*硬件抽象层的几个文件
#include "HAL_BASE.C" // 基本子程序及中断查询子程序
/* 硬件接口层,以下连接方式任选一种 */
#include "PARA_HW.C" //硬件标准8位并口
//#include "..\PARA_SW.C" // 软件I/O模拟8位并口
//#include "..\SPI_HW.C" // 硬件标准4线SPI串口
//#include "SPI_SW.C" // 软件I/O模拟4线SPI串口
//#include "SPI3_SW.C" // 软件I/O模拟3线SPI串口,SDO和SDI合用一个引脚
/* 获取设备描述符 */
const UINT8C SetupGetDevDescr[] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 };
/* 获取配置描述符 */
const UINT8C SetupGetCfgDescr[] = { 0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00 };
/* 设置USB地址 */
const UINT8C SetupSetUsbAddr[] = { 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
/* 设置USB配置 */
const UINT8C SetupSetUsbConfig[] = { 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/* SET IDLE */
unsigned char code SetupSetidle[]={0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00};
/* 获取HID 报告描述符 */
unsigned char code SetupGetHidDes[]={0x81,0x06,0x00,0x22,0x00,0x00,0x81,0x00};
/* SET REPORT */
unsigned char code SetupSetReport[]={0x21,0x09,0x00,0x02,0x00,0x00,0x01,0x00};
/* 常\变量定义:*/
// BOOL Set_Report_flag; //Set_Report 发送标志,只要用来点亮、熄灭键盘上的灯 (Set_Report_flag=1时,代表亮)
BOOL LOW_SPEED_BIT;
BOOL tog1; //读取数据时的同步标志
UINT8 endp_out_addr; // out端点地址,由于一般鼠标键盘不支持out端点,一般用不到
UINT8 endp_in_addr; // in 端点地址
UINT8 hid_des_leng; // HID类报告描述符的长度
UINT8 endp_num; // 数据 hid 类键盘、鼠标的端点数目
UINT8 UsbDevEndpSize = DEFAULT_ENDP0_SIZE; // USB设备的端点0的最大包尺寸
UINT8 FlagDeviceStatus; // 当前USB设备状态,通常用于中断方式的全局变量,本程序中未使用
/* 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 );
/* 执行控制传输,ReqBuf指向8字节请求码,DatBuf为收发缓冲区 */
// 如果需要接收和发送数据,那么DatBuf需指向有效缓冲区用于存放后续数据,实际成功收发的总长度保存在ReqLen指向的字节变量中
UINT8 HostCtrlTransfer374( PUINT8 ReqBuf, PUINT8 DatBuf, PUINT8 RetLen );
/* 查询当前是否存在USB设备 */
//BOOL Query374DeviceIn( void );
#define Query374DeviceIn( ) ( ( Read374Byte( REG_INTER_FLAG ) & BIT_IF_DEV_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设备运行环境
void HostSetLowSpeed( void ); // 设定低速USB设备运行环境
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 )
{ // 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化
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 ); // 取消暂停
// mDelayuS( 200 );
s = Wait374Interrupt( );
if ( s == ERR_USB_UNKNOWN ) return( s ); // 中断超时,可能是硬件异常
s = Read374Byte( REG_INTER_FLAG ); // 获取中断状态
if ( s & BIT_IF_DEV_DETECT ) { // USB设备插拔事件
mDelayuS( 250 ); // 等待传输完成
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_TRANSFER ); // 清中断标志
if ( s & BIT_IF_DEV_ATTACH ) { // USB设备连接事件
mDelayuS( 200 ); // 等待传输完成
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状态
r = s & BIT_STAT_DEV_RESP; // USB设备应答状态
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 { // 其它中断,不应该发生的情况
mDelayuS( 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 < 1; i ++ ) {
s = HostTransact374( endp_addr, pid, tog );
if ( s != ( DEF_USB_PID_NAK | 0x20 ) || timeout == 0 ) return( s );
mDelayuS( 20 );
}
if ( timeout < 0xFFFF ) timeout --;
}
}
/* 执行控制传输,ReqBuf指向8字节请求码,DatBuf为收发缓冲区 */
UINT8 HostCtrlTransfer374( PUINT8 ReqBuf, PUINT8 DatBuf, PUINT8 RetLen )
// 如果需要接收和发送数据,那么DatBuf需指向有效缓冲区用于存放后续数据,实际成功收发的总长度保存在ReqLen指向的字节变量中
{
UINT8 s, len, count, total;
BOOL tog;
Write374Block( RAM_HOST_TRAN, 8, ReqBuf );
Write374Byte( REG_USB_LENGTH, 8 );
mDelayuS( 100 );
s = WaitHostTransact374( 0, DEF_USB_PID_SETUP, FALSE, 200 ); // SETUP阶段,200mS超时
if ( s == USB_INT_SUCCESS ) // SETUP成功
{
tog = TRUE; // 默认DATA1,默认无数据故状态阶段为IN
if((*(ReqBuf+3))==0x22)
{
total=*( ReqBuf + 6 )-0x40;
}
else
total = *( ReqBuf + 6 );
if ( total && DatBuf ) // 需要收数据
{
len = total;
if ( *ReqBuf & 0x80 ) // 收
{
while ( len )
{
mDelayuS( 100 );
s = WaitHostTransact374( 0, DEF_USB_PID_IN, tog, 200 ); // IN数据
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; // 状态阶段为OUT
}
else { // 发
while ( len )
{
mDelayuS( 100 );
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数据
if ( s != USB_INT_SUCCESS ) break;
DatBuf += count;
len -= count;
tog = tog ? FALSE : TRUE;
}
tog = TRUE; // 状态阶段为IN
}
total -= len; // 减去剩余长度得实际传输长度
}
if ( s == USB_INT_SUCCESS ) // 数据阶段成功
{
Write374Byte( REG_USB_LENGTH, 0 );
mDelayuS( 100 );
s = WaitHostTransact374( 0, ( tog ? DEF_USB_PID_IN : DEF_USB_PID_OUT ), TRUE, 200 ); // STATUS阶段
if ( tog && s == USB_INT_SUCCESS ) // 检查IN状态返回数据长度
{
if ( Read374Byte( REG_USB_LENGTH ) ) s = USB_INT_BUF_OVER; // 状态阶段错误
}
}
}
if ( RetLen ) *RetLen = total; // 实际成功收发的总长度
return( s );
}
/*通过中断端点获取鼠标、键盘上传的数据 */
unsigned char Interrupt_Data_Trans(unsigned char *p)
{
UINT8 s,count;
s = WaitHostTransact374( endp_in_addr, DEF_USB_PID_IN, tog1, 1000 ); // IN数据
// printf("s:%x \n",(unsigned short)s);
if ( s != USB_INT_SUCCESS ){ mDelaymS(5); return s;}
else
{
count = Read374Byte( REG_USB_LENGTH );
Read374Block( RAM_HOST_RECV, count, p );
tog1 = tog1 ? FALSE : TRUE;
}
return s;
}
/* 查询当前是否存在USB设备 */
//BOOL Query374DeviceIn( void )
//#define Query374DeviceIn( ) ( ( Read374Byte( REG_INTER_FLAG ) & BIT_IF_DEV_ATTACH ) ? TRUE : FALSE )
/* 查询当前的USB设备是全速还是低速, 返回TRUE为全速 */
//BOOL Query374DevFullSpeed( void )
//#define Query374DevFullSpeed( ) ( ( Read374Byte( REG_SYS_INFO ) & BIT_INFO_USB_DP ) ? TRUE : FALSE )
/* 处理USB设备插拔事件中断 */
void HostDetectInterrupt( void )
{
UINT8 s, u;
s = Read374Byte( REG_INTER_FLAG ); // 获取中断状态
if ( s & BIT_IF_DEV_DETECT ) // USB设备插拔事件
{
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT ); // 清中断标志
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 ) FlagDeviceStatus = USB_INT_CONNECT_LS; // 低速USB设备
else FlagDeviceStatus = USB_INT_CONNECT; // 全速USB设备
}
else // 速度失配,需要切换速度
{
if ( u & BIT_SETP_USB_SPEED ) FlagDeviceStatus = USB_INT_CONNECT; // 全速USB设备
else FlagDeviceStatus = USB_INT_CONNECT_LS; // 低速USB设备
}
}
else FlagDeviceStatus = USB_INT_DISCONNECT; // USB设备断开事件
}
else // 意外的中断
{
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER | BIT_IF_USB_SUSPEND | BIT_IF_WAKE_UP ); // 清中断标志
}
}
/* 设置USB主机当前操作的USB设备地址 */
void SetHostUsbAddr( UINT8 addr )
{
Write374Byte( REG_USB_ADDR, addr );
}
/* USB总线空闲 */
void HostSetBusFree( void )
{
// Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_FREE( Read374Byte( REG_USB_SETUP ) ) ); // USB总线空闲
Write374Byte( REG_USB_SETUP, BIT_SETP_HOST_MODE| BIT_SETP_AUTO_SOF ); // USB总线复位
}
/* USB总线复位 */
void HostSetBusReset( void )
{
UsbDevEndpSize = DEFAULT_ENDP0_SIZE; // USB设备的端点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总线复位
Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_RESET( BIT_SETP_HOST_MODE ) ); // USB总线复位
mDelaymS( 20 ); // USB总线复位期间
// 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 ); // 清中断标志
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -