Overclocking the Teensy 4.x - Ultimate Thread

KenHahn

Well-known member
Teensy 4.x is still the fastest microcontroller module readily available and many people use it primarily for that reason, but it can potentially be even faster if overclocking (OC) is used.

Whenever OC is discussed, it is usually a sidebar to some other discussion. I have created this thread to hopefully be a collection point for general knowledge about OC as well as gather real world experiences from people like @beermat and others that are successfully using OC or those who have tried it and run into issues.

@defragster and I have been tinkering with OC, sometimes with surprising results, and will share some of those results on this thread.

For those successfully using OC, it would be nice to know the following at a minimum:
  • CPU speed used
  • Is the speed set using the IDE or via code.
  • Heatsink used if any.
  • Airflow if any.
  • Type of baseboard used i.e. large power/ground planes or more point-to-point power wiring.
  • Type of circuit it is plugged into e.g. exercising SPI/I2C modules with LCD display, driving addressable LEDs, motor control, etc.
  • Typical ambient operating temperature range.
  • CPU temperature range.
  • Insights into why OC is being used.
  • Estimated run-time with that setup.
Here are a few general topics related to using OC with Teensy that I can think of, though I'm sure there are probably others to add to the list.
  • When is OC actually useful to consider in an application.
  • How much does the application itself affect CPU thermals.
  • How does the external circuit a Teensy is plugged into affect CPU or overall Teensy module thermals including the 3.3V regulator.
  • Methods to control the CPU/module thermals to keep within safe limits - related to above.
  • Effect of OC on CPU lifespan due to increased wear on the chip.
 
Here is my current testing platform. It is a Teensy 4.1NE on my Prototyping System for Teensy 4.1 baseboard.

1771281499522.jpeg


  • CPU Speed = 1.008GHz
  • CPU speed is set through IDE. Setting in code using set_arm_clock(1008000000); gave intermittent results and occasional boot loops during startup.
  • Heatsink = Relatively large 12x12x18mm black anodized aluminum https://protosupplies.com/product/cpu-heatsink-12x12x18-anodized-aluminum/.
  • Airflow = None, but sits in open air.
  • Type of Baseboard = Large power / ground planes with traces and male header pins connected to all 48 Teensy pins. It also has USB Host and VBAT connections to the baseboard as well, so there is a fair amount of overall heatsinking.
  • Ambient Temp = 21C typical
  • CPU Temp = 60-61C. Heatsink sits at about 40C.
  • Application is for testing purposes. It currently has CoreMark running in a continuous loop. During the loop, an ISR provided by @defragster is cycling 16 LEDs at a 100mS rate with each drawing 0.75mA to add varying loads to some of the pins. The LCD is updated each loop. It logs the run-time hours and days to an SD card and also will write any CrashReport to the SD card as well.
  • Current runtime = 25 days with no issues noted though there have been various configuration changes during the time, but always running at 1.008GHz.
CoreMark was chosen as the basis for the testing as it was assumed that it would exercise the core CPU very hard and in turn generate more heat. Doing some testing relative to Blink proved that there was surprisingly little difference.

1GHz CoreMark in loop 60C 260mA (no LCD or LEDs)
1GHz Blink 59C 257mA (no LCD or LEDs)
 
Years back this sketch was made to test starting Teensy at 600 MHz and lowering the speed to see it work,

Here is a modified version that after testing it at 600 MHz and LOWER now makes a pass at the two no cooling OC speed changes.

Another section added behind "//#define YES_COOLING" that then cycles for a second or so through the higher OC values.

This was done to see that going to 1.008 GHz worked. Another sketch to follow finds it to FAIL ODDLY. This test may be too brief for the problems to be found with the following sketch.

Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#define MHZ_MHZ 1000000
//#define YES_COOLING 1 // UNCOMMNENT for MAX OC TEST with COOLING in place

