EEPROM writing on T_3.6 in HSRUN mode

Status
Not open for further replies.

defragster

Senior Member+
UPDATE:: TLDR - here is where this got to::

LATEST UPDATE with pull ready code - very simple sample that has been working fine for me. There have been no problems as I've doen this - I just evolved through three different methods - from hardest to trivial. The trivial method is in place in linked post.

------

Blink Simple Sample of HSRUN EEPROM WRITE

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

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.

I did a SNOOZE version of this - dropping out of HSRUN and going to 2 MHz worked. But the net effect is changing speed after power up will mess devices and all up, so may as well just make it work at 120 MHz.
I posted that here: T_3.6 EEPROM write in HSRUN sketch via SNOOZE

HSRUN mode is any T_3.6 speed over 120 MHz! When the T_3.6 is in HSRUN mode EEPROM writes are ignored.

This new version just drops the speed to 120 MHz and gets out of the HSRUN mode and it worked. It is hardcoded to return to 180 MHz - USB (usably) recovers when compiled at 180 and returned to 180. I suspect the same would work as well if the SpeedFast() had been coded using the 240 MHz settings.

This code works as it evolved, it will always restart the Teensy:: (after a Speed Drop is needed && the values read don't match those found). On reboot the process repeats - hopefully to find the values match and just sits in loop().

It is best to assume you need to RESET the Teensy after dropping the speed to do EEPROM write. So this write process should be assumed to be the 'last thing you want to do'. The Teensy cannot make these changes without loss of external data or bus integrity. I found a way to seemingly restore USB, but anything else in progress that had a xxx.begin() to set up the device will likely get confused if any I/O events happen during this. Also the Teensy setup itself is meant to be one time only to calculate the runtime frequencies and processor config. I tested this to work at 180 MHz and the speed recovery is to that speed and it works. The EEPROM WRITE works dropping to 120 MHZ ( tested at 144 and 240 ) from other speeds, but the quick reset to 180 doesn't recover USB in those cases as other things have been missed.

So in general use the code below should really expected be:
Code:
      SpeedSlow();
      WriteFlash();
      delay(1000);
      CPU_RESTART;

This was CUT&PASTE and trial&error. Let me know if you see anything obvious that should or should not be done.

Code:
#include <EEPROM.h>
extern "C" void usb_init(void);

// 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
#define CPU_RESTART (*CPU_RESTART_ADDR = CPU_RESTART_VAL);

const byte TestVal = 32;    // Change this value to test another value and force write
const byte StartLoc = 1800; // Pick a number with room for 100 bytes in EEPROM :: 0-3899
bool DoSpeedSet = 0;  // Set non zero when must drop speed to write to EEPROM
elapsedMicros WriteTime;  // Used when not an HSRUN to see how long a write would take at that speed
uint32_t NeedWrite = 0;   // Do not force speed change when EEPROM values match, prevents infinite CPU_RESTART
uint32_t UsbWait; // Testing if !Serial test is valid after a SpeedFast revocery, it is not

// Took out Blink Feedback when USB worked enough to debug, and writing larger blocks

// At 180 MHz start speed the USB seems to recover
// SpeedFast() is hardcoded to return to 180MHz if that matches compiled speed the USB usably recovers
// When compiled speed is not 180 other things are OFF and USB doesn't recover

// The SPEED Set code was lifted from :: mk2dx128.c , those parts are preceded by commented // #if code

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(38400);
  while (!Serial && (millis ()  <= 8000));
  CPUspecs(); // Show the current config of processor
  Serial.println("Hello World");
  NeedWrite = TestFlash(); // Test Read Flash at F_CPU
#if defined(__MK66FX1M0__)
#if F_CPU > 120000000
  DoSpeedSet = 1;
#endif
#endif
  if ( DoSpeedSet ) {
    if ( NeedWrite ) {
      Serial.println("Hello World : Going to 120 MHz, Bye\n");
      Serial.flush();
      delay(500);
      // -------------------------------------------  THIS IS THE THING
      SpeedSlow();
      WriteFlash();
      SpeedFast();  // Go to 180 MHz
      // -------------------------------------------  THIS IS THE THING
      UsbWait = millis() + 5000;
      while (!Serial && (millis()  <= UsbWait)); // Serial STILL defined - No Effect?
      while ((millis()  <= UsbWait)); // Just wait . . . give the computer time to recover
      Serial.flush();   // USB confused ? - this appears out of order - until .flush() added
      Serial.println("\n\nHello World -DONE 120 MHz Write");
    }
    else {
      DoSpeedSet = 0;
      Serial.println("Hello World - EEPROM values already MATCH!  No speed change Write.");
    }
  }
  else {
    Serial.println("Hello World :: Not a T_3.6 in HSRUN mode, proceed at speed.");
    WriteTime = 0;
    WriteFlash();
    Serial.println(WriteTime);
  }

  NeedWrite = TestFlash(); // Test Read Flash at F_CPU
  if ( NeedWrite ) {
    Serial.println(" EEPROM WRITE FAILED!");
  }
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED_BUILTIN on (HIGH is the voltage level)
  delay(2000);               // wait 2 seconds
  if ( DoSpeedSet )
    Serial.println("Hello World -RESTART PENDING ...");
  else
    Serial.println("Hello World -DONE");
}

void loop() {
  while ( DoSpeedSet ) {
    // Now may be a good time to leave
    Serial.println("Hello World -DONE - CPU_RESTART now");
    digitalWrite(LED_BUILTIN, HIGH); delay(50);
    digitalWrite(LED_BUILTIN, LOW);  delay(25);
    delay(1000);
    CPU_RESTART;
  }
}

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

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 SpeedSlow() {
  // reset USB module :: THIS WAS necessary and useful!!!!!
  // thanks pramilo:: https://forum.pjrc.com/threads/24304-_reboot_Teensyduino()-vs-_restart_Teensyduino()?p=101020&viewfull=1#post101020
[I]  // <edit> removed see post#4 :: USB0_USBTRC0 = USB_USBTRC_USBRESET;
  // while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end
[/I]
  //    #elif F_CPU == 120000000
  MCG_C5 = MCG_C5_PRDIV0(1);
  MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14);
  // wait for PLL to start using xtal as its input
  while (!(MCG_S & MCG_S_PLLST)) ;
  // wait for PLL to lock
  while (!(MCG_S & MCG_S_LOCK0)) ;
  // now we're in PBE mode
  // #else NOT   // #if F_CPU == 216000000 || F_CPU == 180000000
  SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6);

  // now program the clock dividers
  //    #if F_BUS == 60000000
  SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7);
  SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
  while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
}

void SpeedFast() {  // 180
  // BUGBUG - ALWAYS goes back to 180MHx

  SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
  while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
  //    #elif F_CPU == 180000000
  MCG_C5 = MCG_C5_PRDIV0(1);
  MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(29);
  // now program the clock dividers
  // BUGBUG - assumes F_BUS == 60000000 before and after
  // #if F_BUS == 60000000
  SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7);
  // wait for PLL to start using xtal as its input
  while (!(MCG_S & MCG_S_PLLST)) ;
  // wait for PLL to lock
  while (!(MCG_S & MCG_S_LOCK0)) ;
  // now we're in PBE mode
  // #if F_CPU == 216000000 || F_CPU == 180000000
  SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6);

  // reset USB module :: THIS WAS necessary and useful!!!!!
  USB0_USBTRC0 = USB_USBTRC_USBRESET;
  while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end
  delay(800); // Need this and Windows sees the port return
  usb_init();
}

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

Note: There are more efficient ways to write to the EEPROM area, this uses bytes just to test, but other methods will do faster WORD writes.
For best use a block of T_3.6 RAM matching your EEPROM area of interest could be used for normal read/write behavior then when you made changes you wanted saved and can restart, write that block and restart.
 
Last edited:
Hi Defragster,

Sounds like a good start. Hopefully will be able to find a way to be able to do the save and then semi recover without having to reboot.

For example suppose my setup is: Teensy 3.6 talking to Host PC through USB and/or hardware Usart or SPI. In addition I have AX servos connected using USART1, and maybe have either XBee or RF radio connected through either UART or SPI and a display hooked up using SPI.

Now I run through code that wishes to update the servo offsets and save away the new offsets. With many of these devices I can probably handle without much issues. Like assume ILI9341 display, will probably not issue any new display commands while I am doing the EEPROM update. Will not issue any new Servo commands so probably OK there, XBee could simply discard anything or maybe setup CTS pin and assert no...

The places where it could get tricky include:
a) PWM and/or RC servos and/or IntervalTimers. Not sure what would happen here. That is for example if you have an interval setup for lets say 100 times per second and you are running at 180mhz. So the clock dividers and probably compare register is set up to know I should get this number of ticks for the time period. Now you change the clock to run at 120mhz. Would this really screw things up, or would simply the one or so timer periods during EEPROM write, the period would take 1.5 times as long? Might be interesting to see.

I don't have much (read that any) experience with programming the memory system. So wonder when I do the EEPROM.write(...), which simply updates a place in memory, can I detect when the system has actually completed the updating of storage in the EEPROM? Or do you need to just issue a long delay assuming it is done?

Again great stuff! Wish I knew more
 
Cool, I'm hoping for code review/feedback - not sure if I missed anything essential when changing operating frequencies or core internal processor dependency setup, about which I know only what I inferred from PJRC code. Hopefully FrankB or Paul of DUFF will also give it a look. When I cut from MK20dx128 I just RE-did the few things during the initial power up that led to turning the machine on - setting up clocks - and getting into user sketch setup(). I didn't need to reset the interrupt vectors or anything inherently damaging.

I'll be really surprised if I somehow did the complete and perfect subset of what is needed for the TWIN speed change in my sample.
One critical issue is: I did not disable interrupts across my Speed_set_() code and I expect I should?
I added USB 'RESET' on SLOW and FAST - without it in FAST it didn't come online. But doing it at SLOW might be better done with USB_DISABLE as SNOOZE does so the PC doesn't see it leave and return an extra time?

Indeed with device behavior YMMV - many things may be oblivious to the processor doing this between 'I/O' calls and if the processor returns to the initial running state. For bulk 32 bit word writes the entire EEPROM can certainly be fully flashed in less than near 1.8 seconds I saw with byte writes at 120 MHz. I have thought of a few tests, but if it needs a fundamental fix I didn't catch in my single sample I don't want to have to repeat it all. And if I do stumble on a problem I'll likely be BLIND to debug it as the system will just quit.

It was my assumption that EEPROM writes are all but instantaneous and done on return - but I did put a delay(1000) in my sample to be sure. One test would be a single automated pass through all EEPROM space - using the EEPROM to track the last segment and do a group and INSTANT restart - confirm that group (or wait until after the last group) on boot and do the next group ... repeat - but before I focused on seeing if I could break it - I wanted to hear I did a sane and essential set of efforts to expect it to work.

Also when I know it is worth the effort - I could clean up my code and return to the processor speed that was in use on entry : 144, 168, 180, 192, 216, 240. But if I do that now and have to edit/test the resultant code for each of 6 cases ... that would suck. That's why I picked the single default supported speed of 180 MHZ with a common 60 MHz freq - and keep the code cleaner. Of course it also should be 'librarized' into a selectively callable set of essential functions. Duff uses a really cool macro in SNOOZE that encapsulates in a finite window his speed drop to 2 MHz. I could make two versions of that - one that terminates in RESTART and one the does the windowed tasks and restores the CPU to power up settings and CONTINUES. That would be safer and easier for the user than calling SLOW, FLASHING then remembering to call FAST before doing anything problematic.
 
Below is the CPU slowdown code from post#1 - nothing exotic just need to be able to turn off HSRUN.
<edit>:SpeedSlow above USBRESET was unneeded as the CPU hasn't changed , as long as the USB is flushed before changing clock values, perhaps I should pull in DUFF's USB_Disable code.
These operations should probably be done with interrupts off?
EEPROM writes have been 100% successful with this code alone - Don't want to make USB or anything else work as long as the processor is stable to write EEPROM.

The above SpeedFast() just does this same process for 180 MHz - and then resets the USB and does an init on it.

Code:
// revised code in following post
 
Last edited:
Calling interface has been simplified - thanks for sharing your "_BLOCK_" code DUFF!
Turned off interrupts and cleaned up timing for USB to restore when not doing RESET.
Tested once to work on T_3.1, it should work on any Teensy. But following on T_3.6 only restores to 180 MHz when starting over 120 MHz
This works as I tested it : YMMV

Caller does this:
Code:
    REDUCED_CPU_BLOCK_RESET(  ) {        // or REDUCED_CPU_BLOCK_RUN(  ) {
      WriteFlash();
    }

This is the header file to include:
Code:
// THIS FILE :: #include "respeed.h"
extern "C" void usb_init(void);

// At 180 MHz start speed the USB seems to recover
// BUGBUG is hardcoded to return to 180MHz if that matches compiled speed the USB usably recovers
// When compiled speed is not 180 other things are incorrect and USB doesn't recover

// The SPEED Set code was lifted from :: mk2dx128.c , those parts are preceded by commented // #if code

/*********************************************************************************************
    RESPEED_CPU_BLOCK_RUN - Teensy 3.6 over 120 MHz will slow to 120 MHz drop HSRUN. Will restore speed and return

    @param none

    @return none

    Sample Usage:
      REDUCED_CPU_BLOCK_RUN(  ) {
        // WRITE TO EEPROM ALLOWED HERE :: 
      }

    // DO NO I/O in this block
    // Flushes USB Serial and does delay(100) if dropping speed required
    // If dropping speed required: Flushes USB Serial and does net delay(1300) before returning
 *********************************************************************************************/
/*********************************************************************************************
    RESPEED_CPU_BLOCK_RESET - Teensy 3.6 over 120 MHz will slow to 120 MHz, drop HSRUN. Will RESET the TEENSY

    @param none

    @return none
    
    Sample Usage:
      REDUCED_CPU_BLOCK_RESET(  ) {
        // WRITE TO EEPROM ALLOWED HERE
      }

    // DO NO I/O in this block
    // Flushes USB Serial and does delay(100) if dropping speed required
 *********************************************************************************************/
uint8_t SpeedFastRCB( void );
uint8_t SpeedSlowRCB( void );
uint8_t ReducedResetRCB( void );

#define TYPE uint8_t
#if F_CPU > 120000000 && defined(__MK66FX1M0__)
#define REDUCED_CPU_BLOCK_RUN( )   \
  for ( TYPE __ToDo = SpeedSlowRCB();  __ToDo;  __ToDo = SpeedFastRCB(  ) )
#define REDUCED_CPU_BLOCK_RESET( )   \
  for ( TYPE __ToDo = SpeedSlowRCB();  __ToDo;  __ToDo = ReducedResetRCB() )
#else
#define REDUCED_CPU_BLOCK_RUN( )   \
  for ( TYPE __ToDo = 1;  __ToDo;  __ToDo = 0 )
#define REDUCED_CPU_BLOCK_RESET( )   \
  for ( TYPE __ToDo = 1;  __ToDo;  __ToDo = ReducedResetRCB() )
#endif

uint8_t SpeedSlowRCB() {
  Serial.println("Hello World : Going to 120 MHz, Bye\n"); // BUGBUG DEBUG
  Serial.flush();   // make sure nothing queued to send
  delay(100);       // USB needs time to complete
  __disable_irq( );
  //    #elif F_CPU == 120000000
  MCG_C5 = MCG_C5_PRDIV0(1);
  MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14);
  // wait for PLL to start using xtal as its input
  while (!(MCG_S & MCG_S_PLLST)) ;
  // wait for PLL to lock
  while (!(MCG_S & MCG_S_LOCK0)) ;
  // now we're in PBE mode
  // #else NOT   // #if F_CPU == 216000000 || F_CPU == 180000000
  SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6);
  // now program the clock dividers
  //    #if F_BUS == 60000000
  SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7);
  SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
  while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
  __enable_irq( );
  return 1;
}

uint8_t SpeedFastRCB() {  // 180  // BUGBUG - ALWAYS goes back to 180MHz
  __disable_irq( );
  SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
  while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
  //    #elif F_CPU == 180000000
  MCG_C5 = MCG_C5_PRDIV0(1);
  MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(29);
  // now program the clock dividers
  // BUGBUG - assumes F_BUS == 60000000 before and after with speed restore to 180 MHz
  // #if F_BUS == 60000000
  SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7);
  // wait for PLL to start using xtal as its input
  while (!(MCG_S & MCG_S_PLLST)) ;
  // wait for PLL to lock
  while (!(MCG_S & MCG_S_LOCK0)) ;
  // now we're in PBE mode
  // #if F_CPU == 216000000 || F_CPU == 180000000
  SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6);

  // thanks pramilo:: https://forum.pjrc.com/threads/24304-_reboot_Teensyduino()-vs-_restart_Teensyduino()?p=101020&viewfull=1#post101020
  USB0_USBTRC0 = USB_USBTRC_USBRESET;
  while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end
  __enable_irq( );
  delay(300); // Need this and Windows sees the port return
  usb_init();
  delay(1000);      // for USB setup - delay() added
  Serial.flush();   // for USB setup - output appears out of order - .flush() added
  return 0;
}

// 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); // TODO - confirm no delay needed for EEPROM write to finish
  *CPU_RESTART_ADDR = CPU_RESTART_VAL;
  delay(1000);
  return 0;
}
 
Last edited:
Hi Defragster,

Looks interesting.

I tried hacking up your earlier example to try it out, So far I have not been able to have the Serial Monitor recover after the reset or run... Probably doing something wrong.
Current code:
Code:
#include <EEPROM.h>
#include "respeed.h"
const byte TestVal = 31;    // Change this value to test another value and force write
const uint16_t StartLoc = 1800; // Pick a number with room for 100 bytes in EEPROM :: 0-3899

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(38400);
  while (!Serial && (millis ()  <= 8000));
  CPUspecs(); // Show the current config of processor
  Serial.println("Hello World");
  uint32_t NeedWrite = TestFlash(); // Test Read Flash at F_CPU
  if ( NeedWrite ) {
    Serial.println("Before EEPROM write"); Serial.flush();
    Serial.end();
    REDUCED_CPU_BLOCK_RESET () {
      WriteFlash();
    }
    delay(800);
    Serial.begin(38400);
    while (!Serial && (millis ()  <= 8000));
    Serial.println("After EEPROM Write");
  }
  else {
    Serial.println("Hello World - EEPROM values already MATCH!  No speed change Write.");
  }
  Serial.println("Hello World -DONE");
  delay(1000);
}

void loop() {
  // Now may be a good time to leave
  digitalWrite(LED_BUILTIN, HIGH); 
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);
  delay(800);
}

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

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");
#else
  Serial.println( "\nCPU is not T_3.6");
#endif
  Serial.print( "F_CPU =");   Serial.println( F_CPU );
  Serial.print( "F_PLL =");   Serial.println( F_PLL );
  Serial.print( "F_BUS =");   Serial.println( F_BUS );
  Serial.print( "F_MEM =");   Serial.println( F_MEM );
}
Note: One update I did to the original code was to change StartLoc to a uint16_t to remove compile warning...
 
Hi Defragster and hopefully others:

I am also wondering if it would be worthwhile to also try something completely different as an option.

That is develop a simple EEPROM replacement library that maybe uses SDFAT library. That maybe creates a file like "EEPROM" at the root directory. That the library then caches in current contents.... Have the file maybe grow in some preferred increment like the blocksize...

My guess is it would not be hard to implement a reasonably complete version...

just a thought.

Kurt

P.S - I still think it would be great to be able to make the EEPROM work well.
 
