EEPROM writing on T_3.6 in HSRUN mode

Status
Not open for further replies.
I never tried that, I could with my resume code with 2 line comments, the cpu would return to normal on power up
 
If it works, it might be possible to stay at 180MHz, disable HSRUN, write the eeprom, and enable HSRUN again.. (??)
 
just tried:
Code:
    // if we need faster than the crystal, turn on the PLL
   #if defined(__MK66FX1M0__)
    #if F_CPU > 120000000
//    SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
//    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
    #endif

Hm..commenting that out in mk20dx128.c, works on my K66. are more changes needed ? But i did not try eeprom.
file attached.
 

Attachments

  • mk20dx128.c
    47.1 KB · Views: 201
Ok, works for my 3.6 up to 216MHz.
240MHz does NOT work. But ok, we can enable HSRUN for 240MHz and have no eeprom in this case. Not a too big problem. We can use your code from above for 240MHz :)

But again, i did not test eeprom.
Must stop now. Unfortunately, i have to work tomorrow and have to go to sleep ...
 
Last edited:
Turning off HSRUN is scary - I had not even considered that - they didn't boost voltage and compromise the rest of the system for no reason - and that was for published 180 MHz spec performance - and started at 120 MHz.

Just dropping it across EEPROM access might be okay. I can make a wrapper version for that easily - just a few minutes after I get to my computer.

Could even leave interrupts off across the EEPROM writes? That would avoid other code popping in and limit the code exposed to the low voltage from HSRUN being off. Some hundreds of milliseconds could be LOST - but that is a compromise to consider. We have a RTC at hand so I could even use that int code from Manitou to 'guess' how much was lost. That would be an easier thing to prepare for and recover from than cycling the clocks down and up for sure and that would affect the clock as well.
 
BTW - HSRUN off is simple - no need to hack the core file:

Code:
    __disable_irq( );
    SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
    while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
    __enable_irq( );

putting it back on is:

Code:
    __disable_irq( );
    SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
    __enable_irq( );
 
As I've been seeing this thread, but not really reading it for content, I've been wondering whether long term in might be better to have F_CPU be a variable that is adjusted when the processor has to lower the speed to do things like write EEPROM. Unless you disable interrupts during the EEPROM writing, wouldn't you have the potential problem of an interrupt coming along and something in the interrupt code depending on the current processor speed being what it was compiled for instead of the slower speed for EEPROM writing (unless the interrupts set the HSRUN speed)?

I imagine if it the cpu speed is variable, then in the future, you might be able to dynamically change the speed, slow it down, wait for something interesting to happen, and then speed it up.

Now, since I haven't read the datasheet, I may be completely barking up the wrong tree. I know in the server world, the cpu speed typically varies based on a number of conditions.
 
Last edited:
Michael, you are absolutely correct!

The problem is, there may not be any really good answer.

Yes - You could make something like F_CPU be a variable instead of a constant, which might help if you have everything rework it self. The system as well as many libraries and user code might have to reconfigure itself depending on the new clock speeds.

There are lots of areas where this can hit you. Example suppose the Serial1 object (Uart0) has been queued up with 4 bytes to output, while you are trying to write out to the EEPROM. So the Uart has configured it baud rate registers, to some set of values based on the clock that it is using. Now suppose it has output 4 bits of a character when we change the clock from running at 180mhz down to 120mhz. What will happen to the remaining bits that were being output...

So probably the best we can do is Warn the user that this is problematic. At first thought you might disable interrupts, which may reduce some of the issues, but I don't believe will help if you have active IO going out, or likewise DMA...

But if you can configure your code: to wait until all output has completed, and maybe disable some inputs and/or know to ignore any garbage that came in, and if for example you are using a DMA output to your screen, disable it... Then write your stuff to the EEPROM and then hopefully be able to recover. Then I think this will be workable. If not, then user may have to use another choice like: write data to SDCard, or maybe external EEPROM...
 
Indeed any interrupt coming in would go into the 'twilight zone', thus my comment in the 'test' code:
>> // DO NO I/O in this block
Yes, by definition you don't control interrupt I/O - but my 'special case code' is testing only with system level interrupts, no external devices - and it is generally working.

My last code post #20 "HSRUN EEPROM WRITE then RESET" forces a RESET after every EEPROM write _BLOCK - and that version should leave interrupts disabled if ever put into general use.

