Teensy 4.1 Beta Test

@defragster
Was kind of curious what would happen if I used a external SDCARD on SPI. Basically same issues but slightly different points (kk's at the start):
Code:
Starting logging

 	 BUFF at 70050000
skipped 17	1, 5796045, 3477372866, 0	 	 kk==17  ????
skipped 19	2, 5797045, 3477972866, 0	 	 kk==37  ????
skipped 6	3276, 9071195, 1147495580, 1	 	 kk==16384  ????
skipped 0	3276, 9071245, 1147525564, 1	 	 kk==16385  ????
skipped 3	826, 6621045, 3972372866, 0	 	 kk==16517  ????
skipped 19	827, 6622045, 3972972866, 0	 	 kk==16537  ????
0] 3331.40 mSec fill [lp#3944000] 	Writing dbuff0 to data file.  tmilli =  0  took  25.50 mSec
 	 BUFF at 70090000
skipped 16	3277, 9072045, 1148005570, 1	 	 kk==17  ????
skipped 19	3278, 9073045, 1148605570, 1	 	 kk==37  ????
1] 3276.77 mSec fill [lp#3944000] 	Writing dbuff1 to data file.  tmilli =  3276  took  26.28 mSec
 
@defragster
Going back to the built-in sdcard if you reduce the buffer size to 2048*8 you get rid of those high index errors but you still get the index errors with a repeating patterns on buffer0 and buffer1. Beginning to wonder if its an addressing issue or timing issue?:
Code:
Starting logging

 	 BUFF at 70050000
skipped 14	1, 3562019, 2136979936, 0	 	 [COLOR="#FF0000"]kk==14  ????[/COLOR]
skipped 19	2, 3563019, 2137579936, 0	 	 [COLOR="#FF0000"]kk==34  ????[/COLOR]
0] 848.85 mSec fill [lp#3453197] 	Writing dbuff0 to data file.  tmilli =  0  took   6.42 mSec
 	 BUFF at 70090000
skipped 9	820, 4381019, 2628379931, 1	 	 [COLOR="#008000"]kk==10  ????[/COLOR]
skipped 19	821, 4382019, 2628979930, 1	 	 [COLOR="#008000"][COLOR="#008000"]kk==30  ????[/COLOR][/COLOR]
1] 819.36 mSec fill [lp#3453197] 	Writing dbuff1 to data file.  tmilli =  819  took   6.60 mSec
 	 BUFF at 70050000
skipped 5	1639, 5200019, 3119779930, 0	 	 kk==6  ????
skipped 19	1640, 5201019, 3120379931, 0	 	 kk==26  ????
0] 819.20 mSec fill [lp#438066] 	Writing dbuff0 to data file.  tmilli =  1638  took   6.61 mSec
 	 BUFF at 70090000
skipped 1	2458, 6019019, 3611179931, 1	 	 kk==2  ????
skipped 19	2459, 6020019, 3611779931, 1	 	 kk==22  ????
1] 819.18 mSec fill [lp#1282655] 	Writing dbuff1 to data file.  tmilli =  2457  took   6.60 mSec
 	 BUFF at 70050000
skipped 17	3278, 6839019, 4103179931, 0	 	 kk==18  ????
skipped 19	3279, 6840019, 4103779931, 0	 	 kk==38  ????
0] 819.20 mSec fill [lp#2128225] 	Writing dbuff0 to data file.  tmilli =  3277  took   6.61 mSec
 	 BUFF at 70090000
skipped 13	4097, 7658019, 299612635, 1	 	[COLOR="#FF0000"] kk==14  ????[/COLOR]
skipped 19	4098, 7659019, 300212635, 1	 	[COLOR="#FF0000"] kk==34  ????[/COLOR]
1] 819.19 mSec fill [lp#2972206] 	Writing dbuff1 to data file.  tmilli =  4096  took   6.61 mSec
 	 BUFF at 70050000
skipped 9	4916, 8477019, 791012635, 0	 	 [COLOR="#008000"]kk==10  ????[/COLOR]
skipped 19	4917, 8478019, 791612634, 0	 	 [COLOR="#008000"]kk==30  ????[/COLOR]
0] 819.18 mSec fill [lp#2972206] 	Writing dbuff0 to data file.  tmilli =  4915  took   6.61 mSec
 	 BUFF at 70090000
skipped 5	5735, 9296019, 1282412634, 1	 	 kk==6  ????
skipped 19	5736, 9297019, 1283012635, 1	 	 kk==26  ????
1] 819.19 mSec fill [lp#5] 	Writing dbuff1 to data file.  tmilli =  5734  took   6.61 mSec
 	 BUFF at 70050000
skipped 1	6554, 10115019, 1773812635, 0	 	 kk==2  ????
skipped 19	6555, 10116019, 1774412635, 0	 	 kk==22  ????
0] 819.19 mSec fill [lp#834383] 	Writing dbuff0 to data file.  tmilli =  6553  took   6.61 mSec
 	 BUFF at 70090000
skipped 17	7374, 10935019, 2265812635, 1	 	 kk==18  ????
skipped 19	7375, 10936019, 2266412635, 1	 	 kk==38  ????
1] 819.18 mSec fill [lp#1678883] 	Writing dbuff1 to data file.  tmilli =  7373  took   6.60 mSec
 	 BUFF at 70050000
skipped 13	8193, 11754019, 2757212635, 0	 	 kk==14  ????
skipped 19	8194, 11755019, 2757812635, 0	 	 kk==34  ????
0] 819.20 mSec fill [lp#2524610] 	Writing dbuff0 to data file.  tmilli =  8192  took   6.61 mSec
 	 BUFF at 70090000
skipped 9	9012, 12573019, 3248612635, 1	 	 kk==10  ????
skipped 19	9013, 12574019, 3249212634, 1	 	 kk==30  ????
1] 819.19 mSec fill [lp#3368463] 	Writing dbuff1 to data file.  tmilli =  9011  took   6.61 mSec
 	 BUFF at 70050000
skipped 5	9831, 13392019, 3740012634, 0	 	 kk==6  ????
skipped 19	9832, 13393019, 3740612635, 0	 	 kk==26  ????
0] 819.18 mSec fill [lp#3368463] 	Writing dbuff0 to data file.  tmilli =  9830  took   6.60 mSec
 	 BUFF at 70090000
 
@defragster
Going back to the built-in sdcard if you reduce the buffer size to 2048*8 you get rid of those high index errors but you still get the index errors with a repeating patterns on buffer0 and buffer1. Beginning to wonder if its an addressing issue or timing issue?:

Yes there is something problematic about that 0x4000 offset boundary - from the write under _isr()? OR just the boundary? That can be targeted with changes to these and using any size buffer:
Code:
uint8_t config = INIT_PSRAM_ONLY;
struct datrec *dbuff0 = (datrec *)[B][COLOR="#FF0000"]0x70050000;  // ERROR on this start point of 0x70050000 OFFSET 0x4000[/COLOR][/B]
struct datrec *dbuff1 = (datrec *)0x70090000;
#else

>> Next try here will be remove the intervalTimer and call that code from loop() that is currently running 2+ Millions times per second. Indicated here >> 1] 918.82 mSec fill [lp#2023883]
>> OTHER next try if that hides the problem will be SHIFTING the dbuff# pointers through UP through PSRAM after each buffer ' WRITE to SD ' before the 'LOGGING' uses the pointer. This will cross ALL boundaries over time to see if there is a pattern.
>> Could also adjust the Log data to have useful info :: RAW SAMPLE WRITE count, and the ADDRESS written
>> Could also fully remove the SD card code as this is now a RAM only process.
>> Can also eliminate the '????' for partial on start - it will change run to run but after the first it will be known - will set to a static and not SPEW it when it matches.
- will post complete code with changes soon.

For now those other recurring start of buffer issues are simply from millis() WRAP across the buffer change boundaries - update this code snippet:
Code:
void WriteBinary(volatile struct datrec *drp, size_t numstructs) {

//	dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

	Serial.printf(" \t BUFF at %lX\n", drp );
uint32_t lastM = 0;
	uint32_t kk,lastB = 5;
	uint32_t ii = 0, iiL = 0;
	lastB = drp[0].byteswritten;
	for ( kk=0; kk<numstructs; kk++) {
		if ( lastM != drp[kk].millitime || lastB != drp[kk].byteswritten ) {
			if ( lastM != drp[kk].millitime )
				lastM = drp[kk].millitime;
				
			if ( ii != iiL ) {
			Serial.printf("skipped %lu\t", ii);
			Serial.printf("%lu, %lu, %lu, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
				Serial.printf(" \t kk==%lu  ????\n", kk );
			}
			iiL = ii;
			ii = 0;
		}
		else
			ii++;
	}
[B]			Serial.printf("END WRAP skipped %lu\t", ii);
			kk = numstructs - 1;
			Serial.printf("%lu, %lu, %lu, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
				Serial.printf(" \t kk==%lu  <<<<< done\n", kk );
[/B]
	//dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

Expected ::That code change shows this 'END WRAP' partial set of same millis() written - where the 'skipped 5' at the end completes a set of 20 with the 'skipped 13' on the next buffer start:
Code:
END WRAP[COLOR="#FF0000"] [B]skipped 5[/B][/COLOR]	919, 8345257, 711933969, 0	 	 kk==18379  <<<<< done
0] 958.00 mSec fill [lp#4084149] 	Writing dbuff0 to data file.  tmilli =  0  took   7.47 mSec
 	 BUFF at 70090000
[B][COLOR="#FF0000"]skipped 13[/COLOR][/B]	920, 8346007, 712383962, 1	 	 kk==14  ????
skipped 19	921, 8347007, 712983962, 1	 	 kk==34  ????
END WRAP skipped 5	1838, 9264257, 1263333974, 1	 	 kk==18379  <<<<< done
1] 918.81 mSec fill [lp#4084149] 	Writing dbuff1 to data file.  tmilli =  919  took   7.29 mSec
 	 BUFF at 70050000
skipped 13	1839, 9265007, 1263783963, 0	 	 kk==14  ????
skipped 19	1840, 9266007, 1264383963, 0	 	 kk==34  ????
 
Here is what I can do for now. Removed all need for and use of SD. Compile option for USE_logtime on elapsedMicros versus intervalTimer.
All items in p#328 except :: >> OTHER next try if that hides the problem will be SHIFTING the dbuff# pointers through UP through PSRAM after each buffer ' WRITE to SD ' before the 'LOGGING' uses the pointer. This will cross ALL boundaries over time to see if there is a pattern.

Using 'elapsedMicros' there is NO DATA CORRUPTION! Why does intervalTimer PSRAM write get confused???

Removed extra SPEW prints. There is a log SPEW anomaly on use 'elapsedMicros' - it always shows a 'skipped ###' - but no errors.

These DATA values : skipped 156 10117, 202337, 700909D0, 1
are now:
Code:
skipped 156	// same skip count based on millis continuity 
10117,       // log millis at time of record - SAME
[B]202337,     // Index count of LOG entries made from start 'r' :: Could key on this for continuity to detect anomolies
700909D0,     // "HEX" ADDRESS written for this LOG datrec struct
[/B]1	 // Log buffer index 0 or 1 - SAME

When :: // #define USE_logtime
it used the interval timer and the log anomalies appears as below - compile with #define USE_logtime uses 'elapsedMicros' and the PSRAM error goes away:
Code:
Starting logging
 	 BUFF at 70050000
 	 HIDE overWrap of 9  <<<<< 
 	 HIDE firstWrap of 19  <<<<< 
skipped 14	919, 18380, 70090000, 1	 	 kk==16384  ????
skipped 0	919, 18381, 70090010, 1	 	 kk==16385  ????
skipped 11	827, 16529, 70090910, 0	 	 kk==16529  ????
0] 926.40 mSec fill [lp#71356] 	Writing dbuff0 to data file.  tmilli =  0  took   7.40 mSec
 	 BUFF at 70090000
skipped 8	920, 18389, 70090090, 1	 	 kk==9  ????
1] 918.80 mSec fill [lp#461159] 	Writing dbuff1 to data file.  tmilli =  919  took   7.21 mSec
 	 BUFF at 70050000
skipped 8	1839, 36769, 70050090, 0	 	 kk==9  ????
skipped 14	2757, 55140, 70090000, 1	 	 kk==16384  ????
skipped 0	2757, 55141, 70090010, 1	 	 kk==16385  ????
skipped 15	2665, 53289, 70090910, 0	 	 kk==16529  ????
0] 918.99 mSec fill [lp#891223] 	Writing dbuff0 to data file.  tmilli =  1838  took   7.21 mSec
 	 BUFF at 70090000
skipped 8	2758, 55149, 70090090, 1	 	 kk==9  ????
1] 919.21 mSec fill [lp#1320276] 	Writing dbuff1 to data file.  tmilli =  2757  took   7.43 mSec
 	 BUFF at 70050000
skipped 8	3677, 73529, 70050090, 0	 	 kk==9  ????
skipped 14	4595, 91900, 70090000, 1	 	 kk==16384  ????
skipped 0	4595, 91901, 70090010, 1	 	 kk==16385  ????
skipped 12	4503, 90049, 70090910, 0	 	 kk==16529  ????
0] 918.94 mSec fill [lp#1748168] 	Writing dbuff0 to data file.  tmilli =  3676  took   7.38 mSec
Stopping logging
ADCTimer halted
1719 KBytes written to file.

Current running code
Code:
/**************************************************************
  Simple SD card timing datalogger for Teensy 3.6

  https://forum.pjrc.com/threads/60754-Teensy-3-6-SD-Card-missing-time-in-milliseconds?p=238352&viewfull=1#post238352

  This example shows how to log timing data to an SD card using the SD library
  and SDFat 2.0b
  As much as possible, the code uses the simplest Arduino functions, adding
  teensy-specific code only where necessary (such as IntervalTimer).

  The circuit:

   SD card attached to built-in SD Card slot on t3.6


  This example uses  buffering and interval timer to collect at regular
  intervals without collection timing jitter caused by SDC writes.
  A time stamp is saved with each record.

  A minimal user interface is added with three one-letter commands:
      'r'   Open file and start recording data with verbose output
      'g'   Open file and start recording data with only block write delay output
      'q'   Quit logging data and close file
      'p'   Play back data in CSV format


  NOTES:
    1. Unlike the Simple Logger, this version saves only the binary data.
       Conversion to strings is done on playback.
    2. Playback is done one record at a time.  This is less efficient,
       but output is going to the Serial port, so speed isn't as much
       of an issue.
    3. if you uncomment #define USE_EXFAT the program will use the EXFat
       file system of SDFat 2.0beta.  You will need an SD Card formatted
       for the EXFat file system.  That can be done with the tools
       in the SDFat examples




  Written for Teensy 3.6 by M. Borgerson  May 7, 2020
********************************************************************/

elapsedMicros logTime;
[B][COLOR="#FF0000"]// #define USE_logtime[/COLOR][/B]
#define LOG_US (1000000 / SAMPLERATE)
#ifdef USE_logtime
#else
IntervalTimer ADCTimer;
#endif

// A simple structure to hold time stamp and three analog values
// The structure takes up 16 bytes to align millitime on 4-byte boundary
struct datrec {
	uint32_t millitime;
	uint32_t microtime;
	uint32_t DWTCount;
	uint32_t byteswritten;
};
// Allocate two buffers, each holding over 1 second of data.
// For efficiency, the total length should be a multiple of 512.
// Note that the T3.6 will run out of RAM at about 8000Hz sampling
// as each buffer would have to be 8000 * 16 or 128,000 bytes, leaving
// very little room for the stack, heap, and USB buffers.
//#define BUFFSIZE  1024

// allocate two buffers, each of which holds 1024 records
// each buffer is 1024 * 16 or 16KBytes

uint32_t logIndex = 0;
#define SAMPLERATE 20000
#define USE_PSRAM 1
#ifdef USE_PSRAM // 128KB apart
#define BUFFSIZE  9190*2
const char *logfilename = "TIMELG_R1.DAT";
#include <extRAM_t4.h>
extRAM_t4 eRAM;
//uint8_t config = 2; //0 - init eram only, 1-init flash only, 2-init both
//These have been replaced with defines for:
//INIT_PSRAM_ONLY
//INIT_FLASH_ONLY
//INIT_PSRM_FLASH
uint8_t config = INIT_PSRAM_ONLY;
struct datrec *dbuff0 = (datrec *)0x70050000;
struct datrec *dbuff1 = (datrec *)0x70090000;
#else
//#define BUFFSIZE  1024
#define BUFFSIZE  9190*2
const char *logfilename = "TIMELOG1.DAT";
struct datrec dbuff1[BUFFSIZE];
//struct datrec dbuff1[BUFFSIZE];
struct datrec *dbuff0 = (datrec *)malloc(BUFFSIZE*sizeof(datrec));

#endif


#define DEBUGPRINT true


// when graphout is true, during recording, only the block write
// interval is displayed.  This allows graphing with the Arduino
// Serial Plotter display.
bool graphout = false;
bool logging = false;

// these variables are declared volatile because they are changed or used in the
// interrupt handler
volatile uint16_t saveidx = 0;
volatile int16_t writebuffnum = -1;
volatile uint16_t savebuffnum = 0;
volatile uint32_t filestartmilli = 0;
volatile uint32_t byteswritten = 0;

const int ledpin = 13;

#define LEDON  digitalWriteFast(ledpin, HIGH);
#define LEDOFF digitalWriteFast(ledpin, LOW);

const char compileTime [] = "Timing Data Logger  Compiled on " __DATE__ " " __TIME__;
void setup() {
	if ( ARM_DWT_CYCCNT == ARM_DWT_CYCCNT ) {	  // activate ARM cycle counter
		ARM_DEMCR |= ARM_DEMCR_TRCENA; // Assure Cycle Counter active
		ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
	}

	pinMode(ledpin, OUTPUT);
	// Open serial communications and wait for port to open:
	Serial.begin(9600);
	while (!Serial && millis() < 4000 );
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	Serial.println(compileTime);
	// see if the card is present and can be initialized:
	Serial.print("Initializing SD card...");

#ifdef USE_PSRAM // 128KB apart
	eRAM.begin(config);
	Serial.print("Start PSRAM for LOGGING :: ");
	Serial.println( logfilename );
#else
	Serial.print("LOGGING from RAM :: ");
	Serial.println( logfilename );
#endif

	Serial.printf("\nTwin buffers of size %u Bytes\n" , sizeof(datrec)*BUFFSIZE );
	Serial.println("Enter command selected from (r, g, q, p, s)");
}

void FastBlink(void) {  // blink forever
	while (1) {
		LEDON
		delay(50);
		LEDOFF
		delay(50);
	}
}

static uint32_t elapsedUS = 0;
uint32_t loopCnt = 0, loopSpd;
elapsedMillis elapsedLoop = 0;
void loop() {
	// put your main code here, to run repeatedly:
	char ch;
	uint32_t microselapsed;
	elapsedMicros wrtelapsed = 0;
	loopCnt++;
	if ( elapsedLoop >= 1000 ) {
		loopSpd = loopCnt;
		loopCnt = 0;
		elapsedLoop -= 1000;
	}

#ifdef USE_logtime
	if ( logging && logTime > LOG_US ) {
		logTime -= LOG_US;
		ADCChore();
	}
#endif

	if (Serial.available()) {
		ch = Serial.read();
		if (ch == 'r') {
			graphout = false;
			StartLogging();
		}
		if (ch == 'g') {
			graphout = true;
			StartLogging();
		}
		if (ch == 'q') StopLogging();
	}
	// Now check to see if a buffer is ready to be written to SD
	// writebuffnum will be set in the interrupt handler
	if (writebuffnum == 0) { //is dbuff0 ready?
		LEDON
		writebuffnum = -1;
		if (1) { //if the file is open write dbuff0
			wrtelapsed = 0;
			WriteBinary(&dbuff0[0], BUFFSIZE);
			microselapsed = wrtelapsed;
			if (DEBUGPRINT) {
				if (graphout) {
					Serial.println((float)microselapsed / 1000.0);
				} else {
					loopCnt = loopCnt / (micros() - elapsedUS);
					Serial.printf("0] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
					Serial.print("Writing dbuff0 to data file.  tmilli = ");
					Serial.printf(" %lu  took %6.2f mSec\n", dbuff0[0].millitime, (float)microselapsed / 1000.0);
					elapsedUS = micros();
				}
			}
		}
		LEDOFF
	}
	else if (writebuffnum == 1) { // is dbuff1 ready?
		LEDON
		writebuffnum = -1;
		if (1) { //if the file is open write dbuff0
			wrtelapsed = 0;
			WriteBinary(&dbuff1[0], BUFFSIZE);
			microselapsed = wrtelapsed;
			if (DEBUGPRINT) {
				if (graphout) {
					Serial.println((float)microselapsed / 1000.0);
				} else {
					loopCnt = loopCnt / (micros() - elapsedUS);
					Serial.printf("1] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
					Serial.print("Writing dbuff1 to data file.  tmilli = ");
					Serial.printf(" %lu  took %6.2f mSec\n", dbuff1[0].millitime, (float)(microselapsed) / 1000.0);
					elapsedUS = micros();
				}
			}
		}
		LEDOFF
	}
	//delay(5);
}  // end of the loop() function

// write a buffer to the file as binary record. This  takes more time and file space than
// binary format, but can be directly read on PC.
// Note that we have to cast datrec pointer to a uint8_t pointer
// to keep the SD libraryhappy
static uint32_t firstWrap = 999;
static uint32_t overWrap = 999;
void WriteBinary(volatile struct datrec *drp, size_t numstructs) {

//	dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

	Serial.printf(" \t BUFF at %lX\n", drp );
	uint32_t lastM = 0;
	uint32_t kk, lastB = 5;
	uint32_t ii = 0, iiL = 0;
	lastB = drp[0].byteswritten;
	for ( kk = 0; kk < numstructs; kk++) {
		if ( lastM != drp[kk].millitime || lastB != drp[kk].byteswritten ) {
			if ( overWrap == 999 ) {
				overWrap = ii;
				Serial.printf(" \t HIDE overWrap of %lu  <<<<< \n", overWrap );
			}
			else if ( firstWrap == 999 ) {
				firstWrap = ii;
				Serial.printf(" \t HIDE firstWrap of %lu  <<<<< \n", firstWrap );
			}
			if ( lastM != drp[kk].millitime )
				lastM = drp[kk].millitime;

			if ( ii != iiL && ii != firstWrap && ii != overWrap ) {
				Serial.printf("skipped %lu\t", ii);
				Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
				Serial.printf(" \t kk==%lu  ????\n", kk );
			}
			iiL = ii;
			ii = 0;
		}
		else
			ii++;
	}
	if ( 0 ) { // not needed with overWrap detect
		Serial.printf("END WRAP skipped %lu\t", ii);
		kk = numstructs - 1;
		Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
		Serial.printf(" \t kk==%lu  <<<<< done\n", kk );
	}

	//dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

}

// This is the interrupt handler for the interval timer.
// It saves the data in the data buffer structures.  The output is converted
// to CSV text when it is saved to the output file in the main loop.
// We don't want to do the conversion to a string in the interrupt handler
// since it takes a lot more time and many of the string routines are not
// reentrant. (Programmer talk for "They don't play nicely when interrupted")
void ADCChore(void) {
	uint32_t tmilli;
	tmilli = millis() - filestartmilli;
	byteswritten += sizeof(datrec); // update global bytes written count
	// save in  the proper buffer--defined by savebuffnum
	if (savebuffnum == 0) { // put data in dbuff0
		dbuff0[saveidx].millitime = tmilli;
		dbuff0[saveidx].microtime =  logIndex++;
		dbuff0[saveidx].DWTCount = (uint32_t)dbuff0 + (sizeof(datrec) * saveidx);;
		//dbuff0[saveidx].byteswritten = byteswritten;
		dbuff0[saveidx].byteswritten = 0;
		saveidx++;
		if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
			writebuffnum = 0;
			savebuffnum = 1;   // start saving in other buffer on next interrupt
			saveidx = 0;  // start at beginning of next buffer
		}
	} else {  // must be saving to dbuff1
		dbuff1[saveidx].millitime = tmilli;
		dbuff1[saveidx].microtime =  logIndex++;
		dbuff1[saveidx].DWTCount = (uint32_t)dbuff1 + (sizeof(datrec) * saveidx);;
		//dbuff1[saveidx].byteswritten = byteswritten;
		dbuff1[saveidx].byteswritten = 1;
		saveidx++;
		if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
			writebuffnum = 1;
			savebuffnum = 0;   // start saving in other buffer on next interrupt
			saveidx = 0;   // start at beginning of next buffer
		}
	}
}

void StartLogging(void) {
	// we open in a mode that creates a new file each time
	// instead of appending as in the Arduino example
	if ( logging ) return;
	logging = true;
	elapsedUS = micros();
	loopCnt = 0;
	firstWrap = 999;
	overWrap = 999;
	logIndex = 0;

	Serial.println("Starting logging");
	// initialize some variables for the buffers
	saveidx = 0;   // start saving at beginning of buffer
	savebuffnum = 0;  // start saving in dbuff0
	writebuffnum = -1;  // indicates no buffer ready yet
	//  start the interval timer to begin logging
	filestartmilli = millis();
	byteswritten = 0;
#ifdef USE_logtime
	logTime = 0;
#else
	ADCTimer.begin(ADCChore, 1000000 / SAMPLERATE); //begin() expects timer period in microseconds
#endif

}

void StopLogging(void) {
	Serial.println("Stopping logging");
	logging = false;
#ifdef USE_logtime
	logTime = 0;
	if (DEBUGPRINT) Serial.println("eMicros Log halted");
#else
	ADCTimer.end();
	if (DEBUGPRINT) Serial.println("ADCTimer halted");
#endif
	delay(10);
	writebuffnum = -1;
	// dont' write tottal bytes if graphing--it messes up the plot!
	if (!graphout) {
		Serial.printf("%lu KBytes written to file.\n", byteswritten / 1024);
	}
	// in the interest of simplicity, we ignore any partial buffer at the end
}
 
@defragster
Does this mean it works:
Code:
Twin buffers of size 1048576 Bytes
Enter command selected from (r, g, q, p, s)
Allocation succeeded.
Starting logging
Stopping logging
ADCTimer halted
Data file closed.

11207 KBytes written to file.

Sparse Playback complete.

EDIT: Unfortunates if I hit "p" or "s" nothing is read from the file?
 
@defragster
Does this mean it works:
Code:
Twin buffers of size 1048576 Bytes
Enter command selected from (r, g, q, p, s)
Allocation succeeded.
Starting logging
Stopping logging
ADCTimer halted
Data file closed.

11207 KBytes written to file.

Sparse Playback complete.

No that means there was no data logged. There are no writes between START and STOP. Also the Print routines read the data from SD card - and last update had the writes commented, see below for current.

@mjs513 : there is an alternate write pattern to PSRAM i.e. check42() versus check24() - can you #ifdef that in "ADCChore()" rather than direct memory address? If that solves the problem then that shows the problem as direct write confusion. If that also fails then there is a cache problem or something ????

NOTE: IN current p#329 code with ALL SD lib use [open/read/write/…] removed - this is just PSRAM write that fails to have integrity when writes come from intervalTimer _isr() - also removed the Print and Sparse Print code to reduce code at hand so those funcs are GONE.

ALSO @mjs513 - this could be extended to QSPI eFlash usage for logging buffers! The StartLogging() and WriteBinary() function could format the buffer, and then ADCChore() would need to use the eFlash write procedures. I'll be OFFLINE a few hours - let me know if you see time to edit the code in search of the issue.
 
No that means there was no data logged. There are no writes between START and STOP. Also the Print routines read the data from SD card - and last update had the writes commented, see below for current.
Yea, figured that out after I posted. Interesting though same errors show up if I comment out use-PSRAM get the same errors.

EDIT:
@defragster said:
@mjs513 : there is an alternate write pattern to PSRAM i.e. check42() versus check24() - can you #ifdef that in "ADCChore()" rather than direct memory address? If that solves the problem then that shows the problem as direct write confusion. If that also fails then there is a cache problem or something ????
Yep- was actually looking at that earlier today. There are actually a couple ways of doing this but depends on usage.
 
Last edited:
Yea, figured that out after I posted. Interesting though same errors show up if I comment out use-PSRAM get the same errors.
EDIT:
Yep- was actually looking at that earlier today. There are actually a couple ways of doing this but depends on usage.

Same errors without PSRAM ???? :: //#define USE_PSRAM 1
I do not see that - just this which is just an anomaly in the monitor code. The anomaly detect failure in the 'HIDE" detection - would be better served using the (now present) running count than millis - but I didn't do that yet.
It shows the first millis sync on a buffer 'write' - and in fact confirms that buffer writte 1 or 0 matches the dbuff#
Code:
Starting logging
 	 BUFF at 20203068
 	 HIDE overWrap of 17  <<<<< 
 	 HIDE firstWrap of 19  <<<<< 
0] 919.50 mSec fill [lp#3146168] 	Writing dbuff0 to data file.  tmilli =  0  took   0.50 mSec
 	 BUFF at 20001370
skipped 16	920, 18397, 20001480, 1	 	 kk==17  ????
1] 918.73 mSec fill [lp#3600887] 	Writing dbuff1 to data file.  tmilli =  919  took   0.24 mSec
 	 BUFF at 20203068
skipped 16	1839, 36777, 20203178, 0	 	 kk==17  ????
0] 919.27 mSec fill [lp#4059925] 	Writing dbuff0 to data file.  tmilli =  1838  took   0.53 mSec
 	 BUFF at 20001370
skipped 16	2758, 55157, 20001480, 1	 	 kk==17  ????
1] 918.71 mSec fill [lp#4515964] 	Writing dbuff1 to data file.  tmilli =  2757  took   0.25 mSec

I'm only here long enough to make this post then off an hour or so on another task. If you can do the alternate write for PSRAM or even the eFlash that would extend this NON-SD test case for the QSPI chip when running from an _isr. As I understand the code from early beta that should work for eFlash - like the struct write code you did for the FRAM test - with a format before buffer (re)use.

This was something that needed done - but wasn't until @MBorgerson posted this code that I saw it to be something I could do in short order that would mirror REAL USE.
 
Testing the alternate writes now but I know my addressing is off:
Code:
    eRAM.writeLong(sbuff0_addr+saveidx, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx+4, micros());
    eRAM.writeLong(sbuff0_addr+saveidx+8, ARM_DWT_CYCCNT);
    eRAM.writeLong(sbuff0_addr+saveidx+16, 0);
Whats the increment for ramaddr - don't think saveidx is correct.
 
Testing the alternate writes now but I know my addressing is off:
Code:
    eRAM.writeLong(sbuff0_addr+saveidx, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx+4, micros());
    eRAM.writeLong(sbuff0_addr+saveidx+8, ARM_DWT_CYCCNT);
    eRAM.writeLong(sbuff0_addr+saveidx+16, 0);
Whats the increment for ramaddr - don't think saveidx is correct.

Each element in BUFFSIZE is :: sizeof(datrec)

Code:
struct datrec {
	uint32_t millitime;
	uint32_t microtime;
	uint32_t DWTCount;
	uint32_t byteswritten;
};

Prior post #329 has the latest code - with NO SD so anyone (with T_4.1 and PSRAM) can use it:
Code:
void ADCChore(void) {
	uint32_t tmilli;
	tmilli = millis() - filestartmilli;
	byteswritten += sizeof(datrec); // update global bytes written count
	// save in  the proper buffer--defined by savebuffnum
	if (savebuffnum == 0) { // put data in dbuff0
		dbuff0[saveidx].millitime = tmilli;
		[B]dbuff0[saveidx].microtime =  logIndex++;
		dbuff0[saveidx].DWTCount = (uint32_t)dbuff0 + ([U]sizeof(datrec) * saveidx[/U]);;[/B]
		//dbuff0[saveidx].byteswritten = byteswritten;
		[COLOR="#FF0000"]dbuff0[saveidx].byteswritten = 0;[/COLOR]
		saveidx++;
		if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
			writebuffnum = 0;
			savebuffnum = 1;   // start saving in other buffer on next interrupt
			saveidx = 0;  // start at beginning of next buffer
		}
	} else {  // must be saving to dbuff1
		dbuff1[saveidx].millitime = tmilli;
		[B]dbuff1[saveidx].microtime =  logIndex++;
		dbuff1[saveidx].DWTCount = (uint32_t)dbuff1 +[U] (sizeof(datrec) * saveidx)[/U];;[/B]
		//dbuff1[saveidx].byteswritten = byteswritten;
		[COLOR="#FF0000"]dbuff1[saveidx].byteswritten = 1;[/COLOR]
		saveidx++;
		if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
			writebuffnum = 1;
			savebuffnum = 0;   // start saving in other buffer on next interrupt
			saveidx = 0;   // start at beginning of next buffer
		}
	}
}
 
I setup a slightly different way using your previous version:
Code:
void ADCChore(void) {
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  uint32_t dataRecSize = 24;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    //dbuff0[saveidx].millitime = tmilli;
    //dbuff0[saveidx].microtime =  micros();
    //dbuff0[saveidx].DWTCount = ARM_DWT_CYCCNT;
    //dbuff0[saveidx].byteswritten = byteswritten;
    //dbuff0[saveidx].byteswritten = 0;
    //Serial.printf("idx: %d\n", saveidx);
    //Serial.printf("%d, %d\n", saveidx*dataRecSize, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize, tmilli);
    //Serial.printf("%x, %d\n", sbuff0_addr+saveidx*dataRecSize+4, micros());
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+4, micros());
    //Serial.printf("%x, %d\n", sbuff0_addr+saveidx*dataRecSize+8, ARM_DWT_CYCCNT);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+8, ARM_DWT_CYCCNT);
    //Serial.printf("%x, %d\n", sbuff0_addr+saveidx*dataRecSize+16, 99);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+16, 0);
    saveidx++;
    if (saveidx*dataRecSize >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
  } else {  // must be saving to dbuff1
    eRAM.writeLong(sbuff1_addr+saveidx*dataRecSize, tmilli);
    eRAM.writeLong(sbuff1_addr+saveidx*dataRecSize+4, micros());
    eRAM.writeLong(sbuff1_addr+saveidx*dataRecSize+8, ARM_DWT_CYCCNT);
    eRAM.writeLong(sbuff1_addr+saveidx*dataRecSize+16, 1);
    saveidx++;
    if (saveidx*dataRecSize >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
}

Code:
Starting logging

 	 BUFF at 70000000
END WRAP skipped 0	2863329263, 3081251308, 2328667823, 3735353514	 	 kk==16383  <<<<< done
0]  63.09 mSec fill [lp#1] 	Writing dbuff0 to data file.  tmilli =  1599167829  took   6.00 mSec
 	 BUFF at 70090000
skipped 8	135094, 2701869, 1879638160, 1	 	 kk==9  ????
skipped 19	135095, 2701889, 1879638480, 1	 	 kk==29  ????
END WRAP skipped 14	135912, 2718243, 1879900144, 1	 	 kk==16383  <<<<< done
1]  34.00 mSec fill [lp#1] 	Writing dbuff1 to data file.  tmilli =  135093  took   6.00 mSec
 	 BUFF at 70000000
END WRAP skipped 0	2863329263, 3081251308, 2328667823, 3735353514	 	 kk==16383  <<<<< done
0]  34.00 mSec fill [lp#1] 	Writing dbuff0 to data file.  tmilli =  1599167829  took   6.00 mSec
 	 BUFF at 70090000
skipped 8	135094, 2701869, 1879638160, 1	 	 kk==9  ????
skipped 19	135095, 2701889, 1879638480, 1	 	 kk==29  ????
END WRAP skipped 14	135912, 2718243, 1879900144, 1	 	 kk==16383  <<<<< done
1]  34.00 mSec fill [lp#1] 	Writing dbuff1 to data file.  tmilli =  135093  took   6.00 mSec
 	 BUFF at 70000000
END WRAP skipped 0	2863329263, 3081251308, 2328667823, 3735353514	 	 kk==16383  <<<<< done
0]  34.00 mSec fill [lp#1] 	Writing dbuff0 to data file.  tmilli =  1599167829  took   6.00 mSec
 	 BUFF at 70090000
skipped 8	135094, 2701869, 1879638160, 1	 	 kk==9  ????
skipped 19	135095, 2701889, 1879638480, 1	 	 kk==29  ????
END WRAP skipped 14	135912, 2718243, 1879900144, 1
 
@defragster
Try this sketch and tell me what you think:
Code:
/**************************************************************
  Simple SD card timing datalogger for Teensy 3.6

  https://forum.pjrc.com/threads/60754-Teensy-3-6-SD-Card-missing-time-in-milliseconds?p=238352&viewfull=1#post238352

  This example shows how to log timing data to an SD card using the SD library
  and SDFat 2.0b
  As much as possible, the code uses the simplest Arduino functions, adding
  teensy-specific code only where necessary (such as IntervalTimer).

  The circuit:

   SD card attached to built-in SD Card slot on t3.6


  This example uses  buffering and interval timer to collect at regular
  intervals without collection timing jitter caused by SDC writes.
  A time stamp is saved with each record.

  A minimal user interface is added with three one-letter commands:
      'r'   Open file and start recording data with verbose output
      'g'   Open file and start recording data with only block write delay output
      'q'   Quit logging data and close file
      'p'   Play back data in CSV format


  NOTES:
    1. Unlike the Simple Logger, this version saves only the binary data.
       Conversion to strings is done on playback.
    2. Playback is done one record at a time.  This is less efficient,
       but output is going to the Serial port, so speed isn't as much
       of an issue.
    3. if you uncomment #define USE_EXFAT the program will use the EXFat
       file system of SDFat 2.0beta.  You will need an SD Card formatted
       for the EXFat file system.  That can be done with the tools
       in the SDFat examples




  Written for Teensy 3.6 by M. Borgerson  May 7, 2020
********************************************************************/

elapsedMicros logTime;
// #define USE_logtime
#define LOG_US (1000000 / SAMPLERATE)
#ifdef USE_logtime
#else
IntervalTimer ADCTimer;
#endif

// A simple structure to hold time stamp and three analog values
// The structure takes up 16 bytes to align millitime on 4-byte boundary
struct datrec {
  uint32_t millitime;
  uint32_t microtime;
  uint32_t DWTCount;
  uint32_t byteswritten;
};
// Allocate two buffers, each holding over 1 second of data.
// For efficiency, the total length should be a multiple of 512.
// Note that the T3.6 will run out of RAM at about 8000Hz sampling
// as each buffer would have to be 8000 * 16 or 128,000 bytes, leaving
// very little room for the stack, heap, and USB buffers.
//#define BUFFSIZE  1024

// allocate two buffers, each of which holds 1024 records
// each buffer is 1024 * 16 or 16KBytes

uint32_t logIndex = 0;
#define SAMPLERATE 20000
#define USE_PSRAM 1
#ifdef USE_PSRAM // 128KB apart
#define BUFFSIZE  9190*2
const char *logfilename = "TIMELG_R1.DAT";
#include <extRAM_t4.h>
extRAM_t4 eRAM;
//uint8_t config = 2; //0 - init eram only, 1-init flash only, 2-init both
//These have been replaced with defines for:
//INIT_PSRAM_ONLY
//INIT_FLASH_ONLY
//INIT_PSRM_FLASH
uint8_t config = INIT_PSRAM_ONLY;
[COLOR="#FF0000"][COLOR="#FF0000"]struct datrec *dbuff0 = (datrec *)0x70000000;
struct datrec *dbuff1 = (datrec *)0x70090000;[/COLOR][/COLOR]

[COLOR="#FF0000"]uint32_t sbuff0_addr = 0x70000000;
uint32_t sbuff1_addr = 0x70090000;[/COLOR]
#else
//#define BUFFSIZE  1024
#define BUFFSIZE  9190*2
const char *logfilename = "TIMELOG1.DAT";
struct datrec dbuff1[BUFFSIZE];
//struct datrec dbuff1[BUFFSIZE];
struct datrec *dbuff0 = (datrec *)malloc(BUFFSIZE*sizeof(datrec));

#endif


#define DEBUGPRINT true


// when graphout is true, during recording, only the block write
// interval is displayed.  This allows graphing with the Arduino
// Serial Plotter display.
bool graphout = false;
bool logging = false;

// these variables are declared volatile because they are changed or used in the
// interrupt handler
volatile uint16_t saveidx = 0;
volatile int16_t writebuffnum = -1;
volatile uint16_t savebuffnum = 0;
volatile uint32_t filestartmilli = 0;
volatile uint32_t byteswritten = 0;

const int ledpin = 13;

#define LEDON  digitalWriteFast(ledpin, HIGH);
#define LEDOFF digitalWriteFast(ledpin, LOW);

const char compileTime [] = "Timing Data Logger  Compiled on " __DATE__ " " __TIME__;
void setup() {
  if ( ARM_DWT_CYCCNT == ARM_DWT_CYCCNT ) {   // activate ARM cycle counter
    ARM_DEMCR |= ARM_DEMCR_TRCENA; // Assure Cycle Counter active
    ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  }

  pinMode(ledpin, OUTPUT);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println(compileTime);
  // see if the card is present and can be initialized:
  Serial.print("Initializing SD card...");

#ifdef USE_PSRAM // 128KB apart
  eRAM.begin(config);
  Serial.print("Start PSRAM for LOGGING :: ");
  Serial.println( logfilename );
#else
  Serial.print("LOGGING from RAM :: ");
  Serial.println( logfilename );
#endif

  Serial.printf("\nTwin buffers of size %u Bytes\n" , sizeof(datrec)*BUFFSIZE );
  Serial.println("Enter command selected from (r, g, q, p, s)");
}

void FastBlink(void) {  // blink forever
  while (1) {
    LEDON
    delay(50);
    LEDOFF
    delay(50);
  }
}

static uint32_t elapsedUS = 0;
uint32_t loopCnt = 0, loopSpd;
elapsedMillis elapsedLoop = 0;
void loop() {
  // put your main code here, to run repeatedly:
  char ch;
  uint32_t microselapsed;
  elapsedMicros wrtelapsed = 0;
  loopCnt++;
  if ( elapsedLoop >= 1000 ) {
    loopSpd = loopCnt;
    loopCnt = 0;
    elapsedLoop -= 1000;
  }

#ifdef USE_logtime
  if ( logging && logTime > LOG_US ) {
    logTime -= LOG_US;
    ADCChore();
  }
#endif

  if (Serial.available()) {
    ch = Serial.read();
    if (ch == 'r') {
      graphout = false;
      StartLogging();
    }
    if (ch == 'g') {
      graphout = true;
      StartLogging();
    }
    if (ch == 'q') StopLogging();
  }
  // Now check to see if a buffer is ready to be written to SD
  // writebuffnum will be set in the interrupt handler
  if (writebuffnum == 0) { //is dbuff0 ready?
    LEDON
    writebuffnum = -1;
    if (1) { //if the file is open write dbuff0
      wrtelapsed = 0;
      WriteBinary(&dbuff0[0], BUFFSIZE);
      microselapsed = wrtelapsed;
      if (DEBUGPRINT) {
        if (graphout) {
          Serial.println((float)microselapsed / 1000.0);
        } else {
          loopCnt = loopCnt / (micros() - elapsedUS);
          Serial.printf("0] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
          Serial.print("Writing dbuff0 to data file.  tmilli = ");
          Serial.printf(" %lu  took %6.2f mSec\n", dbuff0[0].millitime, (float)microselapsed / 1000.0);
          elapsedUS = micros();
        }
      }
    }
    LEDOFF
  }
  else if (writebuffnum == 1) { // is dbuff1 ready?
    LEDON
    writebuffnum = -1;
    if (1) { //if the file is open write dbuff0
      wrtelapsed = 0;
      WriteBinary(&dbuff1[0], BUFFSIZE);
      microselapsed = wrtelapsed;
      if (DEBUGPRINT) {
        if (graphout) {
          Serial.println((float)microselapsed / 1000.0);
        } else {
          loopCnt = loopCnt / (micros() - elapsedUS);
          Serial.printf("1] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
          Serial.print("Writing dbuff1 to data file.  tmilli = ");
          Serial.printf(" %lu  took %6.2f mSec\n", dbuff1[0].millitime, (float)(microselapsed) / 1000.0);
          elapsedUS = micros();
        }
      }
    }
    LEDOFF
  }
  //delay(5);
}  // end of the loop() function

// write a buffer to the file as binary record. This  takes more time and file space than
// binary format, but can be directly read on PC.
// Note that we have to cast datrec pointer to a uint8_t pointer
// to keep the SD libraryhappy
static uint32_t firstWrap = 999;
static uint32_t overWrap = 999;
void WriteBinary(volatile struct datrec *drp, size_t numstructs) {

//  dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

  Serial.printf(" \t BUFF at %lX\n", drp );
  uint32_t lastM = 0;
  uint32_t kk, lastB = 5;
  uint32_t ii = 0, iiL = 0;
  lastB = drp[0].byteswritten;
  for ( kk = 0; kk < numstructs; kk++) {
    if ( lastM != drp[kk].millitime || lastB != drp[kk].byteswritten ) {
      if ( overWrap == 999 ) {
        overWrap = ii;
        Serial.printf(" \t HIDE overWrap of %lu  <<<<< \n", overWrap );
      }
      else if ( firstWrap == 999 ) {
        firstWrap = ii;
        Serial.printf(" \t HIDE firstWrap of %lu  <<<<< \n", firstWrap );
      }
      if ( lastM != drp[kk].millitime )
        lastM = drp[kk].millitime;

      if ( ii != iiL && ii != firstWrap && ii != overWrap ) {
        Serial.printf("skipped %lu\t", ii);
        Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
        Serial.printf(" \t kk==%lu  ????\n", kk );
      }
      iiL = ii;
      ii = 0;
    }
    else
      ii++;
  }
  if ( 0 ) { // not needed with overWrap detect
    Serial.printf("END WRAP skipped %lu\t", ii);
    kk = numstructs - 1;
    Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
    Serial.printf(" \t kk==%lu  <<<<< done\n", kk );
  }

  //dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

}

// This is the interrupt handler for the interval timer.
// It saves the data in the data buffer structures.  The output is converted
// to CSV text when it is saved to the output file in the main loop.
// We don't want to do the conversion to a string in the interrupt handler
// since it takes a lot more time and many of the string routines are not
// reentrant. (Programmer talk for "They don't play nicely when interrupted")
[COLOR="#FF0000"]void ADCChore(void) {
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  uint32_t dataRecSize = 20;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    //dbuff0[saveidx].millitime = tmilli;
    //dbuff0[saveidx].microtime =  logIndex++;
    //dbuff0[saveidx].DWTCount = (uint32_t)dbuff0 + (sizeof(datrec) * saveidx);;
    //dbuff0[saveidx].byteswritten = byteswritten;
    dbuff0[saveidx].byteswritten = 0;
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+4, logIndex++);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+8, (uint32_t)dbuff0 + (sizeof(datrec) * saveidx));
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+16, 0);

    saveidx++;
    if (saveidx*dataRecSize >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
  } else {  // must be saving to dbuff1
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+4, logIndex++);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+8, (uint32_t)dbuff0 + (sizeof(datrec) * saveidx));
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+16, 1);

    saveidx++;
    if (saveidx*dataRecSize >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
}[/COLOR]

void StartLogging(void) {
  // we open in a mode that creates a new file each time
  // instead of appending as in the Arduino example
  if ( logging ) return;
  logging = true;
  elapsedUS = micros();
  loopCnt = 0;
  firstWrap = 999;
  overWrap = 999;
  logIndex = 0;

  Serial.println("Starting logging");
  // initialize some variables for the buffers
  saveidx = 0;   // start saving at beginning of buffer
  savebuffnum = 0;  // start saving in dbuff0
  writebuffnum = -1;  // indicates no buffer ready yet
  //  start the interval timer to begin logging
  filestartmilli = millis();
  byteswritten = 0;
#ifdef USE_logtime
  logTime = 0;
#else
  ADCTimer.begin(ADCChore, 1000000 / SAMPLERATE); //begin() expects timer period in microseconds
#endif

}

void StopLogging(void) {
  Serial.println("Stopping logging");
  logging = false;
#ifdef USE_logtime
  logTime = 0;
  if (DEBUGPRINT) Serial.println("eMicros Log halted");
#else
  ADCTimer.end();
  if (DEBUGPRINT) Serial.println("ADCTimer halted");
#endif
  delay(10);
  writebuffnum = -1;
  // dont' write tottal bytes if graphing--it messes up the plot!
  if (!graphout) {
    Serial.printf("%lu KBytes written to file.\n", byteswritten / 1024);
  }
  // in the interest of simplicity, we ignore any partial buffer at the end
}

Code:
Starting logging

 	 BUFF at 70000000
 	 HIDE overWrap of 0  <<<<< 
 	 HIDE firstWrap of 0  <<<<< 
0]  52.00 mSec fill [lp#5262636] 	Writing dbuff0 to data file.  tmilli =  1599688045  took   6.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#5262636] 	Writing dbuff1 to data file.  tmilli =  3166384038  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#5262636] 	Writing dbuff0 to data file.  tmilli =  1599688045  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#5262636] 	Writing dbuff1 to data file.  tmilli =  3166384038  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#5262636] 	Writing dbuff0 to data file.  tmilli =  1599688045  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#5262636] 	Writing dbuff1 to data file.  tmilli =  3166384038  took   7.00 mSec

EDIT: Highlighted the changes in red
 
Last edited:
That is GROSS - what did you do ??? SUPER SPEW?

<edit> Repowered my T_4.1 and I get similar results now ??? - see below.

Code:
Twin buffers of size 294080 Bytes
Enter command selected from (r, g, q, p, s)
Starting logging
 	 BUFF at 70000000
 	 HIDE overWrap of 0  <<<<< 
 	 HIDE firstWrap of 0  <<<<< 
0]  52.52 mSec fill [lp#4799523] 	Writing dbuff0 to data file.  tmilli =  2326440874  took   7.00 mSec
 	 BUFF at 70090000
skipped 8	4596, 91909, 70090090, 1	 	 kk==9  ????
skipped 19	4597, 91929, 700901D0, 1	 	 kk==29  ????
skipped 6	4501, 90020, 70090740, 0	 	 kk==116  ????
skipped 7	4502, 90030, 700907E0, 0	 	 kk==126  ????
skipped 7	4502, 90041, 70090890, 0	 	 kk==137  ????
skipped 1	4502, 90044, 700908C0, 0	 	 kk==140  ????
skipped 1	4503, 90050, 70090920, 0	 	 kk==146  ????
skipped 9	4503, 90066, 70090A20, 0	 	 kk==162  ????
skipped 4	4604, 92069, 70090A90, 1	 	 kk==169  ????
skipped 1	4504, 90078, 70090AE0, 0	 	 kk==174  ????
skipped 5	4504, 90086, 70090B60, 0	 	 kk==182  ????
skipped 1	4505, 90090, 70090BA0, 0	 	 kk==186  ????
skipped 9	4505, 90106, 70090CA0, 0	 	 kk==202  ????
skipped 4	4606, 92109, 70090D10, 1	 	 kk==209  ????
skipped 1	4506, 90118, 70090D60, 0	 	 kk==214  ????
skipped 5	4506, 90126, 70090DE0, 0	 	 kk==222  ????
skipped 1	4507, 90130, 70090E20, 0	 	 kk==226  ????
skipped 9	4507, 90146, 70090F20, 0	 	 kk==242  ????
skipped 4	4608, 92149, 70090F90, 1	 	 kk==249  ????
skipped 2	4508, 90156, 70090FC0, 0	 	 kk==252  ????
skipped 6	4609, 92169, 700910D0, 1	 	 kk==269  ????
skipped 1	4509, 90180, 70091140, 0	 	 kk==276  ????
skipped 9	4510, 90192, 70091200, 0	 	 kk==288  ????
skipped 2	4611, 92209, 70091350, 1	 	 kk==309  ????
skipped 1	4512, 90232, 70091480, 0	 	 kk==328  ????
skipped 1	4512, 90244, 70091540, 0	 	 kk==340  ????
skipped 1	4513, 90252, 700915C0, 0	 	 kk==348  ????


… Going to codeCompare …

<edit> : after T_4.1 repowered I get this:
Code:
Twin buffers of size 294080 Bytes
Enter command selected from (r, g, q, p, s)
Starting logging
 	 BUFF at 70000000
 	 HIDE overWrap of 0  <<<<< 
 	 HIDE firstWrap of 0  <<<<< 
0]  52.70 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  45.00 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   6.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  45.00 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   6.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#5] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#5] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#5] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#5] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#5] 	Writing dbuff1 to data file.  tmilli =  2324343466  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#5] 	Writing dbuff0 to data file.  tmilli =  2326440618  took   7.00 mSec
 
@defragster
Just highlighted the changes in red I made to your code base in post #329. A lot of spew but no skips :)
 
This looks confused? We should Make two copies of ADCChore() DIRECT WRITE and eRAM.write:

Code:
void ADCChore_eRAM(void) {
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  uint32_t dataRecSize = 20;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    [COLOR="#FF0000"]dbuff0[/COLOR][saveidx].byteswritten = 0;
    eRAM.writeLong([B][COLOR="#FF0000"]sbuff0[/COLOR][/B]_addr+saveidx*dataRecSize, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+4, logIndex++);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+8, (uint32_t)[COLOR="#FF0000"]dbuff0 [/COLOR]+ (sizeof(datrec) * saveidx));
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+16, 0);

    saveidx++;
    if (saveidx*dataRecSize >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
[B][COLOR="#FF0000"]  } else {  // must be saving to dbuff1[/COLOR][/B]
    eRAM.writeLong([B][COLOR="#FF0000"]sbuff0[/COLOR][/B]_addr+saveidx*dataRecSize, tmilli);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+4, logIndex++);
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+8, (uint32_t)[COLOR="#FF0000"]dbuff0 [/COLOR]+ (sizeof(datrec) * saveidx));
    eRAM.writeLong(sbuff0_addr+saveidx*dataRecSize+16, 1);

    saveidx++;
    if (saveidx*dataRecSize >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
}