void setup() {
  while ( !Serial);
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  set_arm_clock(1008000000);
#ifdef YES_COOLING
  Serial.println("\nWARNING : Overclocking where COOLING IS REQUIRED");
#endif
  TimeDiff();
  uint32_t spdListA[] = { 240, 110, 24, 600, 130, 110, 240, 600, 240, 600, 150, 0 };
  for ( int ii = 0; 0 != spdListA[ii]; ii++ ) {
    set_arm_clock(spdListA[ii] * MHZ_MHZ);
    TimeDiff();
  }
  uint32_t spdListB[] = { 240, 110, 600, 130, 110, 24, 600, 24, 600, 150, 240, 150, 600, 300, 130, 600, 240, 130, 110, 600, 130, 0 };
  for ( int ii = 0; 0 != spdListB[ii]; ii++ ) {
    set_arm_clock(spdListB[ii] * MHZ_MHZ);
    TimeDiff();
  }
  uint32_t spdListC[] = { 600, 720, 600, 816, 600, 600, 720, 600, 816, 600, 0 };
  for ( int ii = 0; 0 != spdListC[ii]; ii++ ) {
    set_arm_clock(spdListC[ii] * MHZ_MHZ);
    TimeDiff();
  }
#ifdef YES_COOLING // WARNING : Overclocking where COOLING IS REQUIRED
  uint32_t spdListD[] = { 600, 912, 600, 960, 600, 1008, 600, 912, 600, 960, 600, 1008, 600, 0 };
  for ( int ii = 0; 0 != spdListD[ii]; ii++ ) {
    set_arm_clock(spdListD[ii] * MHZ_MHZ);
    TimeDiff();
  }
  TimeDiff();
  Serial.printf("\n DONE \n \t F_CPU=%u", F_CPU_ACTUAL );
  Serial.printf( "\tdeg  C=%u\n" , (uint32_t)tempmonGetTemp() );
#endif
}

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

void TimeDiff() {
  uint32_t t0, cc0, t1, t2, foo;
  Serial.printf("\n F_CPU=%u [%d", F_CPU_ACTUAL, F_CPU_ACTUAL / MHZ_MHZ );
  t0 = millis();
  while (!(millis() > (t0 + 1000)));
  t0 = millis();
  t1 = micros(), t2 = millis();
  cc0 = ARM_DWT_CYCCNT;
  delay(50);
  cc0 = ARM_DWT_CYCCNT - cc0;
  foo = millis() - t2;
  Serial.printf("\t50ms delay:: %u us and %u ms\tdeg  C=%u\tCPU cyc/sec=%lu\n", micros() - t1, foo, (uint32_t)tempmonGetTemp(), cc0 * 20);
  if ( foo < 48 || foo > 52 ) {
    Serial.printf("\n >>>>>>>>>>>>>>>>>>>>   BUGBUG   @%u MHz  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", F_CPU_ACTUAL / MHZ_MHZ );
    Serial.printf("\n F_CPU=%u\n", F_CPU_ACTUAL );
    delay(1000);
  }
}
#endif // if defined(__IMXRT1062__)
 
Running this sketch on a T_4.o or T_4.1 exhibits bad behavior when going to 1.008 GHz

Code:
//https://forum.pjrc.com/index.php?threads/t4-1-detect-reboot-type.76679/page-2#post-365582
// https://forum.pjrc.com/index.php?threads/how-to-read-last-reset-reason-for-teensy-4-1.66654/post-286811

extern "C" uint32_t set_arm_clock(uint32_t frequency);
#define MHZ_MHZ 1000000
void setup() {
  Serial.begin(115200);

  unsigned long start = millis();
  while (!Serial && millis() - start < 2000) {
    // just wait
  }
  Serial.printf("\n F_CPU=%u [%d", F_CPU_ACTUAL, F_CPU_ACTUAL / MHZ_MHZ );
  CrashReport.breadcrumb(1, 0xDEADBEEF);
  delay(10);
  if (CrashReport) {
    Serial.print( CrashReport);
    Serial.println("\n\nBooting... NO CHANGE in ARM_CLOCK");
  }
  else {
    Serial.println("\n\nBooting...then... set_arm_clock(1008000000);");
    delay(10);
    set_arm_clock(1008000000);
    CrashReport.breadcrumb(2, F_CPU_ACTUAL/1000000);
    delay(1);
    CrashReport.breadcrumb(3, 0xABC123);
    delay(10);
    CrashReport.breadcrumb(4, 0x98765432);
  }
  Serial.printf("\n F_CPU=%u [%d", F_CPU_ACTUAL, F_CPU_ACTUAL / MHZ_MHZ );
  Serial.printf("\n\n 'SEND' to restart\n" );

  uint32_t cause = SRC_SRSR;
  Serial.print("reason #-");
  Serial.print(cause);

  if (cause & (1 << 0)) Serial.println(" -->Power-on reset");
  else if (cause & (1 << 3)) Serial.println(" External reset pin");
  else if (cause & (1 << 4)) Serial.println(" Watchdog reset");
  else if (cause & (1 << 1)) Serial.println(" -->Software reset");
  else Serial.println(" --> ZERO None Found.");
  SRC_SRSR = cause;   // Clear flags
}