So my dog decided to try to eat my T3.6, now I have to wait for a new one:( I even was going to spend some time this weekend on this.
 
So my dog decided to try to eat my T3.6, now I have to wait for a new one:( I even was going to spend some time this weekend on this.
That is very sad news duff . . . hope your dog is okay . . . my wife says he knew the Teensy would take away his QUALITY time. Now that I think about it - my wife was probably trying to tell me something as a parable (see note below about 3am)? <edit>: I have confirmed that not only was that a valid use of the word parable - but a valid observation.

Kurt -
> Indeed there will be SD solutions - EEPROM_FAT would be cool (or the duct taped EEPROM on the bottom) - this is too painful and limiting with the SD card there that would be perfect. I posted some comment about that - except then when the SD dies or gets swapped - the EEPROM would be a perfect place to restore that from, see recursion.
> DOH! I guess I should have looked for COMPILE warnings. ADDRESS of BYTE won't work - DOH!
> Sorry I didn't include my sketch source - it was 3:30am ... funny 3:30 PM I was driving and wanted to pull over and take a nap ... 12 hours later I have to force myself to quit working with the code.
> Try the new scheme as below (No such thing as Serial.begin and !Serial is always true I found in OP - also the post #6 code shows _RESET?). - timing on the waits to get USB resettled is critical, and for now so is 180 MHz.

Code:
#include <EEPROM.h>
#include "respeed.h"

const byte TestVal = 254;    // Change this value to test another value and force write
const uint16_t StartLoc = 1100; // Pick a number with room for 100 bytes in EEPROM :: 0-3899
elapsedMicros WriteTimer;  // Used when not an HSRUN to see how long a write would take at that speed
uint32_t WriteTime;
uint32_t NeedWrite = 0;   // Do not force speed change when EEPROM values match, prevents infinite CPU_RESTART


// At 180 MHz start speed the USB seems to recover
// BUGBUG is hardcoded to return to 180MHz if that matches compiled speed the USB usably recovers
// When compiled speed is not 180 other things are incorrect and USB doesn't recover

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(38400);
  while (!Serial && (millis ()  <= 8000));
  Serial.println("\n\nHello World <<<-------- - - - - - -");
  CPUspecs(); // Show the current config of processor
  // THIS TEST requires knowing when to stop so NeedWrite of ZERO means no EEPROM change, don't repeat the Write and RESTART
  NeedWrite = TestFlash(); // Test Read Flash at F_CPU
  if ( NeedWrite ) {
    WriteTimer = 0;
    // -------------------------------------------  THIS IS THE THING
    REDUCED_CPU_BLOCK_RESET(  ) {
      // DO NO I/O in this block
      //REDUCED_CPU_BLOCK_RUN(  ) {
      WriteFlash();
      WriteTime = WriteTimer;  // Note at altered CPU speed this number is warped
    }
    // -------------------------------------------  THIS IS THE THING
    Serial.println(WriteTime);
    Serial.println("\n\nHello World -DONE Write -No RESET");
  }
  else {
    Serial.println("Hello World - EEPROM values already MATCH!  No speed change Write.");
  }

  NeedWrite = TestFlash(); // Test Read Flash at F_CPU
  if ( NeedWrite ) {
    Serial.println(" EEPROM WRITE FAILED!");
  }
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED_BUILTIN on (HIGH is the voltage level)
}

void loop() {
}

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

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");
#if F_CPU > 120000000
  Serial.print( "F_CPU =");   Serial.println( F_CPU );
  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
}
 
Last edited:
Hi Defragster,

I tried hacking up your earlier example to try it out, So far I have not been able to have the Serial Monitor recover after the reset or run... Probably doing something wrong.
Current code:

Yes, Very WRONG - USE TYQT!
Just reread this - In my Windows experience - Serial Monitor RARELY works on ANY TEENSY reset! Sometimes on upload - but often requires Restarting SerMon with an icon click.
SerMon is the WORST thing about Teensy on Arduino and should be abandoned for TYQT!

This makes it particularly problematic when the T_3.6 doesn't have a Serial Number recognized and restart might move to a new COM# port.
TYQT solves all those problems and more (download and see images) - as long as the Teensy reports a Serial number it can be directly accessed whether you have one or 5+ Teensys online! Rarely have to push button, and it has a GUI RESET and cleaner UPLOAD prior hex interface.

Easy one file fix for Serial number on HSRUN T_3.6 is add these 3 lines in place in \hardware\teensy\avr\cores\teensy3\mk20dx128.c:
Code:
#if defined(__MK66FX1M0__)
    #if F_CPU > 120000000
[B]	[COLOR="#0FFF0F"]*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
	FTFL_FSTAT = FTFL_FSTAT_CCIF;
	while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {}[/COLOR][/B]
	SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
	while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN

That is just the same code PJRC runs a bit later, but done before HSRUN the serial number persists in hardware across the jump to HSRUN when the wall goes up.

<edit> TYQT has a Tools / Integrate to Arduino feature that is very effective! It replaces TeensyDuino as the loader and allows selecting which Teensy will take the sketch ( as shown in linked pics above ). It requires closing and restarting the IDE for the Integrate to happen then just close TeensyDuino if open - and never use SerMon.
 
Last edited:
Thanks defragster,

I hear you about TYQT, but I sometimes resist as while I am doing a bunch of this for my own fun, I do like trying to help make the product better and so I keep trying to use most of it the way most users do... But I may break down and do it at some point... Now if Paul was to ship TYQT as part of the install...

duff said:
So my dog decided to try to eat my T3.6, now I have to wait for a new one I even was going to spend some time this weekend on this.
Sounds like my dog ate my homework :lol: - Like defragster said, hope your dog is OK.
 
Thanks defragster,

I hear you about TYQT, but I sometimes resist as while I am doing a bunch of this for my own fun, I do like trying to help make the product better and so I keep trying to use most of it the way most users do... But I may break down and do it at some point... Now if Paul was to ship TYQT as part of the install...

The best improvement to Teensy is using TYQT! Everyone should use TYQT. I've gotten by without a Wiki - but without TYQT I might have lost the fun factor some time ago. Well that and posting on this wonderful forum which I find to be very therapeutic :)

It would be ideal if PJRC shipped TYQT in the box - but that would hinge on Doc Koromix (who was too busy to even justify asking for Beta boards). Koromix is continuing his work on TYQT and even working on some MARK II version (current version is 0.7.5).
 
Just found and cut&pasted the usb disable/enable from snooze code - on the T_3.6 it does not help (or function as abused). The way I had it works fine - according to TYQT.

Three things I'll try soon:
> Add support for another speed - something not sharing common bus speeds to 120: 168, 192, 216.
> USB input for directed test without recompile, also to prove USB actually comes back online bi-directionally
> Automated romp with RESET through all of EEPROM in groups of 256(?) controlled by value stored in 3998&3999. while([3998]==42 && block *[3999] in range) do block *([3999]++)
 
Hi Tim,

I tried your Sketch, and the Output is
Code:
CPU is T_3.6 F_CPU =180000000
 F_PLL =180000000
 F_BUS =60000000
 F_MEM =25714286

 Hello World
 Hello World : Going to 120 MHz, Bye
 

 

 

 Hello World -DONE 120 MHz Write
 Hello World -RESTART PENDING ...

 Hello World -DONE - CPU_RESTART now

 

 CPU is T_3.6

 F_CPU =180000000
 F_PLL =180000000
 F_BUS =60000000

 F_MEM =25714286

 Hello World

 Hello World - EEPROM values already MATCH!  No speed change Write.
 Hello World -DONE

Look good and works :)

