greiman / SdFat

Arduino FAT16/FAT32 exFAT Library
MIT License
1.09k stars 511 forks source link

USB HOST SHIELD, USB Flash Drive support #451

Open Stass48 opened 1 year ago

Stass48 commented 1 year ago

Hello! In one of my projects I need support for SD Card and USB storage at the same time. I need to copy files from a USB drive to an SD card. I've been looking for a lot of information about this. Your USBFat library works very conveniently, but working simultaneously with SDFat is not supported.

In one of the threads you wrote that you do not plan to support USBFat and you are not interested in it. I support your opinion. However, a certain part of people need USB and SD card support at the same time.

You also wrote that you have working code for working simultaneously with an SD card and a USB drive, and you planned to include it in the SDFat library. This was back in 2019 (if I’m not mistaken). A lot of time has passed since that moment. Is this support available now? Could you help me with the implementation of this task? Thank you.

greiman commented 1 year ago

I did an example that uses SdFat V2 with a USB key. Here is a link to the example and the USB library.

Stass48 commented 1 year ago

Thank you for your reply. I saw this and tried it just before I wrote to you. The code works, but I can't get the USB Host Shield and the memory card to work at the same time. If I connect only the shield, your example works, but as soon as I connect the memory card (mosi, miso, sck), your example stops working. Nowhere on the Internet have I found information on how to make this shield work in parallel with other devices on the same SPI bus. If you tried it and it worked for you, tell me how to do it correctly.

greiman commented 1 year ago

I can get the USB Host shield on an Arduino ADK to work with a SD. both are on the single SPI bus. The USB Host Shield uses pin 10 for Chip Select. The SD uses pin 53 which is SS on the ADK. The ADK has a built-in Usb Host Shield.

It always seems to be flaky to use the USB Host library with any other SPI device. Poor support for MSC on the USB Host shield is a big problem.

I need to power cycle examples with the USB Host shield sometimes.

I can't help with problems with the USB Host Shield library. It has been too long since I searched it for problems.

Here are my mods to the UsbKey example:


// Edit SdFatConfig.h and enable generic block devices.
// #define USE_BLOCK_DEVICE_INTERFACE 1
#include "UsbMscDriver.h"

USB usb;
BulkOnly bulk(&usb);
UsbMscDriver usbKey(&bulk);

FatVolume key;
File32 file;

SdFs sd;  //  <<<<<<<ADD

// full exFAT FAT32 FAT16
//FsVolume key;
//FsFile file;

//uint8_t lun;

void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}

  pinMode(10, OUTPUT);    //  <<<<<<<ADD
  digitalWrite(10, HIGH);      //  <<<<<<<ADD   
  if (!sd.begin(SS)) sd.initErrorHalt();    //  <<<<<<<ADD
  sd.ls(LS_DATE | LS_SIZE);     //  <<<<<<<ADD
  if (!initUSB(&usb)) {
    Serial.println("initUSB failed");
    while(1){}
  }
  // Must set USE_BLOCK_DEVICE_INTERFACE non-zero in SdFatConfig.h
  if (!key.begin(&usbKey)) {
    Serial.println("key.begin failed");
    while(1) {}
  }
  if (!file.open("usbtest.txt", FILE_WRITE)) {
    Serial.println("file.open failed");
    while(1) {}    
  }
  file.println("test line");
  file.close();

  key.ls(LS_DATE | LS_SIZE);
  Serial.println("\nSD files:");    //  <<<<<<<ADD
  sd.ls(LS_DATE | LS_SIZE);     //  <<<<<<<ADD
}
void loop() {}

Here is the output for a USB flash drive and a SD card:

Type any character to start 2023-01-01 00:00 5000000 bench.dat Host initialized, ms: 1004 USB powered, ms: 1004 USB state: 20, ms: 1009 USB state: 40, ms: 1204 USB state: 50, ms: 1255 USB state: 51, ms: 1255 USB state: 90, ms: 6703 2023-01-01 00:00 77 usbtest.txt 2023-09-23 10:40 54202 RigolDS3.png 2023-09-29 08:25 68868 RigolDS1.png 2023-09-29 08:26 69088 RigolDS4.png 2023-09-29 09:02 70174 RigolDS5.png 2018-09-15 00:28 1004054 img102.jpg 2023-09-24 04:21 1368 BOOTEX.LOG 2023-09-29 09:03 67952 DDR208.png

SD files: 2023-01-01 00:00 5000000 bench.dat

Stass48 commented 1 year ago

I can't understand what's going on at all. Instead of a full answer like yours, I get:

Type any character to start 2023-03-22 17:50 6639097 test.mp3 Host initialized, ms: 1002 USB powered, ms: 1003 USB state: 12, ms: 1007