void loop() {
  if (Serial.available()) SCB_AIRCR = 0x05FA0004;   // do software reboot if USB input
}

Here is output first from Programming where it sets breadcrumb 4 then restarts with a fault recorded.
Pressing SerMon 'Send' restarts and that time it does not set breadcrumb 4.
Other times it just hangs without CrashReport restart, and at least once it went to "RED LED" blinking - and these cases required a Program Button, or worked with the Off/ON pin cycling and CrashReport was shown on restarting.

breadcrumbs:
>1 DEADBEEF before speed change
>2 Save the reported F_CPU_ACTUAL after speed change - this works showing 1008
>3 just a filler after 1 ms delay()
>4 another test filler after 10 ms delay() : missing in 2nd CrashReport
Code:
 F_CPU=600000000 [600

Booting...then... set_arm_clock(1008000000);

 F_CPU=600000000 [600

Booting...then... set_arm_clock(1008000000);

 F_CPU=600000000 [600CrashReport:
  A problem occurred at (system time) 19:33:25
  Code was executing from address 0x898
  CFSR: 1000082
    (DACCVIOL) Data Access Violation
    (MMARVALID) Accessed Address: 0xFFFFFFFF
    (UNALIGNED) Unaligned access UsageFault
  HTSR: 40000000
    (FORCED) Forced Hard Fault
  Temperature inside the chip was inf °C
  Startup CPU clock speed is 600MHz
  Reboot was caused by software write to SCB_AIRCR or CPU lockup
  Breadcrumb #1 was 3735928559 (0xDEADBEEF)
  Breadcrumb #2 was 1008 (0x3F0)
  Breadcrumb #3 was 11256099 (0xABC123)
  Breadcrumb #4 was 2557891634 (0x98765432)


Booting... NO CHANGE in ARM_CLOCK

 F_CPU=600000000 [600

 'SEND' to restart
reason #-0 --> ZERO None Found.

 F_CPU=600000000 [600

Booting...then... set_arm_clock(1008000000);

 F_CPU=600000000 [600CrashReport:
  A problem occurred at (system time) 19:33:32
  Code was executing from address 0x2EB6
  CFSR: 82
    (DACCVIOL) Data Access Violation
    (MMARVALID) Accessed Address: 0x0 (nullptr)
      Check code at 0x2EB6 - very likely a bug!
      Run "addr2line -e mysketch.ino.elf 0x2EB6" for filename & line number.
  Temperature inside the chip was inf °C
  Startup CPU clock speed is 600MHz
  Reboot was caused by software write to SCB_AIRCR or CPU lockup
  Breadcrumb #1 was 3735928559 (0xDEADBEEF)
  Breadcrumb #2 was 1008 (0x3F0)
  Breadcrumb #3 was 11256099 (0xABC123)


Booting... NO CHANGE in ARM_CLOCK

 F_CPU=600000000 [600

 'SEND' to restart
reason #-0 --> ZERO None Found.
 
Here is my info:
  • 816MHz (with PSRAM @ 198MHz and SD card @ 99MHz)
  • Speed set in code via set_arm_clock
  • Copper heatsink, 10mm x 10mm x 4mm
  • Teensy is tightly sandwiched lengthwise between two 4.5” x 2.5” PCBs, but ends are open...screen/audio chip is above, main board below
  • PCBs are two layer, full copper filled ground planes each layer, but has no circuitry that runs “hot”
  • Type of circuit - main app is “kitchen sink”, but primary function is to continuously read light sensors via ADC rapidly (>500KHz), small data processing, then drive a 16 bit 8080 display, with rapidly scrolling graphs (partial sample of data from the ADC read) plus some LVGL elements that are updated at various frequencies from high to low. Occasional SPI interaction for touch and to control a digital potentiometer to scale ADC readings, some I2C activity reading battery current use from a chip. Occasional I2S for audio.
  • Ambient temperature range is generally room temperature, with some outdoor summer temps during thunderstorms
  • CPU is a constant 48-50C when running under load indoors at room temperature. Have never formally timed runtime and monitored temp (it's continuously displayed on my UI and monitored internally), but normal functional usage lasts a few hours by an open window on humid summer evenings during thunderstorms, plus I ran “longevity” tests for days, but focus was on code issues, memory leaks, etc., not temperature per se.

Notes loosely based on your request:

Why OC - Primary function of app is a lightning detector to trigger a camera, and display a responsive GUI with some rapidly updating elements for info/config, plus a memory data dump to SDcard if lightning is detected and needs to be done quickly to be responsive to next strike, so increased CPU speed significantly helps that. I have other functions, such as video playing that decodes a stream of JPGs and audio read from the SDcard, that benefit immensely from OC. It also helps drive the screen controller at the max possible rate by bitbanging the data over GPIO effectively using the CPU speed as a clock and a handful of NOPs to control timing - FlexIO is limited to a handful of specific clock rates, so you always end up having to choose one lower than the screen can handle. OC’ing reduces the time with blocking sends but also helps reduce tearing on screens without a VSYNC signal by moving the data as fast as the controller can handle.

My app monitors CPU temp via tempmonGetTemp() and will automatically drop the CPU speed if temp goes above my internally defined threshold (I think I have it at 70C), and log and play an audio alert, but it’s never kicked in.

I have also used set_arm_clock repeatedly during runtime with no issues (*), so was surprised to see you had some. I can change the CPU speed via UI, and also dynamically change it in code depending on app function called. Also have “sleep” function that drops it to a lower CPU speed with no user activity and back up to full speed on screen touch. The (*) is for changing CPU speed with FlexIO being used to drive an 8080 screen, then some issues have occurred, not sure why. Also, there was a time with a prior Teensy core and my custom linker that updating EEPROM with CPU at 816MHz caused crash/restart, which I resolved at the time by wrapping EEPROM calls with calls to lower then restore selected CPU speed. This doesn’t happen now on latest cores. But, outside FlexIO 8080, I’ve never really had an issue changing CPU speed at runtime.

I have been using a set of 4 different Teensys at 816MHz for 5 years now (obviously not continuously, lol) and have not experienced any HW failures.

Video from around 3 years ago of most of the functions in the app......running at 816MHz. With the heavy GUI load, OC really helps

 
Last edited:
Thanks for sharing @beermat. You weren't kidding about kitchen sink app! Quite the snappy graphics, is that the 7" RA8889 from BuyDisplay?

Besides CPU clock, it looks like you are pushing all the boundaries. I don't think I have successfully run PSRAM past 166MHz, but that was at 600MHz. Will have to play with max PSRAM speeds relative to CPU clock I guess.

I have also used set_arm_clock repeatedly during runtime with no issues (*), so was surprised to see you had some.
@defragster and I have only seen this issue when going to 1.008GHz in code. Other frequencies seem to work fine and 1.008GHz works fine as long as it is set in the IDE. Perhaps at that max speed setting, something in addition to set_arm_clock needs to be configured for it to work correctly - dunno.
 
Thanks for sharing @beermat. You weren't kidding about kitchen sink app! Quite the snappy graphics, is that the 7" RA8889 from BuyDisplay?

Besides CPU clock, it looks like you are pushing all the boundaries. I don't think I have successfully run PSRAM past 166MHz, but that was at 600MHz. Will have to play with max PSRAM speeds relative to CPU clock I guess.


@defragster and I have only seen this issue when going to 1.008GHz in code. Other frequencies seem to work fine and 1.008GHz works fine as long as it is set in the IDE. Perhaps at that max speed setting, something in addition to set_arm_clock needs to be configured for it to work correctly - dunno.
Hahahah, thanks, it started as an essential app (the lightning trigger part) and I just kept adding and adding less and less useful stuff until it eventually just became a catch-all as I had built so much infrastructure for everything :) Screen is a BuyDisplay 7", but SSD1963....pretty fast controller, but non IPS panel and it doesn't have square pixels :) Tried the RA8889 and it's a lot slower for pushing pixels over 8080, and the built-in graphics are a lot slower than just doing it on the T41 itself and pushing over 8080 - that controller is really meant for low horsepower machines.

The PSRAM chips I use are rated 133MHz, but I think I hit the silicon lottery for a handful of them, as I can push them to 198MHz with zero issues. Another pair I have can only go to 180MHz on a different T41. I get those speeds at 600MHz too. I may have an issue with the higher speed PSRAM once I go above 900MHz for the CPU, but I haven't investigated that much further.
 
Back
Top