F_BUS (and others): it is possible to save the value of SIM_CLKDIV1 in a variable, an write it back later when switching back to the higher speed.
Are the while() loops needed ?
 
Frank - Glad it worked for you. it would be nice to be able to recover current values to restore rather than duplicate the whole code set Paul uses. I'll try that next. I wasn't sure they read the same as they wrote?

Nnot sure about the while loops being NEEDED as the clock modes are set - but I figured it may provide time for the clocks to adjust - even if just a NOP.
 
Hi Tim, yes, at least SIM_CLKDIVx read the same as they wrote.
And you can change their values any time in your sketch. For SIM_CLKDIVx this meay, for example, that you can change F_BUS any time.
 
I saved and set these values and it works, I had not been doing the #2 value. On entry as the speed is to be dropped I added:
Code:
  // I don't know the extent of these values in use - I assert that both cannot be zero even if one can be?
  if ( 0 == SIM_CLKDIV1_FAST && 0 == SIM_CLKDIV2_FAST ) {
    SIM_CLKDIV1_FAST = SIM_CLKDIV1;
    SIM_CLKDIV2_FAST = SIM_CLKDIV2;
  }

Have tested this to work in my old sample. I added SerialEvent() processing to ECHO any character but 'c', and on 'c' I reprint the CPUspecs();, that works so I had enough code right to:
> Start at 180
> go to 120
> write EEPROM
> Restore 180
> Have bi-directionally usable USB!

Added another USB scan for 't' for Test where I increment the TestVal and then run the same test code. USB returns and I can repeat . . . BUT ONLY 4 TIMES in a ROW ! ! ! ! After 4 times ( speed swap, write new value, no reset) the USB output display on TYQT stops, but the Teensy is still receiving input. I used SerMon and it also works 4 times ( having to re-open the SerMon window each time ) and then it not only fails - but the IDE is HUNG - not just SerMon - but the whole of the IDE is dead. It hasn't recovered and cannot even kill the 'COM4' task - until I unplug the Teensy. I added some delays on starting test and got 5 in a row to work. No USB comes out but I added 'r' for RESET and that works ( as it seemed 't' was as the USB chimed out and in but no text appeared.) TYQT never HANGS like the IDE did!

Last night I hacked up the full set of speeds from mk20dx128.c - but not the right way and Frank's tip fixes the one issue that stopped me - knowing I was using a compatible F_BUS as tested by the #ifdef code.

Thanks for looking and the feedback Frank.

Not sure if I can trust to Read&cache any other current values rather than divining per the logic of the mk20dx128.c file?

. . . I suppose I could try it- edits to these values shouldn't brick anything . . .
 
I'm not sure why the complete USB reconnect failure happens after 3-5 tries? If I do a RESET of the T_3.6 the count starts over before failure.

I can close TYQT and restart and the USB is still write only from the PC. TYQT never hangs and can still typically write and have the T_3.6 respond. This is Windows, it may have some internal issue going and a conflict with a device coming and going like this. Though on RESET it clears up so maybe the Teensy is - from my actions, or lack of - not refreshing to a fully clean start - this isn't playing by the rules and USB has books of them. I am calling for a full usb_init which may be doing too much? But I pulled a local copy and attempts to exclude some things failed to bring USB back online at all so the USB does require some level of rebuilding as I have it.

I'm heading toward publishing a Write&RESET sample until Paul or somebody can give some guidance on what cannot work - or what can be done to clean it up. It would take any HSRUN speed - drop out of HSRUN to 120 - then RESET after the user has completed any desired set of EEPROM updates. I've already seen this work at the non-180 speeds I tested. If users looking for EEPROM usage can live with this - they at least get write utility and return to a known state on all devices. For better utility on the T_3.6 over 120 MHz, EEPROM_SD (EEPROM as a FAT file) or something else will have to evolve. Then if the SD media changes and it is found to be gone or OLD it could be restored from EEPROM**.

**At least this Write&RESET functionality would offer a way to keep 4 KB on SD (or other) - then on demand transfer it to the local EEPROM (with just a RESET) for safe keeping without having to: take the system offline to a PC to offload data, swap to a low speed sketch to write (like TeensyTransfer), then swap back to the target sketch.
 
Last edited:
HSRUN EEPROM WRITE then RESET

Quick Update:

Here is a sample that does the prior test on command [ enter 't' to USB ], then it writes and resets.

Added 'b' the AllBlockTest() write test that steps through EEPROM and resets as incremental blocks are written until EEPROM is full. You can adjust BlockSize = 255, I have it programmed (see DEBUG_7) to force one error per block to show it works.

<UPDATE :: Sketch code replaced>:
added 'z' check on restart to ZERO the TEST_FLAG_ADDR byte to stop a run-away test.
> [usage: 'z' use TYQT and be quick to stop auto test, or 'z' to stop the 'w' display]
added 'w' to take text from USB and write to EEPROM and display in setup()
> [usage : 'w123456789 the quick brown fox . . . ' ]
** Not I didn't have a runaway problem - I just wanted to allow stopping 'w' text

<UPDATE2>
<Tested at all T_3.6 speeds 120-240 MHz with Write&Reset>
<Tested through speeds again to work with NO delay(1) before restart.>
<Code (as written) should run and perform the same on any T_3.1...T_3.6>

Code:
// HSRUN EEPROM WRITE then RESET :: https://forum.pjrc.com/threads/36808-EEPROM-writing-on-T_3-6-in-HSRUN-mode?p=115214&viewfull=1#post115214
#include <EEPROM.h>
#include "respeed.h"
#define qBlink() (digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ))