That is, the memory card works, but for some reason the host does not start. If you remove the code that relates to the SD card and disable the hardware of the memory card, leaving only the host, then you still receive only three lines in response:

Host initialized, ms: 1002 USB powered, ms: 1003 USB state: 12, ms: 1007

I am using Mega 2560 board.

// Edit SdFatConfig.h and enable generic block devices.
// #define USE_BLOCK_DEVICE_INTERFACE 1
#include "UsbMscDriver.h"

USB usb;
BulkOnly bulk(&usb);
UsbMscDriver usbKey(&bulk);

FatVolume key;
File32 file;

// SdFat sd;  //  <<<<<<<ADD

// full exFAT FAT32 FAT16
//FsVolume key;
//FsFile file;

//uint8_t lun;

void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}

  // pinMode(10, OUTPUT);    //  <<<<<<<ADD
  // digitalWrite(10, HIGH);      //  <<<<<<<ADD   
  // if (!sd.begin(9)) sd.initErrorHalt();    //  <<<<<<<ADD
  // sd.ls(LS_DATE | LS_SIZE);     //  <<<<<<<ADD
  if (!initUSB(&usb)) {
    Serial.println("initUSB failed");
    while(1){}
  }
  // Must set USE_BLOCK_DEVICE_INTERFACE non-zero in SdFatConfig.h
  if (!key.begin(&usbKey)) {
    Serial.println("key.begin failed");
    while(1) {}
  }
  if (!file.open("usbtest.txt", FILE_WRITE)) {
    Serial.println("file.open failed");
    while(1) {}    
  }
  file.println("test line");
  file.close();

  key.ls(LS_DATE | LS_SIZE);
  // Serial.println("\nSD files:");    //  <<<<<<<ADD
  // sd.ls(LS_DATE | LS_SIZE);     //  <<<<<<<ADD
}
void loop() {}

Response:

Type any character to start Host initialized, ms: 1004 USB powered, ms: 1004 USB state: 12, ms: 1009

greiman commented 1 year ago

Sorry I can't help, the ADK is just a Mega 2560 with a built-in USB Host interface.

I have had one or two USB drives that wouldn't initialize but I think they just timed out.

I just looked at your output. I noticed it stopped at state 12. I didn't get that return.

I have no idea what it means since it has been years since I looked at the USB Host library.

Stass48 commented 1 year ago

I appreciate you trying to help. This is really valuable to me. The last thing I would like to do now is put pressure on you, but if my following observations give you something and you can tell me what to do, I would be glad.

If you simply plug the shield into the Mega 2560 board, that is, the 10th pin of the shield is connected to the 10th pin of the Arduino, then the returned code will be 12. I looked at the Arduino ADK circuit, there the CC pin of the shield is connected to the hardware CC pin of the microcontroller. So I thought that this might be the reason. Therefore, I connected the CC pin of the shield to pin 53 of the Arduino. The return code changed to 13, but nothing else happened. It returned 13 and stopped there. See connection photo.

I tried three different USB drives, the answer was the same everywhere, I don’t think they are the problem. I installed version SDfat 2.2.0 (exactly the version with which you tested this code), and I also installed your edition of the USB HOST SHIELD library. Also, I corrected 0 to 1 in the SDfat configuration, as you wrote. In the end, this is the result.

In fact, I solved my problem using the CH376S chip, Ch376msc

It has a special mode of operation via the interrupt pin, so it works great with multiple devices on the same SPI bus. In a word, a great solution. But too slow. I can't increase the block size more than 255 bytes at a time. Copying a 7.8 MB file takes 2 minutes. I wrote a loop that first fills my array with 6 KB and only then copies it to the SD card. Thus, I managed to reduce the waiting time to 1.5 minutes. But it's still slow. By the way, a copy of the same file on one SD card is created in 40 seconds. This kind of waiting time would suit me. Essentially, the purpose of experimenting with the USB HOST SHIELD was in the hope that it would perform faster than the CH376S.

photo_2023-11-12_15-48-55

photo_2023-11-12_15-48-57

greiman commented 1 year ago

I looked at the latest version of the USB Host Shield library here.

The only difference between it and the version I used is the mod I made for USBFat in masstorage.cpp:

Screenshot 2023-11-12 055100

If I comment out the added line many of my USB drives failt like this:

Host initialized, ms: 1002 USB powered, ms: 1003 USB state: 20, ms: 1007 USB state: 40, ms: 1203 USB state: 50, ms: 1253 USB state: 51, ms: 1253 USB state: 90, ms: 14271 key.begin failed

The problem is the ModeSense6() call.

None stop in state 0X12. Here are the state definitions from UsbCore.h:

#define USB_STATE_DETACHED                                  0x10
#define USB_DETACHED_SUBSTATE_INITIALIZE                    0x11
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE               0x12
#define USB_DETACHED_SUBSTATE_ILLEGAL                       0x13
#define USB_ATTACHED_SUBSTATE_SETTLE                        0x20
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE                  0x30
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE           0x40
#define USB_ATTACHED_SUBSTATE_WAIT_SOF                      0x50
#define USB_ATTACHED_SUBSTATE_WAIT_RESET                    0x51
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE    0x60
#define USB_STATE_ADDRESSING                                0x70
#define USB_STATE_CONFIGURING                               0x80
#define USB_STATE_RUNNING                                   0x90
#define USB_STATE_ERROR                                     0xa0

I posted an issue for the library years ago but never got a response.

Edit: USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE sounds like the USB drive is not seen.

I pulled the USB key and I get your result:

Host initialized, ms: 1003 USB powered, ms: 1003 USB state: 12, ms: 1008

greiman commented 1 year ago

This is just a repeat of the above edit.

Edit: USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE sounds like the USB drive is not seen.

I pulled the USB key and I get your result:

Host initialized, ms: 1003
USB powered, ms: 1003
USB state: 12, ms: 1008
Stass48 commented 1 year ago

Now connect 10 pin of the shield to pin 53 (hardware SS of the microcontroller) and you will get 13. That’s why I wrote to you, maybe your experience would allow you to solve 13 :). But if not, I'll have to look for other solutions :(

greiman commented 1 year ago

I used a Mega 2560 with a USB Host Shield. Pin 53 is used for SD chip select and pin 10 used for the USB chip select: USB_SD

Here is the program with #if to make it easier to test with/without SD.

// Edit SdFatConfig.h and enable generic block devices.
// #define USE_BLOCK_DEVICE_INTERFACE 1
#define USE_SD 1
#include "UsbMscDriver.h"

USB usb;
BulkOnly bulk(&usb);
UsbMscDriver usbKey(&bulk);

FatVolume key;
File32 file;
#if USE_SD
SdFs sd;
#endif  // USE_SD
// full exFAT FAT32 FAT16
//FsVolume key;
//FsFile file;

//uint8_t lun;

void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}
#if USE_SD 
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  if (!sd.begin(SS)) sd.initErrorHalt();
  sd.ls(LS_DATE | LS_SIZE);
#endif  // USE_SD
  if (!initUSB(&usb)) {
    Serial.println("initUSB failed");
    while(1){}
  }
  // Must set USE_BLOCK_DEVICE_INTERFACE non-zero in SdFatConfig.h
  if (!key.begin(&usbKey)) {
    Serial.println("key.begin failed");
    while(1) {}
  }
  if (!file.open("usbtest.txt", FILE_WRITE)) {
    Serial.println("file.open failed");
    while(1) {}    
  }
  file.println("test line");
  file.close();

  key.ls(LS_DATE | LS_SIZE);
#if USE_SD   
  Serial.println("\nSD files:");
  sd.ls(LS_DATE | LS_SIZE);
#endif  // USE_SD 
}

void loop() {
} 

Here is the result with the SD:

Type any character to start 2023-01-01 00:00 5000000 bench.dat Host initialized, ms: 1003 USB powered, ms: 1003 USB state: 20, ms: 1008 USB state: 40, ms: 1203 USB state: 50, ms: 1253 USB state: 51, ms: 1253 USB state: 90, ms: 6702 2023-01-01 00:00 33 usbtest.txt 2023-10-23 12:36 16777216 AT0042.cap

SD files: 2023-01-01 00:00 5000000 bench.dat

Stass48 commented 1 year ago

Hmm, did you just try this and it worked?

Stass48 commented 1 year ago

Here is my design and answer. Just just copied and pasted your code:

photo_2023-11-12_17-03-16

Type any character to start 2023-03-22 17:50 6639097 test.mp3 Host initialized, ms: 1002 USB powered, ms: 1003 USB state: 12, ms: 1007

greiman commented 1 year ago

Why do you connect USB Host Shield pin 10 to Mega pin 53?

For these boards the default USB chip select is pin 10.

/* shield pins. First parameter - SS pin, second parameter - INT pin */

USB_Host_Shield_2.0/UsbCore.h:58

typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x

Stass48 commented 1 year ago

In the example above (where I used an MP3 shield as a module for a memory card), the USB HOST SHIELD is connected to pin 10. I tried connecting to pin 53 just for the sake of testing. For example, your USBFAT library only worked when I connected the 10th pin of the shield to the 53rd pin of the Arduino. Thought this might help here.

Thanks for the information above, I spent the whole evening yesterday looking for where this pin was declared...

As a result, I have 10 pin shield connected to 10 pin Arduino and it still doesn't work(

If you just tried it and it worked for you, I don't understand what the reason is. I ordered three of these modules. Tried two of them. The result is the same. Although, they both work with USBFAT.

Stass48 commented 1 year ago

Stop, you wrote that pin 9 is used as INT, in the MP3 shield this pin is used as SDSS, now I’ll try to connect a regular microSD module.

greiman commented 1 year ago

https://www.sigmaelectronica.net/wp-content/uploads/2016/05/A000004_Web.pdf

Arduino communicates with the MAX3421E using the SPI bus (through the ICSP header). This is on digital pins 10, 11, 12, and 13 on the Uno and pins 10, 50, 51, and 52 on the Mega. On both boards, pin 10 is used to select the MAX3421E. Pins 7, 8 and 9 are used for GPX, INT and RES pins.

You will need to edit the USB Host library config if you use other pins.

Stass48 commented 1 year ago

You are amazing, Greiman. Thank you very much. If I manage to launch the host shield, the information above will help me launch the MP3 shield, because after executing init() for the USB host, the MP3 stopped playing. Now I understand that the library will need to be corrected for other pins. However, all this does not make any sense until I can not launch the USB HOST SHIELD. I just tried to do it like in your photo, the result is the same:

Type any character to start 2023-03-22 17:50 6639097 test.mp3 Host initialized, ms: 1004 USB powered, ms: 1004 USB state: 12, ms: 1009

photo_2023-11-12_18-43-29

Stass48 commented 1 year ago

That's the reason I thought of 53 pins. I’m not arguing with you in any way and I’m confident in your words about pin 10. I would just like to clarify my train of thought. Schematic

1

2

greiman commented 1 year ago

The ADK USB does connect to pin 53 and the USB Host shield library uses pin 53 on ADK. On most other Arduino boards USB CS is 10 in the USB Host library.

Here is the section that defined USB_INT and USB_CS. See the last #else section at the end.

/* shield pins. First parameter - SS pin, second parameter - INT pin */
#ifdef BOARD_BLACK_WIDDOW
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
#if EXT_RAM
typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
#else
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
#endif
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(ARDUINO_AVR_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#elif defined(__ARDUINO_X86__) && PLATFORM_ID == 0x06
typedef MAX3421e<P3, P2> MAX3421E; // The Intel Galileo supports much faster read and write speed at pin 2 and 3
#elif defined(ESP8266)
typedef MAX3421e<P15, P5> MAX3421E; // ESP8266 boards
#elif defined(ESP32)
typedef MAX3421e<P5, P17> MAX3421E; // ESP32 boards
#elif defined(MIGHTYCORE)
typedef MAX3421e<Pb4, Pb3> MAX3421E; // MightyCore
#elif (defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__))
typedef MAX3421e<Pb4, Pb3> MAX3421E; // Sanguino
#else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x
#endif

I got away with using SS for SD on ADK in the example. Probably because SPI.beginTransaction() blocks the USB interrupt routine.

On Mega SD can use SS since the USB host shield uses 10.

Stass48 commented 1 year ago

I repeated your example exactly as you said. The SS pin of the shield was connected to pin 10 of the Arduino. Pin 53 of the Arduino is connected as the SS pin of the SD memory card. As a result, code 12.

If you tried today and it worked, then it makes sense to look further and work in this direction, but if you have the same result as me, then it’s worth looking for other solutions.

I tried to implement USB on RP2040, it worked. However, other than that, nothing else works for me. I can't even start the SD memory card. Constant compilation errors :( To implement the USB, the SDfat Adafruit Fork library is used. In general, I am in complete despair. I need to copy files from the USB to a memory card, play MP3 and display graphics on the display. I have no idea on what I can do this on. To it wasn't expensive either.

Sorry for wasting too much of your time.

greiman commented 1 year ago

I quickly hacked the example we have been using to add a USB to SD copy. I copied a 5 MB (5,000,000) byte file from USB to SD. It took 31.2 seconds. I use the cheap USB drive in the above photo with the Mega and USB Host shield.

I suspect this is what you can expect with shared SPI and the slow USB Host shield.

Output:

Type any character to start Host initialized, ms: 1003 USB powered, ms: 1003 USB state: 20, ms: 1008 USB state: 40, ms: 1203 USB state: 50, ms: 1253 USB state: 51, ms: 1253 USB state: 90, ms: 6700 5000000 bytes in 31200 millis 2023-01-01 00:00 5000000 bench.dat

Hacked program:

// Edit SdFatConfig.h and enable generic block devices.
// #define USE_BLOCK_DEVICE_INTERFACE 1
#define USE_SD 1
#include "UsbMscDriver.h"

USB usb;
BulkOnly bulk(&usb);
UsbMscDriver usbKey(&bulk);

FatVolume key;
File32 file;
#if USE_SD
SdFs sd;
#endif  // USE_SD
//------------------------------------------------
void copy() {
  FsFile sdFile;
  uint8_t buf[1024];
  // use file from SD bench example
  if (!file.open("bench.dat")) {
    Serial.println("usb file open failed");
    return;
  }
  if (!sdFile.open("bench.dat", O_RDWR | O_CREAT | O_TRUNC)) {
    Serial.println("sd file open failed");
  }
  uint32_t m = millis();
  while (true) {
    int n = file.read(buf, sizeof(buf));
    if (n < 0) {
      Serial.println("read error");
      return;
    }
    if (n == 0) {
      break;
    }
    if (sdFile.write(buf, n) != (unsigned)n) {
      Serial.println("write error");
      return;
    }
  }
  m = millis() - m;
  Serial.print(file.fileSize());
  Serial.print(" bytes in ");
  Serial.print(m);
  Serial.println(" millis");
  sdFile.close();
}
//-------------------------------------------------------
void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}
#if USE_SD
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  if (!sd.begin(SS)) sd.initErrorHalt();
#endif  // USE_SD
  if (!initUSB(&usb)) {
    Serial.println("initUSB failed");
    while (1) {}
  }
  // Must set USE_BLOCK_DEVICE_INTERFACE non-zero in SdFatConfig.h
  if (!key.begin(&usbKey)) {
    Serial.println("key.begin failed");
    while (1) {}
  }
  copy();
  sd.ls(LS_DATE | LS_SIZE);
}
void loop() {
}

This program only works due to luck. I used two different classes for file and sdFile that match key and sd.

I will edit it for a fix.

greiman commented 1 year ago

Fixed program for FAT16/FAT32/exFAT with correct open calls:

// Edit SdFatConfig.h and enable generic block devices.
// #define USE_BLOCK_DEVICE_INTERFACE 1
#define USE_SD 1
#include "UsbMscDriver.h"

USB usb;
BulkOnly bulk(&usb);
UsbMscDriver usbKey(&bulk);

FsVolume key;
FsFile file;
#if USE_SD
SdFs sd;
#endif  // USE_SD
//------------------------------------------------
void copy() {
  FsFile sdFile;
  uint8_t buf[1024];
  // use file from SD bench example
  if (!file.open(&key, "bench.dat")) {
    Serial.println("usb file open failed");
    return;
  }
  if (!sdFile.open(&sd, "bench.dat", O_RDWR | O_CREAT | O_TRUNC)) {
    Serial.println("sd file open failed");
  }
  uint32_t m = millis();
  while (true) {
    int n = file.read(buf, sizeof(buf));
    if (n < 0) {
      Serial.println("read error");
      return;
    }
    if (n == 0) {
      break;
    }
    if (sdFile.write(buf, n) != (unsigned)n) {
      Serial.println("write error");
      return;
    }
  }
  m = millis() - m;
  Serial.print((uint32_t)sdFile.fileSize());
  Serial.print(" bytes in ");
  Serial.print(m);
  Serial.println(" millis");
  sdFile.close();
}
//-------------------------------------------------------
void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}
#if USE_SD
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  if (!sd.begin(SS)) sd.initErrorHalt();
#endif  // USE_SD
  if (!initUSB(&usb)) {
    Serial.println("initUSB failed");
    while (1) {}
  }
  // Must set USE_BLOCK_DEVICE_INTERFACE non-zero in SdFatConfig.h
  if (!key.begin(&usbKey)) {
    Serial.println("key.begin failed");
    while (1) {}
  }
  copy();
  sd.ls(LS_DATE | LS_SIZE);
}
void loop() {
}
Stass48 commented 1 year ago

This program is actually what would suit me! I don't know how to thank you for your time. I think your work will be useful not only to me. But it doesn't work for me :( It just hangs on code 12. But if it works for you, then why doesn’t it work for me? Yesterday I tested the USBfat library, it displayed a list of files on the same flash drive! I don't understand what could be the reason((((((((

Stass48 commented 1 year ago

You did not make any changes to the files: UsbMscDriver.cpp UsbMscDriver.h ? Are the same files used for this code?

Stass48 commented 1 year ago

I just tried to connect the USBfat library again. Specifically, the example is UsbDriveInfo. Despite the fact that the following is written in the USBCore.h file:

/* shield pins. First parameter - SS pin, second parameter - INT pin */
#ifdef BOARD_BLACK_WIDDOW
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
#if EXT_RAM
typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
#else
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
#endif
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(ARDUINO_AVR_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.) or Teensy 2.0 and 3.0
#endif

That is, pins 10, 9 are indicated for Mega 2560. You will laugh or, at a minimum, be very surprised, but. This example did not work for me until I connected pin 53 on the Arduino to pin 10 of the shield. Moreover, the 10th pin of the Arduino must also be connected to the 10th pin of the shield. I repeat once again)))) 10 pins and 53 pins of the Arduino had to be connected together and both of them connected to the 10 pin of the shield! This example wouldn’t work any other way!

