Pages: [1]   Go Down
Author Topic: Mass Storage Device using the usb host interface  (Read 1643 times)
0 Members and 1 Guest are viewing this topic.
The Netherlands
Offline Offline
Full Member
***
Karma: 1
Posts: 139
MKDS hacker and Programmer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've been working on support for usb mass storage devices using the usb host interface. It works good atm. When using inquiry command for example it returns the correct data. But when using read10 command it returns some weird random data. It returns the same data for all sectors. But when resetting the arduino the data changes. I have no idea where this behaviour comes from.

I will upload the code if needed.
Logged

Subscribe my youtube channel: http://www.youtube.com/user/MKDS3

Norfolk UK
Offline Offline
Faraday Member
**
Karma: 69
Posts: 2556
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you will need to upload your code for anyone to have a chance of helping.
Logged


The Netherlands
Offline Offline
Full Member
***
Karma: 1
Posts: 139
MKDS hacker and Programmer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

MSD.cpp:
Quote
#include <Arduino.h>
#include <Usb.h>
#include <LiquidCrystal.h>
#include "MSD.h"

//uint32_t idxIn;
//uint32_t idxOut;

//Capacity cap;

MassStorageDevice::MassStorageDevice(){
}
MassStorageDevice::MassStorageDevice(USBHost UsbHostController, UsbDevice *Device, LiquidCrystal* lc)
{
  usb = UsbHostController;
  msc = Device;
  lcd = lc;

  /*ushort len[2];
   
   usb.getConfDescr(msc->address, 0, 4, 0, (byte*)&len);
   
   byte* data = new byte[len[1]];
   
   usb.getConfDescr(msc->address, 0, len[1], 0, &data[0]);
   
   USB_CONFIGURATION_DESCRIPTOR* Config = (USB_CONFIGURATION_DESCRIPTOR*)data;
   
   data += CONF_DESCR_LEN;
   
   USB_INTERFACE_DESCRIPTOR* Interface0 = (USB_INTERFACE_DESCRIPTOR*)data;
   
   data+=INTR_DESCR_LEN;
   
   for(int i = 0; i < Interface0->bNumEndpoints; i++)
   {
   USB_ENDPOINT_DESCRIPTOR* Endpoint = (USB_ENDPOINT_DESCRIPTOR*)data;
   
   if((Endpoint->bmAttributes & 3) == 2)
   {
   if(Endpoint->bEndpointAddress & 0x80 == 0x80)
   {
   //idxIn = UHD_Pipe_Alloc(msc->address, Endpoint->bEndpointAddress & 0xF, Endpoint->bmAttributes & 3, 0x80, Endpoint->wMaxPacketSize, Endpoint->bInterval, 2);
   idxIn = UHD_Pipe_Alloc(msc->address, 2, 2, 0x80, 512, 0, 2);
   }
   else
   {
   //idxOut = UHD_Pipe_Alloc(msc->address, Endpoint->bEndpointAddress & 0xF, Endpoint->bmAttributes & 3, 0, Endpoint->wMaxPacketSize, Endpoint->bInterval, 2);
   idxOut = UHD_Pipe_Alloc(msc->address, 2, 2, 0, 512, 0, 2);
   }
   }
   
   data += EP_DESCR_LEN;
   }  */


  idxIn = UHD_Pipe_Alloc(msc->address, 0x82, 2, 0x80, 512, 0, 2);
  idxOut = UHD_Pipe_Alloc(msc->address, 0x2, 2, 0, 512, 0, 2);

  InquiryResponse resp = SCSI_Inquiry();

  lcd->clear();
  lcd->setCursor(0, 0);
  lcd->print((char*)&resp.ProductID[0]);

  cap = SCSI_ReadCapacity10();

  uint32_t capacity = cap.dwBlockAddress * cap.dwBlockLength;

  lcd->setCursor(0, 1);
  lcd->print(capacity);
  lcd->print(" B");

  delay(100);

  SCSI_StartStop(1);



  delay(150);


  uint8_t buf[512];

  lcd->clear();
  for(int i = 0; i < 1000; i++)
  {
    SCSI_Read12(i, 1, &buf[0]);
    lcd->setCursor(0, 0);
    for(int i = 0; i < 16; i++)
    {
      lcd->print(buf, HEX);
    }
  }




  while(true);


}

uint32_t MassStorageDevice::GetBlockSize()
{
  return cap.dwBlockLength;
}

InquiryResponse MassStorageDevice::SCSI_Inquiry()
{
  CommandBlockWrapper cmd;
  cmd.dCBWSignature = MASS_CBW_SIGNATURE;
  cmd.dCBWTag = 123;
  cmd.dCBWDataTransferLength = sizeof(InquiryResponse);
  cmd.bmCBWFlags = MASS_CMD_DIR_IN;
  cmd.bmCBWLUN = 0;
  cmd.bmCBWCBLength = 6;
  for (uint8_t i = 0; i < 16; i++) cmd.CBWCB = 0;
  cmd.CBWCB[0] = SCSI_CMD_INQUIRY;
  cmd.CBWCB[1] = 0 << 5;
  cmd.CBWCB[4] = sizeof(InquiryResponse);

  InquiryResponse resp;
  uint32_t length = sizeof(InquiryResponse);
  SendCommand(&cmd, (uint8_t*)&resp, &length, 0);
  return resp;
}

void MassStorageDevice::SCSI_StartStop(uint8_t ctl)
{
  CommandBlockWrapper cbw;

  cbw.dCBWSignature = MASS_CBW_SIGNATURE;
  cbw.dCBWTag = 123;
  cbw.dCBWDataTransferLength = 0;
  cbw.bmCBWFlags = MASS_CMD_DIR_OUT;
  cbw.bmCBWLUN = 0;
  cbw.bmCBWCBLength = 6;

  for (uint8_t i = 0; i < 16; i++)
    cbw.CBWCB = 0;

  cbw.CBWCB[0] = SCSI_CMD_START_STOP_UNIT;
  cbw.CBWCB[1] = 0 << 5;
  cbw.CBWCB[4] = ctl & 0x03;

  SendCommand(&cbw, 0, 0, -1);
}

void MassStorageDevice::SCSI_Read12(uint32_t lba, uint32_t nBlocks, uint8_t* buf)
{
  //SCSI_StartStop(1);
  // delay(150);
  CommandBlockWrapper cmd;
  cmd.dCBWSignature = MASS_CBW_SIGNATURE;
  cmd.dCBWTag = 123;
  cmd.dCBWDataTransferLength = cap.dwBlockLength * nBlocks;
  cmd.bmCBWFlags = MASS_CMD_DIR_IN;
  cmd.bmCBWLUN = 0;
  cmd.bmCBWCBLength = 10;
  for (uint8_t i = 0; i < 16; i++) cmd.CBWCB = 0;
  /*cmd.CBWCB[0] = SCSI_CMD_READ_12;
   cmd.CBWCB[1] = 0 << 5;
   cmd.CBWCB[2] = lba & 0xFF;
   cmd.CBWCB[3] = (lba >> 8) & 0xFF;
   cmd.CBWCB[4] = (lba >> 16) & 0xFF;
   cmd.CBWCB[5] = (lba >> 24) & 0xFF;
   cmd.CBWCB[6] = nBlocks & 0xFF;
   cmd.CBWCB[7] = (nBlocks >> 8) & 0xFF;
   cmd.CBWCB[8] = (nBlocks >> 16) & 0xFF;
   cmd.CBWCB[9] = (nBlocks >> 24) & 0xFF;*/
  cmd.CBWCB[0] = SCSI_CMD_READ_10;
  cmd.CBWCB[1] = 0 << 5;
  cmd.CBWCB[2] = ((lba >> 24) & 0xff);
  cmd.CBWCB[3] = ((lba >> 16) & 0xff);
  cmd.CBWCB[4] = ((lba >> 8) & 0xff);
  cmd.CBWCB[5] = (lba & 0xff);
  cmd.CBWCB[8] = nBlocks;

  uint32_t length = cap.dwBlockLength * nBlocks;
  uint32_t error;

  error = SendCommand(&cmd, buf, &length, 0);

  if(error != 0)
  {
    lcd->clear();
    lcd->setCursor(0, 0);
    lcd->print("error");
    lcd->setCursor(0, 1);
    lcd->print(error);
    while(true);
  }

  /*lcd->clear();
   for(int i = 0; i < 512; i++)
   {
   lcd->setCursor(0, 0);
   lcd->print(buf);
   }*/


  //lcd->print(";");
  // lcd->print(buf[200]);
  /*lcd->setCursor(0, 0);
   lcd->print(error);
   lcd->setCursor(0, 1);
   lcd->print(length);*/
}

Capacity MassStorageDevice::SCSI_ReadCapacity10()
{
  CommandBlockWrapper cmd;
  cmd.dCBWSignature = MASS_CBW_SIGNATURE;
  cmd.dCBWTag = 123;
  cmd.dCBWDataTransferLength = sizeof(Capacity);
  cmd.bmCBWFlags = MASS_CMD_DIR_IN;
  cmd.bmCBWLUN = 0;
  cmd.bmCBWCBLength = 10;
  for (uint8_t i = 0; i < 16; i++) cmd.CBWCB = 0;
  cmd.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
  cmd.CBWCB[1] = 0 << 5;

  Capacity resp;
  uint32_t length = sizeof(Capacity);
  SendCommand(&cmd, (uint8_t*)&resp, &length, 0);

  resp.dwBlockAddress = SwapByteOrder_32(resp.dwBlockAddress);
  resp.dwBlockLength = SwapByteOrder_32(resp.dwBlockLength);

  return resp;
}

uint32_t MassStorageDevice::SendCommand(CommandBlockWrapper* cmd, uint8_t* data, uint32_t* length, int flag)
{
  UHD_Pipe_Write(idxOut, sizeof(CommandBlockWrapper), (uint8_t*)cmd);
  UHD_Pipe_Send(idxOut, tokOUT);

  while(!UHD_Pipe_Is_Transfer_Complete(idxOut, tokOUT));

  if(flag == 0)
  {
    UHD_Pipe_Send(idxIn, tokIN);

    while(uhd_byte_count(idxIn) == 0);

    uint32_t l = uhd_byte_count(idxIn);

    UHD_Pipe_Read(idxIn, *length, data);
    *length = l;
  }
  else if(flag == 1)
  {
    UHD_Pipe_Write(idxOut, *length, data);
    UHD_Pipe_Send(idxOut, tokOUT);

    while(!UHD_Pipe_Is_Transfer_Complete(idxOut, tokOUT));
  }

  UHD_Pipe_Send(idxIn, tokIN);

  while(uhd_byte_count(idxIn) == 0);

  CommandStatusWrapper rest;

  UHD_Pipe_Read(idxIn, sizeof(CommandStatusWrapper), (uint8_t*)&rest);
  if(rest.dCSWTag != 123) while(true);
  return rest.bCSWStatus;
}

Logged

Subscribe my youtube channel: http://www.youtube.com/user/MKDS3

The Netherlands
Offline Offline
Full Member
***
Karma: 1
Posts: 139
MKDS hacker and Programmer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

MSD.h:
Quote
#ifndef MSD_H
#define MSD_H

#include <Arduino.h>
#include <Usb.h>
#include <LiquidCrystal.h>

#define hrBUSY      0x01

#define bmREQ_MASSOUT       USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_MASSIN        USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE

// Mass Storage Subclass Constants
#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00   // De facto use
#define MASS_SUBCLASS_RBC      0x01
#define MASS_SUBCLASS_ATAPI      0x02   // MMC-5 (ATAPI)
#define MASS_SUBCLASS_OBSOLETE1      0x03   // Was QIC-157
#define MASS_SUBCLASS_UFI      0x04   // Specifies how to interface Floppy Disk Drives to USB
#define MASS_SUBCLASS_OBSOLETE2      0x05   // Was SFF-8070i
#define MASS_SUBCLASS_SCSI      0x06   // SCSI Transparent Command Set
#define MASS_SUBCLASS_LSDFS      0x07   // Specifies how host has to negotiate access before trying SCSI
#define MASS_SUBCLASS_IEEE1667      0x08


// Mass Storage Class Protocols
#define MASS_PROTO_CBI         0x00   // CBI (with command completion interrupt)
#define MASS_PROTO_CBI_NO_INT      0x01   // CBI (without command completion interrupt)
#define MASS_PROTO_OBSOLETE      0x02
#define MASS_PROTO_BBB         0x50   // Bulk Only Transport
#define MASS_PROTO_UAS         0x62


// Request Codes
#define MASS_REQ_ADSC         0x00
#define MASS_REQ_GET         0xFC
#define MASS_REQ_PUT         0xFD
#define MASS_REQ_GET_MAX_LUN      0xFE
#define MASS_REQ_BOMSR         0xFF   // Bulk-Only Mass Storage Reset


#define MASS_CBW_SIGNATURE      0x43425355
#define MASS_CSW_SIGNATURE      0x53425355


#define MASS_CMD_DIR_OUT                (0 << 7)
#define MASS_CMD_DIR_IN         (1 << 7)


#define SCSI_CMD_INQUIRY      0x12
#define SCSI_CMD_REPORT_LUNS      0xA0
#define SCSI_CMD_REQUEST_SENSE      0x03
#define SCSI_CMD_FORMAT_UNIT      0x04
#define SCSI_CMD_READ_6         0x08
#define SCSI_CMD_READ_10      0x28
#define SCSI_CMD_READ_12      0xA8
#define SCSI_CMD_READ_CAPACITY_10   0x25
#define SCSI_CMD_TEST_UNIT_READY   0x00
#define SCSI_CMD_WRITE_6      0x0A
#define SCSI_CMD_WRITE_10      0x2A
#define SCSI_CMD_MODE_SENSE_6      0x1A
#define SCSI_CMD_MODE_SENSE_10      0x5A
#define SCSI_CMD_START_STOP_UNIT   0x1B
#define SCSI_CMD_PREVENT_REMOVAL        0x1E
#define SCSI_S_NOT_READY      0x02
#define SCSI_S_MEDIUM_ERROR      0x03
#define SCSI_S_ILLEGAL_REQUEST      0x05
#define SCSI_S_UNIT_ATTENTION      0x06


#define SCSI_ASC_MEDIUM_NOT_PRESENT     0x3A
#define SCSI_ASC_LBA_OUT_OF_RANGE       0x21
#define SCSI_ASC_MEDIA_CHANGED          0x28


#define MASS_ERR_SUCCESS      0x00
#define MASS_ERR_PHASE_ERROR      0x02
#define MASS_ERR_UNIT_NOT_READY      0x03
#define MASS_ERR_UNIT_BUSY      0x04
#define MASS_ERR_STALL         0x05
#define MASS_ERR_CMD_NOT_SUPPORTED   0x06
#define MASS_ERR_INVALID_CSW      0x07
#define MASS_ERR_NO_MEDIA      0x08
#define MASS_ERR_BAD_LBA                0x09
#define MASS_ERR_MEDIA_CHANGED          0x0A
#define MASS_ERR_DEVICE_DISCONNECTED    0x11
#define MASS_ERR_UNABLE_TO_RECOVER   0x12   // Reset recovery error
#define MASS_ERR_INVALID_LUN      0x13
#define MASS_ERR_WRITE_STALL       0x14
#define MASS_ERR_READ_NAKS              0x15
#define MASS_ERR_WRITE_NAKS             0x16
#define MASS_ERR_WRITE_PROTECTED        0x17
#define MASS_ERR_GENERAL_SCSI_ERROR   0xFE
#define MASS_ERR_GENERAL_USB_ERROR   0xFF
#define MASS_ERR_USER         0xA0   // For subclasses to define their own error codes


#define MASS_TRANS_FLG_CALLBACK         0x01   // Callback is involved
#define MASS_TRANS_FLG_NO_STALL_CHECK   0x02   // STALL condition is not checked
#define MASS_TRANS_FLG_NO_PHASE_CHECK   0x04   // PHASE_ERROR is not checked


#define MASS_MAX_ENDPOINTS      3


