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 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:
This was CUT&PASTE and trial&error. Let me know if you see anything obvious that should or should not be done.
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.
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: