AT89C5131实现U盘


初始化USB外设:

// created by perry.peng 2012/04/21
void
main (void)
{
  LEDCON = 0xff;		// 10 mA current source.
  CKCON0 |= 7;			// Set the system and the T0 working in X2 mode.
 TMOD = 0x01; // 
M10=0; 
M00=1; 16bit-timer 
TH0 = 0; // init values 
TL0 = 0; 
TF0 = 0; // reset interrupt flag (already done by hardware) 
TR0 = 1; // timer0 

run ms_multiple_drive = 0; 

USBCON |= MSK_USBE; ///< Suspend USB Clock 
PLLDIV = PLL_12MHz; ///< PLL clock source is 12MHz 
PLLCON |= MSK_PLLEN; ///< enable PLL 
USBCON &= ~MSK_SUSPCLK; 
USBINT &= ~MSK_SPINT; 
USBCON |= MSK_DETACH; /* Attach Command, Vref pin at high level. */ 

while (!TF0); 
TF0 = 0; 
TR0 = 0; /* timer0 stop */ 

P3 = 0; 
USBCON &= ~MSK_DETACH; /* Attach Command, Vref pin at high level. */ 
USBIEN = MSK_ESPINT | MSK_EWUPCPU | MSK_EEORINT | MSK_ESOFINT; 
IEN1 |= MSK_EUSB; 
sei (); 
Usb_ep_setup (EP_CTRL, EP_ENABLE | EP_TYPE_CONTROL | EP_DIR_OUT); 
USBCON &= ~MSK_DETACH; /* Attach Command, Vref pin at high level. */ 
UsbConnected = TRUE;处理USB协议中的Setup包:

void Usb_setup_packet_handler (void)
{
#define D2H(x)                  ((x) << 8 | 0x80)	///< 设备到主机包
#define D2HX(x, n)              (((x) << 8) | (n))	///< 设备到主机包,子功能。
#define H2D(x)                  ((x) << 8)	///< 主机到设备包
#define H2DX(x, n)              (((x) << 8) | (n))	///< 主机到设备包,子功能

#define GDT(x)                  ((x) << 8)
#define GDTS(x, n)              (((x) << 8) | (n))

  UEPNUM = EP_CTRL;		                  // select control endport.
  if (!(UEPSTAX & MSK_RXSETUP))	        /* Check if a Setup packet is received. */
    return;

  cfgPacket.bytes[1] = UEPDATX;         //!< bmRequestType
  cfgPacket.bytes[0] = UEPDATX;         //!< bRequest

  /* SETUP packet:
     bmRequestType   bRequest    wValue           wIndex    wLength
     GET_DESCRIPTOR: 0x80            0x06        DType & DIndex   Lang ID   DLength    *D=Descriptor
     GET_DESCRIPTOR: 0x80            0x06
   */
  switch (cfgPacket.reqId) {
  case D2H (GET_DESCRIPTOR):
    cfgPacket.bytes[3] = UEPDATX; /* read LSB of wValue    */
    cfgPacket.bytes[2] = UEPDATX; /* read MSB of wValue    */
    cfgPacket.bytes[5] = UEPDATX; /* read LSB of wValue    */
    cfgPacket.bytes[4] = UEPDATX; /* read MSB of wValue    */
    cfgPacket.bytes[7] = UEPDATX; /* read LSB of wLength    */
    cfgPacket.bytes[6] = UEPDATX; /* read MSB of wLength    */
    switch (cfgPacket.R.wValue) {
    case GDT(DEVICE_DESCRIPTOR):
      TransferDataSize = DeviceDescriptor[0];	          //!< sizeof (DeviceDescriptor);
      TransferDataPtr = &DeviceDescriptor[0];
      break;
    case GDT(CONFIGURATION_DESCRIPTOR):
      TransferDataSize = ConfigurationDescriptor[2];	  //!< sizeof (ConfigurationDescriptor);
      TransferDataPtr = &ConfigurationDescriptor[0];
      break;
    case GDTS(STRING_DESCRIPTOR, USB_STRING_LANG):
      TransferDataSize = StringDescriptorLanguageID[0];	//!< sizeof (StringDescriptorLanguageID);
      TransferDataPtr = &StringDescriptorLanguageID[0];
      break;
    case GDTS(STRING_DESCRIPTOR, USB_STRING_MANU):
      TransferDataSize = StringDescriptorManuf[0];	    //!< sizeof (StringDescriptorManuf);
      TransferDataPtr = &StringDescriptorManuf[0];
      break;
    case GDTS(STRING_DESCRIPTOR, USB_STRING_PROD):
      TransferDataSize = StringDescriptorProduct[0];	  //!< sizeof (StringDescriptorProduct);
      TransferDataPtr = &StringDescriptorProduct[0];
      break;
    case GDTS(STRING_DESCRIPTOR, USB_STRING_SN):
      TransferDataSize = StringDescriptorSerialNumber[0];	//!< sizeof (StringDescriptorSerialNumber);
      TransferDataPtr = &StringDescriptorSerialNumber[0];
      break;
    default:  
  	  UEPSTAX |= MSK_STALLRQ;
  	  UEPSTAX &= ~MSK_RXSETUP;
      return;
    }

    NeedZeroPacket = FALSE;			/* no zero length packet */
    UEPSTAX &= ~MSK_RXSETUP;	                          //!< clear the receive setup flag
    UEPSTAX |= MSK_DIR;		/* set out on EP0 */

    if (cfgPacket.R.wLength > TransferDataSize) {
    	if ((TransferDataSize % EP_CONTROL_LENGTH) == 0)
    	  NeedZeroPacket = TRUE;
    	else
    	  NeedZeroPacket = FALSE;                       //!< no need of zero length packet
  	} else {
      TransferDataSize = (uint8_t) cfgPacket.R.wLength;	//!< send only requested number of data
    }

    while ((TransferDataSize != 0) && (!(UEPSTAX & MSK_RXOUTB0B1))) {
      uint8_t c;			// New
      if (TransferDataSize > EP_CONTROL_LENGTH)
    	  c = EP_CONTROL_LENGTH;
      else
    	  c = TransferDataSize;
      TransferDataSize -= c;
      while (c != 0) {
    	  UEPDATX = *TransferDataPtr;
    	  TransferDataPtr++;
    	  c--;
    	}
      UEPSTAX |= MSK_TXRDY;
      while ((!(UEPSTAX & MSK_TXCMPL)) && (!(UEPSTAX & MSK_RXOUTB0B1)));
      UEPSTAX &= ~MSK_TXCMPL;
    }
  
    if (UEPSTAX & MSK_RXOUTB0B1) {	//!< abort from Host
      UEPSTAX &= ~MSK_RXOUT;
      return;
    }
    
    if (NeedZeroPacket == TRUE) {
      UEPSTAX |= MSK_TXRDY;
      while ((!(UEPSTAX & MSK_TXCMPL)) && (!(UEPSTAX & MSK_RXOUTB0B1)));
      UEPSTAX &= ~MSK_TXCMPL;
    }
  
    while (!(UEPSTAX & MSK_RXOUTB0B1));
    UEPSTAX &= ~MSK_RXOUT;
    break;
  case D2H (GET_CONFIGURATION):
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_DIR;	/* set out on EP0 */
    UEPDATX = UsbCurrentConfig;
    UEPSTAX |= MSK_TXRDY;
    while (!UEPSTAX & MSK_TXCMPL);
    UEPSTAX &= ~MSK_TXCMPL;
    while (!UEPSTAX & MSK_RXOUTB0B1);
    UEPSTAX &= ~MSK_RXOUT;
    break;
  case H2D (SET_ADDRESS):
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_TXRDY;	//!< send a ZLP for STATUS phase
    while (!(UEPSTAX & MSK_TXCMPL));	//!< waits for status phase done
    //!< before using the new address
    UEPSTAX &= ~MSK_TXCMPL;	// for Tiger compatibility
    USBADDR &= ~MSK_FEN;
    USBADDR = cfgPacket.bytes[2];
    USBADDR |= MSK_FEN;
    break;
  case H2D (SET_CONFIGURATION):
    cfgPacket.bytes[3] = UEPDATX;
    cfgPacket.bytes[2] = UEPDATX;
    if (cfgPacket.bytes[3] > NB_CONFIGURATIONS) {
  	  UEPSTAX |= MSK_STALLRQ;
  	  UEPSTAX &= ~MSK_RXSETUP;
  	  break;
  	}

    UEPSTAX &= ~MSK_RXSETUP;
    UsbCurrentConfig = cfgPacket.bytes[3];

    UEPSTAX |= MSK_TXRDY;	//!< send a ZLP for STATUS phase
    while (!UEPSTAX & MSK_TXCMPL);
    UEPSTAX &= ~MSK_TXCMPL;

    Usb_ep_setup (EP_MS_IN, EP_ENABLE | EP_TYPE_BULK | EP_DIR_IN);
    Usb_ep_setup (EP_MS_OUT, EP_ENABLE | EP_TYPE_BULK | EP_DIR_OUT);
    break;
  case H2DX (SET_FEATURE, ENDPOINT_TYPE):
    cfgPacket.bytes[3] = UEPDATX;
    cfgPacket.bytes[2] = UEPDATX;
    cfgPacket.bytes[5] = UEPDATX;
    cfgPacket.bytes[4] = UEPDATX;
    if (cfgPacket.R.wValue == FEATURE_ENDPOINT_HALT) {
  	  uint8_t wIndex;
  	  wIndex = cfgPacket.R.wIndex & EP_DIR;
  
  	  UEPNUM = wIndex;
  	  if (wIndex != EP_CTRL && UEPCONX & MSK_EPEN) {
	      UEPSTAX |= MSK_STALLRQ;
	      UEPNUM = EP_CTRL;
	      endpoint_status[wIndex] = 0x01;
	      UEPSTAX &= ~MSK_RXSETUP;
	      UEPSTAX |= MSK_TXRDY;
	      break;
	    }
  	}
	  UEPSTAX |= MSK_STALLRQ;
	  UEPSTAX &= ~MSK_RXSETUP;
    break;
  case D2HX (GET_STATUS, REQUEST_DEVICE_STATUS):
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_DIR;
    UEPDATX = DEVICE_STATUS;
    UEPDATX = 0x00;
    UEPSTAX |= MSK_TXRDY;
    while (!UEPSTAX & MSK_TXCMPL);
    UEPSTAX &= ~MSK_TXCMPL;
    while (!UEPSTAX & MSK_RXOUTB0B1);
    UEPSTAX &= ~MSK_RXOUT;
    break;
  case D2HX (GET_STATUS, REQUEST_INTERFACE_STATUS):
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_DIR;
    UEPDATX = INTERFACE_STATUS;
    UEPDATX = 0x00;
    UEPSTAX |= MSK_TXRDY;
    while (!UEPSTAX & MSK_TXCMPL);
    UEPSTAX &= ~MSK_TXCMPL;
    while (!UEPSTAX & MSK_RXOUTB0B1);
    UEPSTAX &= ~MSK_RXOUT;
    break;
  case D2HX (GET_STATUS, REQUEST_ENDPOINT_STATUS):
    cfgPacket.bytes[3] = UEPDATX;
    cfgPacket.bytes[2] = UEPDATX;
    cfgPacket.bytes[5] = UEPDATX;
    cfgPacket.bytes[4] = UEPDATX;
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_DIR;
    UEPDATX = endpoint_status[cfgPacket.R.wIndex & EP_DIR];
    UEPDATX = 0x00;
    UEPSTAX |= MSK_TXRDY;
    while (!UEPSTAX & MSK_TXCMPL);
    UEPSTAX &= ~MSK_TXCMPL;
    while (!UEPSTAX & MSK_RXOUTB0B1);
    UEPSTAX &= ~MSK_RXOUT;
    break;
  case H2DX (CLEAR_FEATURE, ENDPOINT_TYPE):
    cfgPacket.bytes[3] = UEPDATX;
    cfgPacket.bytes[2] = UEPDATX;
    cfgPacket.bytes[5] = UEPDATX;
    cfgPacket.bytes[4] = UEPDATX;

    if (cfgPacket.R.wValue == FEATURE_ENDPOINT_HALT) {
  	  cfgPacket.R.wIndex &= EP_DIR;
  
  	  UEPNUM = cfgPacket.R.wIndex;
  	  if (UEPCONX & MSK_EPEN) {
	      if (cfgPacket.R.wIndex != EP_CTRL) {
    		  UEPSTAX &= ~MSK_STALLRQ;
    		  UEPRST = 1 << (uint8_t) cfgPacket.R.wIndex;
    		  UEPRST = 0;
    		}
	      UEPNUM = EP_CTRL;
	      endpoint_status[cfgPacket.R.wIndex] = 0x00;
	      UEPSTAX &= ~MSK_RXSETUP;
	      UEPSTAX |= MSK_TXRDY;
        break;
	    }
  	}
	  UEPSTAX |= MSK_STALLRQ;
	  UEPSTAX &= ~MSK_RXSETUP;
    break;
  //case D2H (MASS_STORAGE_RESET):
  case H2D (MASS_STORAGE_RESET):
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_TXRDY;
    break;
  //case D2H (GET_MAX_LUN):
  case H2D (GET_MAX_LUN):
    UEPSTAX &= ~MSK_RXSETUP;
    UEPSTAX |= MSK_DIR;	/* set out on EP0 */
    UEPDATX = MAX_LUN - 1;
    UEPSTAX |= MSK_TXRDY;
    while (!UEPSTAX & MSK_TXCMPL);
    UEPSTAX &= ~MSK_TXCMPL;
    ms_multiple_drive = 1;
    break;
  case H2D (SET_DESCRIPTOR):
  case H2D (SET_INTERFACE):
  case H2DX (SET_FEATURE, ZERO_TYPE):
  case H2DX (SET_FEATURE, INTERFACE_TYPE):
  case H2DX (CLEAR_FEATURE, ZERO_TYPE):
  case H2DX (CLEAR_FEATURE, INTERFACE_TYPE):
  case D2H (SYNCH_FRAME):
  case D2H (GET_INTERFACE):
  default:
    UEPSTAX |= MSK_STALLRQ;
    UEPSTAX &= ~MSK_RXSETUP;
    break;
  }
}

定义一堆USB协议中定义的描述符:

//! Usb Device Descriptor
static const uint8_t const __code DeviceDescriptor[] = {
/* bLength = */           0x12,                         //!< Size of this descriptor in bytes
/* bDescriptorType = */   DEVICE_DESCRIPTOR,   	        //!< DEVICE descriptor type
/* bscUSB = */            0x02,                	        //!< Binay Coded Decimal Spec. release
                          0x00,
/* bDeviceClass = */		  0x00,                         //!< Class code assigned by the USB
/* bDeviceSubClass = */	  0x00,                         //!< Sub-class code assigned by the USB
/* bDeviceProtocol = */	  0x00,                         //!< Protocol code assigned by the USB
/* bMaxPacketSize0 = */	  EP_CONTROL_LENGTH,            //!< Max packet size for EP0
/* idVender = */          0x03,                         //!< ??ID?,ATMEL?ID?0xeb03,??????,??????*/
                          0xeb,
/* idProduct = */         0x13,                         //!< ??ID?,HID??0x2013, ??????,??????*/
                          0x20,
/* bcdDevice = */         0x00,                         //!< ????USB??????,???1.0??,?0x0100?*/
                          0x01,
/* iManufacturer = */     USB_STRING_MANU,              //!< ?????????,?????????,???????1????*/
/* iProduct = */          USB_STRING_PROD,              //!< ??????????????1,????2???????????????????*/
/* iSerialNumber = */     USB_STRING_SN,                //!< ????????????????3?????*/
/* bNumConfigurations=*/  0x01                          //!< ???????????????????????,???????1?*/
};

//! Usb Device Descriptor
__code uint8_t DeviceQualifierDescriptor[] = {
/* bLength = */           0x0a,                         //!< Size of this descriptor in bytes
/* bDescriptorType = */   DEVICE_QUALIFIER_DESCRIPTOR,  //!< DEVICEQUALIFIER descriptor type
/* bscUSB = */		        0x02,                         //!< Binay Coded Decimal Spec. release
                          0x00,
/* bDeviceClass = */		  0x00,                         //!< Class code assigned by the USB
/* bDeviceSubClass = */	  0x00,                         //!< Sub-class code assigned by the USB
/* bDeviceProtocol = */	  0x00,                         //!< Protocol code assigned by the USB
/* bMaxPacketSize0 = */	  EP_CONTROL_LENGTH,            //!< Max packet size for EP0
/* bNumConfigurations = */0x01,                         //!< Number of possible configurations
/* bReserved = */		      0x00                          //!< Reserved for future use, must be zero
};

//! Configuration Descriptor
__code uint8_t ConfigurationDescriptor[] = {
/* bLength = */		        0x09,                         //!< size of this descriptor in bytes
/* bDescriptorType = */	  CONFIGURATION_DESCRIPTOR,     //!< CONFIGURATION descriptor type
/* wTotalLength = */	    (0x09+0x09+0x07+0x07),        //!< total length of data returned
                          0x00,
/* bNumInterfaces = */	  0x01,                         //!< number of interfaces for this conf.
/* bConfigurationValue = */0x01,                        //!< value for SetConfiguration resquest
/* iConfiguration = */	  0x00,                         //!< index of string descriptor
/* bmAttibutes = */		    USB_CONFIG_BUSPOWERED,      	//!< Configuration characteristics
/* MaxPower = */		      50,                           //!< 50 = 100mA, maximum power consumption

/* bLength = */		        0x09,                         //!< size of this descriptor in bytes
/* bDescriptorType = */	  INTERFACE_DESCRIPTOR,         //!< INTERFACE descriptor type
/* bInterfaceNumber = */	0x00,                         //!< Number of interface
/* bAlternateSetting = */	0x00,                         //!< value to select alternate setting
/* bNumEndpoints = */	    0x02,                         //!< Number of EP except EP 0
/* bInterfaceClass = */	  0x08,                         //!< 0x08 = Mass Storage, Class code assigned by the USB
/* bInterfaceSubClass = */0x06,                         //!< 0x06 = SCSI transparent Cammand Set, Sub-class code assigned by the USB
/* bInterfaceProtocol = */0x50,                         //!< 0x50 = Bulk-Only Transport, Protocol code assigned by the USB
/* iInterface = */		    0x00,                         //!< Index of string descriptor

/* bLength = */		        0x07,                         //!< size of this descriptor in bytes
/* bDescriptorType = */	  ENDPOINT_DESCRIPTOR,          //!< ENDPOINT descriptor type
/* bEndpointAddress = */	(EP_MS_IN | 0x80),            //!< Address of the endpoint
/* bmAttributes = */		  EP_TYPE_BULK,                 //!< Endpoint's attributes
/* wMaxPacketSize = */	  64,                           //!< Maximum packet size for this EP
                          0x00,
/* bInterval = */		      0x00,                         //!< Interval for polling EP in ms

/* bLength = */		        0x07,                         //!< size of this descriptor in bytes
/* bDescriptorType = */	  ENDPOINT_DESCRIPTOR,          //!< ENDPOINT descriptor type
/* bEndpointAddress = */	EP_MS_OUT,                    //!< Address of the endpoint
/* bmAttributes = */		  EP_TYPE_BULK,                 //!< Endpoint's attributes
/* wMaxPacketSize = */	  64,                           //!< Maximum packet size for this EP
                          0x00,
/* bInterval = */		      0x00                          //!< Interval for polling EP in ms
};

// StringDescriptor LanguageID
__code uint8_t StringDescriptorLanguageID[] = {
/* bLength = */		        0x04,                         //!< size of this descriptor in bytes
/* bDescriptorType = */   STRING_DESCRIPTOR,            //!< STRING_DESCRIPTOR descriptor type
/* wLanguageID = */       0x09,                         //!< wLanguageID = 0x0409
                          0x04
};

// StringDescriptor Manufacture
__code uint8_t StringDescriptorManuf[] = {
/* bLength = */		        24,                           //!< size of this descriptor in bytes
/* bDescriptorType = */   STRING_DESCRIPTOR,            //!< STRING_DESCRIPTOR descriptor type
                          WCHAR('F'), 
                          WCHAR('l'), 
                          WCHAR('e'), 
                          WCHAR('x'), 
                          WCHAR('t'), 
                          WCHAR('r'), 
                          WCHAR('o'), 
                          WCHAR('n'), 
                          WCHAR('i'), 
                          WCHAR('c'), 
                          WCHAR('s') };

// StringDescriptor Product
__code uint8_t StringDescriptorProduct[] = {
/* bLength = */		        14,                           //!< size of this descriptor in bytes
/* bDescriptorType = */   STRING_DESCRIPTOR,            //!< STRING_DESCRIPTOR descriptor type
                          WCHAR('U'), 
                          WCHAR('S'), 
                          WCHAR('B'), 
                          WCHAR('D'), 
                          WCHAR('i'), 
                          WCHAR('s'), 
                          WCHAR('k') };

// StringDescriptor SerialNumber, Serial Number should be at least 12 characters long
__code uint8_t StringDescriptorSerialNumber[] = {
/* bLength = */		        16,                           //!< size of this descriptor in bytes
/* bDescriptorType = */   STRING_DESCRIPTOR,            //!< STRING_DESCRIPTOR descriptor type
                          WCHAR('2'), 
                          WCHAR('A'), 
                          WCHAR('S'), 
                          WCHAR('4'), 
                          WCHAR('2'), 
                          WCHAR('5'), 
                          WCHAR('6') };

处理CBW和CSW:

void usb_mass_storage_cbw (void)
{
  __bit cbw_error;
  uint8_t c;

  cbw_error = FALSE;
  UEPNUM = EP_MS_OUT;		//! check if dCBWSignature is correct
  if (0x55 != UEPDATX) cbw_error = TRUE; //! 'U'
  if (0x53 != UEPDATX) cbw_error = TRUE; //! 'S'
  if (0x42 != UEPDATX) cbw_error = TRUE; //! 'B'
  if (0x43 != UEPDATX) cbw_error = TRUE; //! 'C'

  dCBWTag[0] = UEPDATX;		//! Store CBW Tag to be repeated in CSW
  dCBWTag[1] = UEPDATX;
  dCBWTag[2] = UEPDATX;
  dCBWTag[3] = UEPDATX;

  ((uint8_t *) & g_scsi_data_remaining)[3] = UEPDATX;
  ((uint8_t *) & g_scsi_data_remaining)[2] = UEPDATX;
  ((uint8_t *) & g_scsi_data_remaining)[1] = UEPDATX;
  ((uint8_t *) & g_scsi_data_remaining)[0] = UEPDATX;

  if (UEPDATX != 0x00) {
    ms_data_direction = 1;
    if (cbw_error) {
  	  Usb_ack_receive_out_ms ();
  	  UEPNUM = EP_MS_IN;
  	  UEPSTAX |= MSK_STALLRQ;
  	  return;
  	}
	} else {
    ms_data_direction = 0;
    if (cbw_error) {
  	  UEPSTAX |= MSK_STALLRQ;
  	  Usb_ack_receive_out_ms ();
  	  return;
  	}
	}

  usb_LUN = UEPDATX;

  if (!ms_multiple_drive) {
 	  usb_LUN = 0;
	}

  ACC = UEPDATX;		//! dummy CBWCBLength read

  for (c = 0; c < 16; c++)	// store scsi_command
  {
    g_scsi_command[c] = UEPDATX;
  }

  Usb_ack_receive_out_ms ();

  if (ms_data_direction == 1) {
    UEPNUM = EP_MS_IN;
  }

  if (TRUE != scsi_decode_command ()) {
	  if (g_scsi_data_remaining != 0) {
	    UEPSTAX |= MSK_STALLRQ;
	  }
	}
}

void usb_mass_storage_csw (void)
{
  UEPNUM = EP_MS_IN;
  while (UEPSTAX & MSK_STALLRQ) {
    Usb_setup_packet_handler ();
    UEPNUM = EP_MS_IN;
  }

  UEPNUM = EP_MS_OUT;
  while (UEPSTAX & MSK_STALLRQ) {
    Usb_setup_packet_handler ();
    UEPNUM = EP_MS_OUT;
  }
  UEPNUM = EP_MS_IN;
  //! write CSW Signature
  Usb_write_byte (0x55);	//! 'U'
  Usb_write_byte (0x53);	//! 'S'
  Usb_write_byte (0x42);	//! 'B'
  Usb_write_byte (0x53);	//! 'S'
  //! write stored CBW Tag
  Usb_write_byte (dCBWTag[0]);
  Usb_write_byte (dCBWTag[1]);
  Usb_write_byte (dCBWTag[2]);
  Usb_write_byte (dCBWTag[3]);
  //! write data residue value
  Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[3]);
  Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[2]);
  Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[1]);
  Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[0]);

  //! write command status
  Usb_write_byte (g_scsi_status);	//! 0 -> PASS, 1 -> FAIL
  Usb_send_in ();
}


  LEDCON = 0xff;		// 10 mA current source.
  CKCON0 |= 7;			// Set the system and the T0 working in X2 mode.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值