The ELSE case should using sbuff1_addr not sbuff0_addr

Also odd to have any use of dbuff0 left where it might use the new pointers?

… may be missing something - home to eat now ...
 
This looks confused? We should Make two copies of ADCChore() DIRECT WRITE and eRAM.write:

…..
The ELSE case should using sbuff1_addr not sbuff0_addr

Also odd to have any use of dbuff0 left where it might use the new pointers?

… may be missing something - home to eat now ...

Oh D...n, copy and paste error. Just fixed it and it still works (small spew):
Code:
Starting logging

 	 BUFF at 70000000
 	 HIDE overWrap of 0  <<<<< 
 	 HIDE firstWrap of 0  <<<<< 
0]  52.42 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  1599688525  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  4240125862  took   7.00 mSec
 	 BUFF at 70000000
0]  46.00 mSec fill [lp#4799524] 	Writing dbuff0 to data file.  tmilli =  1599688525  took   7.00 mSec
 	 BUFF at 70090000
1]  46.00 mSec fill [lp#4799524] 	Writing dbuff1 to data file.  tmilli =  4240125862  took   7.00 mSec

Probably just over writing the dbuf0 instead of going to dfub1, if we printed the data we would probably see it.
 
@defragster = yep - does that mean it works, I hope

Not clear yet - the base used address was changed - so that may just be preventing the area used a dbuff0 that saw corruption from being used?

Code:
struct datrec *dbuff0 = (datrec *)[B][COLOR="#FF0000"]0x70050000;[/COLOR][/B]
struct datrec *dbuff1 = (datrec *)0x70090000;

versus:
Code:
struct datrec *dbuff0 = (datrec *)[B][COLOR="#FF0000"]0x70000000;[/COLOR][/B]
struct datrec *dbuff1 = (datrec *)0x70090000;

uint32_t sbuff0_addr = [B][COLOR="#FF0000"]0x70000000;[/COLOR][/B]
uint32_t sbuff1_addr = 0x70090000;

Where the detected fault so far was 0x70050000 + 0x4000

Also there seems to be address VAR name copy paste errors noted in p#341
 
crossposting is fun :)

Yes - copy paste errors - that part of the code using two base names is a pain causing dupe code - but the other code from MBorg was very nice to get to this. THOUGH the DUAL names did allow easy alloc of one buffer in RAM1 and the other in RAM2 to prove it works from RAM.

Post a copy of your current corrected code as ADCChore_eRAM() - then we can leave the other old direct access method ADCChore() there and change which one is called with 'r' or 'R' perhaps?

Any sort of error in accumulated data should TRIGGER the Sparse Detection - reading the printed data is too long and hard to track in a BINARY file that can grow to 9 GIGABYTES in short order :)
>> IN FACT that may be why my first RUN FAILED! See p#238 - '0' and '1' records were oddly interwoven.
 
Also wondering why :: uint32_t dataRecSize = 20; and not :: uint32_t dataRecSize = sizeof(datrec); - which should be 16?

Busy a bit - will look for your update when I return or edit and see …

<edit>:: Hope to get back to it here before you arrive and make the ADCChore_eRAM() version seem right and add the switch for that. Maybe even roll the Buffer addresses forward by (BUFFSIZE/2) after each write sequence?
 
Last edited:
Ok, I got my PSRAM chip in the mail, and just soldered it in. I changed the flashtest7FL to init the PSRAM (which formats a lot quicker than flash). It seems to work, except it reports the wrong ID.

Code:
/shared/arduino/tests/flashtest7FLx/flashtest7FLx.ino May 10 2020 01:50:37

 Enter 'y' in 6 seconds to format FlashChip - other to skip
hardware initialized
ERAM ID: 0F FF FF FF FF FF FF FF
at 0x 7000000
Wrong ID  :-(
Start erasing device
..................................................
..................................
device erased
...... ...... ......

Mount SPIFFS:
hardware initialized
ERAM ID: 7F FF FF FF FF FF FF FF
at 0x 7000000
Wrong ID  :-(
Mount ADDR 0x0 with res: 0
Write file:
Hello World! What a wonderful World :)

Directory contents:
my_file1 [0001] size:38
Read file:
Hello World! What a wonderful World :)


Mount SPIFFS:
Mount ADDR 0x0 with res: 0
Directory contents:
my_file1 [0001] size:38

Also, I glanced at extRAM_t4.cpp and I noticed this logic error:
Code:
        if(_config == 0){
                config = 0;
                _spiffs_region = 1;
                result = 1;
        } else if (_config == 1) {
                config = 1;
                _spiffs_region = 0;
                result = 0;
        } else if (_config == 0) {
                config = 1;
                _spiffs_region = 2;
                result = 0;             
        } else {
                config = 2;
                _spiffs_region = 0;
                result = 0;
        }

I.e. the second _config == 0 will never succeed.
 
Glad the added 'flashtest7FL' is working! The code shows another 'command' to enter to repeat adding files.

Seeing "Wrong ID :-(" has been more common than not IIRC since PSRAM started working. Something about the init process. Chips start as SPI and need switched for QSPI use. The speed is right for QSPI - and they take the commands to get there - but some other commands only respond when in SPI mode. That was noted as ignorable as the only QSPI PSRAM chips are the 8MB version and of the two known maker markings - it is expected one is just a relabel.

A lot of testing was done on a few specific access tests and SPIFFS was added - after Paul gave enable instructions for access. A lib - not by Paul - was created and mods made on the fly and @mjs513 did spend some time cleaning it up a bit some of the config stuff he added. But not much new stuff has gone on lately as it was just working as tested. Paul has a big picture idea - but not had time to fix it into place yet for final implementation.

Good to get further testing - as perhaps the recent SD posts above show - it may have undetected anomalies for certain use cases that need attention.
 
@mjs513 - latest code below.
> removed more extraneous from prior
> changed default start pointers to the failing spot
> hit 's' for change to successful address :: 0x70000000
> hit 'f' for change to failing address :: 0x70050000
> hit 'r' to run DIRECT PSRAM index method :: ADCChore()
> hit "R" to run eRAM access method :: ADCChore_eRAM() // Edited please confirm it should be right?

NOTES:
> Fresh start the "R" seems to work on 's' of 'f' address :: but …
- > look at the printed data from sparse print - those struct vals are wrong :: DONE 18379 >> 2290748074, 680061674, EA86AAAA, 547400360
- > for some reason "R" prints much faster and loop cnt is much lower like [lp#5] or [lp#81,282] versus this with 'r' [lp#4,752,752]
->-> probably because this is wrong " if (saveidx >= BUFFSIZE) { // mark buffer for write to SD " in ADCChore_eRAM(), it should be BUFFSIZE*sizeof(datrec) - but that hangs or restarts T_4.1
- > Once 'r' is run after fresh start "R" fails miserably? The struct values print correctly - but shows fail on the same 16384
>> It seems like the eRAM write is not working at all somehow?
>> Does eRAM use change anything about the read method used for direct access?
>> It is ERAM write but WriteBinary() where SPARSE print is done uses direct access for read - should that be conditional to use eRAM read on the new :: if ( logging == 2 )


Code:
/**************************************************************
  timing PSRAM datalogger for Teensy 4.1 with PSRAM - NO SD LOGGING - ONLY extRAM_t4.h required

  https://forum.pjrc.com/threads/60754-Teensy-3-6-SD-Card-missing-time-in-milliseconds?p=238352&viewfull=1#post238352
  Written for Teensy 3.6 by M. Borgerson  May 7, 2020
********************************************************************/

elapsedMicros logTime;
//#define USE_logtime
#define LOG_US (1000000 / SAMPLERATE)
#ifdef USE_logtime
#else
IntervalTimer ADCTimer;
#endif

struct datrec {
  uint32_t millitime;
  uint32_t microtime;
  uint32_t DWTCount;
  uint32_t byteswritten;
};

uint32_t logIndex = 0;
#define SAMPLERATE 20000
#define USE_PSRAM 1
#ifdef USE_PSRAM
#include <extRAM_t4.h>
extRAM_t4 eRAM;
#define BUFFSIZE  9190*2
//uint8_t config = 2; //0 - init eram only, 1-init flash only, 2-init both
//These have been replaced with defines for:
//INIT_PSRAM_ONLY
//INIT_FLASH_ONLY
//INIT_PSRM_FLASH
uint8_t config = INIT_PSRAM_ONLY;
// FAILS with 0x70050000 at offset 0x4000
struct datrec *dbuff0 = (datrec *)0x70050000;
struct datrec *dbuff1 = (datrec *)0x70090000;
uint32_t sbuff0_addr = 0x70050000;
uint32_t sbuff1_addr = 0x70090000;

#else  // THIS USES RAM1 and RAM2 buffer to show _isr() log works with same size buffers
#define BUFFSIZE  9190*2
struct datrec dbuff1[BUFFSIZE];
struct datrec *dbuff0 = (datrec *)malloc(BUFFSIZE*sizeof(datrec));
#endif


#define DEBUGPRINT true

int logging = 0;

// these variables are declared volatile because they are changed or used in the
// interrupt handler
volatile uint16_t saveidx = 0;
volatile int16_t writebuffnum = -1;
volatile uint16_t savebuffnum = 0;
volatile uint32_t filestartmilli = 0;
volatile uint32_t byteswritten = 0;

const int ledpin = 13;

#define LEDON  digitalWriteFast(ledpin, HIGH);
#define LEDOFF digitalWriteFast(ledpin, LOW);

const char compileTime [] = "Timing Data Logger  Compiled on " __DATE__ " " __TIME__;
void setup() {
  if ( ARM_DWT_CYCCNT == ARM_DWT_CYCCNT ) {   // activate ARM cycle counter
    ARM_DEMCR |= ARM_DEMCR_TRCENA; // Assure Cycle Counter active
    ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  }

  pinMode(ledpin, OUTPUT);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println(compileTime);
  // see if the card is present and can be initialized:
  Serial.print("Initializing SD card...");

#ifdef USE_PSRAM
  eRAM.begin(config);
  Serial.print("Start PSRAM for LOGGING :: ");
#else
  Serial.print("LOGGING from RAM :: ");
#endif

  Serial.printf("\nTwin buffers of size %u Bytes\n" , sizeof(datrec)*BUFFSIZE );
  Serial.println("Enter command selected from ( r, R{eRAM}, q, s, f )");
}

void FastBlink(void) {  // blink forever
  while (1) {
    LEDON
    delay(50);
    LEDOFF
    delay(50);
  }
}

static uint32_t elapsedUS = 0;
uint32_t loopCnt = 0, loopSpd;
elapsedMillis elapsedLoop = 0;
void loop() {
  // put your main code here, to run repeatedly:
  char ch;
  uint32_t microselapsed;
  elapsedMicros wrtelapsed = 0;
  loopCnt++;
  if ( elapsedLoop >= 1000 ) {
    loopSpd = loopCnt;
    loopCnt = 0;
    elapsedLoop -= 1000;
  }

#ifdef USE_logtime
  if ( logging && logTime > LOG_US ) {
    logTime -= LOG_US;
    if ( logging == 1 )
      ADCChore();
    esle if ( logging == 2 )
      ADCChore_eRAM();
  }
#endif

  if (Serial.available()) {
    ch = Serial.read();
    if (ch == 'r') {
      StartLogging(1);
    }
    if (ch == 'R') {
#ifdef USE_PSRAM
      StartLogging(2);
#endif
    }

    if (ch == 's') {
      StopLogging();
      Serial.print("SUCCESS:: working address ZERO at 0x70000000");
      dbuff0 = (datrec *)0x70000000;
      dbuff1 = (datrec *)0x70090000;
      sbuff0_addr = 0x70000000;
      sbuff1_addr = 0x70090000;
    }

    if (ch == 'f') {  // FAILS with 0x70050000 at offset 0x4000
      StopLogging();
      Serial.print("FAIL:: working address ZERO at 0x70050000");
      dbuff0 = (datrec *)0x70050000;
      dbuff1 = (datrec *)0x70090000;
      sbuff0_addr = 0x70050000;
      sbuff1_addr = 0x70090000;
    }

    if (ch == 'q') StopLogging();
  }
  // Now check to see if a buffer is ready to be written to SD
  // writebuffnum will be set in the interrupt handler
  if (writebuffnum == 0) { //is dbuff0 ready?
    LEDON
    writebuffnum = -1;
    if (1) { //if the file is open write dbuff0
      wrtelapsed = 0;
      WriteBinary(&dbuff0[0], BUFFSIZE);
      microselapsed = wrtelapsed;
      if (DEBUGPRINT) {
        loopCnt = loopCnt / (micros() - elapsedUS);
        Serial.printf("0] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
        Serial.print("Writing dbuff0 to data file.  tmilli = ");
        Serial.printf(" %lu  took %6.2f mSec\n", dbuff0[0].millitime, (float)microselapsed / 1000.0);
        elapsedUS = micros();
      }
    }
    LEDOFF
  }
  else if (writebuffnum == 1) { // is dbuff1 ready?
    LEDON
    writebuffnum = -1;
    if (1) { //if the file is open write dbuff0
      wrtelapsed = 0;
      WriteBinary(&dbuff1[0], BUFFSIZE);
      microselapsed = wrtelapsed;
      if (DEBUGPRINT) {
        loopCnt = loopCnt / (micros() - elapsedUS);
        Serial.printf("1] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
        Serial.print("Writing dbuff1 to data file.  tmilli = ");
        Serial.printf(" %lu  took %6.2f mSec\n", dbuff1[0].millitime, (float)(microselapsed) / 1000.0);
        elapsedUS = micros();
      }
    }
    LEDOFF
  }
  //delay(5);
}  // end of the loop() function

// write a buffer to the file as binary record. This  takes more time and file space than
// binary format, but can be directly read on PC.
// Note that we have to cast datrec pointer to a uint8_t pointer
// to keep the SD libraryhappy
static uint32_t firstWrap = 999;
static uint32_t overWrap = 999;
void WriteBinary(volatile struct datrec *drp, size_t numstructs) {

//  dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

  Serial.printf(" \t BUFF at %lX\n", drp );
  uint32_t lastM = 0;
  uint32_t kk, lastB = 5;
  uint32_t ii = 0, iiL = 0;
  lastB = drp[0].byteswritten;
  for ( kk = 0; kk < numstructs; kk++) {
    if ( lastM != drp[kk].millitime || lastB != drp[kk].byteswritten ) {
      if ( overWrap == 999 ) {
        overWrap = ii - 1;
        Serial.printf(" \t HIDE overWrap of %lu  <<<<< \n", overWrap );
      }
      else if ( firstWrap == 999 ) {
        firstWrap = ii;
        Serial.printf(" \t HIDE firstWrap of %lu  <<<<< \n", firstWrap );
      }
      if ( lastM != drp[kk].millitime )
        lastM = drp[kk].millitime;

      if ( ii != iiL && ii != firstWrap && ii != overWrap ) {
        Serial.printf("skipped %lu\t", ii);
        Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
        Serial.printf(" \t kk==%lu  ????\n", kk );
      }
      iiL = ii;
      ii = 0;
    }
    else
      ii++;
  }
  kk = numstructs - 1;
  Serial.printf("\tDONE %lu >> %lu, %lu, %lX, %lu\n", kk, drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);

  //dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

}

void ADCChore_eRAM(void) { // eRAM function access
#ifdef USE_PSRAM // avoid eRAM non-def error on RAM only test
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    eRAM.writeLong(sbuff0_addr + saveidx , tmilli);
    eRAM.writeLong(sbuff0_addr + saveidx + 4, logIndex++);
    eRAM.writeLong(sbuff0_addr + saveidx + 8, (uint32_t)sbuff0_addr + (sizeof(datrec) * saveidx));
    eRAM.writeLong(sbuff0_addr + saveidx + 16, 0);
    saveidx += sizeof(datrec);
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
  } else {  // must be saving to dbuff1
    eRAM.writeLong(sbuff1_addr + saveidx , tmilli);
    eRAM.writeLong(sbuff1_addr + saveidx  + 4, logIndex++);
    eRAM.writeLong(sbuff1_addr + saveidx  + 8, (uint32_t)sbuff1_addr + (sizeof(datrec) * saveidx));
    eRAM.writeLong(sbuff1_addr + saveidx  + 16, 1);
    saveidx += sizeof(datrec);
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
#endif
}

void ADCChore(void) { // DIRECT ACCESS
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    dbuff0[saveidx].millitime = tmilli;
    dbuff0[saveidx].microtime =  logIndex++;
    dbuff0[saveidx].DWTCount = (uint32_t)dbuff0 + (sizeof(datrec) * saveidx);;
    dbuff0[saveidx].byteswritten = 0;
    saveidx++;
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
  } else {  // must be saving to dbuff1
    dbuff1[saveidx].millitime = tmilli;
    dbuff1[saveidx].microtime =  logIndex++;
    dbuff1[saveidx].DWTCount = (uint32_t)dbuff1 + (sizeof(datrec) * saveidx);;
    //dbuff1[saveidx].byteswritten = byteswritten;
    dbuff1[saveidx].byteswritten = 1;
    saveidx++;
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
}

void StartLogging(int logType) {
  // we open in a mode that creates a new file each time
  // instead of appending as in the Arduino example
  if ( logging ) return;
  logging = logType;
  elapsedUS = micros();
  loopCnt = 0;
  firstWrap = 999;
  overWrap = 999;
  logIndex = 0;

  Serial.println("Starting logging");

  // initialize some variables for the buffers
  saveidx = 0;   // start saving at beginning of buffer
  savebuffnum = 0;  // start saving in dbuff0
  writebuffnum = -1;  // indicates no buffer ready yet
  //  start the interval timer to begin logging
  filestartmilli = millis();
  byteswritten = 0;
#ifdef USE_logtime
  logTime = 0;
#else
  if ( logging == 1 ) {
    Serial.println("PSRAM DIRECT _isr() logging");
    ADCTimer.begin(ADCChore, 1000000 / SAMPLERATE); //begin() expects timer period in microseconds
  }
  else if ( logging == 2 ) {
    Serial.println("PSRAM eRAM _isr() logging");
    ADCTimer.begin(ADCChore_eRAM, 1000000 / SAMPLERATE); //begin() expects timer period in microseconds
  }
#endif

}

void StopLogging(void) {
  if ( 0 == logging ) return;
  Serial.println("Stopping logging");
  logging = 0;
#ifdef USE_logtime
  logTime = 0;
  if (DEBUGPRINT) Serial.println("eMicros Log halted");
#else
  ADCTimer.end();
  if (DEBUGPRINT) Serial.println("ADCTimer halted");
#endif
  delay(10);
  writebuffnum = -1;
  Serial.printf("%lu KBytes written to file.\n", byteswritten / 1024);
  // in the interest of simplicity, we ignore any partial buffer at the end
}
 
@mjs513 - latest code below.
> removed more extraneous from prior
> changed default start pointers to the failing spot
> hit 's' for change to successful address :: 0x70000000
> hit 'f' for change to failing address :: 0x70050000
> hit 'r' to run DIRECT PSRAM index method :: ADCChore()
> hit "R" to run eRAM access method :: ADCChore_eRAM() // Edited please confirm it should be right?

NOTES:
> Fresh start the "R" seems to work on 's' of 'f' address :: but …
- > look at the printed data from sparse print - those struct vals are wrong :: DONE 18379 >> 2290748074, 680061674, EA86AAAA, 547400360
- > for some reason "R" prints much faster and loop cnt is much lower like [lp#5] or [lp#81,282] versus this with 'r' [lp#4,752,752]
->-> probably because this is wrong " if (saveidx >= BUFFSIZE) { // mark buffer for write to SD " in ADCChore_eRAM(), it should be BUFFSIZE*sizeof(datrec) - but that hangs or restarts T_4.1
- > Once 'r' is run after fresh start "R" fails miserably? The struct values print correctly - but shows fail on the same 16384
>> It seems like the eRAM write is not working at all somehow?
>> Does eRAM use change anything about the read method used for direct access?
>> It is ERAM write but WriteBinary() where SPARSE print is done uses direct access for read - should that be conditional to use eRAM read on the new :: if ( logging == 2 )

…..
Found a minor error and a major error for the way we are using the extRAM lib.

Mirror error:
Code:
writeLong(sbuff0_addr + saveidx + 16, 0);
should be
Code:
writeLong(sbuff0_addr + saveidx + 12, 0);
Same applies to sbuff1.

Major issue I found was that the lib for writeLong's and readLong's with uses writeArray and readArray respectively uses the ramAddr as an offset to 0x70000000 (base address for PSRAM). So question is for the lib do we keep it this way or change it to absolute addr?

Anyway to fix the issue as a test I brought those functions for now I brought a few of those functions into the sketch as a test and fixed the read's for the sketch. Oh btw once we decide which way we want go you will be able to set the struct up to read anything for longs, bool, floats etc.

Here is the modified test sketch for now:
Code:
/**************************************************************
  timing PSRAM datalogger for Teensy 4.1 with PSRAM - NO SD LOGGING - ONLY extRAM_t4.h required

  https://forum.pjrc.com/threads/60754-Teensy-3-6-SD-Card-missing-time-in-milliseconds?p=238352&viewfull=1#post238352
  Written for Teensy 3.6 by M. Borgerson  May 7, 2020
********************************************************************/

elapsedMicros logTime;
//#define USE_logtime
#define LOG_US (1000000 / SAMPLERATE)
#ifdef USE_logtime
#else
IntervalTimer ADCTimer;
#endif

struct datrec {
  uint32_t millitime;
  uint32_t microtime;
  uint32_t DWTCount;
  uint32_t byteswritten;
};

uint32_t logIndex = 0;
#define SAMPLERATE 20000
#define USE_PSRAM 1
#ifdef USE_PSRAM
#include <extRAM_t4.h>
extRAM_t4 eRAM;
#define BUFFSIZE  9190*2
//uint8_t config = 2; //0 - init eram only, 1-init flash only, 2-init both
//These have been replaced with defines for:
//INIT_PSRAM_ONLY
//INIT_FLASH_ONLY
//INIT_PSRM_FLASH
uint8_t config = INIT_PSRAM_ONLY;
// FAILS with 0x70050000 at offset 0x4000
struct datrec *dbuff0 = (datrec *)0x70050000;
struct datrec *dbuff1 = (datrec *)0x70090000;
uint32_t sbuff0_addr = 0x70050000;
uint32_t sbuff1_addr = 0x70090000;

//define a struct joining MYDATA_t to an array of bytes to be stored
uint32_t arraySize = sizeof(datrec);
typedef union MYDATA4RAM_t {
 datrec datastruct;
 uint8_t Packet[sizeof(datrec)];
};
MYDATA4RAM_t readdata; //data read from memory


#else  // THIS USES RAM1 and RAM2 buffer to show _isr() log works with same size buffers
#define BUFFSIZE  9190*2
struct datrec dbuff1[BUFFSIZE];
struct datrec *dbuff0 = (datrec *)malloc(BUFFSIZE*sizeof(datrec));
#endif


#define DEBUGPRINT true

int logging = 0;

char method = 0;

// these variables are declared volatile because they are changed or used in the
// interrupt handler
volatile uint16_t saveidx = 0;
volatile int16_t writebuffnum = -1;
volatile uint16_t savebuffnum = 0;
volatile uint32_t filestartmilli = 0;
volatile uint32_t byteswritten = 0;

const int ledpin = 13;

#define LEDON  digitalWriteFast(ledpin, HIGH);
#define LEDOFF digitalWriteFast(ledpin, LOW);

const char compileTime [] = "Timing Data Logger  Compiled on " __DATE__ " " __TIME__;
void setup() {
  if ( ARM_DWT_CYCCNT == ARM_DWT_CYCCNT ) {   // activate ARM cycle counter
    ARM_DEMCR |= ARM_DEMCR_TRCENA; // Assure Cycle Counter active
    ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  }

  pinMode(ledpin, OUTPUT);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println(compileTime);
  // see if the card is present and can be initialized:
  Serial.print("Initializing SD card...");

#ifdef USE_PSRAM
  eRAM.begin(config);
  Serial.print("Start PSRAM for LOGGING :: ");
#else
  Serial.print("LOGGING from RAM :: ");
#endif

  Serial.printf("\nTwin buffers of size %u Bytes\n" , sizeof(datrec)*BUFFSIZE );
  Serial.println("Enter command selected from ( r, R{eRAM}, q, s, f )");
}

void FastBlink(void) {  // blink forever
  while (1) {
    LEDON
    delay(50);
    LEDOFF
    delay(50);
  }
}

static uint32_t elapsedUS = 0;
uint32_t loopCnt = 0, loopSpd;
elapsedMillis elapsedLoop = 0;
void loop() {
  // put your main code here, to run repeatedly:
  char ch;
  uint32_t microselapsed;
  elapsedMicros wrtelapsed = 0;
  loopCnt++;
  if ( elapsedLoop >= 1000 ) {
    loopSpd = loopCnt;
    loopCnt = 0;
    elapsedLoop -= 1000;
  }

#ifdef USE_logtime
  if ( logging && logTime > LOG_US ) {
    logTime -= LOG_US;
    if ( logging == 1 )
      ADCChore();
    esle if ( logging == 2 )
      ADCChore_eRAM();
  }
#endif

  if (Serial.available()) {
    ch = Serial.read();
    if (ch == 'r') {
      method = ch;
      StartLogging(1);
    }
    if (ch == 'R') {
#ifdef USE_PSRAM
      method = ch;
      StartLogging(2);
#endif
    }

    if (ch == 's') {
      StopLogging();
      Serial.print("SUCCESS:: working address ZERO at 0x70000000");
      dbuff0 = (datrec *)0x70000000;
      dbuff1 = (datrec *)0x70090000;
      sbuff0_addr = 0x70000000;
      sbuff1_addr = 0x70090000;
    }

    if (ch == 'f') {  // FAILS with 0x70050000 at offset 0x4000
      StopLogging();
      Serial.print("FAIL:: working address ZERO at 0x70050000");
      dbuff0 = (datrec *)0x70050000;
      dbuff1 = (datrec *)0x70090000;
      sbuff0_addr = 0x70050000;
      sbuff1_addr = 0x70090000;
    }

    if (ch == 'q') StopLogging();
  }
  // Now check to see if a buffer is ready to be written to SD
  // writebuffnum will be set in the interrupt handler
  if (writebuffnum == 0) { //is dbuff0 ready?
    LEDON
    writebuffnum = -1;
    if (1) { //if the file is open write dbuff0
      wrtelapsed = 0;
      WriteBinary(&dbuff0[0], BUFFSIZE);
      microselapsed = wrtelapsed;
      if (DEBUGPRINT) {
        loopCnt = loopCnt / (micros() - elapsedUS);
        Serial.printf("0] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
        Serial.print("Writing dbuff0 to data file.  tmilli = ");
        Serial.printf(" %lu  took %6.2f mSec\n", dbuff0[0].millitime, (float)microselapsed / 1000.0);
        elapsedUS = micros();
      }
    }
    LEDOFF
  }
  else if (writebuffnum == 1) { // is dbuff1 ready?
    LEDON
    writebuffnum = -1;
    if (1) { //if the file is open write dbuff0
      wrtelapsed = 0;
      WriteBinary(&dbuff1[0], BUFFSIZE);
      microselapsed = wrtelapsed;
      if (DEBUGPRINT) {
        loopCnt = loopCnt / (micros() - elapsedUS);
        Serial.printf("1] %6.2f mSec fill [lp#%lu] \t", (float)(micros() - elapsedUS) / 1000.0, loopSpd );
        Serial.print("Writing dbuff1 to data file.  tmilli = ");
        Serial.printf(" %lu  took %6.2f mSec\n", dbuff1[0].millitime, (float)(microselapsed) / 1000.0);
        elapsedUS = micros();
      }
    }
    LEDOFF
  }
  //delay(5);
}  // end of the loop() function

// write a buffer to the file as binary record. This  takes more time and file space than
// binary format, but can be directly read on PC.
// Note that we have to cast datrec pointer to a uint8_t pointer
// to keep the SD libraryhappy
static uint32_t firstWrap = 999;
static uint32_t overWrap = 999;
void WriteBinary(volatile struct datrec *drp, size_t numstructs) {

//  dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));

  Serial.printf(" \t BUFF at %lX\n", drp );
  uint32_t lastM = 0;
  uint32_t kk, lastB = 5;
  uint32_t ii = 0, iiL = 0;
  if(method == 'r'){
      lastB = drp[0].byteswritten;
      for ( kk = 0; kk < numstructs; kk++) {
        if ( lastM != drp[kk].millitime || lastB != drp[kk].byteswritten ) {
          if ( overWrap == 999 ) {
            overWrap = ii - 1;
            Serial.printf(" \t HIDE overWrap of %lu  <<<<< \n", overWrap );
          }
          else if ( firstWrap == 999 ) {
            firstWrap = ii;
            Serial.printf(" \t HIDE firstWrap of %lu  <<<<< \n", firstWrap );
          }
          if ( lastM != drp[kk].millitime )
            lastM = drp[kk].millitime;
    
          if ( ii != iiL && ii != firstWrap && ii != overWrap ) {
            Serial.printf("skipped %lu\t", ii);
            Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
            Serial.printf(" \t kk==%lu  ????\n", kk );
          }
          iiL = ii;
          ii = 0;
        }
        else
          ii++;
      }
      kk = numstructs - 1;
      Serial.printf("\tDONE %lu >> %lu, %lu, %lX, %lu\n", kk, drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
    
      //dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));
  } else {
    uint32_t ramAddr = (uint32_t *)drp;
    uint32_t dataArray[4];
      //lastB = drp[0].byteswritten;
      for ( kk = 0; kk < numstructs; kk++) {
[COLOR="#FF0000"]        readArray(ramAddr+arraySize*kk, arraySize, readdata.Packet);[/COLOR]
        drp[kk].millitime = readdata.datastruct.millitime;
        drp[kk].microtime = readdata.datastruct.microtime;
        drp[kk].DWTCount = readdata.datastruct.DWTCount;
        drp[kk].byteswritten = readdata.datastruct.byteswritten;
        if ( lastM != drp[kk].millitime || lastB != drp[kk].byteswritten ) {
          if ( overWrap == 999 ) {
            overWrap = ii - 1;
            Serial.printf(" \t HIDE overWrap of %lu  <<<<< \n", overWrap );
          }
          else if ( firstWrap == 999 ) {
            firstWrap = ii;
            Serial.printf(" \t HIDE firstWrap of %lu  <<<<< \n", firstWrap );
          }
          if ( lastM != drp[kk].millitime )
            lastM = drp[kk].millitime;
    
          if ( ii != iiL && ii != firstWrap && ii != overWrap ) {
            Serial.printf("skipped %lu\t", ii);
            Serial.printf("%lu, %lu, %lX, %lu\t", drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
            Serial.printf(" \t kk==%lu  ????\n", kk );
          }
          iiL = ii;
          ii = 0;
        }
        else
          ii++;
      }
      kk = numstructs - 1;
      Serial.printf("\tDONE %lu >> %lu, %lu, %lX, %lu\n", kk, drp[kk].millitime, drp[kk].microtime, drp[kk].DWTCount, drp[kk].byteswritten);
    
      //dataFile.write((uint8_t *)drp, numstructs * sizeof(datrec));
  }
}

void ADCChore_eRAM(void) { // eRAM function access
#ifdef USE_PSRAM // avoid eRAM non-def error on RAM only test
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    writeLong(sbuff0_addr + saveidx , tmilli);
    writeLong(sbuff0_addr + saveidx + 4, logIndex++);
    writeLong(sbuff0_addr + saveidx + 8, (uint32_t)sbuff0_addr + (sizeof(datrec) * saveidx));
    writeLong(sbuff0_addr + saveidx + 12, 0);
    saveidx += sizeof(datrec);
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
  } else {  // must be saving to dbuff1
    writeLong(sbuff1_addr + saveidx , tmilli);
    writeLong(sbuff1_addr + saveidx  + 4, logIndex++);
    writeLong(sbuff1_addr + saveidx  + 8, (uint32_t)sbuff1_addr + (sizeof(datrec) * saveidx));
    writeLong(sbuff1_addr + saveidx  + 12, 1);
    saveidx += sizeof(datrec);
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
#endif
}

void ADCChore(void) { // DIRECT ACCESS
  uint32_t tmilli;
  tmilli = millis() - filestartmilli;
  byteswritten += sizeof(datrec); // update global bytes written count
  // save in  the proper buffer--defined by savebuffnum
  if (savebuffnum == 0) { // put data in dbuff0
    dbuff0[saveidx].millitime = tmilli;
    dbuff0[saveidx].microtime =  logIndex++;
    dbuff0[saveidx].DWTCount = (uint32_t)dbuff0 + (sizeof(datrec) * saveidx);;
    dbuff0[saveidx].byteswritten = 0;
    saveidx++;
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 0;
      savebuffnum = 1;   // start saving in other buffer on next interrupt
      saveidx = 0;  // start at beginning of next buffer
    }
  } else {  // must be saving to dbuff1
    dbuff1[saveidx].millitime = tmilli;
    dbuff1[saveidx].microtime =  logIndex++;
    dbuff1[saveidx].DWTCount = (uint32_t)dbuff1 + (sizeof(datrec) * saveidx);;
    //dbuff1[saveidx].byteswritten = byteswritten;
    dbuff1[saveidx].byteswritten = 1;
    saveidx++;
    if (saveidx >= BUFFSIZE) { // mark buffer for write to  SD
      writebuffnum = 1;
      savebuffnum = 0;   // start saving in other buffer on next interrupt
      saveidx = 0;   // start at beginning of next buffer
    }
  }
}

void StartLogging(int logType) {
  // we open in a mode that creates a new file each time
  // instead of appending as in the Arduino example
  if ( logging ) return;
  logging = logType;
  elapsedUS = micros();
  loopCnt = 0;
  firstWrap = 999;
  overWrap = 999;
  logIndex = 0;

  Serial.println("Starting logging");

  // initialize some variables for the buffers
  saveidx = 0;   // start saving at beginning of buffer
  savebuffnum = 0;  // start saving in dbuff0
  writebuffnum = -1;  // indicates no buffer ready yet
  //  start the interval timer to begin logging
  filestartmilli = millis();
  byteswritten = 0;
#ifdef USE_logtime
  logTime = 0;
#else
  if ( logging == 1 ) {
    Serial.println("PSRAM DIRECT _isr() logging");
    ADCTimer.begin(ADCChore, 1000000 / SAMPLERATE); //begin() expects timer period in microseconds
  }
  else if ( logging == 2 ) {
    Serial.println("PSRAM eRAM _isr() logging");
    ADCTimer.begin(ADCChore_eRAM, 1000000 / SAMPLERATE); //begin() expects timer period in microseconds
  }
#endif

}

void StopLogging(void) {
  if ( 0 == logging ) return;
  Serial.println("Stopping logging");
  logging = 0;
#ifdef USE_logtime
  logTime = 0;
  if (DEBUGPRINT) Serial.println("eMicros Log halted");
#else
  ADCTimer.end();
  if (DEBUGPRINT) Serial.println("ADCTimer halted");
#endif
  delay(10);
  writebuffnum = -1;
  Serial.printf("%lu KBytes written to file.\n", byteswritten / 1024);
  // in the interest of simplicity, we ignore any partial buffer at the end
}

void readArray (uint32_t ramAddr, uint32_t length, uint8_t *data)
{
  uint32_t ii;
  uint8_t *ptrERAM = (uint8_t *)(ramAddr);

  //uint32_t timenow = micros();
  for ( ii = 0; ii < length; ii++ ) {
    data[ii] = ptrERAM[ii];
  }
  //Serial.printf("Read (us): %d\n", micros()-timenow);
  //Serial.printf("read @%06X: ", ramAddr);
  //for (uint32_t i=0; i < length; i++) Serial.printf(" %02X", *(((uint8_t *)data) + i));
  //Serial.printf("\n");
  //Serial.printf("rd @%08X: ", (uint32_t)ptrERAM);
  //for (uint32_t i=0; i < length; i++) Serial.printf(" %02X", ptrERAM[i]);
  //Serial.printf("\n");
}

void writeArray (uint32_t ramAddr, uint32_t items, uint8_t values[])
{ 
  uint32_t ii;
  uint8_t *ptrERAM = (uint8_t *)(ramAddr);
  
  //Serial.printf("write @%06X:\n", ramAddr);
  //for (uint32_t i=0; i < items; i++) Serial.printf(" %02X", *(((uint8_t *)values) + i));
  //Serial.printf("\n");
  //uint32_t timenow = micros();
  for ( ii = 0; ii < items; ii++ ) {
    ptrERAM[ii] = values[ii];
  }
  //Serial.printf("Write (us): %d\n", micros()-timenow);

}

void writeLong(uint32_t ramAddr, uint32_t value)
{
  uint8_t *buffer = reinterpret_cast<uint8_t *>(&value);
  writeArray(ramAddr, 4, buffer);
  
}

void readLong(uint32_t ramAddr, uint32_t *value)
{
  uint8_t buffer[4];
  readArray(ramAddr, 4, buffer);
  *value = *reinterpret_cast<uint32_t *>(buffer);

}

EDIT: fix readarray function call to local function. But funny thing is now it needs a 'r' first before a 'R'. Strange.

Here is a sample of data with the fixes:
Code:
PSRAM eRAM _isr() logging

 	 BUFF at 70000000
 	 HIDE overWrap of 4294967295  <<<<< 
 	 HIDE firstWrap of 0  <<<<< 
	DONE 18379 >> 2757, 55139, 70047CB0, 0
0]  70.24 mSec fill [lp#5216875] 	Writing dbuff0 to data file.  tmilli =  0  took  12.79 mSec
 	 BUFF at 70090000
	DONE 18379 >> 1838, 36759, 700D7CB0, 1
1]  57.86 mSec fill [lp#5216875] 	Writing dbuff1 to data file.  tmilli =  58  took  13.21 mSec
 	 BUFF at 70000000
	DONE 18379 >> 2757, 55139, 70047CB0, 0
0]  57.21 mSec fill [lp#5216875] 	Writing dbuff0 to data file.  tmilli =  115  took  12.98 mSec
 	 BUFF at 70090000
	DONE 18379 >> 1838, 36759, 700D7CB0, 1
1]  57.56 mSec fill [lp#5216875] 	Writing dbuff1 to data file.  tmilli =  173  took  13.10 mSec
 
Last edited:
Ok, I got my PSRAM chip in the mail, and just soldered it in. I changed the flashtest7FL to init the PSRAM (which formats a lot quicker than flash). It seems to work, except it reports the wrong ID.

.....

Also, I glanced at extRAM_t4.cpp and I noticed this logic error:
Code:
        if(_config == 0){
                config = 0;
                _spiffs_region = 1;
                result = 1;
        } else if (_config == 1) {
                config = 1;
                _spiffs_region = 0;
                result = 0;
        } else if (_config == 0) {
                config = 1;
                _spiffs_region = 2;
                result = 0;             
        } else {
                config = 2;
                _spiffs_region = 0;
                result = 0;
        }

I.e. the second _config == 0 will never succeed.

Have to go back and fix. @defragster gave a good description of the history of the lib. Was a combo of Paul's initial test sketches, with Frank's SPIFFs. Did a bunch of clean up and added a few functions for SPIFFs that weren't there before. Including the options for what you wanted to initialize. If I remember right that redundant if can be deleted. Looks like I set it up to default to both chips present. This kind of explains the different configs:
Code:
//uint8_t config = 2; //0 - init eram only, 1-init flash only, 2-init both
//These have been replaced with defines for:
//INIT_PSRAM_ONLY
//INIT_FLASH_ONLY
//INIT_PSRM_FLASH
 
Back
Top