String HelpMe = "\n EEPROM Testing: ?:this text,  b:test_BLOCK,  c:CPUspecs,  r:RESET,  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
// Perhaps change it now and then and EEPROM won't get worn
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));
  delay(100); yield(); // short time to process 'z' stop test
  Serial.println("\nHello World <<<-------- - - - - - -");
  delay(200); yield(); // short time to process 'z' stop test
  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(1000);
      REDUCED_CPU_BLOCK_RESET(  ) {
        // 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 );

  REDUCED_CPU_BLOCK_RESET(  ) {
    // 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 '?':
        Serial.println(HelpMe);
        break;
      case 'b':
        AllBlockTest( 0 );
        break;
      case 'c':
        CPUspecs();
        break;
      case 'r':
        ReducedResetRCB();
        break;
      case 't':
        TestVal++;
        Serial.print("\nIn One Second :: Test with TestVal=");
        Serial.println(TestVal);
        Serial.flush();
        delay(1000);
        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;
          REDUCED_CPU_BLOCK_RESET(  ) {  // 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 
        break;
      case 'z': // ZERO the test in progress byte
        Serial.print("\nIn One Second :: Zero test byte and RESET . . .");
        Serial.flush();
        delay(1000);
        REDUCED_CPU_BLOCK_RESET(  ) {  // 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 ) {
    // -------------------------------------------  THIS IS THE THING
    REDUCED_CPU_BLOCK_RESET(  ) {
      // DO NO I/O in this block
      WriteFlash();
    }
    // -------------------------------------------  THIS IS THE THING
  }
  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 the current RESET only version of the includable header::
Code:
// THIS FILE :: #include "respeed.h"
// HSRUN EEPROM WRITE then RESET :: https://forum.pjrc.com/threads/36808-EEPROM-writing-on-T_3-6-in-HSRUN-mode?p=115214&viewfull=1#post115214
extern "C" void usb_init(void);

// At 180 MHz start speed the USB seems to recover
// BUGBUG is hardcoded to return to 180MHz if that matches compiled speed the USB usably recovers
// When compiled speed is not 180 other things are incorrect and USB doesn't recover

// The SPEED Set code was lifted from :: mk2dx128.c , those parts are preceded by commented // #if code

/*********************************************************************************************
    RESPEED_CPU_BLOCK_RESET - Teensy 3.6 over 120 MHz will slow to 120 MHz, drop HSRUN. Will RESET the TEENSY

    @param none

    @return none

    Sample Usage:
      REDUCED_CPU_BLOCK_RESET(  ) {
        // WRITE TO EEPROM ALLOWED HERE
      }

    // DO NO I/O in this block
    // Flushes USB Serial and does delay(100) if dropping speed required
 *********************************************************************************************/
uint8_t SpeedSlowRCB( void );
uint8_t ReducedResetRCB( void );

#define TYPE uint8_t
#if F_CPU > 120000000 && defined(__MK66FX1M0__)
#define REDUCED_CPU_BLOCK_RESET( )   \
  for ( TYPE __ToDo = SpeedSlowRCB();  __ToDo;  __ToDo = ReducedResetRCB() )
#else
#define REDUCED_CPU_BLOCK_RESET( )   \
  for ( TYPE __ToDo = 1;  __ToDo;  __ToDo = ReducedResetRCB() )
#endif

uint8_t SpeedSlowRCB() {
  Serial.println("Going to 120 MHz, Write&RESET ...\n"); // BUGBUG DEBUG
  Serial.flush();   // make sure nothing queued to send
  delay(100);       // USB needs time to complete
  __disable_irq( );
  //    #elif F_CPU == 120000000
  MCG_C5 = MCG_C5_PRDIV0(1);
  MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14);
  // wait for PLL to start using xtal as its input
  while (!(MCG_S & MCG_S_PLLST)) ;
  // wait for PLL to lock
  while (!(MCG_S & MCG_S_LOCK0)) ;
  // now we're in PBE mode
  // #else NOT   // #if F_CPU == 216000000 || F_CPU == 180000000
  SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6);
  // now program the clock dividers
  //    #if F_BUS == 60000000
  SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7);
  SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
  while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
[B]  // __enable_irq( ); // interrupts should be left disabled through the RESTART[/B]
  return 1;
}

// 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;
}
 
Last edited:
Great work Defragster!

I verified that Windows Terminal Monitor does not recover yet. Will play with TYQT.

Would be great if Paul in all of his abundant spare time might take a look and maybe figure out why TYQT works in this case but not the terminal monitor...
 
Thanks, Glad you got to test it to work for you Kurt. Hopefully my tests show working usage of a couple of possible suggestive cases. And make it easy to use the USB input to create your own dynamic test to see it work. A bigger case would be to make a block of RAM and set up a series of struct pointers into that RAM - then the RAM could be block transferred to the EEPROM and all the structs would get stored and restored as a group with a single Write&Reset of the RAM block like the 'b' test in AllBlockTest() does with .put().

I'll get back to the RESUME case ( I should rename from _RUN ) with my best case sample so Paul can give it a quick look and maybe see what is wrong.

I've written the JAVA based SerMon off as a lost cause. At least it isn't just me on Windows. I'm sure it could be cleaned up - but being tied to the IDE makes it a bigger hit on the machine and it doesn't have a clean way to open multiple instances. I just noted on the K66 thread that I should switch my debug to Serial1 for the RESUME case to see if that works where the USB fails after a few speed swaps. That would mean dual Teensies for which TYQT is perfect and SerMon would be out of it's element (I have not tried starting the EXE twice - that would get confusing because I often have 4-10 sketches open in a single IDE for cut&paste and review)

Oh - the Duff macro used has a fight with the switch statement I had to resolve with a spare set of {braces} to contain it to the 'w' case as it spilled over the break and the compiler complained about using the local 'ii' across the break. I commented that above. This is not readily fixed with () or {} as I tried around the 'macro'.
 
Last edited:
The KINETISK cpus have two locations that might be innteresting.
Both are 128 bytes wide. The first survives a RESET, the second a deep sleep and gets powered by VBAT, if "main" power ist lost.

https://github.com/PaulStoffregen/cores/pull/171
https://github.com/PaulStoffregen/cores/pull/171/commits/1eb25c8ad21df20a99f777800baee5cbe13d936d

I think Pauls merges them if we find a better name.
Any idea how they can be defined as array ?

For more information, please refer to the manual.
I have used the first one in my serial-number library.
 
Frank - are you noting that as a way to have 128 bytes of EEPROM like memory? - survives a reset - but not a power loss (except w/vbat)? Or something that might help the EEPROM write case?
 
Last edited:
Not sure.. :) maybe we can use that somehow.. yes one can use it as a kind of "eeprom" if a battery is attached..
Dunno if it really useful, or not.
Another thing, that (eventually) might work: Did anyone try to run the MK6x without HSRUN at > 120MHz ?
I mean, the teensy 3.2 works good up to 144MHZ, some up to 168. 180MHz are not too far away...
 
Status
Not open for further replies.
Back
Top