Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

Thread: USB Host to read/write data on USB-Stick?

  1. #1

    USB Host to read/write data on USB-Stick?

    Hello!

    Is it possible to read/write CSV data on a MSD using the USB-host functionality of the Teensy 4.0 ?

    Technically this should work but are there any examples for Arduino? Maybe with the USBHost_t36 libary?

    Thanks for your help,

    schlank

  2. #2
    Senior Member wwatson's Avatar
    Join Date
    Aug 2017
    Posts
    885
    Quote Originally Posted by schlank View Post
    Hello!

    Is it possible to read/write CSV data on a MSD using the USB-host functionality of the Teensy 4.0 ?

    Technically this should work but are there any examples for Arduino? Maybe with the USBHost_t36 libary?

    Thanks for your help,

    schlank
    Yes it is. With the Teensy 4.0 you will need a breakout board to access USB Host functionality. There are two pads underneath the USB device connector on the bottom side of the T4.0 that provide the D+ and D- signals used for USB Host. If I am correct this requires a little support circuitry as well.
    Click image for larger version. 

Name:	teensy40_card10b_rev2.png 
Views:	20 
Size:	146.9 KB 
ID:	31092

    The T4.1 already has access to USB Host through a 5 pin connector onboard.
    Click image for larger version. 

Name:	teensy41_4.png 
Views:	19 
Size:	344.8 KB 
ID:	31094

    And PJRC sells a matching cable for use with it.

    There are examples in the USBHost_t36 library in the "examples/storage" folder that you can use to get an idea of how to use a USB thumb drive with the T4.x.

    Here is an example of MSC usage that shows how to read and write to a file on a USB drive:
    Code:
    /*
       MSC SdFat usage from SD library
    
      Starting with Teensyduino 1.54, the SD library is a thin wrapper for SdFat.
    
      You can access the main SdFat filesystem with ".mscfs".
      This example shows some of the ways to select optimized SdFat drivers and
      how to use special file truncation and pre-allocation for optimized data
      logging.
    
      This example code is in the public domain.
    */
    #include <USBHost_t36.h>
    
    // Setup USBHost_t36 and as many HUB ports as needed.
    USBHost myusb;
    USBHub hub1(myusb);
    USBHub hub2(myusb);
    USBHub hub3(myusb);
    USBHub hub4(myusb);
    
    // Setup MSC for the number of USB Drives you are using. (Two for this example)
    // Mutiple  USB drives can be used. Hot plugging is supported. There is a slight
    // delay after a USB MSC device is plugged in. This is waiting for initialization
    // but after it is initialized ther should be no delay.
    // mscController is now USBDrive. 
    USBDrive msDrive1(myusb);
    
    // USBFilesystem is a class based on claimed partitions discovered during
    // initialization. We are using the first discovered partition here. More
    // discovered partitions can be used by adding more instances of the
    // 'USBFilesystem' class.
    USBFilesystem partition1(myusb);
    elapsedMillis mscTimeOut; 
    
    void setup()
    {
      Serial.begin(9600);
      while (!Serial); // wait for Arduino Serial Monitor
    
      // Start USBHost_t36, HUB(s) and USB devices.
      myusb.begin();
      myusb.Task();
    
      Serial.print("Initializing MSC drive...");
      uint8_t errCode = MS_INIT_PASS;
      mscTimeOut = 0;
      // Wait for MSC drive to be auto detected. Uses 5 second timeout
      // and no drive detected error. Waits for drive to be inserted.
      while(!msDrive1) {
        if((mscTimeOut > MSC_CONNECT_TIMEOUT) && (msDrive1.errorCode() == MS_NO_MEDIA_ERR)) {
          Serial.println("No drive connected yet!!!!");
          Serial.println("Connect a drive to continue...\n");
          while(!msDrive1);
        } 
    	delay(1);
      }
      mscTimeOut = 0;
    
      while(!partition1) {
        myusb.Task();
        if(mscTimeOut >  MEDIA_READY_TIMEOUT) {
          Serial.println("initialization failed!");
          return;
        }
        delay(1);
      }
      Serial.println("initialization done.");
      Serial.println();
    
      // After the MSC drive is initialized, you can access it using the ordinary
      // SD library functions, regardless of whether it was initialized by
      // SD library SD.begin() or SdFat library SD.sdfs.begin() or MSC auto
      // initialization. MSC access to SdFat is achieved as in this example:
      // "partition1.mscfs.ls()".
      Serial.println("Print directory using SD functions");
      File root = partition1.open("/");
      while (true) {
        File entry = root.openNextFile();
        if (!entry) break; // no more files
        Serial.print(entry.name());
        if (entry.isDirectory()) {
          Serial.println("/");
        } else {
          printSpaces(40 - strlen(entry.name()));
          Serial.print("  ");
          Serial.println(entry.size(), DEC);
        }
        entry.close();
      }
    
      // You can also access the SD card with SdFat's functions
      // 
      Serial.println();
      Serial.println("Print directory using SdFat ls() function");
      partition1.mscfs.ls(LS_R);
    
      // You can access files using SdFat which uses "FsFile" for open files
      // FsFile offers more capability than regular SD "File".  As shown in this
      // example, you can truncate tiles.  You can also pre-allocate a file on
      // the MSC drive (if it does not yet have any data, the reason we truncate
      // first).  Pre-allocation impoves the speed of writes within the already
      // allocated space while data logging or performing other small writes.
      //
      Serial.println();
      Serial.println("Writing to datalog.bin using SdFat functions");
      FsFile myfile = partition1.mscfs.open("datalog.bin", O_WRITE | O_CREAT);
      unsigned int len = myfile.fileSize();
      Serial.print("datalog.bin started with ");
      Serial.print(len);
      Serial.println(" bytes");
      if (len > 0) {
        // reduce the file to zero if it already had data
        myfile.truncate();
      }
      if (myfile.preAllocate(40*1024*1024)) {
        Serial.print("  Allocate 40 megabytes for datalog.bin");
      } else {
        Serial.print("  unable to preallocate this file");
      }
      myfile.print("Just some test data written to the file (by SdFat functions)");
      myfile.write((uint8_t)'\0'); // add a null byte to mark end of string
      myfile.close();
    
      // You can also use regular SD functions, even to access the same file.  Just
      // remember to close the SdFat FsFile before opening as a regular SD File.
      //
      Serial.println();
      Serial.println("Reading to datalog.bin using SD functions");
      File f = partition1.open("datalog.bin");
      if (f) {
        char mybuffer[100];
        int index = 0;
        while (f.available()) {
          char c = f.read();
          mybuffer[index] = c;
          if (c == 0) break;  // end of string
          index = index + 1;
          if (index == 99) break; // buffer full
        }
        mybuffer[index] = 0;
        Serial.print("  Read from file: ");
        Serial.println(mybuffer);
      } else {
        Serial.println("unable to open datalog.bin :(");
      }
      f.close();
    
      // When mixing SD and SdFat file access, remember for writing that
      // SD defaults to appending if you open with FILE_WRITE.  You must
      // use FILE_WRITE_BEGIN if you wish to overwrite the file from the
      // start.  With SdFat, O_WRITE or O_RDWR starts overwriting from the
      // beginning.  You must add O_AT_END if you wish to appead.
    }
    
    void loop()
    {
      // nothing happens after setup finishes.
    }
    
    
    void printSpaces(int num) {
      for (int i = 0; i < num; i++) {
        Serial.print(" ");
      }
    }
    Hopefully this will give you a starting point...

  3. #3
    Hi wwatson,

    Thanks for your reply.
    I just ordered the PCBs of this tiny board to have a solid connection to any USB device:

    https://www.partsnotincluded.com/tee...b-host-shield/

    Unfortunately the code provided by you is not compiling without error in Platform I/O.


    Code:
    [env:teensy40]
    platform = teensy
    board = teensy40
    framework = arduino
    lib_deps = paulstoffregen/USBHost_t36@^0.2
    Compiler output:

    Code:
    src/main.cpp:28:1: error: 'USBDrive' does not name a type
     USBDrive msDrive1(myusb);
    I installed the library in Platform I/O library installer.

    Any idea?


    Thanks,

    schlank

  4. #4
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    17,427
    Using IDE 2.1 with TD 1.58.1 the post #2 code built here and created the indicated 40MB file with just one line.

    Didn't seem to activate MSC connect to Host PC ... but it built fine with and without USB having MSC included.

    One warning about unused errCode in setup()

    It shows this for used libraries:
    Code:
    Using library USBHost_t36 at version 0.2 in folder: C:\Users\Tim\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\USBHost_t36 
    Using library SdFat at version 2.1.2 in folder: C:\Users\Tim\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\SdFat 
    Using library SPI at version 1.0 in folder: C:\Users\Tim\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\SPI 
    Using library EEPROM at version 2.0 in folder: C:\Users\Tim\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\EEPROM
    Not sure where the PIO is on released Teensy sources?

    Update from 1.58 to 1.58.1 IIRC would not affect this.

  5. #5
    Quote Originally Posted by defragster View Post
    Using IDE 2.1 with TD 1.58.1 the post #2 code built here .
    Hi!

    How can I solve the issue to make the code compile in Platofrm I/O?

  6. #6
    Senior Member wwatson's Avatar
    Join Date
    Aug 2017
    Posts
    885
    @schlank - I have never used Platform I/O The error makes it look like the USBHost_t36 library is not being recognized or installed properly.
    Here is a tutorial from @shawn:
    https://forum.pjrc.com/threads/71730...ormIO?p=317673

    And:
    https://docs.platformio.org/en/lates...ms/teensy.html

    Good luck

  7. #7
    Quote Originally Posted by wwatson View Post
    Good luck
    Yeah thanks

    I managed the code to compile (not yet tested) after getting the library and teensy-platform directly from Git:

    Code:
    [env:teensy40]
    platform = https://github.com/platformio/platform-teensy.git
    board = teensy40
    framework = arduino
    lib_deps = 
    	https://github.com/PaulStoffregen/USBHost_t36.git

  8. #8
    Hello!

    I am about to do some coding using the library.
    To get the size of a file os not a big deal:
    Code:
    File configFile = partition1.open("/config/config.txt", O_READ);
    ..
    Serial.println(configFile.size());
    This works. But I want to use getCreateTime() to get the time of creation. How can I manage that?

    Thanks,

    schlank

  9. #9
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,783
    Quote Originally Posted by schlank View Post
    Hello!

    I am about to do some coding using the library.
    To get the size of a file os not a big deal:
    Code:
    File configFile = partition1.open("/config/config.txt", O_READ);
    ..
    Serial.println(configFile.size());
    This works. But I want to use getCreateTime() to get the time of creation. How can I manage that?

    Thanks,

    schlank
    Maybe something like:

    Code:
        DateTimeFields dtf;
        configFile.getCreateTime(dtf);
        Serial.printf("Updated Options file found date: M: %02u/%02u/%04u %02u:%02u\n",
             dtf.mon + 1, dtf.mday, dtf.year + 1900, dtf.hour, dtf.min );

  10. #10
    Hi Kurt,

    Thanks for this. This works.

    However could you maybe tell me HOW I can set now the internal RCT clock of the Teensy 4.0 to the time of the date read from the file?

    This is important if the battery runs out out energy.

    Thanks!

  11. #11
    Senior Member
    Join Date
    Mar 2023
    Posts
    210
    I have a sneaking suspicion there is some code in the Teensy Loader app (the one that uploads code onto the device) that sets the RTC based on the host PC's time - I've never had a battery connected but have noticed the Teensy's clock is often set correctly regardless...

  12. #12
    I am an artist and I want to give the project to a museum. If the batter runs low they should be able to set the time again by them selves.

  13. #13
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    4,457
    Quote Originally Posted by jmarsh View Post
    I have a sneaking suspicion there is some code in the Teensy Loader app (the one that uploads code onto the device) that sets the RTC based on the host PC's time - I've never had a battery connected but have noticed the Teensy's clock is often set correctly regardless...
    Yes, when you program the Teensy using the Arduino IDE, it resets the Teensy real time clock.

  14. #14
    Senior Member
    Join Date
    Aug 2018
    Location
    Brisbane, Australia
    Posts
    185
    To set the RTC clock, call
    Code:
    Teensy3Clock.set(unsigned long t);

  15. #15
    Hello Friends!

    I am using this snippet from the example:

    Code:
          if ((mscTimeOut > MSC_CONNECT_TIMEOUT) &&
              (msDrive1.errorCode() == MS_NO_MEDIA_ERR)) {
              Serial.println("No drive connected!");
              return false;  // Return false if no drive is connected yet
          }
          delay(1);
      }
    However is it possible to check for a attached or removed MSD in a non-blocking way? E.g interrupt based?

    Thanks,

    schlank.

  16. #16
    Senior Member wwatson's Avatar
    Join Date
    Aug 2017
    Posts
    885
    Quote Originally Posted by schlank View Post
    Hello Friends!

    I am using this snippet from the example:

    Code:
          if ((mscTimeOut > MSC_CONNECT_TIMEOUT) &&
              (msDrive1.errorCode() == MS_NO_MEDIA_ERR)) {
              Serial.println("No drive connected!");
              return false;  // Return false if no drive is connected yet
          }
          delay(1);
      }
    However is it possible to check for a attached or removed MSD in a non-blocking way? E.g interrupt based?

    Thanks,

    schlank.
    Sorry for the delayed response. There is a way to check for that at the driver level. The claim() function and disconnect() function are interrupt driven.
    Here is a small sketch that demonstrates this:
    Code:
    #include <USBHost_t36.h>
    
    // Setup USBHost_t36 and as many HUB ports as needed.
    USBHost myusb;
    USBHub hub1(myusb);
    USBHub hub2(myusb);
    USBHub hub3(myusb);
    USBHub hub4(myusb);
    
    // Instances for the number of USB drives you are using.
    USBDrive myDrive1(myusb);
    
    void setup()
    {
      Serial.begin(9600);
      while (!Serial) {
        ; // wait for Arduino Serial Monitor to connect.
      }
    
      myusb.begin();
      delay(1000);  // Give USBHost a little time to startup
    }
    
    void loop() {
      myusb.Task();
    
      //===================================================================
      // myDrive1.msDriveInfo.connected is set or cleared by USBHost_t36
      // interrupts in the claim() and disconnect() functions. See 
      // MassStorageDriver.cpp at line 141 for claim() and line 175 in the 
      // disconnect() function.
      //===================================================================
    
      if(myDrive1.msDriveInfo.connected) 
        Serial.printf(F("       myDrive1 is connected...\n"));
      else
        Serial.printf(F("       myDrive1 is NOT connected...\n"));
      delay(10); // Slow it down a bit...
    }
    Run this sketch and plug/unplug a USB drive to demonstrate hot plugging.

    Each instance of USBDrive has a struct called msDriveInfo so each USB drive that you connect will have this struct available:
    Code:
    // MSC Drive status/info struct
    typedef struct {
    	bool connected;    // Device is connected
    	bool initialized;  // Device is initialized
    	bool mounted;      // Device is mounted
    	const char * drvName;
    	uint32_t bufferSize;
    	uint8_t hubNumber;
    	uint8_t hubPort;
    	uint8_t deviceAddress;
    	uint16_t idVendor;
    	uint16_t idProduct;
    	msSCSICapacity_t capacity;
    	msInquiryResponse_t inquiry;	
    } __attribute__((packed)) msDriveInfo_t;
    Check out the example sketch in "USBHost_t36/storage/DriveInfo". This prints out the drive information. Also checkout "USBHost_t36/storage/DriveInfoAll" sketch which prints out even more information about all connected USB drives.

    Hope this is what you are after...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •