Teensyduino File System Integration, including MTP and MSC

Personally I would only send one device reset event, after you have changed the file or file(s).
What it does is it tells the host to end the current session, the host will send MTP a new begin session, at which point the teensy code will remove our cache information...

It is sort of the sledgehammer approach. There are some more delicate solutions, like addobject...
Code:
  // Send a device reset event, when processed by the host
  // they will start a new session, at which point we will
  // clear our file system store file as the object ids are
  // only valid during  a sesion. 

  int send_DeviceResetEvent(void);

  // Send an event telling the host, that we added another storeage
  // to our list.  Example:  USBHost detects a new USB device has
  // been inserted, and we wish to show the new filesystem(s)
  int send_StoreAddedEvent(uint32_t store);


  // Send an event telling the host, that a file system is no longer
  // available and for the host to remove it from their list. 
  int send_StoreRemovedEvent(uint32_t store);

  // higer level version of sending events
  // unclear if should pass in pfs or store?
  bool send_addObjectEvent(uint32_t store, const char *pathname);
  bool send_removeObjectEvent(uint32_t store, const char *pathname);
Which take more understanding of the objects and the like, and not all MTP implementations, implement them... So for example it may work for Windows, but may not work on a MAC.
 
Kurt:
This is the way that I have done it currently:

Code:
if (currentTime[2] == 0)  // Seconds = zero.
                        {
                            if (currentTime[1] == 0)  // Minutes = zero.
                                {
                                    if (currentTime[0] == 0)  // Hours = zero, It is Midnight 00:00:00.
                                        {
                                            itsMidnight = true;  // The clock has just struck midnight.

                                            #if defined(DEBUG_LOOP_MIDNIGHT_TIME)
                                                Serial.println(F("\nMain Loop - Now stopping the logging of data and moving the Environmental data file to SD Card..."));      
                                            #endif

                                            stopLoggingDataToRamDisk();  // This stops the logging and closes the existing data file.

                                            if(!copyDataFileFromRAMDiskToSDCard(FileNameChars, SDDataDirectory, FileNameChars))  // This moves the data file to the SD Card, the source file name and destination file name are the same.
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Error - Copying data file to SD Card from RAMDISK...\n"));
                                                    #endif
                                                }
                                            else
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Copying data file to SD Card from RAMDISK was successful...\n"));
                                                    #endif
                                                }
                        

                                            #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                Serial.println(F("Now creating a new Environmental data file in QSPI-RAM...\n"));                                            
                                            #endif

                                            if(!createNewDataFileAndStartLogging())  // This creates the new data file and begins logging again.
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Error - Creating new data file to log data...\n"));
                                                    #endif
                                                }
                                            else
                                                {
                                                    MTP.send_DeviceResetEvent();  // Make sure the MTP system updates the new file name and file copied to the SD Card.
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Creating new data file was successful...\n"));                                            
                                                    #endif
                                                }

                                            //insideDailyHighTemp = sensorState.Temperature;  // Set inside Daily High Temp to ambient at midnight.
                                            //insideDailyLowTemp = sensorState.Temperature;  // Set inside Daily Low Temp to ambient at midnight.
                        
                                            //outsideDailyHighTemp = WeatherDataStruct.Temperature;  // Set outside Daily High Temp to ambient at midnight.
                                            //outsideDailyLowTemp = WeatherDataStruct.Temperature;  // Set outside Daily Low Temp to ambient at midnight.
                                        }
                                }
                        }

As you can see I did it the way you suggested, however this does not work. It does not see the most recent changes to the two mounted volumes.

I was considering using the "send_removeObjectEvent()" and the "send_addObjectEvent()" but I cannot figure out how to use them on my own, and I have not found any detailed use of these functions in any of the examples.

Thanks,
Ed
 
@KurtE - @sbfreddie

Not sure this is still an open issue but decided to play a bit and see if I was having the same issue. So I picked up a BME688 put together a MTP sketch that does three things.

1. Reads data from the BME688 every 5 seconds (sorry don't have all night) using the RTC - I could have used intervaltimer for this but was curious for a total of 10 readings.
2. When it completes it automatically stops logging data
3. Manually you run a copy command to copy the data from program flash to a SD Card.

Basically you start the sketch by typing the 's' command to start logging then when it completes you type the 'c' command to copy the file to the SD Card. NOTE: Make sure you delete the files when you get done - didn't put anything in the test sketch to do that. If you have the SD Card directory open you do need to hit the refresh button in windows dirctory but it works.

Note. At first I was having the same issue as you - after copying the file to the sd card it wouldn't appear unless i restarted the Teensy. To get around that added the MTP.send_DeviceResetEvent(); and then was able to see it.

I am attaching the sketch if you want to take a look.View attachment bme680test.ino

Here is a test session
1. Send the start logging command
Code:
Add **SDClass** file system
BME680/Prog/SD Logger test
RTC has set the system time
&&&&& Dump MTPStorage Loop Data &&&&&
	Callback Data:		0	0x0	0
		1	0xb989	1
		2	0x0	0
		3	0x0	0
		4	0x0	0
	File Systems:
		0	0x2000684c	0
		1	0x200069a4	1

Logging Data!!!
18:25:40 3 4 2023
Second: 40, Old: 0
Second: 40, Old: 0
18:25:40 3 4 2023
Second: 40, Old: 0
18:25:40 3 4 2023
...
...
18:27:29 3 4 2023
Second: 30, Old: 20
Record Count: 10

Stopped Logging Data!!!
Records written = 10
18:27:30 3 4 2023
Capture0.PNG

2. send the copy command:
Code:
Copy File on Flash to SD Card
Files Writing
Record Number: 1, BytesWritten: 2036
Files Closed
before refreshing - notice the file LITF.txt is not there, this is copied data file.
Capture1.PNG
after refreshing - notice that the LITF.txt is there
Capture2.PNG

think I will work on the sketch some more just for the fun of it
 
mjs513:
I use a very similar approach to yours, accept that I use real time data from 3 sensors for twenty four hours at ten second intervals. The file is approx. 700Kbytes per day. You do the close and MTP.send_DeviceResetEvent(); in the same subroutine, where I first do the close, copy, and reopen/rename subs and then do the MTP.send_DeviceResetEvent() in the calling section in the Main loop, it looks like this:

Code:
if (currentTime[2] == 0)  // Seconds = zero.
                        {
                            if (currentTime[1] == 0)  // Minutes = zero.
                                {
                                    if (currentTime[0] == 0)  // Hours = zero, It is Midnight 00:00:00.
                                        {
                                            itsMidnight = true;  // The clock has just struck midnight.

                                            #if defined(DEBUG_LOOP_MIDNIGHT_TIME)
                                                Serial.println(F("\nMain Loop - Now stopping the logging of data and moving the Environmental data file to SD Card..."));      
                                            #endif

                                            stopLoggingDataToRamDisk();  // This stops the logging and closes the existing data file.

                                            if(!copyDataFileFromRAMDiskToSDCard(FileNameChars, SDDataDirectory, FileNameChars))  // This moves the data file to the SD Card, the source file name and destination file name are the same.
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Error - Copying data file to SD Card from RAMDISK...\n"));
                                                    #endif
                                                }
                                            else
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Copying data file to SD Card from RAMDISK was successful...\n"));
                                                    #endif
                                                }
                        

                                            #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                Serial.println(F("Now creating a new Environmental data file in QSPI-RAM...\n"));                                            
                                            #endif

                                            if(!createNewDataFileAndStartLogging())  // This creates the new data file and begins logging again.
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Error - Creating new data file to log data...\n"));
                                                    #endif
                                                }
                                            else
                                                {
                                                    MTP.send_DeviceResetEvent();  // Make sure the MTP system updates the new file name and file copied to the SD Card.
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Creating new data file was successful...\n"));                                            
                                                    #endif
                                                }

                                            //insideDailyHighTemp = sensorState.Temperature;  // Set inside Daily High Temp to ambient at midnight.
                                            //insideDailyLowTemp = sensorState.Temperature;  // Set inside Daily Low Temp to ambient at midnight.
                        
                                            //outsideDailyHighTemp = WeatherDataStruct.Temperature;  // Set outside Daily High Temp to ambient at midnight.
                                            //outsideDailyLowTemp = WeatherDataStruct.Temperature;  // Set outside Daily Low Temp to ambient at midnight.
                                        }
                                }
                        }

It does not make any difference, although the files are actually there and working they do not show up in the Mac's finder using Macdroid (this app checks for changes every 20 seconds which is an option that can be changed). I have even tried unmounting and remounting the volume on the Mac desktop, but that makes no difference.

There is another free MTP app I have that I have not tried called openMTP, perhaps I will try that when I have time.

Thanks,
Ed
 
mjs513:
I use a very similar approach to yours, accept that I use real time data from 3 sensors for twenty four hours at ten second intervals. The file is approx. 700Kbytes per day. You do the close and MTP.send_DeviceResetEvent(); in the same subroutine, where I first do the close, copy, and reopen/rename subs and then do the MTP.send_DeviceResetEvent() in the calling section in the Main loop, it looks like this:
...

It does not make any difference, although the files are actually there and working they do not show up in the Mac's finder using Macdroid (this app checks for changes every 20 seconds which is an option that can be changed). I have even tried unmounting and remounting the volume on the Mac desktop, but that makes no difference.

There is another free MTP app I have that I have not tried called openMTP, perhaps I will try that when I have time.

Thanks,
Ed

Ok had a chance to get back to this and tried to incorporate your approach with my setup just for testing purposes. Basically logging every minute until the next hour is reach. Here is the sketch:
Code:
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"

#include <TimeLib.h>
int hour_old;
int current_time[3];
#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO,  BME_SCK);


#include "SD.h"
#include <MTP_Teensy.h>

SDClass sd;
#define CS_SD BUILTIN_SDCARD
#define SPI_SPEED SD_SCK_MHZ(16) // adjust to sd card

File myFile, dataFile;
int iRecord = 0;
int line = 0;

#define BUFFER_SIZE_INDEX 128
uint8_t write_buffer[BUFFER_SIZE_INDEX];
#define buffer_mult 16
uint8_t buffer_temp[buffer_mult*BUFFER_SIZE_INDEX];

int bytesRead;

int record_count = 0;
bool write_data = false;
uint32_t diskSize;

#include <LittleFS.h>
LittleFS_Program lfsProg; // Used to create FS on the Flash memory of the chip

FS *myfs = &lfsProg; // current default FS...

static const uint32_t file_system_size = 1024 * 1024 * 1;

void setup() {
  while (!Serial && millis() < 5000) {}

  if (CrashReport) {
    Serial.print(CrashReport);
  }
  
  delay(2000);
  MTP.begin();  
  
  // Lets add the Program memory version:
  // checks that the LittFS program has started with the disk size specified
  if (lfsProg.begin(file_system_size)) {
    MTP.addFilesystem(lfsProg, "Program");
  } else {
    Serial.println("Error starting Program Flash storage");
  }
  
  // Lets add SD Card
  if (sd.begin(CS_SD)) {
    MTP.addFilesystem(sd, "SD");
  }

  
  Serial.println(F("BME680/Prog/SD Logger test"));
  
  // set the Time library to use Teensy 3.0's RTC to keep time
  setSyncProvider(getTeensy3Time);
  hour_old = hour();
  delay(100);
  
  if (timeStatus()!= timeSet) {
    Serial.println("Unable to sync with the RTC");
  } else {
    Serial.println("RTC has set the system time");
  }
  if (!bme.begin()) {
    Serial.println("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }

  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
}

void loop() {

  if ( Serial.available() ) {
    uint8_t command = Serial.read();
    int ch = Serial.read();
    while (ch == ' ') ch = Serial.read();

    switch (command) {
    case 't':
    {
      if (Serial.available()) {
        time_t t = processSyncMessage();
        if (t != 0) {
          Teensy3Clock.set(t); // set the RTC
          setTime(t);
        }
      }
    }
	  break;
    case 's':
    {
      Serial.println("\nLogging Data!!!");
      write_data = true;   // sets flag to continue to write data until new command is received
      // opens a file or creates a file if not present,  FILE_WRITE will append data to
      // to the file created.
      dataFile = myfs->open("datalog.txt", FILE_WRITE_BEGIN);
      digitalClockDisplay();
      hour_old = minute();
      logData();
    }
      break;
	  case 'x': stopLogging(); break;
    case 'd': dumpLog(); break;
    case 'c': copyProg2SD(); break;
    case '\r':
    case '\n':
    case 'h': menu(); break;
    }
    while (Serial.read() != -1) ; // remove rest of characters.
  } else {
    MTP.loop();
  }

  if (write_data) {
    logData();
    //delay(500);
  }

}

/* **************************************************
 * BME Functions
 ****************************************************/
void logData()
{
  String dataString = "";
  //Serial.printf("Minute: %d, Old: %d\n", minute(), hour_old);
  if((minute()-hour_old) == 1 || minute() == 0) {    
    hour_old = minute();
    digitalClockDisplay();
    if (! bme.performReading()) {
      Serial.println("Failed to perform reading :(");
      //myfs.printf("%f, %f, %f, %f, %f\n", 0, 0, 0, 0 );
      dataString = String(hour()) + ", " + String(minute()) + ", " + String(second()) +", " ;
      dataString += String(day()) + ", " + String(month()) + ", " + String(year());
      dataString += ", 0, 0, 0, 0, 0";
	    dataFile.println(dataString);
      record_count += 1;
      Serial.printf("Record Count: %d\n", record_count);
      return;
    }
	  //myfs.printf("%f, %f, %f, %f, %f\n", bme.temperature,bme.pressure / 100.0, bme.humidity,bme.gas_resistance / 1000.0, bme.readAltitude(SEALEVELPRESSURE_HPA));
      dataString = String(hour()) + ", " + String(minute()) + ", " + String(second()) +", " ;
      dataString += String(day()) + ", " + String(month()) + ", " + String(year()); 
	    dataString += ", ";
	    dataString += String(bme.temperature) + ", ";
	    dataString += String(bme.pressure / 100.0) + ", ";
	    dataString += String(bme.humidity) + ", ";
	    dataString += String(bme.gas_resistance / 1000.0) + ", ";
	    dataString += String(bme.readAltitude(SEALEVELPRESSURE_HPA));
      dataFile.println(dataString);
      record_count += 1;
      Serial.printf("Record Count: %d\n", record_count);
  }
  //if(record_count == 10) stopLogging();
  
  checkLogging();
}

void stopLogging()
{
  Serial.println("\nStopped Logging Data!!!");
  write_data = false;
  // Closes the data file.
  dataFile.close();
  Serial.printf("Records written = %d\n", record_count);
  //MTP.send_DeviceResetEvent();
}


/* **************************************************
 * RTC Functions
 ****************************************************/

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

/*  code to process time sync messages from the serial port   */
#define TIME_HEADER  "T"   // Header tag for serial time sync message

unsigned long processSyncMessage() {
  unsigned long pctime = 0L;
  const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 

  if(Serial.find(TIME_HEADER)) {
     pctime = Serial.parseInt();
     return pctime;
     if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
       pctime = 0L; // return 0 to indicate that the time is not valid
     }
  }
  return pctime;
}

void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}


void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void menu()
{
  Serial.println();
  Serial.println("Menu Options:");
  Serial.println("\ts - Start Logging data (Restarting logger will append records to existing log)");
  Serial.println("\tx - Stop Logging data");
  Serial.println("\td - Dump Log");
  Serial.println("\tc - Copy datafile to SD Card");

  Serial.println("\th - Menu");
  Serial.println();
}

uint8_t copyProg2SD()
{
  // open the file on SD Card.
  Serial.println("Copy File on Flash to SD Card");
  dataFile = myfs->open("datalog.txt", FILE_READ);
  
  //open file on flash
  myFile = sd.open("LITF.txt", FILE_WRITE_BEGIN);
  
  if(!dataFile || !myFile) return 0;
  //dataFile.truncate();
  if (dataFile) {
    Serial.println("Files Writing");
    while (dataFile.available()) {
        memset(write_buffer, 0, sizeof(write_buffer));
        memset(buffer_temp, 0, sizeof(buffer_temp));
		    uint16_t byteCount = 0;
        for(uint8_t i=0; i < buffer_mult; i++) {
          bytesRead = dataFile.read(write_buffer, line? BUFFER_SIZE_INDEX : BUFFER_SIZE_INDEX-12); 
          if(bytesRead > 0) {
            for(int j = 0; j < (line? BUFFER_SIZE_INDEX : BUFFER_SIZE_INDEX-12); j++) {
              buffer_temp[byteCount+j] = write_buffer[j];
            }
          }
      byteCount += (line? BUFFER_SIZE_INDEX : BUFFER_SIZE_INDEX-12);
      line += 1;
        }
        myFile.write((void *)buffer_temp, byteCount);
        
        iRecord += 1;
        Serial.printf("Record Number: %d, BytesWritten: %d\n", iRecord, byteCount);
        if(bytesRead < 0) break;
      }  // if the file isn't open, pop up an error:
  }
  myFile.close();
  dataFile.close();
  Serial.println("Files Closed");
  
  //MTP.send_DeviceResetEvent();
  
  return 1;
}

void dumpLog()
{
  Serial.println("\nDumping Log!!!");
  // open the file.
  dataFile = myfs->open("datalog.txt");

  // if the file is available, write to it:
  if (dataFile) {
    while (dataFile.available()) {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}

bool itsMidnight = false;
#define DEBUG_LOOP_MIDNIGHT_TIME
void checkLogging()
{
if (second() == 0)  // Seconds = zero.
                        {
                            if (minute() == 0)  // Minutes = zero.
                                {
                                    if (hour() == 17)  // Hours = zero, It is Midnight 00:00:00.
                                        {
                                            itsMidnight = true;  // The clock has just struck midnight.

                                            #if defined(DEBUG_LOOP_MIDNIGHT_TIME)
                                                Serial.println(F("\nMain Loop - Now stopping the logging of data and moving the Environmental data file to SD Card..."));      
                                            #endif

                                            //stopLoggingDataToRamDisk();  // This stops the logging and closes the existing data file.
											stopLogging();
											
                                            //if(!copyDataFileFromRAMDiskToSDCard(FileNameChars, SDDataDirectory, FileNameChars))  // This moves the data file to the SD Card, the source file name and destination file name are the same.
											if(!copyProg2SD())
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Error - Copying data file to SD Card from RAMDISK...\n"));
                                                    #endif
                                                }
                                            else
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Copying data file to SD Card from RAMDISK was successful...\n"));
                                                    #endif
                                                }
                        

                                            #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                Serial.println(F("Now creating a new Environmental data file in QSPI-RAM...\n"));                                            
                                            #endif

                                            if(!createNewDataFileAndStartLogging())  // This creates the new data file and begins logging again.
                                                {
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Error - Creating new data file to log data...\n"));
                                                    #endif
                                                }
                                            else
                                                {
                                                    MTP.send_DeviceResetEvent();  // Make sure the MTP system updates the new file name and file copied to the SD Card.
                                                    #if defined(DEBUG_LOOP_MIDNIGHT_TIME )
                                                        Serial.println(F("Creating new data file was successful...\n"));                                            
                                                    #endif
                                                }

                                            //insideDailyHighTemp = sensorState.Temperature;  // Set inside Daily High Temp to ambient at midnight.
                                            //insideDailyLowTemp = sensorState.Temperature;  // Set inside Daily Low Temp to ambient at midnight.
                        
                                            //outsideDailyHighTemp = WeatherDataStruct.Temperature;  // Set outside Daily High Temp to ambient at midnight.
                                            //outsideDailyLowTemp = WeatherDataStruct.Temperature;  // Set outside Daily Low Temp to ambient at midnight.
                                        }
                                }
                        }
}

uint8_t createNewDataFileAndStartLogging() 
{
  myfs->remove("datalog.txt");
  return 1;
	
}
Still seeing the file on the SD card when it completes transferring. Let me know how you think I should change the sketch. Maybe it the MAC app you are using. I am running on a Windows machine so that is the only other variable.
 
Mjs513:
I do not not see any major difference in the way that you are doing this than I am. Accept that my program logs a lot more data than just the BME280 stuff.
It must be the different implementation on the Mac than the PC. Since this is a Windows only protocol (MTP) it does not surprise me that it works differently on Windows than it does on the Mac.
Probably some nuance about MTP that has not been implemented in Macdroid.

Thanks,
Ed
 
Mjs513:
I do not not see any major difference in the way that you are doing this than I am. Accept that my program logs a lot more data than just the BME280 stuff.
It must be the different implementation on the Mac than the PC. Since this is a Windows only protocol (MTP) it does not surprise me that it works differently on Windows than it does on the Mac.
Probably some nuance about MTP that has not been implemented in Macdroid.

Thanks,
Ed

You had mentioned trying a different MAC app for MTP and I think @KurtE mentioned one as well. Maybe if you have time to play around with it you can check out one of the other MTP implementations. Good luck
 
Hi all,

I have a small problem with MTP and hoping for some guidance...

I'm using a Teensy 4.1 as a data-logger using the in-built SD card. After the datalogging has concluded, I would like the the SD card to appear in Windows Explorer. The Teensy is always connected to the PC via USB. I do not want the SD card to appear in Windows Explorer during logging, because if it is accidentally clicked in Explorer during logging, it slows the datalogger down (tested).

I'm using the MTP_Teensy library and the Example_3_SD.ino outline in MTP, MSC, USB, SD, LittleFS.. what do I use and how?, withTeensyduino 1.59 and Arduino IDE 1.8.13, MTP Disk (Experimental).

If I place

Code:
  MTP.addFilesystem(SD, "SD Card", MTP_FSTYPE_SD);
  MTP.begin();

after the datalogging part of the program, the SD card only appears in Windows Explorer after datalogging if the datalogging period is less than about 30 seconds. If the datalogging period is longer than 30 seconds, I have to disconnect and reconnect the USB for it to appear in Windows Explorer. The logged file size at that point is about 1 MB.

If I place the same code right after I call SD.begin(CS_SD), effectively at the start of the program, the SD card appears in Windows Explorer during logging (which is not what I want) but it does cope reliably with longer data logging durations--tested up to 180 seconds.

I've tried a couple of things but with no joy:
  1. added send_DeviceResetEvent(); before calling MTP.addFilesystem
  2. searched for timeouts within MTP_Teensy.h/.cpp. There is an const uint32_t EVENT_TIMEOUT = 60, which I changed to 1000000, but that did not make a difference
  3. before calling MTP.addFilesystem, close the current SD file, then begin and open a new SD file.
On an old project using a Teensy 3.5, I solved this problem using hardware - I pulled down D+ in the USB to ground after logging had concluded, which reliably made the SD card appear in windows explorer. Rather not go down that route again (unless there is a way of doing something with D+ via software?)

Any pointers much appreciated.

P.S. thank you @KurtE for making the simplified example very accessible.


UPDATE #1365 had the answer - thank you @VictorFS! I should have looked one page back on the thread :oops:
 
Last edited:
similar to what you figured out, my applications make sure that at the beginning that MTP is initiated by host but during data acquisition mtp.loop() is NOT called inhibiting responses to PC requests. After acquisition, MTP is reset (either by sending a reset event, or by resetting the USB). IMO, resetting(stop/restart) USB is the best way as it always reinitializes USB (including MTP)
 
Back
Top