我爱嵌入式系统

当前位置:首页 > 软件天地 > 业内资讯 > 详细内容
CH375作为USB主机接口的程序示例
发布时间:2009-11-13  阅读次数:498  字体大小: 【】 【】【

/* 2004.03.05
****************************************
**                                    **
**                                    **
****************************************
**  USB 1.1 Host Examples for CH375   **
**  KC7.0@MCS-51                      **
****************************************
*/
/* CH375作为USB主机接口的程序示例 */

/* MCS-51单片机C语言的示例程序, U盘数据读写 */

#include "common.h"
#include "config.h"
//#include "CH375.h"

//UINT8 volatile CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */
//UINT8 char volatile CH375_DAT_PORT _at_ 0xBCF0; /* CH375数据端口的I/O地址 */
extern UINT8 DBUF[BUFFER_LENGTH];

//sbit LED_OUT   =  0x90^4; /* P1.4 低电平驱动LED显示,用于监控演示程序的进度 */
//sbit CH375_INT_WIRE =  0xB0^2; /* P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */


//#define mDelay1uS( )   /* 对于MCS51单片机,通常不需要1uS延时 */

/* 延时2微秒,请根据单片机速度 */
//void mDelay1uS( )
//{
// unsigned char i;
// for ( i = 1; i != 0; i -- );
//}

/* 延时2微秒,请根据单片机速度 */
void mDelayms(UINT32 ms)
{
  UINT32 i;
  while(ms--)for(i=2500;i!=0;i--);
}
void    Delay2us( ){
    UINT8 i;
    for(i=0;i!=8;i++);
}
void   Delay1us( ){
    UINT8 i;
    for(i=0;i!=4;i++);
}
/* 向CH375命令端口写命令数据 */
void CH375_CMD_PORT_d_out( INT8 d_out )
{
 
   Delay2us( );
   IO0DIR|=USB_DATA;//P0.16~P0.23口设置为OUT
   IO0CLR|=0xff<<16;
   IO0SET|=((UINT32) d_out<<16)|USB_A|USB_RD;
   //IO0SET|=USB_A;
   //IO0SET|=USB_RD|USB_A;
   IO0CLR|=USB_WR|USB_CS;
   IO0DIR=IO0DIR;IO0DIR=IO0DIR;
   
   //mDelayms(1);
   
   
   IO0SET=(IO1SET&0xffffffff)|USB_WR|USB_CS|USB_RD;//WR(P0.12)为1,RD(P0.11)=1,CS(P0.13)=1,A0(P0.10)=1;
   IO0CLR|=USB_A;
   IO0DIR &= 0xFF00FFFF;
   Delay2us( );
}

/* 向CH375数据端口写数据 */
void CH375_DAT_PORT_d_out( INT8 d_out )
{
   Delay2us();
   IO0DIR|=USB_DATA;//P0.16~P0.23口设置为OUT
   IO0CLR|=0xff<<16;
   IO0SET|=((UINT32) d_out<<16)|USB_RD;
   IO0CLR|=USB_WR|USB_A|USB_CS;//设置WR(P0.12)为1,RD(P0.11)=0,CS(P0.13)=0,A0(P0.10)=0
   IO0DIR=IO0DIR;IO0DIR=IO0DIR;
   
   IO0SET=(IO1SET&0xffffffff)|USB_WR|USB_CS|USB_RD;//WR(P0.12)为1,RD(P0.11)=1,CS(P0.13)=1,A0(P0.10)=1;
   IO0CLR|=USB_A;
   IO0DIR &= 0xFF00FFFF;
   Delay2us();
}