Now I will try to do the same with your example.

Stass48 commented 1 year ago

Yeah))) Look. I was able to initialize the host with almost your code. I threw out the memory card code from it. I would say he gnawed it out, sloppily. I give the code as it is:

// Edit SdFatConfig.h and enable generic block devices.
// #define USE_BLOCK_DEVICE_INTERFACE 1
#define USE_SD 0
#include "UsbMscDriver.h"

USB usb;
BulkOnly bulk(&usb);
UsbMscDriver usbKey(&bulk);

FsVolume key;
FsFile file;
#if USE_SD
SdFs sd;
#endif  // USE_SD
//------------------------------------------------
void copy() {
  FsFile sdFile;
  uint8_t buf[1024];
  // use file from SD bench example
  if (!file.open(&key, "bench.dat")) {
    Serial.println("usb file open failed");
    return;
  }

  Serial.print(" bytes in ");
  Serial.println(" millis");
}
//-------------------------------------------------------
void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}
#if USE_SD
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  if (!sd.begin(SS)) sd.initErrorHalt();
#endif  // USE_SD
  if (!initUSB(&usb)) {
    Serial.println("initUSB failed");
    while (1) {}
  }
  // Must set USE_BLOCK_DEVICE_INTERFACE non-zero in SdFatConfig.h
  if (!key.begin(&usbKey)) {
    Serial.println("key.begin failed");
    while (1) {}
  }
  copy();
  // sd.ls(LS_DATE | LS_SIZE);
}
void loop() {
}

Here is the output from this code:

Type any character to start Host initialized, ms: 1003 USB powered, ms: 1003 USB state: 20, ms: 1008 USB state: 40, ms: 1203 USB state: 50, ms: 1252 USB state: 51, ms: 1253 USB state: 90, ms: 1636 bytes in millis

To get this, I had to connect Arduino pins 10 and 53 to pin 10 on the shield!

Now, knowing this, let's figure out why it works like this, but does not work normally.

Stass48 commented 1 year ago

Sorry for the many messages, but this is important. I'll give you some more information:

I added the line to that code:

key.ls(LS_DATE | LS_SIZE);

The SD memory card is physically disconnected (see photo).

So,

10 pin Arduino + 53 pin Arduino + 10 pin HOST SHIELD:

Type any character to start Host initialized, ms: 1003 USB powered, ms: 1003 USB state: 20, ms: 1008 USB state: 40, ms: 1204 USB state: 50, ms: 1253 USB state: 51, ms: 1254 USB state: 90, ms: 1403 2022-12-31 23:00 8161567 bench.dat bytes in millis

(now I'm sure that the flash drive is really readable)

53 pin Arduino + 10 pin HOST SHIELD:

Type any character to start No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? No USB HOST Shield? initUSB failed

10 pin Arduino + 10 pin HOST SHIELD:

Type any character to start Host initialized, ms: 1002 USB powered, ms: 1003 USB state: 12, ms: 1007

By the way, if after this you immediately connect pin 53, the flash drive will continue to initialize even without resetting the microcontroller.

photo_2023-11-13_00-43-19

Stass48 commented 1 year ago

Also, I want to show the difference in work between libraries taken from different places:

This is how the library taken from HERE works:

https://github.com/greiman/SdFat/assets/143362590/d8b22bb7-703d-47cb-841e-ae25aa213504

This is how the library taken from HERE works:

https://github.com/greiman/SdFat/assets/143362590/25160c90-adf5-44b7-bcb9-596d4f889219

As you can see, there is a difference between them. So which one is better to use? Here you recommend the one that runs slower.

greiman commented 1 year ago

The USB Host library in USBFat is nine years old and has a different method of mapping pins. Looks like there have been hundreds of commits to since the version I posted with the last USBFat.

I did a diff of the current version and the version in USBFat and the diff had over 7000 lines so there have been major changes.

I have no idea what has happened to the USB library in nine years. I am using the newest one from here with the one line change.

I am using an unmodified USB Host shield of the original design with no bridges cut so USB_SS is connected only to pin 10 of the Mega.

If you take the old library and have a problem you will need to fix it since no one will look at your problem.

The version in USBFat initializes faster since I shortened long delay calls. Here is a diff of how I modified the nine year old library. Note the diff is backwards. I replaced delay(x) with DELAY(x).

I suggest you download the current version of the USB Host library and add the line at about 799 of massstorage.cpp.

Here is the place:

/**
 * For driver use only.
 *
 * Page 3F contains write protect status.
 *
 * @param lun Logical Unit Number to test.
 * @return Write protect switch status.
 */
uint8_t BulkOnly::Page3F(uint8_t lun) {
        uint8_t buf[192];
        for(int i = 0; i < 192; i++) {
                buf[i] = 0x00;
        }
        WriteOk[lun] = true;
        return 0;  // WHG - Many USB keys don't respond.  //<<<<<<<<<<<<<<<<<<ADD
        uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
        if(!rc) {
                WriteOk[lun] = ((buf[2] & 0x80) == 0);
                Notify(PSTR("Mode Sense: "), 0x80);
                for(int i = 0; i < 4; i++) {
                        D_PrintHex<uint8_t > (buf[i], 0x80);
                        Notify(PSTR(" "), 0x80);
                }
                Notify(PSTR("\r\n"), 0x80);
        }
        return rc;
}
greiman commented 1 year ago

I noticed you mentioned the Adafruit version of SdFat. It is missing a number of bug fixes and changes. It will continue to diverge from this version of SdFat.

Stass48 commented 1 year ago

I noticed you mentioned the Adafruit version of SdFat. It is missing a number of bug fixes and changes. It will continue to diverge from this version of SdFat.

No, I am using your library. Just SDfat, 2.0.0. Adafruit fork it's just for rp2040 TinyUSB and PIOusb support (other SDfat library gives errors with compilation).

Can I ask you to upload your full working project with library what you using? I try to connect just 10 to 10 pin, and 53 pin SS for SD card and will see how it works for me.

I saw yesterday on your photo, that bridges on your HOST SHIELD are connected (SS, INT). On my SHIELD it also connected (connection is under solder mask, it not visible). I also tried soldering them, but the result did not change.

greiman commented 1 year ago

Too bad about Adafruit's SdFat. Many companies have a version. I have been able to merge Teensy changes and most Sparkfun changes but Adafruit is too far behind.

I have a RP2040 PIO SPI for SdFat that does about 5 MB/sec and a PIO SDIO 4-bit that does over 20 MB/sec. Guess you won't be able to use it with Adafruit. I hope to release a beta soon.

Here is a zip of the sketch folder, SdFat V2.2.2 configured as I used it and the current version of USB_Host_Shield_2.0 with my one line mod.

UsbCopy.zip

greiman commented 1 year ago

I just commented out all the long delays in masstorage.cpp in the current USB library like this:

 Arduino\libraries\USB_Host_Shield_2.0\masstorage.cpp (5 hits)
    Line  346:         //delay(2000);
    Line  408:         //delay(1000);
    Line  417:         //delay(1000); // Delay a bit for slow firmware.
    Line  474:                                 //delay(1000);
    Line 1029:         //delay(1000);

And get a much faster init:

Type any character to start Host initialized, ms: 1004 USB powered, ms: 1004 USB state: 20, ms: 1009 USB state: 40, ms: 1205 USB state: 50, ms: 1255 USB state: 51, ms: 1255 USB state: 90, ms: 1702 5000000 bytes in 31205 millis 2023-01-01 00:00 5000000 bench.dat

greiman commented 1 year ago

I assume you are not selecting ADK for the Arduino board. This compiles for a Mega 2560 but would use pin 53 for USB_CS.

This is my Arduino board selection:

Screenshot 2023-11-13 075420

Stass48 commented 1 year ago

I'm now home and have the opportunity to work on the project. I will write as I make progress. Yes, the board was chosen correctly, I didn’t choose ADK.

image

Stass48 commented 1 year ago

I don’t understand at all what the reason is. I downloaded your entire project with libraries and I get code 12. I don’t believe in mysticism, there must be a reason for this!

greiman commented 1 year ago

I ran the original USB only example.

Edit: This is the example that inits the USB drive writes a one line text file and calls ls().

I decided to put a logic analyzer on pin 10, pin 53 and SPI. Pin 53 is set high by SPI.begin() - this is necessary for AVR in master mode. pin 53 just stays high. Pin 10 is clearly CS .

Here is the trace for the entire run:

Screenshot 2023-11-13 121553

I suspect more delay() calls could be deleted - nothing happens for about a second on startup.

Here is a closeup of data transfer. Gaps between bytes but not too bad.

Screenshot 2023-11-13 121924

Stass48 commented 1 year ago

My head is already spinning, such “miracles” are happening here... Here is one of them:

https://github.com/greiman/SdFat/assets/143362590/109ec051-24b0-46f9-8129-f070e301f72a

Stass48 commented 1 year ago

I tried setting a pull-up resistor of 4.7K and 10K to +5V on pin 10 of the shield. The result did not change. Unfortunately, I do not have either a logic analyzer or an oscilloscope to see what is happening on pin 53.

Stass48 commented 1 year ago

Also, I found a mention of pin 53 in the usbhost.h file. I tried changing this pin to Pb4, but it didn’t help. Also, I tried changing the P10 pin in the UsbCore.h file to P53, this also did not help.

image

Stass48 commented 1 year ago

I also suggested that the problem might be with the MAX chip. I remembered that I ordered a chip separately from China, then in a slightly different case. in general, it was very difficult to re-solder it, but I did it. The result hasn't changed at all. image

Stass48 commented 1 year ago

I no longer know where to look for the problem. I ordered this module. Should arrive the day after tomorrow. For now we are waiting for him. Unless you have other ideas first.

Stass48 commented 1 year ago

I tried your project on Arduino Leonardo and Arduino Due. On Leonardo the same problem, but on Due the USB HOST has passed initialization! Only the memory card on Due refuses to initialize, both with and without the host.

greiman commented 1 year ago

I also suspect a problem with the USB HOST shield. Pin 53 is initialize OUTPUT HIGH by SPI begin()

void SPIClass::begin()
{
  uint8_t sreg = SREG;
  noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  if (!initialized) {
    // Set SS to high so a connected chip will be "deselected" by default
    uint8_t port = digitalPinToPort(SS);
    uint8_t bit = digitalPinToBitMask(SS);
    volatile uint8_t *reg = portModeRegister(port);

    // if the SS pin is not already configured as an output
    // then set it high (to enable the internal pull-up resistor)
    if(!(*reg & bit)){
      digitalWrite(SS, HIGH);    //<<<<<<<<<<<<<<<<<<Here<<<<<<
    }

    // When the SS pin is set as OUTPUT, it can be used as
    // a general purpose output port (it doesn't influence
    // SPI operations).
    pinMode(SS, OUTPUT);  //<<<<<<<<<<<<<<<<<<<Here<<<<<<

    // Warning: if the SS pin ever becomes a LOW INPUT then SPI
    // automatically switches to Slave, so the data direction of
    // the SS pin MUST be kept as OUTPUT.
    SPCR |= _BV(MSTR);
    SPCR |= _BV(SPE);

    // Set direction register for SCK and MOSI pin.
    // MISO pin automatically overrides to INPUT.
    // By doing this AFTER enabling SPI, we avoid accidentally
    // clocking in a single bit since the lines go directly
    // from "input" to SPI control.
    // http://code.google.com/p/arduino/issues/detail?id=888
    pinMode(SCK, OUTPUT);
    pinMode(MOSI, OUTPUT);
  }
  initialized++; // reference count
  SREG = sreg;
}

When you connect pin 53 to pin 10 the voltage seen by the shield will be some combination of pin 10 and Pin 53. Probably always higher than pin 10 alone.

If you look at the schematic for the Host shield, Chip Select is connected to two 74HC125 buffers to handle 5V - 3V3 level shifting.

Maybe the two pins in output mode with 53 HIGH makes the shield work.

I have seen 74HC125 buffers fail. They don't have very good input protection. 74HC4050 tend to be used now since they have better input protection.

In 2008 when I did the first SD library for Arduino I used 74HC125 buffers to replace resistor voltage dividers on the first SD modules. They are not the best choice since they are a bit slow and have a 6V input limit.

greiman commented 1 year ago

Here is a program that shows what I think the USB shield sees for CS.

// connect pins A0, 10, and 53 together
void setup() {
  Serial.begin(9600);
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  pinMode(53, OUTPUT);
  digitalWrite(53, HIGH);
}

void loop() {
  delay(1000);
  Serial.println(analogRead(A0));
  digitalWrite(10, LOW);
  delay(1000);
  Serial.println(analogRead(A0));
  digitalWrite(10, HIGH);
}

Output:

500 1023 500 1023 500 1023 500 1023 500

Stass48 commented 1 year ago

Exactly! You're ahead of me. Just last night the thought came to me that the problem might be in bad Chinese buffers. These modules were ordered from China. Don't think that they are made of something good. In addition, the host shield works perfectly on Due without any intervention. It is worth remembering that the Due levels are 3.3V, while on the Mega2560 and Leonardo they are 5V. This is where my suspicions about voltage level converters arose. As I said yesterday, I ordered another module from our local online store. Although they sell Chinese goods, they are, in theory, proven. I paid today. They will send it today and I will pick it up at the post office tomorrow. Let's hope that there are other converters in that module. But while we are waiting for the parcel, today I can try to solder the following modules with wiring:

5.0-3.3V Level Converter

This is purely to test another theory. Do you think it should work through such converters?

greiman commented 1 year ago

This is purely to test another theory. Do you think it should work through such converters?

I have had mixed luck with I2C level shifters for use other than open drain I2C.

greiman commented 1 year ago

Here is a typical I2C level shifter circuit.

SPI at 8MHz can be quite distorted with 10K pull-ups.

greiman commented 1 year ago

I expect you could have 50 pf stray capacitance. Then a 10K pull-up is way too large for 8MHz. Or you need 5 pf capacitance.

Screenshot 2023-11-14 075828

Stass48 commented 1 year ago

Please tell me which converters are on your board? It's hard to see in the photo.