我爱嵌入式系统

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

/* 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号