Does TyCommander handle FTDI? Or am I doing something wrong?

Start the logging whenever, at PSRAM address 0, and when you get to the end of PSRAM, jump back to the beginning and keep going. Whenever you STOP logging, you will have the N most recent seconds of data.

Would that contain all the data you want?
Maybe. First glance, yes, but you know how it is. I may just want it to stop, so I can see what happened up to that point. I mean if the address counter is at the end, I can just stop, correct? I don't want rollover to wipe out the initial conditions...
FYI, I’m working on updates to the QuadEncoder library to support interrupt callbacks and set interrupt priority. I’ve got a working test program that uses the Position Compare feature to interrupt on every edge. It ran overnight last night with 1024 PPR encoder running at 1200 rpm and never missed an edge.
Very interesting! I find these programs work great (even EncoderTool) when testing synthetically. I had it running to a 250 KHz rate no problem, but that was not under "full load". Real life seems to always introduce new quirks. Keep us up to date with your progress.
 
Maybe. First glance, yes, but you know how it is. I may just want it to stop, so I can see what happened up to that point. I mean if the address counter is at the end, I can just stop, correct? I don't want rollover to wipe out the initial conditions...

You have 8 MB of storage. It's up to you to decide (a) how often you write, and (b) how much you write on each interrupt. Those determine your total logging time, which you can call N seconds. You can either define a start condition and log for N seconds after "start", or define an end condition and log for the N seconds before "end". The more quantitative you can be about these things, the easier it will be for us to help, so please try to tell use what are the values for (a) and (b), and what is the value of N.
 
You have 8 MB of storage. It's up to you to decide (a) how often you write, and (b) how much you write on each interrupt. Those determine your total logging time, which you can call N seconds. You can either define a start condition and log for N seconds after "start", or define an end condition and log for the N seconds before "end". The more quantitative you can be about these things, the easier it will be for us to help, so please try to tell use what are the values for (a) and (b), and what is the value of N.
I understand. Just suffering from some analysis paralysis. Not really sure what I need. So I'll try something and dare to be wrong.
Need to go to the lathe with a stop watch or something like that and time how long a test is. It's been a while since I've been in the shop. N will basically define the problem...
 
I understand. Just suffering from some analysis paralysis. Not really sure what I need. So I'll try something and dare to be wrong. Need to go to the lathe with a stop watch or something like that and time how long a test is. It's been a while since I've been in the shop. N will basically define the problem...

Could each record be as simple as position (encoder edge count) and interrupt execution time for each edge? That would be 8 bytes and you would have 1024*1024 samples. At 400 rpm that make N = 38.4 seconds, and you would be able to confirm that you are capturing every edge (position changes by exactly 1 for each sample) and maximum ISR execution time.
 
... typed this an hour ago and got phone call - now just handed dinner ...
Seems just logging continuously wrapping around at the end of memory - then hitting STOP after the period to review when you have a free hand

As noted not sure if logging is [4 or 16 or more] 32 bit values? Make a structure Array and write that to PSRAM and Index to the end of memory and set index back to 0 and continue.

8MB writing 16 DWORDS would give 131,072 or 0x2000 locations to wrap on 0x1FFF
Not sure how much data or how fast 128K reads/loop()'s will pass ... 8 or 4 DWORDS woould double or quadruple that.
Something like this code simulation:
Code:
struct {
uint32_t data[16]
} foo

foo *pFoo = 0x20200000; // check this start value for PSRAM begin
uint32_t idxFoo=0;
bool stopped = false;
bool wasrunning = false;

while (!stopped) { // obv. not a while but filled data saved when indexed inc++;
    // fill in pFoo[idxFoo].data[0-15]
    idxFoo++;
    idxFoo = idxFoo&0x1fff; // power of two makes wrapping enforement easy
}
if (digtalReadFast( pin# )) {
    stopped=true;
    if ( !wasrunning ) {
        wasrunning = true;
        serial.printf( "Last data saved before %d", idxFoo );
        // if it wrapped saved data starts at idxfoo, else at index Zero
        // if one of the saved values is the carriage X value, data starts where it begins to change after engagement?
    }
}
 
Could each record be as simple as position (encoder edge count) and interrupt execution time for each edge? That would be 8 bytes and you would have 1024*1024 samples. At 400 rpm that make N = 38.4 seconds, and you would be able to confirm that you are capturing every edge (position changes by exactly 1 for each sample) and maximum ISR execution time.
That's reasonable. I have to start somewhere. Tomorrow morning will strap on the noise cancelling head phones and have a go at it! No matter what, I'm sure there will be some interesting finds.
 
400 rpm
(400/60)*4096 -> 27306.67 Hz

8 bytes -> 38.4 s
16 bytes-> 19.2 s
32 bytes -> 9.6 s
64 bytes -> 4.8 s

How much time do you think you need? Cut down your data so you can capture as much time as you need.
 
p#205 math was funny? - or missing something in this test code? Off by factor of 8?
8 MB runs out with 65535 sets of 4 DWORDS (16 bytes) in 2.359 seconds in this code???
Uses a 36us intervaltimer to record values 27,777 times per second. See BUGBUG that stops it when it gets to the end of 8MB?

But recording in a wrapped loop some 4 DWORDS and pressing a button to stop yields 2.3 seconds of data for review that would be prior 920 revolutions.
So, engage the lathe - count two seconds and press button to stop logging
Code:
// 36us is 27400/sec
IntervalTimer myTimer;

uint32_t tStart;
struct fooData {
  uint32_t data[4];
};

struct fooData *pFoo = (struct fooData *)0x20200000; // start value for PSRAM
volatile uint32_t idxFoo = 0;
bool stopped = false;
bool wasrunning = false;

void fooISR() {
  // fill in pFoo[idxFoo].data[0-3]
  pFoo[idxFoo].data[ 0 ] = millis();
  pFoo[idxFoo].data[ 1 ] = idxFoo;
  pFoo[idxFoo].data[ 2 ] = ARM_DWT_CYCCNT;
  pFoo[idxFoo].data[ 3 ] = 3;
  idxFoo++;
  idxFoo = idxFoo & 0xffff; // power of two makes wrapping enforement easy
  if (!digitalReadFast( 22 ) || 0 == idxFoo) { // BUGBUG just stop on WRAP to see how long it takes
    stopped = true;
    myTimer.end();
  }
}

void setup() {
  // put your setup code here, to run once:
  pinMode( 22, INPUT_PULLUP );
  Serial.begin(1);
  if ( CrashReport ) Serial.print( CrashReport );
  Serial.printf( "STARTING Index %d\n", idxFoo );
  Serial.printf( "sizeof fooData %d\n", sizeof( fooData ) );
  Serial.printf( "pFoo[0] %p\n", &pFoo[0].data[0] );
  Serial.printf( "pFoo[1] %p\n", &pFoo[1].data[0] );
  Serial.printf( "pFoo[65535] %p\n", &pFoo[65535].data[0] );
  delay(2000);
  tStart=millis();
  Serial.printf( "STARTING time %dms\n", tStart );
  myTimer.begin(fooISR, 36);
}

elapsedMillis emFoo;
void loop() {
  if ( stopped ) {
    if ( !wasrunning ) {
      wasrunning = true;
      myTimer.end();
      tStart = millis() - tStart;
      Serial.printf( "RUN time %dms\n", tStart );
      Serial.printf( "Last data saved before %d\n", idxFoo );
      Serial.printf( "pFoo[idxFoo] %p\n", &pFoo[idxFoo].data[0] );
    }
  } else if ( emFoo > 200 ) {
    emFoo = 0;
    Serial.printf( "Index %d\n", idxFoo );
  }
}

And output here - with 200ms output in loop() of current index value:
Code:
STARTING Index 0
sizeof fooData 16
pFoo[0] 0x20200000
pFoo[1] 0x20200010
pFoo[65535] 0x202ffff0
STARTING time 2614ms
Index 0
Index 5582
Index 11166
Index 16749
Index 22332
Index 27916
Index 33499
Index 39082
Index 44666
Index 50249
Index 55832
Index 61416
RUN time 2359ms
Last data saved before 0
pFoo[idxFoo] 0x20200000
 
400 rpm
(400/60)*4096 -> 27306.67 Hz

8 bytes -> 38.4 s
16 bytes-> 19.2 s
32 bytes -> 9.6 s
64 bytes -> 4.8 s

How much time do you think you need? Cut down your data so you can capture as much time as you need.
I will check how long a time interval I need, perhaps I'm overestimating it. Will time it this morning. Parts of the process are manual, which can be variable. Synchronization with the lead screw is discrete, and there's a human (me) in the loop. Worst case, I'll have to double the PSRAM to buy more time. I have a spare PSRAM chip.

Hmm, I made a couple videos of the thread to stop operation, I'll look at it and measure the time, it gives me a different data point. Might represent the upper bound of the time needed.
 
p#205 math was funny? - or missing something in this test code? Off by factor of 8?
8 MB runs out with 65535 sets of 4 DWORDS (16 bytes) in 2.359 seconds in this code???
Uses a 36us intervaltimer to record values 27,777 times per second. See BUGBUG that stops it when it gets to the end of 8MB?

But recording in a wrapped loop some 4 DWORDS and pressing a button to stop yields 2.3 seconds of data for review that would be prior 920 revolutions.
So, engage the lathe - count two seconds and press button to stop logging
Code:
// 36us is 27400/sec
IntervalTimer myTimer;

uint32_t tStart;
struct fooData {
  uint32_t data[4];
};

struct fooData *pFoo = (struct fooData *)0x20200000; // start value for PSRAM
volatile uint32_t idxFoo = 0;
bool stopped = false;
bool wasrunning = false;

void fooISR() {
  // fill in pFoo[idxFoo].data[0-3]
  pFoo[idxFoo].data[ 0 ] = millis();
  pFoo[idxFoo].data[ 1 ] = idxFoo;
  pFoo[idxFoo].data[ 2 ] = ARM_DWT_CYCCNT;
  pFoo[idxFoo].data[ 3 ] = 3;
  idxFoo++;
  idxFoo = idxFoo & 0xffff; // power of two makes wrapping enforement easy
  if (!digitalReadFast( 22 ) || 0 == idxFoo) { // BUGBUG just stop on WRAP to see how long it takes
    stopped = true;
    myTimer.end();
  }
}

void setup() {
  // put your setup code here, to run once:
  pinMode( 22, INPUT_PULLUP );
  Serial.begin(1);
  if ( CrashReport ) Serial.print( CrashReport );
  Serial.printf( "STARTING Index %d\n", idxFoo );
  Serial.printf( "sizeof fooData %d\n", sizeof( fooData ) );
  Serial.printf( "pFoo[0] %p\n", &pFoo[0].data[0] );
  Serial.printf( "pFoo[1] %p\n", &pFoo[1].data[0] );
  Serial.printf( "pFoo[65535] %p\n", &pFoo[65535].data[0] );
  delay(2000);
  tStart=millis();
  Serial.printf( "STARTING time %dms\n", tStart );
  myTimer.begin(fooISR, 36);
}

elapsedMillis emFoo;
void loop() {
  if ( stopped ) {
    if ( !wasrunning ) {
      wasrunning = true;
      myTimer.end();
      tStart = millis() - tStart;
      Serial.printf( "RUN time %dms\n", tStart );
      Serial.printf( "Last data saved before %d\n", idxFoo );
      Serial.printf( "pFoo[idxFoo] %p\n", &pFoo[idxFoo].data[0] );
    }
  } else if ( emFoo > 200 ) {
    emFoo = 0;
    Serial.printf( "Index %d\n", idxFoo );
  }
}

And output here - with 200ms output in loop() of current index value:
Code:
STARTING Index 0
sizeof fooData 16
pFoo[0] 0x20200000
pFoo[1] 0x20200010
pFoo[65535] 0x202ffff0
STARTING time 2614ms
Index 0
Index 5582
Index 11166
Index 16749
Index 22332
Index 27916
Index 33499
Index 39082
Index 44666
Index 50249
Index 55832
Index 61416
RUN time 2359ms
Last data saved before 0
pFoo[idxFoo] 0x20200000
So I understand the output, in an ideal situation, the index value should be what every time? Index at every 200 ms? And one would expect a plus minus 1 count from the average difference?
 
Got down to the shop. After setting up, which took 10 minutes, the actual threading pass I timed at 7.5 seconds. That was setting the cutter 2.5mm before the work piece, and cutting 4 threads at 10 TPI. This includes fumbling to sync the lead screw. I can't imagine being faster than this, 10 seconds would be more comfortable. This was at 200 RPM. It's harder to mechanically sync the lead screw at 400 RPM, since it's moving so quickly. While doing this, I felt like a one armed wallpaper hanger, there was a lot going on all at once.

So 200/60*4096 = 13653 Hz --> 73.24us/interrupt for the encoder (or timer)
8*1024*1024/13653.333/32 --> 19.2 seconds for 32 byte payload, I think. This gives me some margin, for screwing up - which is really easy.
48 byte payload gives 12.8 seconds at this speed. That is still ok. 64 byte payload is 9.6 seconds which is borderline. Might be doable in a pinch however.

This bounds the problem for me. I'll see what I can cobble up.
 
OPPS - that code points to DMAMEM not PSRAM EXTMEM.
And EXTMEM just moved ...
understand the output,
Those 'index' numbers were printing only to show that loop() is running and that the index is advancing under the ISR. And show how many are logged each 200ms.

The demo code shown (except for the BUGBUG: || 0 == idxFoo) will run and log and overwrite continuously until an INPUT triggers to stop the ISR. Assuming you have a way to configure a similar input as the threads start? Or another way to TIME since cutting was engaged?

Your code wouldn't trigger like that - as you know when the needed values are secure - but would need a similar method to stop the log indexing and overwriting the initial data of concern.

Something isn't "mathing" with the memory consumption? That example logging 16 bytes (4 DWORDS) will fault if more than 65535 groups are written???? That is only 1 MB when it should run to 8MB? The Pointer math or the way the pointer is created is wrong?

200 RPM is better as it will assure the PSRAM writes don't cause any slowdown as they pass through the cache and into physical PSRAM.
 
OPPS - that code points to DMAMEM not PSRAM EXTMEM.
And EXTMEM just moved ...

Those 'index' numbers were printing only to show that loop() is running and that the index is advancing under the ISR. And show how many are logged each 200ms.

The demo code shown (except for the BUGBUG: || 0 == idxFoo) will run and log and overwrite continuously until an INPUT triggers to stop the ISR. Assuming you have a way to configure a similar input as the threads start? Or another way to TIME since cutting was engaged?

Your code wouldn't trigger like that - as you know when the needed values are secure - but would need a similar method to stop the log indexing and overwriting the initial data of concern.

Something isn't "mathing" with the memory consumption? That example logging 16 bytes (4 DWORDS) will fault if more than 65535 groups are written???? That is only 1 MB when it should run to 8MB? The Pointer math or the way the pointer is created is wrong?

200 RPM is better as it will assure the PSRAM writes don't cause any slowdown as they pass through the cache and into physical PSRAM.
Thanks for the explanation. I need to figure out how to trigger this intelligently, as there's not a lot of spare memory. A simple way for me is to start when I touch the start button. But after the start, I have to physically engage the half nut lever, and that can take a random amount of time. A better way would be after start AND the carriage is moving - but that may take some time to debug. The log can stop automatically at some Z value, as that is easy to query.

About the memory, it's easy to mess this up, I've done it a lot!

Mem = 8MB [bytes], encoder is 4096 counts/revolution.

time between interrupts = 60/(RPM x 4096) = 60/(200 *4096) = 73.24 us
bytes saved = 32 (size of the struct). If saving uint32's that's 4 bytes/uint32, or 8 uint32's. (8 x sizeof(uint32_t) = 32)

Number of structs that can fit in 8MB = (8*1024*1024) / 32 = 262144.0

Time to write all these structs (assuming one is written every interrupt): = 262144 [structs] * 73.24us/[struct] = 19.2 sec
Rotations of the spindle in 19.2 s (@200 RPM) = 19.2/(60/200) = 64

Double check.
64 rotations * 4096 interrupts/rotation * 32 bytes/interrupt = 8388608 bytes = 8MB.

This is better than I expected, so this is good.

Spent about 1/2 hour doing some old school printing. When programs get too large, I need to lay it all out before me to figure out what to do. I'll figure it out on paper, mark it up, and have at it. If I had 4 more 4k monitors I could do it on screen, alas, I don't have space for that:).
 
This program does what I think was intended. I used a typedef because I think it makes the syntax clearer. EXTMEM locates data in PSRAM, which is assumed to be 8MB. The number of samples is computed from size of PSRAM and size of struct, so you can try different struct sizes. For a struct with 4 * DWORD, there are 524,288 samples.

There is also a macro to #define RPM, and that is used to compute the period of the IntervalTimer, so you can vary that, too. Note that the period argument to IntervalTimer on T4 is a float, so you can get closer to the actual period of 36.62 us @ 400 rpm.

On my T4.1 with 8MB PSRAM, the time to write all of PSRAM is 19.2 sec, so that matches my post #209

Code:
IntervalTimer myTimer;

typedef struct {
  uint32_t data[4];
} fooStruct;

#define PSRAMSIZE (8*1024*1024)
#define NSAMPLE   (PSRAMSIZE/sizeof(fooStruct))

#define PPR       (1024)
#define RPM       (400)
#define EDGE_F_HZ ((RPM/60.0)*(PPR*4))
#define TIMER_US  (1'000'000/EDGE_F_HZ) // timer interval = us between encoder edges

EXTMEM fooStruct fooData[NSAMPLE];

uint32_t tStart;
volatile uint32_t idxFoo = 0;
bool stopped = false;
bool wasrunning = false;

void fooISR() {
  // fill in pFoo[idxFoo].data[0-3]
  fooData[idxFoo].data[ 0 ] = millis();
  fooData[idxFoo].data[ 1 ] = idxFoo;
  fooData[idxFoo].data[ 2 ] = ARM_DWT_CYCCNT;
  fooData[idxFoo].data[ 3 ] = 3;
  idxFoo++;
  if (idxFoo >= NSAMPLE)
    idxFoo = 0;
  if (!digitalReadFast( 22 ) || 0 == idxFoo) { // BUGBUG just stop on WRAP to see how long it takes
    stopped = true;
    myTimer.end();
  }
}

void setup() {
  // put your setup code here, to run once:
  pinMode( 22, INPUT_PULLUP );
  Serial.begin(1);
  if ( CrashReport ) Serial.print( CrashReport );
  Serial.printf( "STARTING Index %d\n", idxFoo );
  Serial.printf( "sizeof fooData %d\n", sizeof( fooData ) );
  Serial.printf( "pFoo[0] %p\n", &fooData[0] );
  Serial.printf( "pFoo[1] %p\n", &fooData[1] );
  Serial.printf( "pFoo[65535] %p\n", &fooData[65535] );
  delay(2000);
  tStart=millis();
  Serial.printf( "STARTING time %dms\n", tStart );
  myTimer.begin(fooISR, TIMER_US);
}

elapsedMillis emFoo;
void loop() {
  if ( stopped ) {
    if ( !wasrunning ) {
      wasrunning = true;
      myTimer.end();
      tStart = millis() - tStart;
      Serial.printf( "RUN time %dms\n", tStart );
      Serial.printf( "Last data saved before %d\n", idxFoo );
      Serial.printf( "&fooData[idxFoo] %p\n", &fooData[idxFoo] );
    }
  } else if ( emFoo > 200 ) {
    emFoo = 0;
    Serial.printf( "Index %d\n", idxFoo );
  }
}
 
This program does what I think was intended. I used a typedef because I think it makes the syntax clearer. EXTMEM locates data in PSRAM, which is assumed to be 8MB. The number of samples is computed from size of PSRAM and size of struct, so you can try different struct sizes. For a struct with 4 * DWORD, there are 524,288 samples.

There is also a macro to #define RPM, and that is used to compute the period of the IntervalTimer, so you can vary that, too. Note that the period argument to IntervalTimer on T4 is a float, so you can get closer to the actual period of 36.62 us @ 400 rpm.

On my T4.1 with 8MB PSRAM, the time to write all of PSRAM is 19.2 sec, so that matches my post #209

Code:
IntervalTimer myTimer;

typedef struct {
  uint32_t data[4];
} fooStruct;

#define PSRAMSIZE (8*1024*1024)
#define NSAMPLE   (PSRAMSIZE/sizeof(fooStruct))

#define PPR       (1024)
#define RPM       (400)
#define EDGE_F_HZ ((RPM/60.0)*(PPR*4))
#define TIMER_US  (1'000'000/EDGE_F_HZ) // timer interval = us between encoder edges

EXTMEM fooStruct fooData[NSAMPLE];

uint32_t tStart;
volatile uint32_t idxFoo = 0;
bool stopped = false;
bool wasrunning = false;

void fooISR() {
  // fill in pFoo[idxFoo].data[0-3]
  fooData[idxFoo].data[ 0 ] = millis();
  fooData[idxFoo].data[ 1 ] = idxFoo;
  fooData[idxFoo].data[ 2 ] = ARM_DWT_CYCCNT;
  fooData[idxFoo].data[ 3 ] = 3;
  idxFoo++;
  if (idxFoo >= NSAMPLE)
    idxFoo = 0;
  if (!digitalReadFast( 22 ) || 0 == idxFoo) { // BUGBUG just stop on WRAP to see how long it takes
    stopped = true;
    myTimer.end();
  }
}

void setup() {
  // put your setup code here, to run once:
  pinMode( 22, INPUT_PULLUP );
  Serial.begin(1);
  if ( CrashReport ) Serial.print( CrashReport );
  Serial.printf( "STARTING Index %d\n", idxFoo );
  Serial.printf( "sizeof fooData %d\n", sizeof( fooData ) );
  Serial.printf( "pFoo[0] %p\n", &fooData[0] );
  Serial.printf( "pFoo[1] %p\n", &fooData[1] );
  Serial.printf( "pFoo[65535] %p\n", &fooData[65535] );
  delay(2000);
  tStart=millis();
  Serial.printf( "STARTING time %dms\n", tStart );
  myTimer.begin(fooISR, TIMER_US);
}

elapsedMillis emFoo;
void loop() {
  if ( stopped ) {
    if ( !wasrunning ) {
      wasrunning = true;
      myTimer.end();
      tStart = millis() - tStart;
      Serial.printf( "RUN time %dms\n", tStart );
      Serial.printf( "Last data saved before %d\n", idxFoo );
      Serial.printf( "&fooData[idxFoo] %p\n", &fooData[idxFoo] );
    }
  } else if ( emFoo > 200 ) {
    emFoo = 0;
    Serial.printf( "Index %d\n", idxFoo );
  }
}
Since you are sampling at twice the rate (due to the 400 RPM vs 200 RPM of my test) you can only have 4 uint32_t's in your struct. What you have is consistent with my calculations. Thanks. This is going to be one heck of a hack-a-thon.
 
