There Seems to be a Problem with MTP_Teensy and SD

BriComp

Well-known member
I have a system where I gather data and write it to a file every minute.
If I cut the file (from Teensy) and paste elsewhere on the PC the Teensy will not re-create the file and write to it.
dataFile = SD.open("datalogZ.csv", FILE_WRITE); is supposed to open a file if it exists or create it if it does not.
In fact any operation on the Teensy file by the PC STOPS Teensy from writing to the file WITH NO ERROR THROWN.
Below is a program which demonstrates the problem.
Code:
/*
Demonstrate MTP/SD Problem
 */
#define softwareId "S.0004.0004.003 - Added MTP support"

#include <SD.h>
#include <timelib.h>

#include <MTP_Teensy.h>

#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1

#define ledPin 13
File dataFile;

String GenerateDateStr(char c) {
    String s = "";

    int n = day();
    if (n < 10) s.concat( "0");
    s.concat(n);
    s.concat('/');
    n = month();
    if (n < 10) s.concat("0");
    s.concat(n);
    s.concat('/');
    n = year();
    if (n < 10) s.concat("0");
    s.concat(n);
    if (c != 0x0) s.concat(c);
    return s;
}

String GenerateTimeStr(bool andSeconds, char c ) {
    String s = "";

    int n = hour();
    if (n < 10) s.concat("0");
    s.concat(n);
    s.concat(':');
    n = minute();
    if (n < 10) s.concat("0");
    s.concat(n);
    if (andSeconds) {
        s.concat(':');
        n = second();
        if (n < 10) s.concat("0");
        s.concat(n);
    }
    if (c != 0x0) s.concat(c);
    return s;
}

time_t getTeensy3Time(){
    return Teensy3Clock.get();
}

bool   sdSetup = true;

void setup()
{

    setSyncProvider(getTeensy3Time);

    Serial.begin(115200);
    while (!Serial && millis() < 5000);
    Serial1.begin(115200);

    Serial.print("Initializing SD card...");

    pinMode(ledPin, OUTPUT);
    // see if the card is present and can be initialized:
    if (SD.begin(CS_SD)) {
        MTP.addFilesystem(SD, "SD Card");
        Serial.println("card initialized.");
    }
    else {
        Serial.println("Card failed, or not present");
        sdSetup = false;
        // No SD card, so don't do anything more - stay stuck here
    }

    if (timeStatus() != timeSet) {
        Serial.println("Unable to sync with the RTC");
    } else Serial.println("RTC has set the system time");

    // mandatory to begin the MTP session.
    MTP.begin();

    Serial.println(GenerateDateStr(0x0));
}


void PrintNN(uint16_t n) {
    uint16_t q;

    dataFile.print(n / 100);
    dataFile.print(".");
    q = n % 100;
    if (q < 10) dataFile.print("0");
    dataFile.print(q);
}

String tim;
String date;
uint8_t lastMin = 99;
uint8_t currMin = 98;
uint8_t p;

// Add the main program code into the continuous loop() function
void loop()
{
    MTP.loop();  //This is mandatory to be placed in the loop code.
    currMin = minute();
    while (lastMin != currMin) {
        digitalWrite(ledPin, HIGH);
        if (currMin != lastMin) {
            if (lastMin != 99) {
                Serial.print("sdSetup:"); Serial.print(sdSetup); Serial.print("  SD.mediaPresent:"); Serial.print(SD.mediaPresent());
                if (sdSetup && SD.mediaPresent()) {
                    dataFile = SD.open("datalogZ.csv", FILE_WRITE);
                    Serial.print("   dataFile:"); Serial.println(dataFile);
                    // if the file is available, write to it:
                    if (dataFile) {
                        Serial.println("Writing to file");
                        date = GenerateDateStr(' ');
                        tim = GenerateTimeStr(true, 0x0);

                        dataFile.print(date);
                        dataFile.println(tim);
                        dataFile.close();
                    }
                }
            }
            lastMin = currMin;
        }
//        Serial.print("currMin: "); Serial.print(currMin); Serial.print("  lastMin: "); Serial.println(lastMin);
//        delay(1000);
        digitalWrite(ledPin, LOW);

    }
    delay(1);

}
 
If I cut the file (from Teensy) and paste elsewhere on the PC the Teensy will not re-create the file and write to it.
From a Windows perspective, cutting the file from Teensy, means copy the file first and then subsequently delete the original file on Teensy.
If you, from Windows, make it a 2-step action like copy the file first and then as next action delete the file, will Teensy re-create a new writable file correctly in that case?

Paul
 
I think I tried that and NO it won't.
I tried all sorts of action on the PC and they all resorted in Teensy ignoring the file.
It's interesting that when the file is opened a file is returned but Teensy then does not carry out any actions on the file.
 
I think I tried that and NO it won't.
I tried all sorts of action on the PC and they all resorted in Teensy ignoring the file.
It's interesting that when the file is opened a file is returned but Teensy then does not carry out any actions on the file.
Actually the issue is that windows isn't updating the directory listing to show that file is actually being rewritten to again. I just did the same thing but pulled the after doing a cut and paste to PC (of course I waited for the next write and turn off the Teensy). Putting it in the PC showed that the file was actually recreated and had data :)

I added the following:
Code:
MTP.send_DeviceResetEvent();
before the setting curmin = lastmin and seemed to refresh the sd card directory in MTP (note you probably have to hit refresh as well in windows explorer. Here is the whole sketch I used:

Code:
/*
Demonstrate MTP/SD Problem
 */
#define softwareId "S.0004.0004.003 - Added MTP support"

#include <SD.h>
#include <TimeLib.h>

#include <MTP_Teensy.h>

#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1

#define ledPin 13
File dataFile;

String GenerateDateStr(char c) {
    String s = "";

    int n = day();
    if (n < 10) s.concat( "0");
    s.concat(n);
    s.concat('/');
    n = month();
    if (n < 10) s.concat("0");
    s.concat(n);
    s.concat('/');
    n = year();
    if (n < 10) s.concat("0");
    s.concat(n);
    if (c != 0x0) s.concat(c);
    return s;
}

String GenerateTimeStr(bool andSeconds, char c ) {
    String s = "";

    int n = hour();
    if (n < 10) s.concat("0");
    s.concat(n);
    s.concat(':');
    n = minute();
    if (n < 10) s.concat("0");
    s.concat(n);
    if (andSeconds) {
        s.concat(':');
        n = second();
        if (n < 10) s.concat("0");
        s.concat(n);
    }
    if (c != 0x0) s.concat(c);
    return s;
}

time_t getTeensy3Time(){
    return Teensy3Clock.get();
}

bool   sdSetup = true;

void setup()
{

    setSyncProvider(getTeensy3Time);

    Serial.begin(115200);
    while (!Serial && millis() < 5000);
    Serial.begin(115200);

    Serial.print("Initializing SD card...");

    pinMode(ledPin, OUTPUT);
    // see if the card is present and can be initialized:
    if (SD.begin(CS_SD)) {
        MTP.addFilesystem(SD, "SD Card");
        Serial.println("card initialized.");
    }
    else {
        Serial.println("Card failed, or not present");
        sdSetup = false;
        // No SD card, so don't do anything more - stay stuck here
    }

    if (timeStatus() != timeSet) {
        Serial.println("Unable to sync with the RTC");
    } else Serial.println("RTC has set the system time");

    // mandatory to begin the MTP session.
    MTP.begin();

    Serial.println(GenerateDateStr(0x0));
}


void PrintNN(uint16_t n) {
    uint16_t q;

    dataFile.print(n / 100);
    dataFile.print(".");
    q = n % 100;
    if (q < 10) dataFile.print("0");
    dataFile.print(q);
}

String tim;
String date;
uint8_t lastMin = 99;
uint8_t currMin = 98;
uint8_t p;

// Add the main program code into the continuous loop() function
void loop()
{
    MTP.loop();  //This is mandatory to be placed in the loop code.
    currMin = minute();
    while (lastMin != currMin) {
        digitalWrite(ledPin, HIGH);
        if (currMin != lastMin) {
            if (lastMin != 99) {
                Serial.print("sdSetup:"); Serial.print(sdSetup); Serial.print("  SD.mediaPresent:"); Serial.print(SD.mediaPresent());
                if (sdSetup && SD.mediaPresent()) {
                    dataFile = SD.open("datalogZ.csv", FILE_WRITE);
                    Serial.print("   dataFile:"); Serial.println(dataFile);
                    // if the file is available, write to it:
                    if (dataFile) {
                        Serial.println("Writing to file");
                        date = GenerateDateStr(' ');
                        tim = GenerateTimeStr(true, 0x0);

                        dataFile.print(date);
                        dataFile.println(tim);
                        dataFile.close();
                    }
                }
            }
            MTP.send_DeviceResetEvent();
            lastMin = currMin;
        }
        Serial.print("currMin: "); Serial.print(currMin); Serial.print("  lastMin: "); Serial.println(lastMin);
        delay(1000);
        digitalWrite(ledPin, LOW);

    }
    delay(1);

}
 
The proper operation with MTP is to do either generating files or using mtp-loop. Well, at least that is the mode that works.
Also, after writing to uSD, the PC must be told (e.g. by user) to remount/reset the MTP responder (on the Teensy).
when cut and paste files, the PC must first copy the file, and then issue a delete command to Teensy. In other words, only the PC can give commands and the Teensy must only respond. There should be the possibility to log all commands/responses, that could help to nail down possible issues.
Caveat: As I only use the MTP_t4 (original port to Teensy) there may be additional features on MTP_Teensy, but the concept has not changed.

Overlap with mjs513
 
I am also having some difficulties with MTP. Using the MTP_Teensy I have included
Code:
MTP.send_DeviceResetEvent();
Which has allowed for the Teensy to remain connected to the PC and refreshing the directory in windows now shows newly written files.

However transfer speeds to and from the SD card are very slow. Using T4.0 and audio shield I understand the limitations, what speed should be attainable ignoring microSD limitations?

Further to that if I am browsing the SDcard on the PC and directly open a file in the directory, it opens fine etc. Subsequent files cannot be opened as windows says it cannot access the device. Is this a quirk of the current MTP setup or another problem in itself.
 
Further to that if I am browsing the SDcard on the PC and directly open a file in the directory, it opens fine etc. Subsequent files cannot be opened as windows says it cannot access the device. Is this a quirk of the current MTP setup or another problem in itself.
Don't remember the transfer speeds we say off hand but I did just check that I can open multiple cards from a micromod buit-in SD card no issues. I am on a Windows 11 pc - also tested on a Win 10 machine a long time back.

In terms of writing to the SD Card I am seeing:
Code:
Start Big write of 2048000 Bytes.........................
Big write /0_2MBfile.txt took  0.13 Sec for 2048000 Bytes : file3.size()=2048000
    Big write KBytes per second 15229.60

Bytes Used: 20987904, Bytes Total:31921913856

For a 4.6Mb file transfer to - from the Teensy to the PC is less than or close to a 1 seconds. That is not too bad.

Have to remember also what MTP is meant for. From Wikipedia:
MTP is a high level file transfer protocol, as opposed to a general storage protocol like USB mass storage.
Its now meant as a file system even though we tried to make it useful for that.
 
Don't remember the transfer speeds we say off hand but I did just check that I can open multiple cards from a micromod buit-in SD card no issues. I am on a Windows 11 pc - also tested on a Win 10 machine a long time back.
Seems this is only an issue based on the program used to open the files. Using an alternative has solved that problem..

For a 4.6Mb file transfer to - from the Teensy to the PC is less than or close to a 1 seconds. That is not too bad.
As for transfer speed with a sample 4MB file takes just over 6 seconds. This is with T4.0 and Audio shield mounted SDcard.

Is there an updated alternative library using the general storage protocol?
 
I know that I am sort of late to the game. It has been a while since I have played with MTP.

As far as alternatives, I believe it was either MicroPython or CircuitPython that implemented something like TinyUSB or the like, which allowed you to transfer files to and from the host. But if I remember correctly the File system had two modes, one where your code on the Teensy (or other microcontroller) was in control of the file system and could access/create the files, and one where the host is fully in control of the file system, where it would mount on your host like a normal disk drive... Sorry I am a bit hazy on the details as it has been awhile since I played with it.

Another possible alternative is to roll your own. That is for example if your goal is to quickly download some specific things like a log file, you could for example have the teensy implement RAWHID, and have a program that you run on the PC that implements RAWHID. There is a version of it that I played with that transferred 512-byte packets instead of 64, which sped things up by a factor of 8... But this is not general purpose, but I have seen posts of others who have implemented downloading that way.

Sorry, I know not much help.

Good luck
 
Back
Top