
Originally Posted by
schlank
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.

The T4.1 already has access to USB Host through a 5 pin connector onboard.

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...