Since you are sampling at twice the rate (due to the 400 RPM vs 200 RPM of my test) you can only have 4 uint32_t's in your struct. What you have is consistent with my calculations. Thanks. This is going to be one heck of a hack-a-thon.
Not sure whether it was your program or @defragster's, but it had timer period of 36 us, which is consistent with 400 rpm, not 200, and you get 19.2 seconds with 4 x DWORD. At 200 rpm you would get 38.4 seconds.
 
Not sure whether it was your program or @defragster's, but it had timer period of 36 us, which is consistent with 400 rpm, not 200, and you get 19.2 seconds with 4 x DWORD. At 200 rpm you would get 38.4 seconds.
Originally I was doing this all at 400 RPM to stress things. That was the ~36us. I don't know what a DWORD is. C and microprocessors are extremely inconsistent. The micro guys are always redefining terms. What is a DWORD? What is sizeof(DWORD) for a Teensy4.x? 4 bytes?

That's why I used bytes in my calculations. Bytes are always 8 bits. Words and Dwords may vary according to platform.

I dropped the RPM to reduce the memory fill rate. That allows me to increase the struct size (the payload) if I need it for some reason.

I'm basically agreeing with you.
 
HWORD half word, WORD, DWORD double word, which all depends on what the word size is on the particular architecture. In C and C++ now you can use uint8_t, int16_t, int32_t and so forth from stdint header file.

Bytes on a DEC system 10 were 6 bits (and words 36 bits), so no, bytes are not always 8 bits. We use the term octet to be fully explicit https://en.wikipedia.org/wiki/Octet_(computing)

"byte - a group of binary digits or bits (usually eight) operated on as a unit."

This may seem confusing if you're not aware of the history of computers. Language is never planned.
 
My problem was the PTR ADDRESS hard coded was WRONG to DMAMEM - and PSRAM is now at:

struct fooData *pFoo = (struct fooData *)0x70000000;

After move to accommodate 16MB PSRAM's IIRC - so that is in the newest BETA

This isn't clean with hard coding - but is the gist:
Code:
// 36us is 27400/sec :: 200/60*4096 = 13653 Hz --> 73.24us/interrupt for the encoder (or timer)
// https://forum.pjrc.com/index.php?threads/does-tycommander-handle-ftdi-or-am-i-doing-something-wrong.77159/post-361306
IntervalTimer myTimer;

uint32_t tStart;
struct fooData {
  uint32_t data[16];
};
extern "C" uint8_t external_psram_size;

struct fooData *pFoo = (struct fooData *)0x70000000; // check this start value for PSRAM begin
uint32_t maxPTR = 0x70000000 + (external_psram_size*1024*1024/sizeof( fooData ));
volatile uint32_t idxFoo = 0;
bool stopped = false;
bool wasrunning = false;
volatile uint32_t idxFooLast;
volatile uint32_t idxFooLimit;

void fooISR() {
  // fill in pFoo[idxFoo].data[0-15]
  pFoo[idxFoo].data[ 0 ] = millis();
  pFoo[idxFoo].data[ 1 ] = idxFoo;
  pFoo[idxFoo].data[ 2 ] = ARM_DWT_CYCCNT;
  pFoo[idxFoo].data[ 3 ] = 3;
  idxFooLast = idxFoo;
  idxFoo++;
  if ( maxPTR <= (uint32_t)&pFoo[idxFoo].data[ 0 ] ) idxFooLimit = idxFoo;
  idxFoo = idxFoo & 0x1ffff; // power of two makes wrapping enforement easy [ (8MB/sizeof(fooData)) -1 ) ]
  if (!digitalReadFast( 22 ) || 0 == idxFoo) { // BUGBUG just stop on WRAP to see how long it takes
    stopped = true;
    myTimer.end();
  }
}

elapsedMillis emFoo;
void setup() {
  // put your setup code here, to run once:
  pinMode( 22, INPUT_PULLUP );
  Serial.begin(1);
  if ( CrashReport ) Serial.print( CrashReport );
  //fooData *pFoo = (struct fooData *)extmem_malloc(32);

  Serial.printf( "\nSTARTING Index %d\n", idxFoo );
  Serial.printf( "sizeof fooData %d\n", sizeof( fooData ) );
  Serial.printf( "pFoo[0] %p\n", &pFoo[0].data[0] );
  Serial.printf( "pFoo[1] %p\n", &pFoo[1].data[0] );
  Serial.printf( ">> maxPTR %X\n", maxPTR );
  //while ( digitalReadFast( 22 ) );
  delay(200);
  tStart = millis();
  Serial.printf( "STARTING time %dms\n", tStart );
  emFoo = 0;
  myTimer.begin(fooISR, 73);
}

void loop() {
  if ( stopped ) {
    if ( !wasrunning ) {
      wasrunning = true;
      myTimer.end();
      tStart = millis() - tStart;
      Serial.printf( "RUN time %dms\n", tStart );
      Serial.printf( "Last data saved before %d\n", idxFoo );
      Serial.printf( "pFoo[idxFoo] %p\n", &pFoo[idxFoo].data[0] );
      Serial.printf( "idxFooLast %d >> pFoo[idxFooLast] %p\n", idxFooLast, &pFoo[idxFooLast].data[0] );
      Serial.printf( "idxFooLimit %p\n", idxFooLimit );
      
    }
  } else if ( emFoo > 1000 ) {
    emFoo = 0;
    Serial.printf( "Index %d\n", idxFoo );
  }
}

Output with 1 second index prints for ref - the "idxFooLast" print shows something unexpected from math though:
Code:
STARTING Index 0
sizeof fooData 64
pFoo[0] 0x70000000
pFoo[1] 0x70000040
>> maxPTR 70020000
STARTING time 799ms
Index 13712
Index 27424
Index 41136
Index 54849
Index 68561
Index 82273
Index 95986
Index 109698
Index 123410
RUN time 9568ms
Last data saved before 0
pFoo[idxFoo] 0x70000000
idxFooLast 131071 >> pFoo[idxFooLast] 0x707fffc0
idxFooLimit 0x20000
 
uint32_t maxPTR = 0x70000000 + (external_psram_size*1024*1024/sizeof( fooData ));

I don't understand this. Isn't the max PTR value = 0x70000000 + sizeof(PSRAM) - sizeof(fooData) ? maxPTR should be the address of the last struct in PSRAM, correct?
 
The problem is that your index wrapping logic is wrong. Please review and run the alternative approach that I posted in message #214. It does what your program is trying to do, but with no explicit addresses and no use of pointers, which are prone to error. The storage variable is placed into PSRAM using EXTMEM. It still prints the address of that variable, but it doesn't explicitly define it. It also lets you try different settings easily.
 
The problem is that your index wrapping logic is wrong. Please review and run the alternative approach that I posted in message #214. It does what your program is trying to do, but with no explicit addresses and no use of pointers, which are prone to error. The storage variable is placed into PSRAM using EXTMEM. It still prints the address of that variable, but it doesn't explicitly define it. It also lets you try different settings easily.
Your method is simpler and easier to understand (for me). I rarely use pointers, unless I really have to, because I know I make pointer errors!
 
EXTMEM is handy - except pre alloc prevents using this that is also good saying if PSRAM is 0, 8, 16, 32 ....

extern "C" uint8_t external_psram_size;
 
Back
Top