I just completed a version of the block that does and as suggested in my prior comment - no interrupts. It fails at 240 MHz - does seem to be working at 216:

Code:
  if (DropState ) { // TODO - do we want to see that we are in HSRUN - we should be per F.M. spec
    __disable_irq( ); [B]// Turn off interrupts for the DURATION ???[/B]
    SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
    while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
  }
  else {
    SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
    __enable_irq( ); [B]// Restore interrupts only when HSRUN restored[/B]
  }

In the _BLOCK this code is called:: once with DropState==1, the EEPROM writes are done, then called with DropState==0
 
UPDATE: In writing post #34 - that died at 240 MHz - it seemed a short wait might help HSRUN restore to full value before turning back on interrupts. My test code is now working at 240MHz where it died before. Here I use delay(10), testing at delay(3) fails and seems to work at delay(6).

Code:
  else {
    SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
    delay(10);
    __enable_irq( ); // Restore interrupts only when HSRUN restored
  }
 
MM - reading the rest of your post - I think I left a note ...

Many devices - I confirmed I2C calculate clocking values at compile time - like PJRC does at present for CPU (and USB) when setting the clock values. Any variation in clock speed as Kurt notes affects Serial as the clocks change.

All devices driver code would need to have a way to be told to 'go offline' and wait for a callback to restart to do a new .begin using any variable clock rates to recalculate their personal clocking values. This would be a major rewrite with the code growing much fatter in the process as right now the clock math is all done at compile time and for instance most of the code for options of 'other speeds' F_CPU and F_BUS drops out with #ifdef.

Duff would have a real understanding of what does and doesn't work with his SNOOZE code.
 
HSRUN DROP and RESTORE EEPROM WRITE

Here is an All in one testable version of my current code.

I have tested it to work as follows on both my T_3.6's.

Same test code as posted before - except it just drops HSRUN - and interrupts - across the _BLOCK.

I removed some delays in the prior code that suited when a RESET was being forced.

I BOLD marked the key code you can take into the sketch of your choice and use per my example. Feel free to drop the BUGBUG DEBUG lines of USB output. If you don't see the matching pair of prints, press the button on your Teensy :)

On startup and if you enter USB '?' you get this HELP:
EEPROM Testing: ?:this text, b:test_BLOCK, c:CPUspecs, r:RESET, s:Show_EEtext t:Test1_RESET, w:Text_Write, z:Stop else:echo

What I do:
't': will increment and write a single test value to EEPROM, without RESET you can count
'b': Block writes as before - only it cycles without restarting, driven by loop() code.
// 'b' "forced" error count now off by one - ...
'w text goes here': will write string " text goes here" to EEPROM and then display it on boot or 's'
'r': still resets the teensy
'c': proves USB read/write and shows the current CPU speed in case you forgot

<UPDATED> modified delay after enable HSRUN, now uses a run time variable waitHSRUN, added +/- USB commands
>>> put a delay(1) in empty while loop wait for HSRUN to restore, now I can run at ZERO added wait, before I needed min of 4(?) - don't know how long it sits
'+': increase wait before disable interrupts
'-': decrease wait before disable interrupts


Code:
// HSRUN DROP and RESTORE EEPROM WRITE :: https://forum.pjrc.com/threads/36808-EEPROM-writing-on-T_3-6-in-HSRUN-mode?p=115314&viewfull=1#post115314
#include <EEPROM.h>

[B]// ------------------- COPY THIS TO YOUR CODE \/ \/ \/ \/ \/ \/ \/ \/ \/ \/
uint8_t waitHSRUN = 4;
uint8_t DropHSRUN( uint8_t DropState ) {
  if (DropState) {
    Serial.print ("\n ----- HSRUN drop ... "); // BUGBUG DEBUG
    Serial.flush();   // make sure nothing queued to send
    delay(120);       // USB needs time to complete
  }
  if (DropState ) { // TODO - Compile time was HSRUN - is it now?
    __disable_irq( ); // Turn off interrupts for the DURATION !!!!
    SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
    while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
  }
  else {
    SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) delay(1); // wait for HSRUN
    delay(waitHSRUN);
    __enable_irq( ); // Restore interrupts only when HSRUN restored
  }
  if ( !DropState ) {
    delay(100);       // Allow USB a pause
    Serial.print(" ... HSRUN raised +++++ @"); Serial.println(waitHSRUN); // BUGBUG DEBUG
  }
  return DropState; // macro needs 1 on drop call and 0 on raise call to process
}

#define TYPE uint8_t
#if F_CPU > 120000000 && defined(__MK66FX1M0__)
#define HSRUN_DROP_BLOCK( ) for ( TYPE __ToDo = DropHSRUN( 1 );  __ToDo;  __ToDo = DropHSRUN( 0 ) )
#else
#define HSRUN_DROP_BLOCK( ) for ( TYPE __ToDo = 1;  __ToDo;  __ToDo = 0 )
#endif
// ------------------- COPY THIS TO YOUR CODE /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\
[/B]
// thanks stevech :: https://forum.pjrc.com/threads/24304-_reboot_Teensyduino()-vs-_restart_Teensyduino()?p=45253&viewfull=1#post45253
#define CPU_RESTART_ADDR (uint32_t *)0xE000ED0C
#define CPU_RESTART_VAL 0x5FA0004

uint8_t ReducedResetRCB() {
  //delay(1); // confirmed no delay needed for EEPROM write to finish
  *CPU_RESTART_ADDR = CPU_RESTART_VAL;
  delay(1000);
  return 0;
}

#define qBlink() (digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ))

String HelpMe = "\n EEPROM Testing: ?:this text,  b:test_BLOCK,  c:CPUspecs,  r:RESET,  s:Show_EEtext  t:Test1_RESET,  w:Text_Write,  z:Stop  else:echo";

#define WT_FLAG 43
char getText[256];

#define BT_FLAG 42
#define TEXT_ADDR (E2END / 2)
#define TEST_FLAG_ADDR  (E2END - 2)
#define BT_INDEX_ADDR (E2END - 1)
const uint16_t BlockSize = 255;
uint8_t TestBlock[ BlockSize ];

byte TestVal = 100;    // Change this value to test another value and force write
const uint16_t StartLoc = 3500; // Pick a number with room for 100 bytes in EEPROM :: 0-3899
uint32_t NeedWrite = 0;   // Do not force speed change when EEPROM values match, prevents extra CPU_RESTART

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(38400);
  while (!Serial && (millis ()  <= 8000));
  if ( BT_FLAG != EEPROM[TEST_FLAG_ADDR] ) {
    CPUspecs(); // Show the current config of processor
    Serial.println(HelpMe);
  }
  if ( WT_FLAG == EEPROM[TEST_FLAG_ADDR] ) {
    ShowEEtext();
  }
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED_BUILTIN on (HIGH is the voltage level)
}

void loop() {

  if ( BT_FLAG == EEPROM[TEST_FLAG_ADDR] ) {
    // This indicates run through all of EEPROM test was selected
    // As long as there is more EEPROM Write the next block and resume test
    int ii, jj, aa = 0;
    if ( (EEPROM[BT_INDEX_ADDR] * BlockSize) < E2END ) {
      AllBlockTest( EEPROM[BT_INDEX_ADDR] );
    }
    else {
      for ( ii = 0; ii < E2END / BlockSize; ii++) {
        for ( jj = 0; jj < BlockSize; jj++) {
          if ( ii != EEPROM[ jj + ii * BlockSize] )
            aa++;
        }
      }
      Serial.print( "\n # Errors Found in full EEPROM block test =");   Serial.println( aa );
      Serial.print( "\n # One more RESET to CLEAR EEPROM block test. . . ");
      delay(10);
      HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
        EEPROM[BT_INDEX_ADDR] = EEPROM[TEST_FLAG_ADDR] = 255;
      }
    }
  }
}

uint32_t TestFlash1() {
  uint32_t ErrCnt = 0;
  for ( int ii = StartLoc; ii < StartLoc + 100; ii++ ) {
    if ( TestVal != EEPROM[ ii ] ) {
      ErrCnt++;
    }
  }
  return (ErrCnt);
}

void AllBlockTest( uint8_t CurrentBlock ) {
  int ii;
  for ( ii = 0; ii < BlockSize; ii++ )
    TestBlock[ ii ] = CurrentBlock;
  Serial.print( "EEPROM block test BLOCK =");   Serial.println( CurrentBlock );

  HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
    EEPROM.put(CurrentBlock * BlockSize, TestBlock);
    EEPROM[TEST_FLAG_ADDR] = BT_FLAG; // Write after to preserve flag on last block
    EEPROM[ 7 + (CurrentBlock * BlockSize) ] = 7; // DEBUG_7 - force one error per block
    EEPROM[BT_INDEX_ADDR] = CurrentBlock + 1;
  }
}

void WriteFlash() {
  for ( int ii = StartLoc; ii < StartLoc + 100; ii++ ) {
    EEPROM[ ii ] = TestVal;
    if (TestVal != EEPROM[ ii ]) {
      digitalWrite(LED_BUILTIN, HIGH); delay(50);
      digitalWrite(LED_BUILTIN, LOW);  delay(25);
    }
  }
}


void CPUspecs() {
#if defined(__MK66FX1M0__)
  Serial.println( "\nCPU is T_3.6");
  Serial.print( "F_CPU =");   Serial.println( F_CPU );
#if F_CPU > 120000000
  Serial.print( "F_PLL =");   Serial.println( F_PLL );
  Serial.print( "F_BUS =");   Serial.println( F_BUS );
  Serial.print( "F_MEM =");   Serial.println( F_MEM );
#else
  Serial.println( "CPU not in HSRUN");
#endif
#else
  Serial.println( "\nCPU is not T_3.6");
#endif
}

void serialEvent() {
  qBlink();
  while (Serial.available() ) {
    char inChar = (char)Serial.read();
    switch ( inChar ) {
      case '+':
        if (waitHSRUN < 10 )
          waitHSRUN++;
        Serial.print("waitHSRUN="); Serial.println(waitHSRUN);
        break;
      case '-':
        if (waitHSRUN > 0 )
          waitHSRUN--;
        Serial.print("waitHSRUN="); Serial.println(waitHSRUN);
        break;
      case '?':
        Serial.println(HelpMe);
        break;
      case 'b':
        AllBlockTest( 0 );
        break;
      case 'c':
        CPUspecs();
        break;
      case 'r':
        ReducedResetRCB();
        break;
      case 's':
        ShowEEtext();
        break;
      case 't':
        TestVal++;
        Serial.print(" Test write with TestVal="); Serial.println(TestVal);
        Serial.flush();
        delay(10);
        Serial.flush();
        DoTestReset();
        break;
      case 'w':
        { // This set of braces is needed here to compile and contain the macro
          int ii = 0;
          while ( Serial.available() && ii < 255 ) {
            getText[ii] = (char)Serial.read();
            if ( '\n' == getText[ii] )
              getText[ii] = 0;
            ii++;
            delayMicroseconds(10);  // allow time for full text to arrive through USB
          }
          getText[ii] = 0;
          HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
            for ( int jj = 0; jj <= ii; jj++ )
              EEPROM[ TEXT_ADDR + jj ] = getText[jj];
            EEPROM[TEST_FLAG_ADDR] = WT_FLAG;
          }
        } // This set of braces is needed here to compile and contain the macro
        ShowEEtext();
        break;
      case 'z': // ZERO the test in progress byte
        Serial.print("\nIn One Second :: Zero test byte and RESET . . .");
        Serial.flush();
        delay(10);
        HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
          EEPROM[TEST_FLAG_ADDR] = 0;
        }
        break;
      default:
        Serial.print(inChar);
        break;
    }
  }
}

void DoTestReset(void) {
  NeedWrite = TestFlash1(); // Test Read Flash at F_CPU
  if ( NeedWrite ) {
    HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
      WriteFlash();
    }
  }
  else Serial.println("Hello World - EEPROM values already MATCH!  No speed change Write.");
}

void ShowEEtext() {
  for ( int ii = TEXT_ADDR; ii < TEXT_ADDR + 256; ii++ ) {
    if ( EEPROM[ ii ] ) {
      Serial.print( (char)EEPROM[ ii ]);
      if ( !((ii - (TEXT_ADDR - 1)) % 61) )
        Serial.println( "..." );
    }
    else
      break;
  }
  Serial.println( "<<<\n -----   Done Showing Write Text. " );
}

Here is a copy of my output doing commands above - except the 'r'/reset and 's'/show:
In One Second :: Test with TestVal=117

----- HSRUN drop ... ... HSRUN raised +++++

EEPROM block test BLOCK =0

----- HSRUN drop ... ... HSRUN raised +++++

EEPROM block test BLOCK =1

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =2

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =3

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =4

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =5

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =6

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =7

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =8

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =9

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =10

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =11

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =12

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =13

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =14

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =15

----- HSRUN drop ... ... HSRUN raised +++++
EEPROM block test BLOCK =16

----- HSRUN drop ... ... HSRUN raised +++++

# Errors Found in full EEPROM block test =15

# One more RESET to CLEAR EEPROM block test. . .
----- HSRUN drop ... ... HSRUN raised +++++

----- HSRUN drop ... ... HSRUN raised +++++
text goes here<<<
----- Done Showing Write Text.

CPU is T_3.6
F_CPU =240000000
F_PLL =240000000
F_BUS =60000000
F_MEM =30000000
 
Last edited:
I'm linking to these two posts of usable versions as I found them and will trust them to be tested and used as needed to find any issues or needed corrections:

HSRUN EEPROM WRITE then RESET (post_20)

Two files - I edited posted code to leave interrupts off from the _BLOCK start that ends with a RESET of the TEENSY. The reset is coded and if used will reset even if not on a T_3.6 or at HSRUN speeds as determined at compile time.

HSRUN DROP and RESTORE EEPROM WRITE (post_38)

All in one file - This most recent version dares to simply disable the HSRUN state while AT SPEED, leaves interrupts off - performs the _BLOCK'ed code then turns on HSRUN, delay(10), turns on interrupts.

For post_38 code: this could perhaps be used in sketch to read the serial number or other HSRUN restricted info. But this would be too late for the USB reported serial # to be updated. These and other simple things as needed could be tried. Outside the _BLOCK of code everything should return to normal except for the loss of systimerticks and other interrupt events that were held off.


Note: I'll put this in the OP too
 
I'm not sure that HSRUN does anything. We have an external voltage regulator - HSRUN had to increase its voltage.. i suspect this does not work ?
The only way is, if there is a chargepump or the MCU ist connected to VIN. Or does the MCU work with less voltage internally ? Maybe Paul can answer this ??
Is the schematic already available?
 
Frank - are you saying you ran my code and it did not work at 240? In my testing enable HRUN at speed and turning on interrupts too fast made it die. The wait as noted and placed in the code lets it work reliably at 240 MHz.

<UPDATED>
I just updated HSRUN DROP and RESTORE EEPROM WRITE (post_38) code above as noted and shown here:
Code:
    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) delay(1); // wait for HSRUN
    delay(waitHSRUN);
    __enable_irq( ); // Restore interrupts only when HSRUN restored

Compile this sketch at 240 MHz down and on USB enter something like:
"tttttt-tttttt-tttttt-tttttt-tttttt-" // six t's and a '-' five times
"b" // if that worked then do a BLOCK test 'b'

It should end like with the TestVal at 130 this if it doesn't die before ('b' output not shown):
----- HSRUN drop ... ... HSRUN raised +++++ @0
Test write with TestVal=130

----- HSRUN drop ... ... HSRUN raised +++++ @0
waitHSRUN=0

BTW: I just did this to both of my T_3.6's and the both worked from 120MHz through 240 Mhz going down to 0 added wait outside the while.
Even better I did it with both uploaded in parallel with TYQT!
 
Last edited:
No i just said that my own quick test @240MHz did not work. Maybe this test had an other problem.. i had not much time.
I 'll do it again with your code this evening.

But this question is very interesting: Does HSRUN really do something on the 3.6 ? And, if yes: How does it increase the voltage?
 
Last edited:
Sorry I read your line to suggest: HSRUN does nothing. [ using my onboard English to English translator :) ]

Your change in the CORES would make it crash! Let me know what you see when you run the latest posted code.

Those changes as noted only apply HSRUN_OFF at speed across nothing but EEPROM writes while interrupts are disabled.
Even enabling interrupts before HSRUN_ON was stable killed my test, but the added wait seems to be good.

Even the incoming USB strings are buffered and handled one character at a time though sent in a group.

It seems putting the indicated code block in any sketch and once a second: Reading/updating/Writing an EEPROM value during any code would be a good test.

I should write into that block a timer interrupt that calls an isr() that does that. Then user sketch would just have to call a function I should include to print the current value, and the number of called times to show it working.
 
RTC isr() with HSRUN DROP and RESTORE EEPROM WRITE

Added new version INCLUDE for RTC isr() with HSRUN DROP and RESTORE EEPROM WRITE

Frank - I'd expect there must be internal voltage regulation limiter for the chip as needed (doesn't the T_3.2 have one internal for supply?). Especially for HSRUN to run high and low and control the EEPROM write voltage, and other parts of the chip. If it could safely run higher they wouldn't have spec'd it at 180 when we can see 240 as a large 33% safety margin already.

Updated version of prior HSRUN dropping at speed now also running Manitou's RTC one second ISR and FLOAT and DOUBLE test. Each isr() tick reads&updates an EEPROM value. That value is staying with the count of ticks in RAM and it also responds to my USB command tests as before. With that running one T_3.6 gets 10,000,098 usecs in 10 secs and the PROTO is always just under 9,999,940 usecs (and always +/- 1 usec over 10 seconds) - and both drop with more EEPROM killing the interrupts - expecting the RTC is isolated from all this and keeps 1 second tick on time. It looks like it loses 20 msecs to write most all of EEPROM in 14 blocks

The LED is normally off, and blinks on each HSRUN change - instead of the debug line. Without other testing over USB it will blink once per RTC isr() second for most of the duration of the HSRUN OFF - except for 40 ms. I reduced the normal delays as I stopped sending so much to USB each time.

It is running perfectly as I see it - remember to USB enter '----' to drop the HSRUN extra delay to zero to see if that works on your T_3.6. I just did that and it changed my numbers above.

Here is it:
View attachment EESpeedDHRpost38.ino


output line each 10 seconds:
__ Math loopCount=36421 >>> RTCcompare=10001__ticks=81_=?=_LastRTCval=81__us delta=10000097

__ Math loopCount=36421 // number of passes in loop()
>>> RTCcompare=10001 // this is the elapsedMillis value that times the print
__ticks=81 // this is the BYTE number of ticks seen by the RTC stored in RAM
_=?=_LastRTCval=81 // this is the BYTE number of ticks seen by the RTC stored in EEPROM
__us delta=10000097 // the difference in microseconds since the last 10 second elapsedMillis

that same line from the PROTO T_3.6:
__ Math loopCount=36422 >>> RTCcompare=10001__ticks=245_=?=_LastRTCval=245__us delta=9999940

Those count and time values change based on activity of course - the RTC should be constant, the two RTC counts matching means the EEPROM writes and reads are working no matter what else is going on with user USB testing.

There is a lot more to copy to your sketch if you want this to test in your sketch ( drop the math ) - should all be blocked in comments: TOP, setup() and loop(), math at bottom (math will report errors).

*** This seems to work - but will need tested in various hardware situations to know that if hot or stressed HSRUN can quickly drop and not lose out for lack of HSRUN for brief periods!

I stopped the block write from filling the last segment of EEPROM so the RTC count can survive. It will update it 86000 times a day though, so move the address, I could have it count and update less often, or shifted the address in a range each minute?
 
Last edited:
Defragster, like the new stuff that only drops HSRUN. So far it looks like the terminal monitor continues to work fine with this version!

Kurt
 
INCLUDE for RTC isr() with HSRUN DROP and RESTORE EEPROM WRITE

<Updated 9/1616 2 AM US> new sketch code below. Includes cycle times as usecs across _BLOCK calls to see how long it took, Other minor cleanup of test features. Added 'f' for write of 255 or 254 across most of FLASH to time write time of BlockSize pieces. 'v' turns off some verbose output. Seems to be very usable.

Updated layout if you want to test in your own hardware specific test:: All code saved as HEADER file to include in sketch of your choice. Add this file in your sketch folder:
#include "EESpeedDHR.h" >> View attachment EESpeedDHR.h

I just added this to my Manitou etherraw sketch that is also doing some prior SDHC test that is looping through the many serial ports while being ping'd. Only conflict I had was SerialEvent() which I took out in favor of the EEPROM test, If your sketch needs the USB input you can disable SerialEvent() in the header file and lose that functionality. If you don't do that remember to give command '----' if your T_3.6 can run without the safety delay coming out of HSRUN [ if it cannot please post! ]


This will add one line of USB output each 10 seconds that is detailed below.
It does toggle the LED - comment out qBlink() usage if that will interfere.
Commenting these lines like this unburdens the processor [__ Math loopCount goes from 35,969 to 8,136,238]:
Code:
  //  ----- OPTIONAL BUSY WORK MATH
  //TestDouble();
  //TestFloat();

Only code needed in your sketch are these lines in the primary sketch [this skeleton sketch will also work standalone with the EESpeedDHR.h]:
Code:
[B]#include "EESpeedDHR.h"[/B] 

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(38400);
  while (!Serial && (millis ()  <= 8000));
  // put your setup code here, to run once:

[B]  setupEESpeedDHR();[/B]
}

void loop() {
  // put your main code here, to run repeatedly:

[B]  loopEESpeedDHR();[/B]
}

This starts the T_3.6 RTC [not compiled for any other Teensy] one second isr().

Once a second it will do an EEPROM update to a location. Every 10 seconds that location is MOVED within an area of 'BlockSize = 255' at the END of EEPROM to extend the life of the EEPROM. You can use any EEPROM value from 0 to (E2END-BlockSize) for your own testing [unless you run the 'b' BLOCK test will overwrite that area on command ]

You can do an EEPROM write in your code at any time with something like this:
Code:
  HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
    EEPROM[ RTCTestLoc ] = LastRTCval;
  }

This line of USB output shows each 10 seconds:
Code:
 [B]__ Math loopCount=34376 >>> RTCcompare=10000_=~=_us delta=10000.09 <> __ticks=206_=?=_LastRTCval=27[/B]

MEANING::
 __ Math loopCount=34376 :: How many loop cycles per 10 seconds
 >>> RTCcompare=10000 :: should be 10,000 this is the elapsedMillis trigger for output
_=~=_us delta=10000.09 :: should be near 10,000 is the diff in usecs from last RTC interrupt
 <> __ticks=206 :: rolling BYTE count of RTC isr() calls [B]**[/B]
_=?=_LastRTCval=27 :: rolling BYTE count of RTC isr() calls as recorded in EEPROM [B]**[/B]
**NOTE: ticks should equal LastRTCval, as you can see sometimes it wanders - block 'b' overwrites when at the low end. I may have fixed this - should match if no block test done. I removed the forced error test.
 
Last edited:
No problems found in function testing - removed some delays, some cleanup to the test functions, new single large flash write. Will try to update posted code above in the next day, nothing critical. Above code calling once per second with other tests and all good at 240 MHz with my T_3.6, even with Ethernet pings and Serial# running. I see a couple downloads of code - hopefully it is working for others?

I wondered how long it was taking but had no clocks with interrupts off. BING-Forum search for 'cycle counter' got a KPC/duff note that got me a working function. It works across EEPROM calls with HSRUN drop/raise.

Fifteen 255 byte block [EEPROM.put()]writes to some 3825 bytes takes :: 489,637 us when values change and 1,176 when they don't change [at 240 MHz with '----' to drop the extra delay]. Took out delays that seemed to be unneeded if USB out queue wasn't stuffed, but seems okay if it has hundreds just sent.

So the EEPROM scheme seems to be working, and this timer code may be of interest (the .prints can go):
Code:
#define CPU_RESET_CYCLECOUNTER    do { ARM_DEMCR |= ARM_DEMCR_TRCENA;          \
    ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; \
    ARM_DWT_CYCCNT = 0; } while(0)
volatile int TTcycles;
uint32_t TimeThis( char *szDisplay ) { // call TimeThis( NULL ); then after TimeThis( "text" );
  if ( !szDisplay ) {
    Serial.print( "TT>>" );
    CPU_RESET_CYCLECOUNTER;
  }
  else {
    TTcycles = ARM_DWT_CYCCNT;
    Serial.print( szDisplay );   Serial.println( TTcycles / (F_CPU/1000000.0) );
  }
  return TTcycles;
}
 
Updated sketch header code in post 48 :: INCLUDE for RTC isr() with HSRUN DROP and RESTORE EEPROM WRITE

Seems good to me - Feedback on use of the HSRUN_DROP_BLOCK( ) code?

Should be able to include in your code and have it work as noted.

You can choose to call test functions as used in the serialEvent() periodically if you want, just find the function called by the 'letter' in the switch statement.

Enter ' USB '----' or set waitHSRUN=0; to take out delays to see if it works without added delay as it does for me.
 
Status
Not open for further replies.
Back
Top