/* 从CH375命令端口读数据 */
INT8 CH375_DAT_PORT_in( )
{   UINT8 temp;
   Delay2us( );
   
   IO0DIR&=~USB_DATA;//设置P0.16~P0.23口为IN
   IO0SET|=USB_WR;
   IO0CLR|=USB_A|USB_RD|USB_CS;
   
   //IO0CLR|=;
   //IO0DIR=IO0DIR;IO0DIR=IO0DIR;IO0DIR=IO0DIR;
   IO0DIR=IO0DIR;IO0DIR=IO0DIR;
   temp=(IO0PIN&0x00ff0000)>>16;
  
     //delay100ns;
   
   IO0SET|=USB_WR|USB_RD|USB_CS;
   IO0CLR|=USB_A;
   Delay1us( );
   
   return temp;

}

/* 等待CH375中断并获取状态 */
unsigned char mWaitInterrupt( )
{
 unsigned char c;
 while ( CH375_INT_WIRE );  /* 如果CH375的中断引脚输出高电平则等待 */
 CH375_CMD_PORT_d_out( CMD_GET_STATUS);  /* 获取当前中断状态 */
 c = CH375_DAT_PORT_in();  /* 返回中断状态 */
///* if ( c == USB_INT_DISCONNECT )  /* 检测到USB设备断开事件 */
///* else if ( c == USB_INT_CONNECT )  /* 检测到USB设备连接事件 */
 return( c );
}

/* 设置CH375为USB主机方式 */
unsigned char mCH375Init( )
{
 UINT8 i;
//#ifdef TEST_CH375_PORT
 UINT8 c;
 CH375_CMD_PORT_d_out(CMD_CHECK_EXIST);  /* 测试工作状态 */
 CH375_DAT_PORT_d_out( 0x55);  /* 测试数据 */
 c = CH375_DAT_PORT_in();  /* 返回数据应该是测试数据取反 */
 if ( c != 0xaa ) {  /* CH375出错 */
  for ( i = 100; i != 0; i -- ) {  /* 强制数据同步 */
   CH375_CMD_PORT_d_out( CMD_RESET_ALL );  /* CH375执行硬件复位 */
   c = CH375_DAT_PORT_in();  /* 延时 */
  }
  mDelayms( 50 );  /* 延时至少30mS */
 }
//#endif
 CH375_CMD_PORT_d_out( CMD_SET_USB_MODE);  /* 设置USB工作模式 */
 CH375_DAT_PORT_d_out( 6);  /* 模式代码,自动检测USB设备连接 */
 mDelayms(50);
 
 for ( i = 0xff; i != 0; i -- ) {  /* 等待操作成功,通常需要等待10uS-20uS */
  if ( CH375_DAT_PORT_in() == CMD_RET_SUCCESS ) break;  /* 操作成功 */
 }
 if ( i != 0 ) return( 0 );  /* 操作成功 */
 else return( 0xff );  /* CH375出错,例如芯片型号错或者处于串口方式或者不支持 */
}

/* 初始化磁盘 */
unsigned char mInitDisk( )
{
 UINT8 mIntStatus;
 CH375_CMD_PORT_d_out( CMD_DISK_INIT);  /* 初始化USB存储器 */
 mIntStatus = mWaitInterrupt( );  /* 等待中断并获取状态 */
 //if ( mIntStatus == USB_INT_SUCCESS ) return( 0 );  /* U盘已经成功初始化 */
  return  mIntStatus ;  /* 出现错误 */
}

UINT8 ReadCapacity(void)
{
 UINT8 *mBufferPoint;
 UINT8  mIntStatus,mLength;
 CH375_CMD_PORT_d_out( CMD_DISK_SIZE);  /* 读取容量 */
 mBufferPoint=DBUF;
 mIntStatus = mWaitInterrupt( );
 if ( mIntStatus == USB_INT_SUCCESS)
 {  /* USB存储器读数据块,请求数据读出 */
   CH375_CMD_PORT_d_out( CMD_RD_USB_DATA);  /* 从CH375缓冲区读取数据块 */
   mLength = CH375_DAT_PORT_in();  /* 后续数据的长度 */
   while ( mLength ) {  /* 根据长度读取数据 */
    *mBufferPoint = CH375_DAT_PORT_in();  /* 读出数据并保存 */
    mBufferPoint ++;
    mLength --;
   }
  return 1;
    }
    return 0;
}

UINT32 SwapINT32(UINT32 dData)
{
    dData = (dData&0xff)<<24|(dData&0xff00)<<8|(dData&0xff000000)>>24|(dData&0xff0000)>>8;
 return dData;
}

UINT16 SwapINT16(UINT16 dData)
{
    dData = (dData&0xff00)>>8|(dData&0x00ff)<<8;
 return dData;
}

/* 从U盘中读取多个扇区的数据块到缓冲区中 */
UINT8 RBC_Read(UINT32 iLbaStart, UINT8 iSectorCount,UINT8 *mBufferPoint)
/* iLbaStart 是读取的线起始性扇区号, iSectorCount 是读取的扇区数 */
{
 UINT8 mIntStatus;
 UINT16  mBlockCount;
 UINT8 mLength;
 CH375_CMD_PORT_d_out(CMD_DISK_READ);  /* 从USB存储器读数据块 */
 CH375_DAT_PORT_d_out((UINT8)iLbaStart);  /* LBA的最低8位 */
 CH375_DAT_PORT_d_out ((UINT8)( iLbaStart >> 8 ));
 CH375_DAT_PORT_d_out((UINT8)( iLbaStart >> 16 ));
 CH375_DAT_PORT_d_out((UINT8)( iLbaStart >> 24 ));  /* LBA的最高8位 */
 mDelayms(1);
 CH375_DAT_PORT_d_out( iSectorCount);  /* 扇区数 */
 mDelayms(1);
 mBufferPoint = DBUF;  /* 指向缓冲区起始地址 */
 for ( mBlockCount = iSectorCount * CH375_BLK_PER_SEC; mBlockCount != 0; mBlockCount -- ) {  /* 数据块计数 */
  mIntStatus = mWaitInterrupt( );  /* 等待中断并获取状态 */
  if ( mIntStatus == USB_INT_DISK_READ ) {  /* USB存储器读数据块,请求数据读出 */
   CH375_CMD_PORT_d_out(CMD_RD_USB_DATA);  /* 从CH375缓冲区读取数据块 */
   mLength = CH375_DAT_PORT_in();  /* 后续数据的长度 */
/* 通常数据长度是64,有些U盘要求单片机必须在2mS之内取走64字节数据,否则U盘可能数据丢失 */
/* 建议优化下面的循环程序,确保单片机在1mS之内完成64字节的数据传输 */
   if ( mLength ) {  /* 根据长度读取数据 */
    do {  // 对于C51,这个DO+WHILE结构效率高,速度快
     *mBufferPoint = CH375_DAT_PORT_in();  /* 读出数据并保存 */
     mBufferPoint ++;
    } while ( -- mLength );
   }
   CH375_CMD_PORT_d_out( CMD_DISK_RD_GO);  /* 继续执行USB存储器的读操作 */
   mDelayms(10);
  }
  else break;  /* 返回错误状态 */
 }
 if ( mBlockCount == 0 ) mIntStatus = mWaitInterrupt( );  /* 等待中断并获取状态 */
 if ( mIntStatus == USB_INT_SUCCESS ) return 1;  /* 操作成功 */
 else return 0;  /* 操作失败 */
}