struct CommandBlockWrapperBase {
  uint32_t dCBWSignature;
  uint32_t dCBWTag;
  uint32_t dCBWDataTransferLength;
  uint8_t bmCBWFlags;

__attribute__((packed));


struct CommandBlockWrapper : 
public CommandBlockWrapperBase {


  struct {
uint8_t bmCBWLUN : 
    4;
uint8_t bmReserved1 : 
    4;
  };


  struct {
uint8_t bmCBWCBLength : 
    4;
uint8_t bmReserved2 : 
    4;
  };


  uint8_t CBWCB[16];

__attribute__((packed));


struct CommandStatusWrapper {
  uint32_t dCSWSignature;
  uint32_t dCSWTag;
  uint32_t dCSWDataResidue;
  uint8_t bCSWStatus;

__attribute__((packed));


struct InquiryResponse {
uint8_t DeviceType : 
  5;
uint8_t PeripheralQualifier : 
  3;


unsigned Reserved :
  7;
unsigned Removable :
  1;


  uint8_t Version;


unsigned ResponseDataFormat :
  4;
unsigned Reserved2 :
  1;
unsigned NormACA :
  1;
unsigned TrmTsk :
  1;
unsigned AERC :
  1;


  uint8_t AdditionalLength;
  uint8_t Reserved3[2];


unsigned SoftReset :
  1;
unsigned CmdQue :
  1;
unsigned Reserved4 :
  1;
unsigned Linked :
  1;
unsigned Sync :
  1;
unsigned WideBus16Bit :
  1;
unsigned WideBus32Bit :
  1;
unsigned RelAddr :
  1;


  uint8_t VendorID[8];
  uint8_t ProductID[16];
  uint8_t RevisionID[4];

__attribute__((packed));

struct Capacity {
  //uint8_t data[8];
  uint32_t dwBlockAddress;
  uint32_t dwBlockLength;

__attribute__((packed));

inline uint32_t SwapByteOrder_32(uint32_t value) {
  uint32_t Byte0 = value & 0x000000FF;
  uint32_t Byte1 = value & 0x0000FF00;
  uint32_t Byte2 = value & 0x00FF0000;
  uint32_t Byte3 = value & 0xFF000000;
  return (Byte0 << 24) | (Byte1 << smiley-cool | (Byte2 >> smiley-cool | (Byte3 >> 24);
}

class MassStorageDevice
{
public:
  MassStorageDevice(void);
  MassStorageDevice(USBHost UsbHostController, UsbDevice *Device, LiquidCrystal* lc);
  uint32_t GetBlockSize();
  void SCSI_Read12(uint32_t lba, uint32_t nBlocks, uint8_t* buf);
private:
  uint32_t idxIn;
  uint32_t idxOut;
  Capacity cap;
  USBHost usb;
  UsbDevice *msc;
  LiquidCrystal* lcd;
  InquiryResponse SCSI_Inquiry();
  void SCSI_StartStop(uint8_t ctl);
  Capacity SCSI_ReadCapacity10();
  uint32_t SendCommand(CommandBlockWrapper* cmd, uint8_t* data, uint32_t* length, int flag);
};

#endif
Logged

Subscribe my youtube channel: http://www.youtube.com/user/MKDS3

The Netherlands
Offline Offline
Full Member
***
Karma: 1
Posts: 139
MKDS hacker and Programmer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I found the problem. There is a bug in the function UHD_Pipe_Read. (As described here: https://github.com/arduino/Arduino/issues/1519)

I fixed it by putting the fixed version of the function with a different name in my code. Here is it if you want:

Quote
uint32_t UHD_Pipe_Read_FIX(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data)
{
   uint8_t *ptr_ep_data = 0;
   uint16_t nb_byte_received = 0;
   uint32_t ul_nb_trans = 0;

   // Get information to read data
   nb_byte_received = uhd_byte_count(ul_pipe);

   ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(ul_pipe, 8);

   // Copy data from pipe to payload buffer
   while (ul_size && nb_byte_received) {
      *data++ = *ptr_ep_data++;
      ul_nb_trans++;
      ul_size--;
      nb_byte_received--;
   }

   return ul_nb_trans;
}

Logged

Subscribe my youtube channel: http://www.youtube.com/user/MKDS3

Norfolk UK
Offline Offline
Faraday Member
**
Karma: 69
Posts: 2556
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Glad you managed to fix the problem.
Logged


The Netherlands
Offline Offline
Full Member
***
Karma: 1
Posts: 139
MKDS hacker and Programmer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Glad you managed to fix the problem.
Yea, it works great (but not with all usb sticks yet). I tested it with audio streaming from the usb stick. And it sounds so great! (8bit 44100 Hz)
Logged

Subscribe my youtube channel: http://www.youtube.com/user/MKDS3

Pages: [1]   Go Up
Jump to: