LittleFS port to Teensy/SPIFlash

@KurtE - @defragster -@PaulStoffregen

Just pushed a change up to the repository for W25N01G NAND flash to support Bad Block Management. I brought it to the point of actually writing the Table. A little reluctant to do that until I can test the logic. May have to write a test sketch just for that purpose.

Anyway what I did was I reserved 24 blocks on the N01 for BBM and then copied the lowlevelformat function and moded so it would erase the blocks as specified by the config structure the added the additional block erases for the reserved area. Probably have to do something with quickformat as well but for now its a start.

Didn't add support for the M02 as it looks like it can have 2 BBM areas, 1 for each die - definitely adds alot more complication. Not sure want to keep supporting this one :) - just lazy but will figure it out. As for the N02 - there is no remapping identified to support BBM which is kind of strange - wondering if its a omission in the ref manual or not.

Probably going to just post an issue on the LittleFS repository just for status for Paul to eventual take a look at and do his magic. But at least it works for the most part
 
Last edited:
First the W25Q16JV-DTR is a NOR Flash chip, yes I know that the datasheet is silent on it but if you do a searching you will find that Mouser and Winbond shows it as a NOR flash. Second if you don't include the "LittleFS.h" you won't be using that library in you sketch and you won't be using a FileSystem with that flash chip. You can continue to use SPIMemory in your sketch.

Hope this answers your question?

In your prior post you mentioned using SPI2, unfortunately you can't really use it for Serial Flash chips using the underside pins unless you are breaking the connections out to a castellated board or in some other manner. Those underside pins for the PSRAM and FLASH are really meant to be used for QSPI access.

Hmm, I've been testing this for a couple of days using LFSintegrity-PlusNAND library. It seems to work well enough for my purposes, but after rereading your statement about SPI2 it started me thinking. I my case I have a custom carrier board with Teensy4.1 and prop-shield both incorporated (long header goes through my board with teensy on one side and propshield on the other). Carrier board has extra power supplies and interfaces to instruments for my boat and a raspberry pi 4b, displays, a few buttons, etc.

I have a psram and a winbond nor flash on the back of the teensy.
I did a test with both
LittleFS_SPIFlash myfs;
and then
LittleFS_QSPIFlash myfs;

Now I'm wondering if it was using the flash on the propshield in the first case, and the flash on the teensy board in the second case?
 
Last edited:
Well I just confirmed my own suspicion.
It appears when I do
LittleFS_SPIFlash myfs
vs.
LittleFS_QSPIFlash myfs;
I am indeed talking to different flash chips, I think the first case is the one on the propshield. (I was wondering how I could access both when the latter class removed the chipselect argument from the begin() function.)
 
Well I just confirmed my own suspicion.
It appears when I do
LittleFS_SPIFlash myfs
vs.
LittleFS_QSPIFlash myfs;
I am indeed talking to different flash chips, I think the first case is the one on the propshield. (I was wondering how I could access both when the latter class removed the chipselect argument from the begin() function.)

Look at the LFSintegrity sketch - it has #ifdef for all the known MEDIA types:
Code:
//#define TEST_RAM [B]// can be PSRAM or smaller in processor RAM1 or RAM2[/B]
//#define TEST_SPI [B]// this is Propshield or other SPI based media - where the "FlashChipSelect" is passed[/B]
//#define TEST_QSPI [B]// this is T_4.1 underside QSPI FLASH[/B]
//#define TEST_SPI_NAND [B]// this is a NAND device SPI based media - where the "FlashChipSelect" is passed[/B]
#define TEST_QSPI_NAND [B]// this is T_4.1 underside QSPI NAND device FLASH[/B]
//#define TEST_PROG [B]// this uses PCB onboard FLASH - tested with T_4.x : it is currently erase on every code upload, but static across restarts[/B]
//#define TEST_MRAM [B]// this is a supported SPI MRAM/FRAM chip - where the "FlashChipSelect" is passed[/B]

It only tests 1 at a time - where this code keys off those #define values and always presents "myfs" to the sketch.

There are MTP samples on another thread where ALL available types are Mounted and shares over USB - that just takes using one instance of "myfs" for one and perhaps "myfs2" for the other - names of your choice replacing below for one:
Code:
#ifdef TEST_RAM
LittleFS_RAM myfs;
// RUNTIME :: extern "C" uint8_t external_psram_size;
EXTMEM char buf[MYPSRAM * 1024 * 1024];	// USE DMAMEM for more memory than ITCM allows - or remove
//DMAMEM char buf[490000];	// USE DMAMEM for more memory than ITCM allows - or remove
char szDiskMem[] = "RAM_DISK";
#elif defined(TEST_SPI)
//const int FlashChipSelect = 10; // Arduino 101 built-in SPI Flash
#define FORMATSPI
//#define FORMATSPI2
LittleFS_SPIFlash myfs;
char szDiskMem[] = "SPI_DISK";
#elif defined(TEST_MRAM)
//const int FlashChipSelect = 10; // Arduino 101 built-in SPI Flash
LittleFS_SPIFram myfs;
char szDiskMem[] = "FRAM_DISK";
#elif defined(TEST_PROG)
LittleFS_Program myfs;
char szDiskMem[] = "PRO_DISK";
#elif defined(TEST_QSPI_NAND)
char szDiskMem[] = "QSPI_NAND";
LittleFS_QPINAND myfs;
#elif defined(TEST_SPI_NAND)
char szDiskMem[] = "SPI_NAND";
LittleFS_SPINAND myfs;
#else // TEST_QSPI
LittleFS_QSPIFlash myfs;
char szDiskMem[] = "QSPI_DISK";

#endif
 
@KurtE = @defragster
Just pushed an update to plusNAND to bring LittleFS even with what I have updated for NAND. In the READ_BCC test case I added a quick test of the addbblut function - I think I got it working correctly now but reluctant to turn it on yet with out some further use cases to abuse it - have to find that crazy data logger that @defragster was playing with :)

I also updated the PR to add the same examples that are in LFSIntegriy as well as the update to addBBLUT - this was a result of me playing with it this morning.
 
Good work @mjs513 - I typed on github asking about that ... but never hit post I saw today ... too many distractions ...

Wish I had known about the 2Gb NAND digikey had with last order so I don't have one of any sort to QSPI test yet ...
 
@defragster - @KurtE
Decided to try to modify the MTP_logger example to work with the selected device for logging data. I tested SD, SPI, QSPI, and SPI NAND which all worked without an issue. However, when I tried QSPI NAND ran into a problem. It would see the device but couldn't read anything on the NAND especially the index.dat file. Not sure what I am doing wrong. Just to be clean you can only use 1 device at a time to log to in this version!

Noticed a couple of other things I have to figure out:
1. MTP Serial is throwing errors from SDFAT when I select it
2. Have to figure out where to put the test for events - otherwise if i hit q it doesn't stop logging :) Think I am just tired at this point. Anyway if you want to play along:
Code:
#include "Arduino.h"

#define NDAT 128L
#define NCH_ACQ 1
#define NCH_I2S 4
#define NBUF_ACQ (NCH_ACQ*NDAT)
#define NBUF_I2S (NCH_I2S*NDAT)
#define N_ADC 2
#define FRAME_I2S (NCH_I2S/N_ADC)

#define I2S_CONFIG 1
// CONFIG 1 (PURE RX)
//PIN  36 BCLK
//PIN  37 FS
//PIN  13 RXD0
//PIN  38 RXD1

#include "SD.h"
#include "MTP.h"

#if defined(__IMXRT1062__)
  // following only while usb_mtp is not included in cores
  #if __has_include("usb_mtp.h")
    #include "usb_mtp.h"
  #else
    #include "usb1_mtp.h"
  #endif
#endif

#define USE_SD  0
#define USE_LITTLEFS 1 // set to zero if no LtttleFS is existing or to be used

#if USE_LITTLEFS==1
  #include "LittleFS.h"
  #include "LittleFS_NAND.h"
#ifdef ARDUINO_TEENSY41
  #define USE_RAM 0     // T4.1 PSRAM (or RAM)
#else
  #define USE_RAM 0     // T4.1 PSRAM (or RAM)
#endif
  #define USE_SPI 0
  #define USE_QSPI 1
  #define USE_NAND 0
  #define USE_QSPI_NAND 0
  #define USE_FRAM 0
#endif

#if USE_EVENTS==1
  extern "C" int usb_init_events(void);
#else
  int usb_init_events(void) {}
#endif


#if defined(__IMXRT1062__)
  // following only as long usb_mtp is not included in cores
  #if !__has_include("usb_mtp.h")
    #include "usb1_mtp.h"
  #endif
#else
  #ifndef BUILTIN_SCCARD 
    #define BUILTIN_SDCARD 254
  #endif
  void usb_mtp_configure(void) {}
#endif

/****  Start device specific change area  ****/
#if USE_SD==1
  // edit SPI to reflect your configuration (following is for T4.1)
  #define SD_MOSI 11
  #define SD_MISO 12
  #define SD_SCK  13

  #define stor_SPEED SD_SCK_MHZ(16)  // adjust to sd card 

// SDClasses
  const char *sd_str[]={"sdio"}; // edit to reflect your configuration
  const int cs[] = {BUILTIN_SDCARD}; // edit to reflect your configuration
  const int nsd = sizeof(cs)/sizeof(int);

SDClass storfs[nsd];
#endif

//LittleFS classes
#if USE_LITTLEFS==1
  #include "LittleFS.h"
  #if USE_RAM == 1
    const char *stor_str[]={"RAM0"};     // edit to reflect your configuration
    const int stor_size[] = {2'000'000};
    const int stor_nsd = sizeof(stor_size)/sizeof(int);
    LittleFS_RAM storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_SPI == 1
    const char *stor_str[]={"WINBOND"};     // edit to reflect your configuration
    const int stor_cs[] = {5}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_FRAM == 1
    const char *stor_str[]={"CYPRESS"};     // edit to reflect your configuration
    const int stor_cs[] = {10}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

  #if USE_NAND == 1
    const char *stor_str[]={"WINBOND1G"};     // edit to reflect your configuration
    const int stor_cs[] = {3}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPINAND storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

  #if USE_QSPI_NAND == 1
    const char *stor_str[]={"WINBOND1G"};     // edit to reflect your configuration
    const int stor_nsd = 1;
    LittleFS_QPINAND storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_QSPI == 1
    const char *stor_str[]={"QSPI0"};     // edit to reflect your configuration
    const int stor_nsd = 1;
    LittleFS_QSPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
 
#endif


MTPStorage_SD storage;
MTPD       mtpd(&storage);


void storage_configure()
{
  #if USE_SD==1
    #if defined SD_SCK
      SPI.setMOSI(SD_MOSI);
      SPI.setMISO(SD_MISO);
      SPI.setSCK(SD_SCK);
    #endif

    for(int ii=0; ii<nsd; ii++)
    { if(cs[ii] == BUILTIN_SDCARD)
      {
        if(!storfs[ii].sdfs.begin(SdioConfig(FIFO_SDIO))) {Serial.println("No storage"); while(1);};
        storage.addFilesystem(storfs[ii], sd_str[ii]);
      }
      else if(cs[ii]<BUILTIN_SDCARD)
      {
        pinMode(cs[ii],OUTPUT); digitalWriteFast(cs[ii],HIGH);
        if(!storfs[ii].sdfs.begin(SdSpiConfig(cs[ii], SHARED_SPI, stor_SPEED))) {Serial.println("No storage"); while(1);}
        storage.addFilesystem(storfs[ii], sd_str[ii]);
      }
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,cs[ii],sd_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
    }
    #endif

     #if USE_LITTLEFS==1
      #if USE_RAM == 1
        for(int ii=0; ii<stor_nsd;ii++)
        {
          { if(!ramfs[ii].begin(stor_size[ii])) { Serial.println("No storage"); while(1);}
            storage.addFilesystem(ramfs[ii], stor_str[ii]);
          }
          uint64_t totalSize = ramfs[ii].totalSize();
          uint64_t usedSize  = ramfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_SPI == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_FRAM == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_NAND == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_QSPI_NAND == 1
       for(int ii=0; ii<stor_nsd;ii++) {
          if(!storfs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
     
          uint64_t totalSize = storfs[ii].totalSize();
          uint64_t usedSize  = storfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_QSPI == 1
       for(int ii=0; ii<stor_nsd;ii++) {
          if(!storfs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
     
          uint64_t totalSize = storfs[ii].totalSize();
          uint64_t usedSize  = storfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif
      
    #endif
}
/****  End of device specific change area  ****/

void logg(uint32_t del, const char *txt);

int16_t state;
int16_t do_logger(uint16_t store, int16_t state);
int16_t do_menu(int16_t state);
int16_t check_filing(int16_t state);

void acq_init(int32_t fsamp);
int16_t acq_check(int16_t state);

void setup()
{ 
  Serial.begin(115200);
  #if defined(USB_MTPDISK_SERIAL) 
    while(!Serial); // comment if you do not want to wait for terminal
  #else
    //while(!Serial.available()); // comment if you do not want to wait for terminal (otherwise press any key to continue)
    while(!Serial.available() && millis() < 5000); // or third option to wait up to 5 seconds and then continue
  #endif
  Serial.println("MTP logger");

  #if !__has_include("usb_mtp.h")
    usb_mtp_configure();
  #endif
  storage_configure();

  acq_init(93750); // is fixed for this example, to be modified below
  state=-1;

  Serial.println("Setup done");
  Serial.println(" Enter s to start acquisition and q to stop acquisition");
  Serial.flush();
}

uint32_t loop_count=0;
void loop()
{ loop_count++;
  state = do_menu(state);
  state = acq_check(state);
  state = check_filing(state);
  //
  if(state<0)
    mtpd.loop();
  else
    state=do_logger(0,state);

  if(state>=0) logg(1000,"loop");
  //asm("wfi"); // may wait forever on T4.x


}

/**************** Online logging *******************************/
extern uint32_t loop_count, acq_count, acq_miss, maxDel;
extern uint16_t maxCount;
void logg(uint32_t del, const char *txt)
{ static uint32_t to;
  if(millis()-to > del)
  {
    Serial.printf("%s: %6d %4d %4d %4d %4d %d\n",
            txt,loop_count, acq_count, acq_miss,maxCount, maxDel,state); 
    loop_count=0;
    acq_count=0;
    acq_miss=0;
    maxCount=0;
    maxDel=0;
    to=millis();
  }
}

/*************************** Circular Buffer ********************/
#if defined ARDUINO_TEENSY41
  #define HAVE_PSRAM 1
#else
  #define HAVE_PSRAM 0
#endif

  #if HAVE_PSRAM==1
    #define MAXBUF (1000) // 3000 kB   // < 5461 for 16 MByte PSRAM

//    extern "C" uint8_t external_psram_size;
//    uint8_t size = external_psram_size;
//    uint32_t *memory_begin = (uint32_t *)(0x70000000);
//    uint32_t *data_buffer = memory_begin;

    uint32_t *data_buffer = (uint32_t *)extmem_malloc(MAXBUF*128*sizeof(uint32_t));
  #else
    #if defined(ARDUINO_TEENSY41)
      #define MAXBUF (46)           // 138 kB
    #elif defined(ARDUINO_TEENSY40)
      #define MAXBUF (46)           // 138 kB
    #elif defined(__MK66FX1M0__)
      #define MAXBUF (46)           // 138 kB
    #elif defined(__MK20DX256__)
      #define MAXBUF (12)           // 36 kB
    #endif
    uint32_t data_buffer[MAXBUF*NBUF_ACQ];
  #endif

static uint16_t front_ = 0, rear_ = 0;
uint16_t getCount () { if(front_ >= rear_) return front_ - rear_; return front_+ MAXBUF -rear_; }
uint16_t maxCount=0;

void resetData(void) {  front_ = 0;  rear_ = 0; }

uint16_t pushData(uint32_t * src)
{ uint16_t f =front_ + 1;
  if(f >= MAXBUF) f=0;
  if(f == rear_) return 0;

  uint32_t *ptr= data_buffer+f*NBUF_ACQ;
  memcpy(ptr,src,NBUF_ACQ*4);
  front_ = f;
  //
  uint16_t count;
  count = (front_ >= rear_) ? (front_ - rear_) : front_+ (MAXBUF -rear_) ;
  if(count>maxCount) maxCount=count;
  //
  return 1;
}

uint16_t pullData(uint32_t * dst, uint32_t ndbl)
{ uint16_t r = (rear_/ndbl) ;
  if(r == (front_/ndbl)) return 0;
  if(++r >= (MAXBUF/ndbl)) r=0;
  uint32_t *ptr= data_buffer + r*ndbl*NBUF_ACQ;
  memcpy(dst,ptr,ndbl*NBUF_ACQ*4);
  rear_ = r*ndbl;
  return 1;
}

/*************************** Filing *****************************/
int16_t file_open(uint16_t store);
int16_t file_writeHeader(void);
int16_t file_writeData(void *diskBuffer, uint32_t ndbl);
int16_t file_close(void);
#define NDBL 1
#define NBUF_DISK (NDBL*NBUF_ACQ)
uint32_t diskBuffer[NBUF_DISK];
uint32_t maxDel=0;

int16_t do_logger(uint16_t store, int16_t state)
{ uint32_t to=millis();
  if(pullData(diskBuffer,NDBL))
  {
    if(state==0)
    { // acquisition is running, need to open file
      if(!file_open(store)) return -2;
      state=1;
    }
    if(state==1)
    { // file just opended, need to write header
      if(!file_writeHeader()) return -3;
      state=2;
      
    }
    if(state>=2)
    { // write data to disk
      if(!file_writeData(diskBuffer,NBUF_DISK*4)) return -4;
    }
  }

  if(state==3)
  { // close file, but continue acquisition
    if(!file_close()) return -5;
    state=0;
  }

  if(state==4)
  { // close file and stop acquisition
    if(!file_close()) return -6;
    state=-1;
  }

  uint32_t dt=millis()-to;
  if(dt>maxDel) maxDel=dt;

  return state;
}

/******************** Menu ***************************/
void do_menu1(void);
void do_menu2(void);
void do_menu3(void);

int16_t do_menu(int16_t state)
{ // check Serial input
  if(!Serial.available()) return state;
  char cc = Serial.read();
  switch(cc)
  {
    case 's': // start acquisition
      if(state>=0) return state;
      state=0;
      Serial.println("\nStart");
      break;
    case 'q': // stop acquisition
      if(state<0) return state;
      state=4;
      Serial.println("\nStop");
      break;
    case '?': // get parameters
      do_menu1();
      break;
    case '!': // set parameters
      if(state>=0) return state;
      do_menu2();
      break;
    case ':': // misc commands
      if(state>=0) return state;
      do_menu3();
      break;
    default:
      break;
  }
  return state;
}

/************ Basic File System Interface *************************/
//#include "SD.h"
//extern SDClass sdx[];
static File mfile;

char header[512];

void makeHeader(char *header);
int16_t makeFilename(char *filename);
int16_t checkPath(uint16_t store, char *filename);

int16_t file_open(uint16_t store)
{ char filename[80];
  if(!makeFilename(filename)) return 0;
  if(!checkPath(store, filename)) return 0;
  mfile = storfs[store].open(filename,FILE_WRITE_BEGIN);
  return !(!mfile);
}

int16_t file_writeHeader(void)
{ if(!mfile) return 0;
  makeHeader(header);
  size_t nb = mfile.write(header,512);
  return (nb==512);
}

int16_t file_writeData(void *diskBuffer, uint32_t nd)
{ if(!mfile) return 0;
  uint32_t nb = mfile.write(diskBuffer,nd);
  return (nb==nd);
}

int16_t file_close(void)
{ mfile.close();
  return (!mfile);
}

/*
 * Custom Implementation
 * 
 */
/************************ some utilities modified from time.cpp ************************/
// leap year calculator expects year argument as years offset from 1970
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )

static  const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; 

void day2date(uint32_t dd, uint32_t *day, uint32_t *month, uint32_t *year)
{
  uint32_t yy= 0;
  uint32_t days = 0;
  while((unsigned)(days += (LEAP_YEAR(yy) ? 366 : 365)) <= dd) {yy++;}
  
  days -= LEAP_YEAR(yy) ? 366 : 365;
  dd  -= days; // now it is days in this year, starting at 0

  uint32_t mm=0;
  uint32_t monthLength=0;
  for (mm=0; mm<12; mm++) 
  {
    monthLength = monthDays[mm];
    if ((mm==1) && (LEAP_YEAR(yy))) monthLength++;
    if (dd >= monthLength) { dd -= monthLength; } else { break; }
  }

  *month =mm + 1;   // jan is month 1  
  *day  = dd + 1;   // day of month
  *year = yy + 1970;
}

void date2day(uint32_t *dd, uint32_t day, uint32_t month, uint32_t year)
{
  day -= 1;
  month -= 1;
  year -= 1970;
  uint32_t dx=0;
  for (uint32_t ii = 0; ii < year; ii++) { dx += LEAP_YEAR(ii)? 366: 365; } 
  for (uint32_t ii = 0; ii < month; ii++)
  {
    dx += monthDays[ii];
    if((ii==2) && (LEAP_YEAR(year))) dx++; // after feb check for leap year
  }
  *dd = dx + day;
}

/************* Menu implementation ******************************/
void do_menu1(void)
{  // get parameters
}
void do_menu2(void)
{  // set parameters
}
void do_menu3(void)
{  // misc commands
}

/****************** File Utilities *****************************/
void makeHeader(char *header)
{
  memset(header,0,512);
}

int16_t makeFilename(char *filename)
{
  uint32_t tt = rtc_get();
  int hh,mm,ss;
  int dd;
  ss= tt % 60; tt /= 60;
  mm= tt % 60; tt /= 60;
  hh= tt % 24; tt /= 24;
  dd= tt;
  sprintf(filename,"/%d/%02d_%02d_%02d.raw",dd,hh,mm,ss);
  Serial.println(filename);
  return 1;
}

int16_t checkPath(uint16_t store, char *filename)
{
  int ln=strlen(filename);
  int i1=-1;
  for(int ii=0;ii<ln;ii++) if(filename[ii]=='/') i1=ii;
  if(i1<0) return 1; // no path
  filename[i1]=0;
  if(!storfs[store].exists(filename))
  { Serial.println(filename); 
    if(!storfs[store].mkdir(filename)) return 0;
  }

  filename[i1]='/';
  return 1;
}

uint32_t t_on = 60;
int16_t check_filing(int16_t state)
{
  static uint32_t to;
  if(state==2)
  {
    uint32_t tt = rtc_get();
    uint32_t dt = tt % t_on;
    if(dt<to) state = 3;
    to = dt;
  }
  return state;
}

/****************** Data Acquisition *******************************************/
#define DO_TEST 1
#define DO_I2S 2
#define DO_ACQ DO_TEST

#if DO_ACQ==DO_TEST
  /****************** Intervall timer(dummy example) *****************************/
  #include "IntervalTimer.h"

  IntervalTimer t1;

  static uint32_t acq_buffer[NBUF_ACQ];

  uint32_t acq_period=1000;
  int16_t acq_state=-1;
  void acq_isr(void);

  void acq_init(int32_t fsamp)
  { acq_period=128'000'000/fsamp;
    acq_state=0;
  }

  void acq_start(void)
  { if(acq_state) return;
    resetData();
    t1.begin(acq_isr, acq_period);
    acq_state=1;
  }

  void acq_stop(void)
  { if(acq_state<=0) return;
    t1.end();
    acq_state=0;
  }

  uint32_t acq_count=0;
  uint32_t acq_miss=0;

  void acq_isr(void)
  { acq_count++;
    for(int jj=0;jj<NCH_ACQ;jj++)
    {
      for(int ii=0; ii<NBUF_ACQ;ii++)
      {
        acq_buffer[jj+ii*NCH_ACQ]=acq_count;
      }
    }
    if(!pushData(acq_buffer)) acq_miss++;
  }

  int16_t acq_check(int16_t state)
  { if(!state)
    { // start acquisition
      acq_start();
    }
    if(state>3)
    { // stop acquisition
      acq_stop();
    }
    return state;
  }
#else
// try I2S (not working yet)
  static uint32_t tdm_rx_buffer[2*NBUF_I2S];
  static uint32_t acq_rx_buffer[NBUF_ACQ];
  #define I2S_DMA_PRIO 6

  #include "DMAChannel.h"
  DMAChannel dma;

  void acq_isr(void);

  #if defined(__MK66FX1M0__)
  //Teensy 3.6
      #define MCLK_SRC  3
      #define MCLK_SCALE 1

    // set MCLK to 48 MHz or a integer fraction (MCLK_SCALE) of it 
    // MCLK_MULT is set to 1 or 2 to minimize jitter
    // this reduces the possibilities for sampling frequencies

    #if (F_PLL == 96000000) //PLL is 96 MHz for F_CPU==48 or F_CPU==96 MHz
        #define MCLK_MULT 1 
        #define MCLK_DIV  (2*MCLK_SCALE) 
        //  #define MCLK_DIV  (3*MCLK_SCALE) 
    #elif F_PLL == 120000000
        #define MCLK_MULT 2
        #define MCLK_DIV  (5*MCLK_SCALE)
    #elif F_PLL == 144000000
        #define MCLK_MULT 1
        #define MCLK_DIV  (3*MCLK_SCALE)
    #elif F_PLL == 192000000
        #define MCLK_MULT 1
        #define MCLK_DIV  (4*MCLK_SCALE)
    #elif F_PLL == 240000000
        #define MCLK_MULT 1
        #define MCLK_DIV  (5*MCLK_SCALE)
    #else
        #error "set F_CPU to (48, 96, 120, 144, 192, 240) MHz"
    #endif

#define BIT_DIV 4


    /*
     * estimation of sampling frequency
    MCLK 98 MHz * 1 / 2 = 48 MHz 
  N_ADC =1
  case 0
    nch=8
    Bit clock: 93750*(8*32) = 93750*256 = 24 MHz ->(I2S_RCR2_DIV(0))
  case 1
    nch=4
    Bit clock: 93750*(4*32) = 93750*128 = 12 MHz ->(I2S_RCR2_DIV(1))
  case 2
    nch=2
    Bit clock: 93750*(2*32) = 93750*64 = 6 MHz ->(I2S_RCR2_DIV(3))

  N_ADC =2
  case 3
    nch=4
    Bit clock: 93750*((4/2)*32) = 93750*64 = 6 MHz ->(I2S_RCR2_DIV(3))

  bitclock = fs *( nch*32)/n_adc = f_pll*mckl_mult/mckl_div/(2*bit_div)

  fs=bitclock*((nch/n_adc)*32)

  bitclock= f_pll*mckl_mult/mckl_div/(2*bit_div)
  fs=f_pll*mckl_mult/mckl_div/(2*bit_div)/((nch/n_adc)*32)
*/

    const int32_t fsamp0=(((F_PLL*MCLK_MULT)/MCLK_DIV)/(2*BIT_DIV)/(NCH_I2S*32/N_ADC));


    void acq_init(int32_t fsamp)
    {
        Serial.printf("%d %d\n",fsamp,fsamp0);
        SIM_SCGC6 |= SIM_SCGC6_I2S;
        SIM_SCGC7 |= SIM_SCGC7_DMA;
        SIM_SCGC6 |= SIM_SCGC6_DMAMUX;

/*
P23 PTC2   I2S0_TX_FS (6)
P9  PTC3   I2S0_TX_BCLK (6)
P13 PTC5                    I2S0_RXD0 (4)
P11 PTC6   I2S0_MCLK (6)    I2S0_RX_BCLK (4)
P12 PTC7                    I2S0_RX_FS (4)
P35 PTC8                    I2S0_MCLK (4)
P36 PTC9                    I2S0_RX_BCLK (4)
P37 PTC10                   I2S0_RX_FS (4)
P38 PTC11                   I2S0_RXD1 (4)
*/
        #if I2S_CONFIG==0
//            CORE_PIN39_CONFIG = PORT_PCR_MUX(6);  //pin39, PTA17, I2S0_MCLK
//            CORE_PIN11_CONFIG = PORT_PCR_MUX(4);  //pin11, PTC6,  I2S0_RX_BCLK
//            CORE_PIN12_CONFIG = PORT_PCR_MUX(4);  //pin12, PTC7,  I2S0_RX_FS
//            CORE_PIN13_CONFIG = PORT_PCR_MUX(4);  //pin13, PTC5,  I2S0_RXD0
        #elif I2S_CONFIG==1
            CORE_PIN35_CONFIG = PORT_PCR_MUX(4);   // PTC8,  I2S0_MCLK
            CORE_PIN36_CONFIG = PORT_PCR_MUX(4);   // PTC9,  I2S0_RX_BCLK
            CORE_PIN37_CONFIG = PORT_PCR_MUX(4);   // PTC10, I2S0_RX_FS 
        #elif I2S_CONFIG==2
//            CORE_PIN35_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_SRE | PORT_PCR_DSE;  //pin35, PTC8,   I2S0_MCLK (SLEW rate (SRE)?)
//            CORE_PIN36_CONFIG = PORT_PCR_MUX(4);  //pin36, PTC9,   I2S0_RX_BCLK
//            CORE_PIN37_CONFIG = PORT_PCR_MUX(4);  //pin37, PTC10,  I2S0_RX_FS
//            CORE_PIN27_CONFIG = PORT_PCR_MUX(6);  //pin27, PTA15,  I2S0_RXD0
        #endif

        I2S0_RCSR=0;

        // enable MCLK output // MCLK = INP *((MULT)/(DIV))
        I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));
        while(I2S0_MCR & I2S_MCR_DUF);
        I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
        
        I2S0_RMR=0; // enable receiver mask
        I2S0_RCR1 = I2S_RCR1_RFW(3); 

        I2S0_RCR2 = I2S_RCR2_SYNC(0) 
                    | I2S_RCR2_BCP 
                    | I2S_RCR2_BCD  // Bit clock in master mode
                    | I2S_RCR2_DIV((BIT_DIV-1)); // divides MCLK down to Bitclock (BIT_DIV)*2
                    
        I2S0_RCR4 = I2S_RCR4_FRSZ((FRAME_I2S-1)) 
                    | I2S_RCR4_FSE  // frame sync early
                    | I2S_RCR4_FSD  // Frame sync in master mode
                    | I2S_RCR4_MF;
        
        I2S0_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);


  dma.begin(true); // Allocate the DMA channel first

#if N_ADC==1
          CORE_PIN13_CONFIG = PORT_PCR_MUX(4);  // PTC5,  I2S0_RXD0

          I2S0_RCR3 = I2S_RCR3_RCE;

          dma.TCD->SADDR = &I2S0_RDR0;
          dma.TCD->SOFF = 0;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLNO = 4;
          dma.TCD->SLAST = 0;
#elif N_ADC==2
          CORE_PIN13_CONFIG = PORT_PCR_MUX(4);  // PTC5,  I2S0_RXD0
          CORE_PIN38_CONFIG = PORT_PCR_MUX(4);  // PTC11, I2S0_RXD1

          I2S0_RCR3 = I2S_RCR3_RCE_2CH;

          dma.TCD->SADDR = &I2S0_RDR0;
          dma.TCD->SOFF = 4;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
              DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8) |
              DMA_TCD_NBYTES_MLOFFYES_NBYTES(8);
          dma.TCD->SLAST = -8;
#endif
          dma.TCD->DADDR = tdm_rx_buffer;
          dma.TCD->DOFF = 4;
          dma.TCD->CITER_ELINKNO = NBUF_I2S;
          dma.TCD->DLASTSGA = -sizeof(tdm_rx_buffer);
          dma.TCD->BITER_ELINKNO = NBUF_I2S;
          dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
          dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX);
          dma.enable();

          I2S0_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
          dma.attachInterrupt(acq_isr,I2S_DMA_PRIO*16);	
    }

    void acq_start(void)
    {

    }
    void acq_stop(void)
    {
        
    }

  #elif defined(__IMXRT1062__)
  //Teensy 4.x

    #define IMXRT_CACHE_ENABLED 2 // 0=disabled, 1=WT, 2= WB

    /************************* I2S *************************************************/
    void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL4
      {
          if (!force && (CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_ENABLE)) return;

          CCM_ANALOG_PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_BYPASS | CCM_ANALOG_PLL_AUDIO_ENABLE
                      | CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2) // 2: 1/4; 1: 1/2; 0: 1/1
                      | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(nfact);

          CCM_ANALOG_PLL_AUDIO_NUM   = nmult & CCM_ANALOG_PLL_AUDIO_NUM_MASK;
          CCM_ANALOG_PLL_AUDIO_DENOM = ndiv & CCM_ANALOG_PLL_AUDIO_DENOM_MASK;
          
          CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_POWERDOWN;//Switch on PLL
          while (!(CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK)) {}; //Wait for pll-lock
          
          const int div_post_pll = 1; // other values: 2,4
          CCM_ANALOG_MISC2 &= ~(CCM_ANALOG_MISC2_DIV_MSB | CCM_ANALOG_MISC2_DIV_LSB);
          if(div_post_pll>1) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_LSB;
          if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB;
          
          CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS;   //Disable Bypass
      }

      void acq_init(int32_t fsamp)
      {
          CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);

          // if either transmitter or receiver is enabled, do nothing
          if (I2S1_RCSR & I2S_RCSR_RE) return;
          //PLL:
          int fs = fsamp;
          int ovr = FRAME_I2S*32;
          // PLL between 27*24 = 648MHz und 54*24=1296MHz
          int n1 = 4;                    //4; //SAI prescaler 4 => (n1*n2) = multiple of 4
          int n2 = 1 + (24000000 * 27) / (fs * ovr * n1);
          Serial.printf("fs=%d, n1=%d, n2=%d, %d (>27 && < 54)\r\n", 
                        fs, n1,n2,n1*n2*(fs/1000)*ovr/24000);

          double C = ((double)fs * ovr * n1 * n2) / 24000000;
          int c0 = C;
          int c2 = 10000;
          int c1 = C * c2 - (c0 * c2);
          set_audioClock(c0, c1, c2, true);

          // clear SAI1_CLK register locations
          CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
              | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4

          n1 = n1 / 2; //Double Speed for TDM

          CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
              | CCM_CS1CDR_SAI1_CLK_PRED((n1-1)) // &0x07
              | CCM_CS1CDR_SAI1_CLK_PODF((n2-1)); // &0x3f

          IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
                  | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));	//Select MCLK

          I2S1_RMR = 0;
          I2S1_RCR1 = I2S_RCR1_RFW(4);
          I2S1_RCR2 = I2S_RCR2_SYNC(0) | I2S_TCR2_BCP | I2S_RCR2_MSEL(1)
              | I2S_RCR2_BCD | I2S_RCR2_DIV(0);
          
          I2S1_RCR4 = I2S_RCR4_FRSZ((FRAME_I2S-1)) | I2S_RCR4_SYWD(0) | I2S_RCR4_MF
              | I2S_RCR4_FSE | I2S_RCR4_FSD;
          I2S1_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);

        	CORE_PIN23_CONFIG = 3;  //1:MCLK 
          CORE_PIN21_CONFIG = 3;  //1:RX_BCLK
          CORE_PIN20_CONFIG = 3;  //1:RX_SYNC
#if N_ADC==1
          I2S1_RCR3 = I2S_RCR3_RCE;
          CORE_PIN8_CONFIG  = 3;  //RX_DATA0
          IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2;

          dma.TCD->SADDR = &I2S1_RDR0;
          dma.TCD->SOFF = 0;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLNO = 4;
          dma.TCD->SLAST = 0;
#elif N_ADC==2
          I2S1_RCR3 = I2S_RCR3_RCE_2CH;
          CORE_PIN8_CONFIG  = 3;  //RX_DATA0
          CORE_PIN6_CONFIG  = 3;  //RX_DATA1
          IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; // GPIO_B1_00_ALT3, pg 873
          IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873

          dma.TCD->SADDR = &I2S1_RDR0;
          dma.TCD->SOFF = 4;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
              DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8) |
              DMA_TCD_NBYTES_MLOFFYES_NBYTES(8);
          dma.TCD->SLAST = -8;
#endif
          dma.TCD->DADDR = tdm_rx_buffer;
          dma.TCD->DOFF = 4;
          dma.TCD->CITER_ELINKNO = NBUF_I2S;
          dma.TCD->DLASTSGA = -sizeof(tdm_rx_buffer);
          dma.TCD->BITER_ELINKNO = NBUF_I2S;
          dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
          dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);
          dma.enable();

          I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
          dma.attachInterrupt(acq_isr,I2S_DMA_PRIO*16);	
      }

      void acq_start(void)
      {

      }
      void acq_stop(void)
      {
          
      }
  #endif

  uint32_t acq_count=0;
  uint32_t acq_miss=0;

    void acq_isr(void)
    {
        uint32_t daddr;
        uint32_t *src;
        acq_count++;

        daddr = (uint32_t)(dma.TCD->DADDR);
        dma.clearInterrupt();

        if (daddr < (uint32_t)tdm_rx_buffer + sizeof(tdm_rx_buffer) / 2) {
            // DMA is receiving to the first half of the buffer
            // need to remove data from the second half
            src = &tdm_rx_buffer[NBUF_I2S];
        } else {
            // DMA is receiving to the second half of the buffer
            // need to remove data from the first half
            src = &tdm_rx_buffer[0];
        }

        #if IMXRT_CACHE_ENABLED >=1
            arm_dcache_delete((void*)src, sizeof(tdm_rx_buffer) / 2);
        #endif

        for(int jj=0;jj<NCH_ACQ;jj++)
        {
          for(int ii=0; ii<NBUF_ACQ;ii++)
          {
            acq_rx_buffer[jj+ii*NCH_ACQ]=src[jj+ii*NCH_I2S];
          }
        }

        if(!pushData(acq_rx_buffer)) acq_miss++;

    }

  int16_t acq_check(int16_t state)
  { if(!state)
    { // start acquisition
      acq_start();
    }
    if(state>3)
    { // stop acquisition
      acq_stop();
    }
    return state;
  }
#endif
 
@KurtE - @defragster
Still puzzling me about the problem with using the MTP logger. Wondering if there is some sort of issue with using DMA and/or I2S with QSPI NAND Flash? But funny thing is that it does work with SPI NAND? Didn't really dig into it - think going to try a simple logger just as a test. Any thoughts on if this is possible?

It seems to be failing on mkdir and/or file open if I change to just write a file:
Code:
Logger
Device ID: 0xEFAA21
attempting to mount existing media
Setup done
 Enter s to start acquisition and q to stop acquisition

Start
acquistion start
loop: 20595404    0    0    0    1 0
/17897/00_00_08.raw
MAKING DIRECTORY
/17897
Below is a non-MTP version that I am using to test - figure would take one variable away:
Code:
#include "Arduino.h"

#define NDAT 128L
#define NCH_ACQ 1
#define NCH_I2S 4
#define NBUF_ACQ (NCH_ACQ*NDAT)
#define NBUF_I2S (NCH_I2S*NDAT)
#define N_ADC 2
#define FRAME_I2S (NCH_I2S/N_ADC)

#define I2S_CONFIG 1
// CONFIG 1 (PURE RX)
//PIN  36 BCLK
//PIN  37 FS
//PIN  13 RXD0
//PIN  38 RXD1

#include <LittleFS.h>
#include <LittleFS_NAND.h>

//#define TEST_SPI_NAND
#define TEST_QSPI_NAND

#define USE_W25N01 1
//#define USE_W25N02 1
//#define UES_W25M02 1

// Set for SPI usage
//const int FlashChipSelect = 10; // AUDIO BOARD
#if defined(USE_W25N01)
  const int FlashChipSelect = 3; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
#elif defined(USE_W25N02)
  const int FlashChipSelect = 4; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
#else //W25M02
  const int FlashChipSelect = 6; // digital pin for flash chip CS pin
#endif
//const int FlashChipSelect = 5; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
//const int FlashChipSelect = 6; // digital pin for flash chip CS pin


#if defined(TEST_QSPI_NAND)
char szDiskMem[] = "QPI_NAND";
LittleFS_QPINAND myNAND;
#elif defined(TEST_SPI_NAND)
char szDiskMem[] = "SPI_NAND";
LittleFS_SPINAND myNAND;
#endif



void logg(uint32_t del, const char *txt);

int16_t state;
int16_t do_logger(uint16_t store, int16_t state);
int16_t do_menu(int16_t state);
int16_t check_filing(int16_t state);

void acq_init(int32_t fsamp);
int16_t acq_check(int16_t state);

void setup()
{ 
  Serial.begin(115200);
  while(!Serial.available() && millis() < 5000); // or third option to wait up to 5 seconds and then continue
  Serial.println("Logger");

  #if defined(TEST_SPI_NAND)
    if (!myNAND.begin( FlashChipSelect )) {
  #else
    if (!myNAND.begin()) {
  #endif
    Serial.printf("Error starting %s\n", szDiskMem);
    while( 1 );
  }


  acq_init(93750); // is fixed for this example, to be modified below
  state=-1;

  Serial.println("Setup done");
  Serial.println(" Enter s to start acquisition and q to stop acquisition");
  Serial.flush();
}

uint32_t loop_count=0;
void loop()
{ loop_count++;
  state = do_menu(state);
  state = acq_check(state);
  state = check_filing(state);
  state = do_logger(0,state);

  if(state>=0) logg(1000,"loop");
  //asm("wfi"); // may wait forever on T4.x


}

/**************** Online logging *******************************/
extern uint32_t loop_count, acq_count, acq_miss, maxDel;
extern uint16_t maxCount;
void logg(uint32_t del, const char *txt)
{ static uint32_t to;
  if(millis()-to > del)
  {
    Serial.printf("%s: %6d %4d %4d %4d %4d %d\n",
            txt,loop_count, acq_count, acq_miss,maxCount, maxDel,state); 
    loop_count=0;
    acq_count=0;
    acq_miss=0;
    maxCount=0;
    maxDel=0;
    to=millis();
  }
}

/*************************** Circular Buffer ********************/
#if defined ARDUINO_TEENSY41
  #define HAVE_PSRAM 1
#else
  #define HAVE_PSRAM 0
#endif

  #if HAVE_PSRAM==1
    #define MAXBUF (1000) // 3000 kB   // < 5461 for 16 MByte PSRAM

//    extern "C" uint8_t external_psram_size;
//    uint8_t size = external_psram_size;
//    uint32_t *memory_begin = (uint32_t *)(0x70000000);
//    uint32_t *data_buffer = memory_begin;

    uint32_t *data_buffer = (uint32_t *)extmem_malloc(MAXBUF*128*sizeof(uint32_t));
  #else
    #if defined(ARDUINO_TEENSY41)
      #define MAXBUF (46)           // 138 kB
    #elif defined(ARDUINO_TEENSY40)
      #define MAXBUF (46)           // 138 kB
    #elif defined(__MK66FX1M0__)
      #define MAXBUF (46)           // 138 kB
    #elif defined(__MK20DX256__)
      #define MAXBUF (12)           // 36 kB
    #endif
    uint32_t data_buffer[MAXBUF*NBUF_ACQ];
  #endif

static uint16_t front_ = 0, rear_ = 0;
uint16_t getCount () { if(front_ >= rear_) return front_ - rear_; return front_+ MAXBUF -rear_; }
uint16_t maxCount=0;

void resetData(void) {  front_ = 0;  rear_ = 0; }

uint16_t pushData(uint32_t * src)
{ uint16_t f =front_ + 1;
  if(f >= MAXBUF) f=0;
  if(f == rear_) return 0;

  uint32_t *ptr= data_buffer+f*NBUF_ACQ;
  memcpy(ptr,src,NBUF_ACQ*4);
  front_ = f;
  //
  uint16_t count;
  count = (front_ >= rear_) ? (front_ - rear_) : front_+ (MAXBUF -rear_) ;
  if(count>maxCount) maxCount=count;
  //
  return 1;
}

uint16_t pullData(uint32_t * dst, uint32_t ndbl)
{ uint16_t r = (rear_/ndbl) ;
  if(r == (front_/ndbl)) return 0;
  if(++r >= (MAXBUF/ndbl)) r=0;
  uint32_t *ptr= data_buffer + r*ndbl*NBUF_ACQ;
  memcpy(dst,ptr,ndbl*NBUF_ACQ*4);
  rear_ = r*ndbl;
  return 1;
}

/*************************** Filing *****************************/
int16_t file_open(uint16_t store);
int16_t file_writeHeader(void);
int16_t file_writeData(void *diskBuffer, uint32_t ndbl);
int16_t file_close(void);
#define NDBL 1
#define NBUF_DISK (NDBL*NBUF_ACQ)
uint32_t diskBuffer[NBUF_DISK];
uint32_t maxDel=0;

int16_t do_logger(uint16_t store, int16_t state)
{ uint32_t to=millis();
  if(pullData(diskBuffer,NDBL))
  {
    if(state==0)
    { // acquisition is running, need to open file
      if(!file_open(store)) 
        return -2;
      state=1;
      Serial.println("file_open");
    }
    if(state==1)
    { // file just opended, need to write header
      if(!file_writeHeader()) return -3;
      Serial.println("wrote header");
      state=2;
      
    }
    if(state>=2)
    { // write data to disk
      if(!file_writeData(diskBuffer,NBUF_DISK*4)) return -4;
      Serial.println("write data to disk");
    }
  }

  if(state==3)
  { // close file, but continue acquisition
    if(!file_close()) return -5;
    Serial.println("close file");
    state=0;
  }

  if(state==4)
  { // close file and stop acquisition
    if(!file_close()) return -6;
    Serial.println("file_close and stop");
    state=-1;
  }

  uint32_t dt=millis()-to;
  if(dt>maxDel) maxDel=dt;

  return state;
}

/******************** Menu ***************************/
void do_menu1(void);
void do_menu2(void);
void do_menu3(void);

int16_t do_menu(int16_t state)
{ // check Serial input
  if(!Serial.available()) return state;
  char cc = Serial.read();
  switch(cc)
  {
    case 's': // start acquisition
      if(state>=0) return state;
      state=0;
      Serial.println("\nStart");
      break;
    case 'q': // stop acquisition
      if(state<0) return state;
      state=4;
      Serial.println("\nStop");
      break;
    case '?': // get parameters
      do_menu1();
      break;
    case '!': // set parameters
      if(state>=0) return state;
      do_menu2();
      break;
    case ':': // misc commands
      if(state>=0) return state;
      do_menu3();
      break;
    default:
      break;
  }
  return state;
}

/************ Basic File System Interface *************************/
//#include "SD.h"
//extern SDClass sdx[];
static File mfile;

char header[512];

void makeHeader(char *header);
int16_t makeFilename(char *filename);
int16_t checkPath(uint16_t store, char *filename);

int16_t file_open(uint16_t store)
{ char filename[80];
  if(!makeFilename(filename)) {
    Serial.println("filename created");
    return 0;
  }
  if(!checkPath(store, filename)){
    Serial.println("check path fail");
    return 0;
  }
  Serial.println("Opening FIle");
  mfile = myNAND.open(filename,FILE_WRITE_BEGIN);
  Serial.printf("File Open: %d\n", mfile);
  return !(!mfile);
}

int16_t file_writeHeader(void)
{ if(!mfile) return 0;
  makeHeader(header);
  size_t nb = mfile.write(header,512);
  return (nb==512);
}

int16_t file_writeData(void *diskBuffer, uint32_t nd)
{ if(!mfile) return 0;
  uint32_t nb = mfile.write(diskBuffer,nd);
  return (nb==nd);
}

int16_t file_close(void)
{ mfile.close();
  return (!mfile);
}

/*
 * Custom Implementation
 * 
 */
/************************ some utilities modified from time.cpp ************************/
// leap year calculator expects year argument as years offset from 1970
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )

static  const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; 

void day2date(uint32_t dd, uint32_t *day, uint32_t *month, uint32_t *year)
{
  uint32_t yy= 0;
  uint32_t days = 0;
  while((unsigned)(days += (LEAP_YEAR(yy) ? 366 : 365)) <= dd) {yy++;}
  
  days -= LEAP_YEAR(yy) ? 366 : 365;
  dd  -= days; // now it is days in this year, starting at 0

  uint32_t mm=0;
  uint32_t monthLength=0;
  for (mm=0; mm<12; mm++) 
  {
    monthLength = monthDays[mm];
    if ((mm==1) && (LEAP_YEAR(yy))) monthLength++;
    if (dd >= monthLength) { dd -= monthLength; } else { break; }
  }

  *month =mm + 1;   // jan is month 1  
  *day  = dd + 1;   // day of month
  *year = yy + 1970;
}

void date2day(uint32_t *dd, uint32_t day, uint32_t month, uint32_t year)
{
  day -= 1;
  month -= 1;
  year -= 1970;
  uint32_t dx=0;
  for (uint32_t ii = 0; ii < year; ii++) { dx += LEAP_YEAR(ii)? 366: 365; } 
  for (uint32_t ii = 0; ii < month; ii++)
  {
    dx += monthDays[ii];
    if((ii==2) && (LEAP_YEAR(year))) dx++; // after feb check for leap year
  }
  *dd = dx + day;
}

/************* Menu implementation ******************************/
void do_menu1(void)
{  // get parameters
}
void do_menu2(void)
{  // set parameters
}
void do_menu3(void)
{  // misc commands
}

/****************** File Utilities *****************************/
void makeHeader(char *header)
{
  memset(header,0,512);
}

int16_t makeFilename(char *filename)
{
  uint32_t tt = rtc_get();
  int hh,mm,ss;
  int dd;
  ss= tt % 60; tt /= 60;
  mm= tt % 60; tt /= 60;
  hh= tt % 24; tt /= 24;
  dd= tt;
  sprintf(filename,"/%d/%02d_%02d_%02d.raw",dd,hh,mm,ss);
  Serial.println(filename);
  return 1;
}

int16_t checkPath(uint16_t store, char *filename)
{
  int ln=strlen(filename);
  int i1=-1;
  for(int ii=0;ii<ln;ii++) if(filename[ii]=='/') i1=ii;
  if(i1<0) {
    Serial.println("NO PATH");
    return 1; // no path
  }
  filename[i1]=0;
  if(!myNAND.exists(filename))
  { 
    Serial.println("MAKING DIRECTORY");
    Serial.println(filename); 
    if(!myNAND.mkdir(filename)) 
    {
      Serial.println("directory fail");
      return 0;
    }
  }
  Serial.println("Check path OK");
  filename[i1]='/';
  return 1;
}

uint32_t t_on = 60;
int16_t check_filing(int16_t state)
{
  static uint32_t to;
  if(state==2)
  {
    uint32_t tt = rtc_get();
    uint32_t dt = tt % t_on;
    if(dt<to) state = 3;
    to = dt;
  }
  return state;
}

/****************** Data Acquisition *******************************************/
#define DO_TEST 1
#define DO_I2S 2
#define DO_ACQ DO_TEST

#if DO_ACQ==DO_TEST
  /****************** Intervall timer(dummy example) *****************************/
  #include "IntervalTimer.h"

  IntervalTimer t1;

  static uint32_t acq_buffer[NBUF_ACQ];

  uint32_t acq_period=1000;
  int16_t acq_state=-1;
  void acq_isr(void);

  void acq_init(int32_t fsamp)
  { acq_period=128'000'000/fsamp;
    acq_state=0;
  }

  void acq_start(void)
  { if(acq_state) return;
      Serial.println("acquistion start");
    resetData();
    t1.begin(acq_isr, acq_period);
    acq_state=1;
  }

  void acq_stop(void)
  { if(acq_state<=0) return;
    t1.end();
    acq_state=0;
  }

  uint32_t acq_count=0;
  uint32_t acq_miss=0;

  void acq_isr(void)
  { acq_count++;
    for(int jj=0;jj<NCH_ACQ;jj++)
    {
      for(int ii=0; ii<NBUF_ACQ;ii++)
      {
        acq_buffer[jj+ii*NCH_ACQ]=acq_count;
      }
    }
    if(!pushData(acq_buffer)) acq_miss++;
  }

  int16_t acq_check(int16_t state)
  { if(!state)
    { // start acquisition
      acq_start();
    }
    if(state>3)
    { // stop acquisition
      acq_stop();
    }
    return state;
  }
#else
// try I2S (not working yet)
  static uint32_t tdm_rx_buffer[2*NBUF_I2S];
  static uint32_t acq_rx_buffer[NBUF_ACQ];
  #define I2S_DMA_PRIO 6

  #include "DMAChannel.h"
  DMAChannel dma;

  void acq_isr(void);

  #if defined(__MK66FX1M0__)
  //Teensy 3.6
      #define MCLK_SRC  3
      #define MCLK_SCALE 1

    // set MCLK to 48 MHz or a integer fraction (MCLK_SCALE) of it 
    // MCLK_MULT is set to 1 or 2 to minimize jitter
    // this reduces the possibilities for sampling frequencies

    #if (F_PLL == 96000000) //PLL is 96 MHz for F_CPU==48 or F_CPU==96 MHz
        #define MCLK_MULT 1 
        #define MCLK_DIV  (2*MCLK_SCALE) 
        //  #define MCLK_DIV  (3*MCLK_SCALE) 
    #elif F_PLL == 120000000
        #define MCLK_MULT 2
        #define MCLK_DIV  (5*MCLK_SCALE)
    #elif F_PLL == 144000000
        #define MCLK_MULT 1
        #define MCLK_DIV  (3*MCLK_SCALE)
    #elif F_PLL == 192000000
        #define MCLK_MULT 1
        #define MCLK_DIV  (4*MCLK_SCALE)
    #elif F_PLL == 240000000
        #define MCLK_MULT 1
        #define MCLK_DIV  (5*MCLK_SCALE)
    #else
        #error "set F_CPU to (48, 96, 120, 144, 192, 240) MHz"
    #endif

#define BIT_DIV 4


    /*
     * estimation of sampling frequency
    MCLK 98 MHz * 1 / 2 = 48 MHz 
  N_ADC =1
  case 0
    nch=8
    Bit clock: 93750*(8*32) = 93750*256 = 24 MHz ->(I2S_RCR2_DIV(0))
  case 1
    nch=4
    Bit clock: 93750*(4*32) = 93750*128 = 12 MHz ->(I2S_RCR2_DIV(1))
  case 2
    nch=2
    Bit clock: 93750*(2*32) = 93750*64 = 6 MHz ->(I2S_RCR2_DIV(3))

  N_ADC =2
  case 3
    nch=4
    Bit clock: 93750*((4/2)*32) = 93750*64 = 6 MHz ->(I2S_RCR2_DIV(3))

  bitclock = fs *( nch*32)/n_adc = f_pll*mckl_mult/mckl_div/(2*bit_div)

  fs=bitclock*((nch/n_adc)*32)

  bitclock= f_pll*mckl_mult/mckl_div/(2*bit_div)
  fs=f_pll*mckl_mult/mckl_div/(2*bit_div)/((nch/n_adc)*32)
*/

    const int32_t fsamp0=(((F_PLL*MCLK_MULT)/MCLK_DIV)/(2*BIT_DIV)/(NCH_I2S*32/N_ADC));


    void acq_init(int32_t fsamp)
    {
        Serial.printf("%d %d\n",fsamp,fsamp0);
        SIM_SCGC6 |= SIM_SCGC6_I2S;
        SIM_SCGC7 |= SIM_SCGC7_DMA;
        SIM_SCGC6 |= SIM_SCGC6_DMAMUX;

/*
P23 PTC2   I2S0_TX_FS (6)
P9  PTC3   I2S0_TX_BCLK (6)
P13 PTC5                    I2S0_RXD0 (4)
P11 PTC6   I2S0_MCLK (6)    I2S0_RX_BCLK (4)
P12 PTC7                    I2S0_RX_FS (4)
P35 PTC8                    I2S0_MCLK (4)
P36 PTC9                    I2S0_RX_BCLK (4)
P37 PTC10                   I2S0_RX_FS (4)
P38 PTC11                   I2S0_RXD1 (4)
*/
        #if I2S_CONFIG==0
//            CORE_PIN39_CONFIG = PORT_PCR_MUX(6);  //pin39, PTA17, I2S0_MCLK
//            CORE_PIN11_CONFIG = PORT_PCR_MUX(4);  //pin11, PTC6,  I2S0_RX_BCLK
//            CORE_PIN12_CONFIG = PORT_PCR_MUX(4);  //pin12, PTC7,  I2S0_RX_FS
//            CORE_PIN13_CONFIG = PORT_PCR_MUX(4);  //pin13, PTC5,  I2S0_RXD0
        #elif I2S_CONFIG==1
            CORE_PIN35_CONFIG = PORT_PCR_MUX(4);   // PTC8,  I2S0_MCLK
            CORE_PIN36_CONFIG = PORT_PCR_MUX(4);   // PTC9,  I2S0_RX_BCLK
            CORE_PIN37_CONFIG = PORT_PCR_MUX(4);   // PTC10, I2S0_RX_FS 
        #elif I2S_CONFIG==2
//            CORE_PIN35_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_SRE | PORT_PCR_DSE;  //pin35, PTC8,   I2S0_MCLK (SLEW rate (SRE)?)
//            CORE_PIN36_CONFIG = PORT_PCR_MUX(4);  //pin36, PTC9,   I2S0_RX_BCLK
//            CORE_PIN37_CONFIG = PORT_PCR_MUX(4);  //pin37, PTC10,  I2S0_RX_FS
//            CORE_PIN27_CONFIG = PORT_PCR_MUX(6);  //pin27, PTA15,  I2S0_RXD0
        #endif

        I2S0_RCSR=0;

        // enable MCLK output // MCLK = INP *((MULT)/(DIV))
        I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));
        while(I2S0_MCR & I2S_MCR_DUF);
        I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
        
        I2S0_RMR=0; // enable receiver mask
        I2S0_RCR1 = I2S_RCR1_RFW(3); 

        I2S0_RCR2 = I2S_RCR2_SYNC(0) 
                    | I2S_RCR2_BCP 
                    | I2S_RCR2_BCD  // Bit clock in master mode
                    | I2S_RCR2_DIV((BIT_DIV-1)); // divides MCLK down to Bitclock (BIT_DIV)*2
                    
        I2S0_RCR4 = I2S_RCR4_FRSZ((FRAME_I2S-1)) 
                    | I2S_RCR4_FSE  // frame sync early
                    | I2S_RCR4_FSD  // Frame sync in master mode
                    | I2S_RCR4_MF;
        
        I2S0_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);


  dma.begin(true); // Allocate the DMA channel first

#if N_ADC==1
          CORE_PIN13_CONFIG = PORT_PCR_MUX(4);  // PTC5,  I2S0_RXD0

          I2S0_RCR3 = I2S_RCR3_RCE;

          dma.TCD->SADDR = &I2S0_RDR0;
          dma.TCD->SOFF = 0;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLNO = 4;
          dma.TCD->SLAST = 0;
#elif N_ADC==2
          CORE_PIN13_CONFIG = PORT_PCR_MUX(4);  // PTC5,  I2S0_RXD0
          CORE_PIN38_CONFIG = PORT_PCR_MUX(4);  // PTC11, I2S0_RXD1

          I2S0_RCR3 = I2S_RCR3_RCE_2CH;

          dma.TCD->SADDR = &I2S0_RDR0;
          dma.TCD->SOFF = 4;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
              DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8) |
              DMA_TCD_NBYTES_MLOFFYES_NBYTES(8);
          dma.TCD->SLAST = -8;
#endif
          dma.TCD->DADDR = tdm_rx_buffer;
          dma.TCD->DOFF = 4;
          dma.TCD->CITER_ELINKNO = NBUF_I2S;
          dma.TCD->DLASTSGA = -sizeof(tdm_rx_buffer);
          dma.TCD->BITER_ELINKNO = NBUF_I2S;
          dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
          dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX);
          dma.enable();

          I2S0_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
          dma.attachInterrupt(acq_isr,I2S_DMA_PRIO*16);  
    }

    void acq_start(void)
    {

    }
    void acq_stop(void)
    {
        
    }

  #elif defined(__IMXRT1062__)
  //Teensy 4.x

    #define IMXRT_CACHE_ENABLED 2 // 0=disabled, 1=WT, 2= WB

    /************************* I2S *************************************************/
    void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL4
      {
          if (!force && (CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_ENABLE)) return;

          CCM_ANALOG_PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_BYPASS | CCM_ANALOG_PLL_AUDIO_ENABLE
                      | CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2) // 2: 1/4; 1: 1/2; 0: 1/1
                      | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(nfact);

          CCM_ANALOG_PLL_AUDIO_NUM   = nmult & CCM_ANALOG_PLL_AUDIO_NUM_MASK;
          CCM_ANALOG_PLL_AUDIO_DENOM = ndiv & CCM_ANALOG_PLL_AUDIO_DENOM_MASK;
          
          CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_POWERDOWN;//Switch on PLL
          while (!(CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK)) {}; //Wait for pll-lock
          
          const int div_post_pll = 1; // other values: 2,4
          CCM_ANALOG_MISC2 &= ~(CCM_ANALOG_MISC2_DIV_MSB | CCM_ANALOG_MISC2_DIV_LSB);
          if(div_post_pll>1) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_LSB;
          if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB;
          
          CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS;   //Disable Bypass
      }

      void acq_init(int32_t fsamp)
      {
          CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);

          // if either transmitter or receiver is enabled, do nothing
          if (I2S1_RCSR & I2S_RCSR_RE) return;
          //PLL:
          int fs = fsamp;
          int ovr = FRAME_I2S*32;
          // PLL between 27*24 = 648MHz und 54*24=1296MHz
          int n1 = 4;                    //4; //SAI prescaler 4 => (n1*n2) = multiple of 4
          int n2 = 1 + (24000000 * 27) / (fs * ovr * n1);
          Serial.printf("fs=%d, n1=%d, n2=%d, %d (>27 && < 54)\r\n", 
                        fs, n1,n2,n1*n2*(fs/1000)*ovr/24000);

          double C = ((double)fs * ovr * n1 * n2) / 24000000;
          int c0 = C;
          int c2 = 10000;
          int c1 = C * c2 - (c0 * c2);
          set_audioClock(c0, c1, c2, true);

          // clear SAI1_CLK register locations
          CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
              | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4

          n1 = n1 / 2; //Double Speed for TDM

          CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
              | CCM_CS1CDR_SAI1_CLK_PRED((n1-1)) // &0x07
              | CCM_CS1CDR_SAI1_CLK_PODF((n2-1)); // &0x3f

          IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
                  | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));  //Select MCLK

          I2S1_RMR = 0;
          I2S1_RCR1 = I2S_RCR1_RFW(4);
          I2S1_RCR2 = I2S_RCR2_SYNC(0) | I2S_TCR2_BCP | I2S_RCR2_MSEL(1)
              | I2S_RCR2_BCD | I2S_RCR2_DIV(0);
          
          I2S1_RCR4 = I2S_RCR4_FRSZ((FRAME_I2S-1)) | I2S_RCR4_SYWD(0) | I2S_RCR4_MF
              | I2S_RCR4_FSE | I2S_RCR4_FSD;
          I2S1_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);

          CORE_PIN23_CONFIG = 3;  //1:MCLK 
          CORE_PIN21_CONFIG = 3;  //1:RX_BCLK
          CORE_PIN20_CONFIG = 3;  //1:RX_SYNC
#if N_ADC==1
          I2S1_RCR3 = I2S_RCR3_RCE;
          CORE_PIN8_CONFIG  = 3;  //RX_DATA0
          IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2;

          dma.TCD->SADDR = &I2S1_RDR0;
          dma.TCD->SOFF = 0;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLNO = 4;
          dma.TCD->SLAST = 0;
#elif N_ADC==2
          I2S1_RCR3 = I2S_RCR3_RCE_2CH;
          CORE_PIN8_CONFIG  = 3;  //RX_DATA0
          CORE_PIN6_CONFIG  = 3;  //RX_DATA1
          IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; // GPIO_B1_00_ALT3, pg 873
          IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873

          dma.TCD->SADDR = &I2S1_RDR0;
          dma.TCD->SOFF = 4;
          dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
          dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
              DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8) |
              DMA_TCD_NBYTES_MLOFFYES_NBYTES(8);
          dma.TCD->SLAST = -8;
#endif
          dma.TCD->DADDR = tdm_rx_buffer;
          dma.TCD->DOFF = 4;
          dma.TCD->CITER_ELINKNO = NBUF_I2S;
          dma.TCD->DLASTSGA = -sizeof(tdm_rx_buffer);
          dma.TCD->BITER_ELINKNO = NBUF_I2S;
          dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
          dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);
          dma.enable();

          I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
          dma.attachInterrupt(acq_isr,I2S_DMA_PRIO*16); 
      }

      void acq_start(void)
      {

      }
      void acq_stop(void)
      {
          
      }
  #endif

  uint32_t acq_count=0;
  uint32_t acq_miss=0;

    void acq_isr(void)
    {
        uint32_t daddr;
        uint32_t *src;
        acq_count++;

        daddr = (uint32_t)(dma.TCD->DADDR);
        dma.clearInterrupt();

        if (daddr < (uint32_t)tdm_rx_buffer + sizeof(tdm_rx_buffer) / 2) {
            // DMA is receiving to the first half of the buffer
            // need to remove data from the second half
            src = &tdm_rx_buffer[NBUF_I2S];
        } else {
            // DMA is receiving to the second half of the buffer
            // need to remove data from the first half
            src = &tdm_rx_buffer[0];
        }

        #if IMXRT_CACHE_ENABLED >=1
            arm_dcache_delete((void*)src, sizeof(tdm_rx_buffer) / 2);
        #endif

        for(int jj=0;jj<NCH_ACQ;jj++)
        {
          for(int ii=0; ii<NBUF_ACQ;ii++)
          {
            acq_rx_buffer[jj+ii*NCH_ACQ]=src[jj+ii*NCH_I2S];
          }
        }

        if(!pushData(acq_rx_buffer)) acq_miss++;

    }

  int16_t acq_check(int16_t state)
  { if(!state)
    { // start acquisition
      acq_start();
    }
    if(state>3)
    { // stop acquisition
      acq_stop();
    }
    return state;
  }
#endif
 
Good morning,

I will have to play later. Looking at larger files receive... More on other thread.
I assume you have already tested that creating a directory works in a simple case.

What Teensy is this supposed to run on? Why I am asking is the mention of using pins like:
Code:
        #elif I2S_CONFIG==1
            CORE_PIN35_CONFIG = PORT_PCR_MUX(4);   // PTC8,  I2S0_MCLK
            CORE_PIN36_CONFIG = PORT_PCR_MUX(4);   // PTC9,  I2S0_RX_BCLK
            CORE_PIN37_CONFIG = PORT_PCR_MUX(4);   // PTC10, I2S0_RX_FS
But looking at my T4.1 Excel document: I see:
Code:
35	B1_12    	IOMUXC_LPUART5_TX_SELECT_INPUT=1	CSI_PIXCLK	ENET_1588_EVENT0_IN	[COLOR="#FF0000"]FLEXIO2_FLEXIO28	[/COLOR]GPIO2_IO28	USDHC1_CD_B			FLEXIO3_FLEXIO28
36	B1_02    	LCD_DATA14	XBAR1_INOUT16	LPSPI4_PCS2	SAI1_TX_BCLK	[COLOR="#FF0000"]FLEXIO2_FLEXIO18	[/COLOR]GPIO2_IO18	FLEXPWM2_PWMA03		ENET2_RDATA01	FLEXIO3_FLEXIO18
37	B1_03    	LCD_DATA15	IOMUXC_XBAR1_IN17_SELECT_INPUT=0x3	LPSPI4_PCS1	SAI1_TX_SYNC	[COLOR="#FF0000"]FLEXIO2_FLEXIO19	[/COLOR]GPIO2_IO19	FLEXPWM2_PWMB03		ENET2_RX_EN	FLEXIO3_FLEXIO19
That MUX(4) is for FlexIO on those pins...
 
Morning - all mornings seem to be the same lately.

I assume you have already tested that creating a directory works in a simple case.
Yep - made sure of that. Right now I am in the process of putting together a basic logger using similar functions for creating files/directories and writing data.

What Teensy is this supposed to run on?
Been using it a T4.1 - works for everything that I tested so far except NAND QSPI.

Kind of along the same lines as I was thinking, that is that is some sort of conflict, but didn't dig into it. Figure it might just be better to try a basic test case.

Taking longer than expected since I have to make more coffee :)
 
Ok just wrote a simple test case that seems to be working - probably do better on next update but wanted to see if this was going to work and it did - so probably a conflict as you identified:
Code:
Logger
Device ID: 0xEFAA21
attempting to mount existing media
Disk Usuage:
Bytes Used: 655360, Bytes Total:131596288
/18639/09_18_28.raw
Check path OK
Opening FIle
File Open: 536873028
printDirectory
--------------
DIR	18639 / 
	FILE	09_16_11.raw		51200
	FILE	09_18_28.raw		51200

 0 dirs with 2 files of Size 102400 Bytes

 1 dirs with 0 files of Size 0 Bytes
here is the sketch I used - its a dup of the key elements from the MTP Logger Sketch:
Code:
#include "Arduino.h"


#include <LittleFS.h>
#include <LittleFS_NAND.h>

//#define TEST_SPI_NAND
#define TEST_QSPI_NAND

#define USE_W25N01 1
//#define USE_W25N02 1
//#define UES_W25M02 1

// Set for SPI usage
//const int FlashChipSelect = 10; // AUDIO BOARD
#if defined(USE_W25N01)
  const int FlashChipSelect = 3; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
#elif defined(USE_W25N02)
  const int FlashChipSelect = 4; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
#else //W25M02
  const int FlashChipSelect = 6; // digital pin for flash chip CS pin
#endif
//const int FlashChipSelect = 5; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
//const int FlashChipSelect = 6; // digital pin for flash chip CS pin


#if defined(TEST_QSPI_NAND)
char szDiskMem[] = "QPI_NAND";
LittleFS_QPINAND myNAND;
#elif defined(TEST_SPI_NAND)
char szDiskMem[] = "SPI_NAND";
LittleFS_SPINAND myNAND;
#endif

File mfile;
uint64_t fTot, totSize1;

#define NDBL 1
#define NBUF_DISK (NDBL*128)
uint32_t diskBuffer[NBUF_DISK];
uint32_t maxDel=0;


void setup() {
  Serial.begin(115200);
  while(!Serial.available() && millis() < 5000); // or third option to wait up to 5 seconds and then continue
  Serial.println("Logger");

  #if defined(TEST_SPI_NAND)
    if (!myNAND.begin( FlashChipSelect )) {
  #else
    if (!myNAND.begin()) {
  #endif
    Serial.printf("Error starting %s\n", szDiskMem);
    while( 1 );
  }
  //myNAND.lowLevelFormat('.');
  Serial.printf("Disk Usuage:\n");
  Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myNAND.usedSize(), myNAND.totalSize());

  file_open();
  memset(diskBuffer, 0x01, NBUF_DISK*4);
  for(int16_t j = 0; j < 100; j++)
    file_writeData(diskBuffer,NBUF_DISK*4);
  file_close();
  printDirectory();
}

void loop() {

}

int16_t makeFilename(char *filename)
{
  uint32_t tt = rtc_get();
  int hh,mm,ss;
  int dd;
  ss= tt % 60; tt /= 60;
  mm= tt % 60; tt /= 60;
  hh= tt % 24; tt /= 24;
  dd= tt;
  sprintf(filename,"/%d/%02d_%02d_%02d.raw",dd,hh,mm,ss);
  Serial.println(filename);
  return 1;
}

int16_t checkPath(char *filename)
{
  int ln=strlen(filename);
  int i1=-1;
  for(int ii=0;ii<ln;ii++) if(filename[ii]=='/') i1=ii;
  if(i1<0) {
    Serial.println("NO PATH");
    return 1; // no path
  }
  filename[i1]=0;
  if(!myNAND.exists(filename))
  { 
    Serial.println("MAKING DIRECTORY");
    Serial.println(filename); 
    if(!myNAND.mkdir(filename)) 
    {
      Serial.println("directory fail");
      return 0;
    }
  }
  Serial.println("Check path OK");
  filename[i1]='/';
  return 1;
}
/*************************** Filing *****************************/



int16_t file_open()
{ char filename[80];
  if(!makeFilename(filename)) {
    Serial.println("filename created");
    return 0;
  }
  if(!checkPath(filename)){
    Serial.println("check path fail");
    return 0;
  }
  Serial.println("Opening FIle");
  mfile = myNAND.open(filename,FILE_WRITE_BEGIN);
  Serial.printf("File Open: %d\n", mfile);
  return !(!mfile);
}

int16_t file_writeData(void *diskBuffer, uint32_t nd)
{ if(!mfile) return 0;
  uint32_t nb = mfile.write(diskBuffer,nd);
  return (nb==nd);
}

int16_t file_close(void)
{ mfile.close();
  return (!mfile);
}

void printDirectory() {

  Serial.println("printDirectory\n--------------");
  printDirectory(myNAND.open("/"), 0);
  Serial.println();
}


void printDirectory(File dir, int numTabs) {
  //dir.whoami();
  uint64_t fSize = 0;
  uint32_t dCnt = 0, fCnt = 0;
  if ( 0 == dir ) {
    Serial.printf( "\t>>>\t>>>>> No Dir\n" );
    return;
  }
  while (true) {
    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      Serial.printf("\n %u dirs with %u files of Size %u Bytes\n", dCnt, fCnt, fSize);
      fTot += fCnt;
      totSize1 += fSize;
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }

    if (entry.isDirectory()) {
      Serial.print("DIR\t");
      dCnt++;
    } else {
      Serial.print("FILE\t");
      fCnt++;
      fSize += entry.size();
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println(" / ");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
    //Serial.flush();
  }
}
Now to figure out a good data pull to log :). Not sure I want to hook up a GPS or not - maybe another sensor :)
 
Ok - reworked the mtp-logger example to just read data from MPU-9250 and store it on any of our flash chips, now it works no problem with the NAND on QSPI. Must be that conflict @KurtE mentioned. If you want to play:
Code:
#include "Arduino.h"

#include "SD.h"
#include "MTP.h"

//used for logger
File mfile;
uint64_t fTot, totSize1;
int16_t state;

uint32_t maxDel=0;
char header[512];

//used for MPU9250 and data structure

#include "MPU9250.h"

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;

//define a struct of various data types
struct MYDATA_t {
  float ax, ay, az;
  float gx, gy, gz;
  float mx, my, mz;
  float temp;
};

//define a struct joining MYDATA_t to an array of bytes to be stored
union MYDATA4I2C_t {
 MYDATA_t datastruct;
 uint8_t I2CPacket[sizeof(MYDATA_t)];
};

MYDATA4I2C_t mydata; //data to be written in memory
MYDATA4I2C_t readdata; //data read from memory


#if defined(__IMXRT1062__)
  // following only while usb_mtp is not included in cores
  #if __has_include("usb_mtp.h")
    #include "usb_mtp.h"
  #else
    #include "usb1_mtp.h"
  #endif
#endif

#define USE_EVENTS 1
#define USE_SD  0
#define USE_LITTLEFS 1 // set to zero if no LtttleFS is existing or to be used

#if USE_LITTLEFS==1
#ifdef ARDUINO_TEENSY41
  #define USE_RAM 0     // T4.1 PSRAM (or RAM)
#else
  #define USE_RAM 0     // T4.1 PSRAM (or RAM)
#endif
  #define USE_SPI 0
  #define USE_QSPI 0
  #define USE_NAND 0
  #define USE_QSPI_NAND 1
  #define USE_FRAM 0
#endif

#if USE_EVENTS==1
  extern "C" int usb_init_events(void);
#else
  int usb_init_events(void) {}
#endif


#if defined(__IMXRT1062__)
  // following only as long usb_mtp is not included in cores
  #if !__has_include("usb_mtp.h")
    #include "usb1_mtp.h"
  #endif
#else
  #ifndef BUILTIN_SCCARD 
    #define BUILTIN_SDCARD 254
  #endif
  void usb_mtp_configure(void) {}
#endif

/****  Start device specific change area  ****/
#if USE_SD==1
  // edit SPI to reflect your configuration (following is for T4.1)
  #define SD_MOSI 11
  #define SD_MISO 12
  #define SD_SCK  13

  #define stor_SPEED SD_SCK_MHZ(16)  // adjust to sd card 

// SDClasses
  const char *sd_str[]={"sdio"}; // edit to reflect your configuration
  const int cs[] = {BUILTIN_SDCARD}; // edit to reflect your configuration
  const int nsd = sizeof(cs)/sizeof(int);

SDClass storfs[nsd];
#endif

//LittleFS classes
#if USE_LITTLEFS==1
  #include "LittleFS.h"
  #include "LittleFS_NAND.h"
  
  #if USE_RAM == 1
    const char *stor_str[]={"RAM0"};     // edit to reflect your configuration
    const int stor_size[] = {2'000'000};
    const int stor_nsd = sizeof(stor_size)/sizeof(int);
    LittleFS_RAM storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_SPI == 1
    const char *stor_str[]={"WINBOND"};     // edit to reflect your configuration
    const int stor_cs[] = {5}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_FRAM == 1
    const char *stor_str[]={"CYPRESS"};     // edit to reflect your configuration
    const int stor_cs[] = {10}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

  #if USE_NAND == 1
    const char *stor_str[]={"WINBOND1G"};     // edit to reflect your configuration
    const int stor_cs[] = {3}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPINAND storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

  #if USE_QSPI_NAND == 1
    const char *stor_str[]={"WINBOND1G"};     // edit to reflect your configuration
    const int stor_nsd = 1;
    LittleFS_QPINAND storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_QSPI == 1
    const char *stor_str[]={"QSPI0"};     // edit to reflect your configuration
    const int stor_nsd = 1;
    LittleFS_QSPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
 
#endif


MTPStorage_SD storage;
MTPD       mtpd(&storage);


void storage_configure()
{
  #if USE_SD==1
    #if defined SD_SCK
      SPI.setMOSI(SD_MOSI);
      SPI.setMISO(SD_MISO);
      SPI.setSCK(SD_SCK);
    #endif

    for(int ii=0; ii<nsd; ii++)
    { if(cs[ii] == BUILTIN_SDCARD)
      {
        if(!storfs[ii].sdfs.begin(SdioConfig(FIFO_SDIO))) {Serial.println("No storage"); while(1);};
        storage.addFilesystem(storfs[ii], sd_str[ii]);
      }
      else if(cs[ii]<BUILTIN_SDCARD)
      {
        pinMode(cs[ii],OUTPUT); digitalWriteFast(cs[ii],HIGH);
        if(!storfs[ii].sdfs.begin(SdSpiConfig(cs[ii], SHARED_SPI, stor_SPEED))) {Serial.println("No storage"); while(1);}
        storage.addFilesystem(storfs[ii], sd_str[ii]);
      }
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,cs[ii],sd_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
    }
    #endif

    #if USE_LITTLEFS==1
      #if USE_RAM == 1
        for(int ii=0; ii<stor_nsd;ii++)
        {
          { if(!ramfs[ii].begin(stor_size[ii])) { Serial.println("No storage"); while(1);}
            storage.addFilesystem(ramfs[ii], stor_str[ii]);
          }
          uint64_t totalSize = ramfs[ii].totalSize();
          uint64_t usedSize  = ramfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_SPI == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_FRAM == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_NAND == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_QSPI_NAND == 1
       for(int ii=0; ii<stor_nsd;ii++) {
          if(!storfs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
     
          uint64_t totalSize = storfs[ii].totalSize();
          uint64_t usedSize  = storfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_QSPI == 1
       for(int ii=0; ii<stor_nsd;ii++) {
          if(!storfs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
     
          uint64_t totalSize = storfs[ii].totalSize();
          uint64_t usedSize  = storfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif
      
    #endif
}
/****  End of device specific change area  ****/


void setup()
{ 
  Serial.begin(115200);
  #if defined(USB_MTPDISK_SERIAL) 
    while(!Serial); // comment if you do not want to wait for terminal
  #else
    //while(!Serial.available()); // comment if you do not want to wait for terminal (otherwise press any key to continue)
    while(!Serial.available() && millis() < 5000); // or third option to wait up to 5 seconds and then continue
  #endif
  Serial.println("MTP logger");

  #if USE_EVENTS==1
    usb_init_events();
  #endif

  #if !__has_include("usb_mtp.h")
    usb_mtp_configure();
  #endif
  storage_configure();

 //Init 9250 i2c
  // start communication with IMU 
  status = IMU.begin();
  if (status < 0) {
    Serial.println("IMU initialization unsuccessful");
    Serial.println("Check IMU wiring or try cycling power");
    Serial.print("Status: ");
    Serial.println(status);
    while(1) {}
  }


  state=-1;

  Serial.println("Setup done");
  Serial.println(" Enter s to start acquisition and q to stop acquisition");
  Serial.flush();
}


uint32_t loop_count=0;
void loop()
{ loop_count++;
  state = do_menu(state);
  state = check_filing(state);
  //
  if(state<0)
    mtpd.loop();
  else
    state=do_logger(0,state);

  if(state>=0) logg(1000,"loop");
  //asm("wfi"); // may wait forever on T4.x

}



/**************** Online logging *******************************/
extern uint32_t loop_count, acq_count, acq_miss, maxDel;
extern uint16_t maxCount;
void logg(uint32_t del, const char *txt)
{ static uint32_t to;
  if(millis()-to > del)
  {
    Serial.printf("%s: %6d %4d %4d %4d %4d %d\n",
            txt,loop_count, state); 
    loop_count=0;
    to=millis();
  }
}

int16_t do_menu(int16_t state)
{ // check Serial input
  if(!Serial.available()) return state;
  char cc = Serial.read();
  switch(cc)
  {
    case 's': // start acquisition
      if(state>=0) return state;
      state=0;
      Serial.println("\nStart");
      break;
    case 'q': // stop acquisition
      if(state<0) return state;
      state=4;
      Serial.println("\nStop");
      break;
    case 'r':
      Serial.println("Reset");
      mtpd.send_DeviceResetEvent();
      break;
    case 'd':
      // first dump list of storages:
      uint32_t fsCount = storage.getFSCount();
      Serial.printf("\nDump Storage list(%u)\n", fsCount);
      for (uint32_t ii = 0; ii < fsCount; ii++) {
        Serial.printf("store:%u name:%s fs:%x\n", ii, storage.getStoreName(ii), (uint32_t)storage.getStoreFS(ii));
      }
      Serial.println("\nDump Index List");
      storage.dumpIndexList();
      break;
  default:
    break;

  }

  return state;
}

int16_t do_logger(uint16_t store, int16_t state)
{ uint32_t to=millis();

    if(state==0)
    { // acquisition is running, need to open file
      if(!file_open(store)) 
        return -2;
      state=1;
      //Serial.println("file_open");
    }
    if(state==1)
    { // file just opended, need to write header
      if(!file_writeHeader()) return -3;
      //Serial.println("wrote header");
      state=2;
      
    }
    if(state>=2)
    { // write data to disk
      if(!file_writeData()) return -4;
      //Serial.println("write data to disk");
    }

  if(state==3)
  { // close file, but continue acquisition
    if(!file_close()) return -5;
    //Serial.println("close file");
    state=0;
  }

  if(state==4)
  { // close file and stop acquisition
    if(!file_close()) return -6;
    //Serial.println("file_close and stop");
    state=-1;
  }

  uint32_t dt=millis()-to;
  if(dt>maxDel) maxDel=dt;

  return state;
}

uint32_t t_on = 60;
int16_t check_filing(int16_t state)
{
  static uint32_t to;
  if(state==2)
  {
    uint32_t tt = rtc_get();
    uint32_t dt = tt % t_on;
    if(dt<to) state = 3;
    to = dt;
  }
  return state;
}


void makeHeader(char *header)
{
  memset(header,0,512);
}

int16_t file_writeHeader(void)
{ if(!mfile) return 0;
  makeHeader(header);
  size_t nb = mfile.write(header,512);
  return (nb==512);
}


int16_t makeFilename(char *filename)
{
  uint32_t tt = rtc_get();
  int hh,mm,ss;
  int dd;
  ss= tt % 60; tt /= 60;
  mm= tt % 60; tt /= 60;
  hh= tt % 24; tt /= 24;
  dd= tt;
  sprintf(filename,"/%d/%02d_%02d_%02d.raw",dd,hh,mm,ss);
  Serial.println(filename);
  return 1;
}

int16_t checkPath(uint16_t store, char *filename)
{
  int ln=strlen(filename);
  int i1=-1;
  for(int ii=0;ii<ln;ii++) if(filename[ii]=='/') i1=ii;
  if(i1<0) {
    //Serial.println("NO PATH");
    return 1; // no path
  }
  filename[i1]=0;
  if(!storfs[store].exists(filename))
  { 
    //Serial.println("MAKING DIRECTORY");
    Serial.println(filename); 
    if(!storfs[store].mkdir(filename)) 
    {
      Serial.println("directory fail");
      return 0;
    }
  }
  //Serial.println("Check path OK");
  filename[i1]='/';
  return 1;
}

/*************************** Filing *****************************/
int16_t file_open(uint16_t store)
{ char filename[80];
  if(!makeFilename(filename)) {
    //Serial.println("filename created");
    return 0;
  }
  if(!checkPath(store, filename)){
    //Serial.println("check path fail");
    return 0;
  }
  //Serial.println("Opening FIle");
  mfile = storfs[store].open(filename,FILE_WRITE_BEGIN);
  Serial.printf("File Open: %d\n", mfile);
  return !(!mfile);
}

int16_t file_writeData()
{ if(!mfile) return 0;
  uint16_t arraySize = sizeof(MYDATA_t);
  uint8_t diskBuffer[arraySize];
  IMU.readSensor();
  mydata.datastruct.ax = IMU.getAccelX_mss();
  mydata.datastruct.ay = IMU.getAccelY_mss();
  mydata.datastruct.az = IMU.getAccelZ_mss();
  mydata.datastruct.gx = IMU.getGyroX_rads();
  mydata.datastruct.gy = IMU.getGyroY_rads();
  mydata.datastruct.gz = IMU.getGyroZ_rads();
  mydata.datastruct.mx = IMU.getMagX_uT();
  mydata.datastruct.my = IMU.getMagY_uT();
  mydata.datastruct.mz = IMU.getMagZ_uT();
  mydata.datastruct.temp = IMU.getTemperature_C();
    for(uint16_t j = 0; j < arraySize; j++) {
      diskBuffer[j]= mydata.I2CPacket[j];
    }
  uint32_t nb = mfile.write(diskBuffer,arraySize);
  return 1;
}

int16_t file_close(void)
{ mfile.close();
  return (!mfile);
}
 
Good morning,

I will have to play later. Looking at larger files receive... More on other thread.
I assume you have already tested that creating a directory works in a simple case.

What Teensy is this supposed to run on? Why I am asking is the mention of using pins like:
Code:
        #elif I2S_CONFIG==1
            CORE_PIN35_CONFIG = PORT_PCR_MUX(4);   // PTC8,  I2S0_MCLK
            CORE_PIN36_CONFIG = PORT_PCR_MUX(4);   // PTC9,  I2S0_RX_BCLK
            CORE_PIN37_CONFIG = PORT_PCR_MUX(4);   // PTC10, I2S0_RX_FS
But looking at my T4.1 Excel document: I see:
Code:
35	B1_12    	IOMUXC_LPUART5_TX_SELECT_INPUT=1	CSI_PIXCLK	ENET_1588_EVENT0_IN	[COLOR="#FF0000"]FLEXIO2_FLEXIO28	[/COLOR]GPIO2_IO28	USDHC1_CD_B			FLEXIO3_FLEXIO28
36	B1_02    	LCD_DATA14	XBAR1_INOUT16	LPSPI4_PCS2	SAI1_TX_BCLK	[COLOR="#FF0000"]FLEXIO2_FLEXIO18	[/COLOR]GPIO2_IO18	FLEXPWM2_PWMA03		ENET2_RDATA01	FLEXIO3_FLEXIO18
37	B1_03    	LCD_DATA15	IOMUXC_XBAR1_IN17_SELECT_INPUT=0x3	LPSPI4_PCS1	SAI1_TX_SYNC	[COLOR="#FF0000"]FLEXIO2_FLEXIO19	[/COLOR]GPIO2_IO19	FLEXPWM2_PWMB03		ENET2_RX_EN	FLEXIO3_FLEXIO19
That MUX(4) is for FlexIO on those pins...

Just to make sure at a glance what that is showing - the issue is using those pins 35,36,37 is in conflict because they have FLEXIO2 conflict with QSPI usage?
 
@defragster - Sorry not really sure what is going on, just that when I saw stuff about configuring some pins for I2S where are not I2S pins, It made me suspicious that maybe some of the other settings like DMA and the like may not be setup to work on a T4.x...
 
@defragster - Sorry not really sure what is going on, just that when I saw stuff about configuring some pins for I2S where are not I2S pins, It made me suspicious that maybe some of the other settings like DMA and the like may not be setup to work on a T4.x...

Okay, I had just glanced at the comments on the pin #'s (and saw i2s comments) before posting - then the 'red notes' on the FLEXIO mux set. So potential issue is not because the are mux'able to FLEXIO - but if the code tried enabling them as i2s when they are not - the side effects could be the problem.
 
@defragster - @KurtE
Pretty much what Kurt said - there is some sort of conflict but didn't spend much time tracking it down specifically as I just rewrote to get rid of I2S/DMA and use the MPU-9250 to get real data. Heres the greatest incarnation of the test sketch if you have a I2C MPU-9250 laying around. Pretty sure you have one left over from days gone by :)

there are a few commands you can send:
s - start data acquisition
q - stop data acquisition
r - read data file you just created on flash
d - first dump list of storages
x - reset.

Code:
#include "Arduino.h"

#include "SD.h"
#include "MTP.h"

//used for logger
File mfile;
uint64_t fTot, totSize1;
int16_t state;

uint32_t maxDel=0;
char header[512];
char filename[80];

//used for MPU9250 and data structure

#include "MPU9250.h"

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;

//define a struct of various data types
struct MYDATA_t {
  float ax, ay, az;
  float gx, gy, gz;
  float mx, my, mz;
  float temp;
};

//define a struct joining MYDATA_t to an array of bytes to be stored
union MYDATA4I2C_t {
 MYDATA_t datastruct;
 uint8_t I2CPacket[sizeof(MYDATA_t)];
};

MYDATA4I2C_t mydata; //data to be written in memory
MYDATA4I2C_t readdata; //data read from memory


#if defined(__IMXRT1062__)
  // following only while usb_mtp is not included in cores
  #if __has_include("usb_mtp.h")
    #include "usb_mtp.h"
  #else
    #include "usb1_mtp.h"
  #endif
#endif

#define USE_EVENTS 1
#define USE_SD  0
#define USE_LITTLEFS 1 // set to zero if no LtttleFS is existing or to be used

#if USE_LITTLEFS==1
#ifdef ARDUINO_TEENSY41
  #define USE_RAM 0     // T4.1 PSRAM (or RAM)
#else
  #define USE_RAM 0     // T4.1 PSRAM (or RAM)
#endif
  #define USE_SPI 0
  #define USE_QSPI 0
  #define USE_NAND 0
  #define USE_QSPI_NAND 1
  #define USE_FRAM 0
#endif

#if USE_EVENTS==1
  extern "C" int usb_init_events(void);
#else
  int usb_init_events(void) {}
#endif


#if defined(__IMXRT1062__)
  // following only as long usb_mtp is not included in cores
  #if !__has_include("usb_mtp.h")
    #include "usb1_mtp.h"
  #endif
#else
  #ifndef BUILTIN_SCCARD 
    #define BUILTIN_SDCARD 254
  #endif
  void usb_mtp_configure(void) {}
#endif

/****  Start device specific change area  ****/
#if USE_SD==1
  // edit SPI to reflect your configuration (following is for T4.1)
  #define SD_MOSI 11
  #define SD_MISO 12
  #define SD_SCK  13

  #define stor_SPEED SD_SCK_MHZ(16)  // adjust to sd card 

// SDClasses
  const char *sd_str[]={"sdio"}; // edit to reflect your configuration
  const int cs[] = {BUILTIN_SDCARD}; // edit to reflect your configuration
  const int nsd = sizeof(cs)/sizeof(int);

SDClass storfs[nsd];
#endif

//LittleFS classes
#if USE_LITTLEFS==1
  #include "LittleFS.h"
  #include "LittleFS_NAND.h"
  
  #if USE_RAM == 1
    const char *stor_str[]={"RAM0"};     // edit to reflect your configuration
    const int stor_size[] = {2'000'000};
    const int stor_nsd = sizeof(stor_size)/sizeof(int);
    LittleFS_RAM storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_SPI == 1
    const char *stor_str[]={"WINBOND"};     // edit to reflect your configuration
    const int stor_cs[] = {5}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_FRAM == 1
    const char *stor_str[]={"CYPRESS"};     // edit to reflect your configuration
    const int stor_cs[] = {10}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

  #if USE_NAND == 1
    const char *stor_str[]={"WINBOND1G"};     // edit to reflect your configuration
    const int stor_cs[] = {3}; // edit to reflect your configuration
    const int stor_nsd = sizeof(stor_cs)/sizeof(int);
    LittleFS_SPINAND storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

  #if USE_QSPI_NAND == 1
    const char *stor_str[]={"WINBOND1G"};     // edit to reflect your configuration
    const int stor_nsd = 1;
    LittleFS_QPINAND storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_QSPI == 1
    const char *stor_str[]={"QSPI0"};     // edit to reflect your configuration
    const int stor_nsd = 1;
    LittleFS_QSPIFlash storfs[stor_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
 
#endif


MTPStorage_SD storage;
MTPD       mtpd(&storage);


void storage_configure()
{
  #if USE_SD==1
    #if defined SD_SCK
      SPI.setMOSI(SD_MOSI);
      SPI.setMISO(SD_MISO);
      SPI.setSCK(SD_SCK);
    #endif

    for(int ii=0; ii<nsd; ii++)
    { if(cs[ii] == BUILTIN_SDCARD)
      {
        if(!storfs[ii].sdfs.begin(SdioConfig(FIFO_SDIO))) {Serial.println("No storage"); while(1);};
        storage.addFilesystem(storfs[ii], sd_str[ii]);
      }
      else if(cs[ii]<BUILTIN_SDCARD)
      {
        pinMode(cs[ii],OUTPUT); digitalWriteFast(cs[ii],HIGH);
        if(!storfs[ii].sdfs.begin(SdSpiConfig(cs[ii], SHARED_SPI, stor_SPEED))) {Serial.println("No storage"); while(1);}
        storage.addFilesystem(storfs[ii], sd_str[ii]);
      }
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,cs[ii],sd_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
    }
    #endif

    #if USE_LITTLEFS==1
      #if USE_RAM == 1
        for(int ii=0; ii<stor_nsd;ii++)
        {
          { if(!ramfs[ii].begin(stor_size[ii])) { Serial.println("No storage"); while(1);}
            storage.addFilesystem(ramfs[ii], stor_str[ii]);
          }
          uint64_t totalSize = ramfs[ii].totalSize();
          uint64_t usedSize  = ramfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_SPI == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_FRAM == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_NAND == 1
        for(int ii=0; ii<stor_nsd;ii++) {
          pinMode(stor_cs[ii],OUTPUT); digitalWriteFast(stor_cs[ii],HIGH);
          if(!storfs[ii].begin(stor_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
          
        uint64_t totalSize = storfs[ii].totalSize();
        uint64_t usedSize  = storfs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,stor_cs[ii],stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_QSPI_NAND == 1
       for(int ii=0; ii<stor_nsd;ii++) {
          if(!storfs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
     
          uint64_t totalSize = storfs[ii].totalSize();
          uint64_t usedSize  = storfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_QSPI == 1
       for(int ii=0; ii<stor_nsd;ii++) {
          if(!storfs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(storfs[ii], stor_str[ii]);
     
          uint64_t totalSize = storfs[ii].totalSize();
          uint64_t usedSize  = storfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,stor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif
      
    #endif
}
/****  End of device specific change area  ****/


void setup()
{ 
  Serial.begin(115200);
  #if defined(USB_MTPDISK_SERIAL) 
    while(!Serial); // comment if you do not want to wait for terminal
  #else
    //while(!Serial.available()); // comment if you do not want to wait for terminal (otherwise press any key to continue)
    while(!Serial.available() && millis() < 5000); // or third option to wait up to 5 seconds and then continue
  #endif
  Serial.println("MTP logger");

  #if USE_EVENTS==1
    usb_init_events();
  #endif

  #if !__has_include("usb_mtp.h")
    usb_mtp_configure();
  #endif
  storage_configure();

 //Init 9250 i2c
  // start communication with IMU 
  status = IMU.begin();
  if (status < 0) {
    Serial.println("IMU initialization unsuccessful");
    Serial.println("Check IMU wiring or try cycling power");
    Serial.print("Status: ");
    Serial.println(status);
    while(1) {}
  }


  state=-1;

  Serial.println("Setup done");
  Serial.println(" Enter s to start acquisition and q to stop acquisition");
  Serial.flush();
}


uint32_t loop_count=0;
void loop()
{ loop_count++;
  state = do_menu(state);
  state = check_filing(state);
  //
  if(state<0)
    mtpd.loop();
  else
    state=do_logger(0,state);

  if(state>=0) logg(1000,"loop");
  //asm("wfi"); // may wait forever on T4.x

}



/**************** Online logging *******************************/
extern uint32_t loop_count, acq_count, acq_miss, maxDel;
extern uint16_t maxCount;
void logg(uint32_t del, const char *txt)
{ static uint32_t to;
  if(millis()-to > del)
  {
    Serial.printf("%s: %6d %d\n",
            txt,loop_count, state); 
    loop_count=0;
    to=millis();
  }
}

int16_t do_menu(int16_t state)
{ // check Serial input
  if(!Serial.available()) return state;
  char cc = Serial.read();
  if(cc == 's'){// start acquisition
      if(state>=0) return state;
      state=0;
      Serial.println("\nStart");
  }
  if(cc == 'q'){ // stop acquisition
      if(state<0) return state;
      state=4;
      Serial.println("\nStop");
  }
  if(cc == 'x'){
      Serial.println("Reset");
      mtpd.send_DeviceResetEvent();
  }
  if(cc == 'd'){
      // first dump list of storages:
      uint32_t fsCount = storage.getFSCount();
      Serial.printf("\nDump Storage list(%u)\n", fsCount);
      for (uint32_t ii = 0; ii < fsCount; ii++) {
        Serial.printf("store:%u name:%s fs:%x\n", ii, storage.getStoreName(ii), (uint32_t)storage.getStoreFS(ii));
      }
      Serial.println("\nDump Index List");
      storage.dumpIndexList();
  }
  if(cc == 'r'){
      Serial.println("r key hit");
      Serial.printf("FILE: %s\n", filename);
      read_data_file();
  }

  return state;
}

int16_t do_logger(uint16_t store, int16_t state)
{ uint32_t to=millis();

    if(state==0)
    { // acquisition is running, need to open file
      if(!file_open(store)) 
        return -2;
      state=1;
      //Serial.println("file_open");
    }
    if(state==1)
    { // file just opended, need to write header
      if(!file_writeHeader()) return -3;
      //Serial.println("wrote header");
      state=2;
      
    }
    if(state>=2)
    { // write data to disk
      if(!file_writeData()) return -4;
      //Serial.println("write data to disk");
    }

  if(state==3)
  { // close file, but continue acquisition
    if(!file_close()) return -5;
    //Serial.println("close file");
    state=0;
  }

  if(state==4)
  { // close file and stop acquisition
    if(!file_close()) return -6;
    //Serial.println("file_close and stop");
    state=-1;
  }

  uint32_t dt=millis()-to;
  if(dt>maxDel) maxDel=dt;

  return state;
}

uint32_t t_on = 60;
int16_t check_filing(int16_t state)
{
  static uint32_t to;
  if(state==2)
  {
    uint32_t tt = rtc_get();
    uint32_t dt = tt % t_on;
    if(dt<to) state = 3;
    to = dt;
  }
  return state;
}


void makeHeader(char *header)
{
  memset(header,0,512);
}

int16_t file_writeHeader(void)
{ if(!mfile) return 0;
  makeHeader(header);
  //size_t nb = mfile.write(header,512);
  //return (nb==512);
  return 1;
}


int16_t makeFilename(char *filename)
{
  uint32_t tt = rtc_get();
  int hh,mm,ss;
  int dd;
  ss= tt % 60; tt /= 60;
  mm= tt % 60; tt /= 60;
  hh= tt % 24; tt /= 24;
  dd= tt;
  sprintf(filename,"/%d/%02d_%02d_%02d.raw",dd,hh,mm,ss);
  Serial.println(filename);
  return 1;
}

int16_t checkPath(uint16_t store, char *filename)
{
  int ln=strlen(filename);
  int i1=-1;
  for(int ii=0;ii<ln;ii++) if(filename[ii]=='/') i1=ii;
  if(i1<0) {
    //Serial.println("NO PATH");
    return 1; // no path
  }
  filename[i1]=0;
  if(!storfs[store].exists(filename))
  { 
    //Serial.println("MAKING DIRECTORY");
    Serial.println(filename); 
    if(!storfs[store].mkdir(filename)) 
    {
      Serial.println("directory fail");
      return 0;
    }
  }
  //Serial.println("Check path OK");
  filename[i1]='/';
  return 1;
}


/*************************** Filing *****************************/
int16_t file_open(uint16_t store)
{ 
  if(!makeFilename(filename)) {
    //Serial.println("filename created");
    return 0;
  }
  if(!checkPath(store, filename)){
    //Serial.println("check path fail");
    return 0;
  }
  //Serial.println("Opening FIle");
  mfile = storfs[store].open(filename,FILE_WRITE_BEGIN);
  Serial.printf("File Open: %d\n", mfile);
  return !(!mfile);
}

int16_t file_writeData()
{ if(!mfile) return 0;
  uint16_t arraySize = sizeof(MYDATA_t);
  uint8_t diskBuffer[arraySize];
  IMU.readSensor();
  mydata.datastruct.ax = IMU.getAccelX_mss();
  mydata.datastruct.ay = IMU.getAccelY_mss();
  mydata.datastruct.az = IMU.getAccelZ_mss();
  mydata.datastruct.gx = IMU.getGyroX_rads();
  mydata.datastruct.gy = IMU.getGyroY_rads();
  mydata.datastruct.gz = IMU.getGyroZ_rads();
  mydata.datastruct.mx = IMU.getMagX_uT();
  mydata.datastruct.my = IMU.getMagY_uT();
  mydata.datastruct.mz = IMU.getMagZ_uT();
  mydata.datastruct.temp = IMU.getTemperature_C();
  for(uint16_t j = 0; j < arraySize; j++) {
    diskBuffer[j]= mydata.I2CPacket[j];
  }
  uint32_t nb = mfile.write(diskBuffer, arraySize);
  return 1;
}

int16_t file_close(void)
{ mfile.close();
  return (!mfile);
}

void read_data_file()
{
    uint16_t arraySize = sizeof(MYDATA_t);
  //Serial.println("Opening FIle");
  mfile = storfs[0].open(filename,FILE_READ);
  Serial.printf("FILE: %s\n", filename);
  
  mfile.seek(0);  
  
  uint64_t file_pos = 0;
  while(file_pos <= mfile.size()) {
    mfile.read(readdata.I2CPacket, arraySize);
    Serial.print(readdata.datastruct.ax,4); Serial.print("\t");
    Serial.print(readdata.datastruct.ay,4); Serial.print("\t");
    Serial.print(readdata.datastruct.az,4); Serial.print("\t");
    Serial.print(readdata.datastruct.gx,4); Serial.print("\t");
    Serial.print(readdata.datastruct.gy,4); Serial.print("\t");
    Serial.print(readdata.datastruct.gz,4); Serial.print("\t");
    Serial.print(readdata.datastruct.mx,4); Serial.print("\t");
    Serial.print(readdata.datastruct.my,4); Serial.print("\t");
    Serial.print(readdata.datastruct.mz,4); Serial.print("\t");
    Serial.println(readdata.datastruct.temp);
    
    file_pos += arraySize;
  }
}
 
@defragster - @KurtE - @Paul
Just did a few more tests using the MPT-logger sketch just as a sanity check and see if I got any ECC errors well everything worked. The below is a table of chips tested and whether they Passed - data was written and read back.

Code:
w25M02
SPI - Passed
QSPI - Passed

W25N01
SPI - Passed
QSPI - Passed

W25N02
SPI - Passed
QSPI - Not tested

w25Q128JV
SPI - Passed
QSPI - Passed

W25Q64JV
SPI - Passed
QSPI - Passed

Cypress 1 MByte
SPI - Pass
 
there are a few commands you can send:
s - start data acquisition
q - stop data acquisition
r - read data file you just created on flash
d - first dump list of storages
x - reset.
]
I only wanted to clarify the "d - first dump list of storages" option
this prints out the relevant info of the index file, mtp uses to access the files.
It is only useful during development and requires understanding of the index file structure , so consider this as a debug tool.
 
@WMXZ
I have been using @KurtE's branch of MTP for testing so I left the 'd' in to test events - as a debug tool as you said.
 
@PaulStoffregen - @defragster - @KurtE

In regards to BBM on the W25N02 I contacted Winbond to see if it was an error in the datasheet for the N02. Well, I got back an answer today and basically its not supported:
Answer 2 : Hi Michael,
The W25N02KV datasheet is correct and does not have BBM. NAND devices are page access where BBM is not as critical and relies on the controller to handle bad blocks.
Regards,
Robin
(2021-01-14 02:12:49)

So not sure what do with the N02 at this point.
 
Back
Top