/* 将缓冲区中的多个扇区的数据块写入U盘 */
UINT8 RBC_Write( UINT32 iLbaStart, UINT8 iSectorCount,UINT8 *mBufferPoint )
/* iLbaStart 是写入的线起始性扇区号, iSectorCount 是写入的扇区数 */
{
 UINT8 mIntStatus;
 UINT16  mBlockCount;
 UINT8 mLength;
 CH375_CMD_PORT_d_out( CMD_DISK_WRITE);  /* 向USB存储器写数据块 */
 CH375_DAT_PORT_d_out((UINT8)iLbaStart);  /* LBA的最低8位 */
 CH375_DAT_PORT_d_out((UINT8)( iLbaStart >> 8 ));
 CH375_DAT_PORT_d_out((UINT8)( iLbaStart >> 16 ));
 CH375_DAT_PORT_d_out((UINT8)( iLbaStart >> 24 ));  /* LBA的最高8位 */
 CH375_DAT_PORT_d_out(iSectorCount);  /* 扇区数 */
 //mBufferPoint = &DATA_BUFFER;  /* 指向缓冲区起始地址 */
 for ( mBlockCount = iSectorCount * CH375_BLK_PER_SEC; mBlockCount != 0; mBlockCount -- ) {  /* 数据块计数 */
  mIntStatus = mWaitInterrupt( );  /* 等待中断并获取状态 */
  if ( mIntStatus == USB_INT_DISK_WRITE ) {  /* USB存储器写数据块,请求数据写入 */
   CH375_CMD_PORT_d_out( CMD_WR_USB_DATA7);  /* 向CH375缓冲区写入数据块 */
   mLength = CH375_BLOCK_SIZE;
   CH375_DAT_PORT_d_out(mLength);  /* 后续数据的长度 */
/* 通常数据长度是64,有些U盘要求单片机必须在2mS之内写入64字节数据,否则U盘可能数据丢失 */
/* 建议优化下面的循环程序,确保单片机在1mS之内完成64字节的数据传输 */
   do {  // 对于C51,这个DO+WHILE结构效率高,速度快
    CH375_DAT_PORT_d_out(*mBufferPoint);  /* 将数据写入 */
    mBufferPoint ++;
   } while ( -- mLength );
   CH375_CMD_PORT_d_out( CMD_DISK_WR_GO);  /* 继续执行USB存储器的写操作 */
  }
  else break;  /* 返回错误状态 */
 }
 if ( mBlockCount == 0 ) mIntStatus = mWaitInterrupt( );  /* 等待中断并获取状态 */
 if ( mIntStatus == USB_INT_SUCCESS ) return 1;  /* 操作成功 */
 else return 0;  /* 操作失败 */
}

UINT8 mCH375Read( INT8 mAddr )
{
 CH375_CMD_PORT_d_out( 0x0A );
 CH375_DAT_PORT_d_out( mAddr );
 if ( mAddr ) return( CH375_DAT_PORT_in( ) );
 else return( 0 );
}

void mCH375Write( UINT8 mAddr, UINT8 mData )
{
 CH375_CMD_PORT_d_out( 0x0B );
 CH375_DAT_PORT_d_out( mAddr );
 CH375_DAT_PORT_d_out( mData );
}

UINT8 epBulkSend( UINT8 *mBuffer, UINT8 mLength )
{
 UINT8 mBulkOut;
 UINT8  CH375IntStatus;
 CH375_CMD_PORT_d_out( CMD_WR_USB_DATA7 );  /* 向CH375的端点缓冲区写入准备发送的数据 */
 CH375_DAT_PORT_d_out( mLength );  /* 后续数据长度4 */
 while( mLength ) {
  CH375_DAT_PORT_d_out( *mBuffer );
  mBuffer ++;
  mLength --;
 }
 mCH375Write( SFR_USB_H_ENDP, mCH375Read( VAR_UDISK_TOGGLE ) );
 mBulkOut = mCH375Read( VAR_UDISK_BULK_OUT );
 CH375IntStatus = 0;  /* 清操作完成的中断状态 */
 CH375_CMD_PORT_d_out( CMD_ISSUE_TOKEN );
 CH375_DAT_PORT_d_out( mBulkOut );  /* 高4位目的端点号, 低4位令牌PID */
// if ( CH375LibConfig & 0x80 ) while ( CH375IntStatus == 0 );  /* 中断方式,等待数据传输操作 */
// else xQueryInterrupt( );  /* 查询方式,查询中断状态 */
 CH375IntStatus=mWaitInterrupt( );
 if ( CH375IntStatus == USB_INT_SUCCESS ) {  /* 操作成功 */
  mCH375Write( VAR_UDISK_TOGGLE, mCH375Read( VAR_UDISK_TOGGLE ) ^ 0x40 );//printf("mUsbBulksend success\n ");
  return 1;
 }
 else return 0;  /* 操作失败 */
}

UINT8 epBulkRcv( UINT8 *mBuffer, UINT8 mLength )
{
 INT8 mBulkIn, mCount,CH375IntStatus;
 mCH375Write( SFR_USB_H_ENDP, mCH375Read( VAR_UDISK_TOGGLE ) );
 mBulkIn = mCH375Read( VAR_UDISK_BULK_IN );
 CH375IntStatus = 0;  /* 清操作完成的中断状态 */
 CH375_CMD_PORT_d_out( CMD_ISSUE_TOKEN );
 CH375_DAT_PORT_d_out( mBulkIn );  /* 高4位目的端点号, 低4位令牌PID */
// if ( CH375LibConfig & 0x80 ) while ( CH375IntStatus == 0 );  /* 中断方式,等待数据传输操作 */
// else xQueryInterrupt( );  /* 查询方式,查询中断状态 */
 CH375IntStatus=mWaitInterrupt( );
 if ( CH375IntStatus == USB_INT_SUCCESS ) {  /* 操作成功 */
  mCH375Write( VAR_UDISK_TOGGLE, mCH375Read( VAR_UDISK_TOGGLE ) ^ 0x80 );
  CH375_CMD_PORT_d_out( CMD_RD_USB_DATA );  /* 从CH375的端点缓冲区读取接收到的数据 */
  mCount = CH375_DAT_PORT_in( );  /* 后续数据长度 */
  mLength = mCount;
  while( mCount ) {
   *mBuffer = CH375_DAT_PORT_in( );
   mBuffer ++;
   mCount --;
  }//printf("mUsbBulkRecv success\n ");
  return 1;
 }
 else return  0;  /* 操作失败 */
}

TPBLK_STRUC TPBulk_Block;
#define     TPBulk_CBW  TPBulk_Block.TPBulk_CommandBlock
#define     CBW_wXferLen TPBulk_CBW.dCBW_DataXferLen
#define     RBC_CDB   TPBulk_CBW.cdbRBC
#define     RBC_LUN   TPBulk_CBW.bCBW_LUN
#define     TPBulk_CSW  TPBulk_Block.TPBulk_CommandStatus

/*unsigned char TPBulk_GetMaxLUN(void)
{
 usbstack.setup.bmRequest=0xa1;
 usbstack.setup.bRequest=0xfe;
 usbstack.setup.wValue=0;
 usbstack.setup.wIndex=0;
 usbstack.setup.wLength=1;
 usbstack.buffer=DBUF;
 return ep0Xfer();

}

unsigned char SPC_READLONG(void)
{
#define cdbReadLong RBC_CDB.SpcCdb_ReadLong 
 //nsigned char retStatus=FALSE;
 TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;
 TPBulk_CBW.dCBW_Tag=0x60a624de;
 TPBulk_CBW.dCBW_DataXferLen=0xfc000000;
 TPBulk_CBW.bCBW_Flag=0x80;
 TPBulk_CBW.bCBW_LUN=0;
 TPBulk_CBW.bCBW_CDBLen=sizeof(READ_LONG_CMD);
 
 /////////////////////////////////////
 cdbReadLong.OperationCode=SPC_CMD_READLONG;
 cdbReadLong.LogicalUnitNum=0;
 cdbReadLong.AllocationLen=0xfc;
 //////////////////////////////////////
 if(!epBulkSend((unsigned char *)&TPBulk_CBW,sizeof(TPBulk_CBW)))
  return FALSE;
 
 if(!epBulkRcv(DBUF,0xfc))
  return FALSE;
 
 if(!epBulkRcv((unsigned char *)&TPBulk_CSW,13))
  return FALSE;
  ////////////////////////////
  return TRUE;
#undef cdbReadLong
}

*/
unsigned char SPC_RequestSense(void)
{
#define cdbRequestSenseSPC RBC_CDB.SpcCdb_RequestSense 
 //unsigned char retStatus=FALSE;
 TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;
 TPBulk_CBW.dCBW_Tag=0x60a624de;
 TPBulk_CBW.dCBW_DataXferLen=0x0e000000;
 TPBulk_CBW.bCBW_Flag=0x80;
 TPBulk_CBW.bCBW_LUN=0;
 TPBulk_CBW.bCBW_CDBLen=sizeof(REQUEST_SENSE_SPC);
  
 /////////////////////////////////////
 cdbRequestSenseSPC.OperationCode=SPC_CMD_REQUESTSENSE;
 cdbRequestSenseSPC.AllocationLen=0x0e;
 //////////////////////////////////////
 if(!epBulkSend((unsigned char *)&TPBulk_CBW,sizeof(TPBulk_CBW)))
  return FALSE;
 
 if(!epBulkRcv(DBUF,18))
  return FALSE;
 
 if(!epBulkRcv((unsigned char *)&TPBulk_CSW,13))
  return FALSE;
/////////////////////////////
 return TRUE;
 
#undef cdbRequestSenseSPC
}

UINT8 SPC_TestUnit(void)
{
#define cdbTestUnit RBC_CDB.SpcCdb_TestUnit 
 //unsigned char retStatus=FALSE;
 TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;
 TPBulk_CBW.dCBW_Tag=0x60a624de;
 TPBulk_CBW.dCBW_DataXferLen=0x00000000;
 TPBulk_CBW.bCBW_Flag=0x00;
 TPBulk_CBW.bCBW_LUN=0;
 TPBulk_CBW.bCBW_CDBLen=sizeof(TEST_UNIT_SPC);
 /////////////////////////////////////
 cdbTestUnit.OperationCode=SPC_CMD_TESTUNITREADY;
 //////////////////////////////////////
 if(!epBulkSend((UINT8 *)&TPBulk_CBW,sizeof(TPBulk_CBW)))
  return FALSE;
 
 if(!epBulkRcv((UINT8 *)&TPBulk_CSW,13))
  return FALSE;
#undef cdbTestUnit
////////////////////////////
 return TRUE;
}

UINT8 SPC_LockMedia(void)
{
#define cdbLockSPC RBC_CDB.SpcCdb_Remove 
 //unsigned char retStatus=FALSE;
 TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;
 TPBulk_CBW.dCBW_Tag=0x60a624de;
 TPBulk_CBW.dCBW_DataXferLen=0x00000000;
 TPBulk_CBW.bCBW_Flag=0x00;
 TPBulk_CBW.bCBW_LUN=0;
 TPBulk_CBW.bCBW_CDBLen=sizeof(MEDIA_REMOVAL_SPC);
 ///////////////////////////////////////////
 cdbLockSPC.OperationCode=SPC_CMD_PRVENTALLOWMEDIUMREMOVAL;
 cdbLockSPC.Prevent=1;
 ///////////////////////////////////////////
 if(!epBulkSend((UINT8 *)&TPBulk_CBW,sizeof(TPBulk_CBW)))
  return FALSE;
  
 if(!epBulkRcv((UINT8 *)&TPBulk_CSW,13))
  return FALSE;
#undef cdbLockSPC
/////////////////////////////
 return TRUE;
}

上一篇:CCS 教程 下一篇: ARP协议实现原理
我要评论
  • 匿名发表
  • [添加到收藏夹]
  • 发表评论:(匿名发表无需登录,已登录用户可直接发表。) 登录状态:未登录
最新评论
所有评论[0]
    暂无已审核评论!

51RTOS.com 版权所有  

Copyright 20006-2009 我爱嵌入式 ( 51RTOS.com ) All rights reserved 沪ICP备09080633号