151.2 MHz when selecting 150 MHz CPU clock?


Well-known member
For a project I prefer lowering the CPU clock so that my Teensy4.1 runs cooler, and may live a longer life.

So in IDE I went Tools, CPU Speed, and picked 150 from the drop down list of options.

When I check what my CPU clock then is with a

          Serial.printf ("F_CPU_ACTUAL is %ld Hz or %1.2f MHz ", F_CPU_ACTUAL, (double)F_CPU_ACTUAL/1E6);

Then its says:

F_CPU_ACTUAL is 151200000 Hz or 151.20 MHz

Is that normal? Is F_CPU_ACTUAL what the frequency in Hz really is, as a measurement using some other time reference like the 24 MHz system clock? Or is it a calculation what it would be given that 24 MHz Teensy crystal is probably 24.00000000000 MHz and PLL nominator/denominator values are as loaded in PLL when booting?

Background: I have a precise elapsed time to be sensed in software using CYCCNT that normally runs at 600 MHz, but will run slower. At 150.000 MHz or at 151.2 MHz - that's what I'm not quite too sure about anymore now... How many ns per CYCCNT tick when 150 is picked in the IDE/Tools/CPU_Speed list of options? And is that number available as a global variable double or uint32 maybe?
The link below will take you to a post where Paul discusses F_CPU_ACTUAL versus F_CPU. It says you should use F_CPU_ACTUAL, which is a uint32_t variable, not a constant. It doesn't say anything about

I added code to my project to change frequencies at runtime. If I request 150MHz, I get F_CPU_ACTUAL = 151'200'000, the same as you report. I use these macros to convert between cycles and us or ns.

#define CYC_TO_NS(cyc)    ((cyc)*(1E9f/F_CPU_ACTUAL))
#define CYC_TO_US(cyc)    ((cyc)*(1E6f/F_CPU_ACTUAL))
Last edited:
OK. So the drop down list in the IDE should not say 150 but 151 as one of the many CPU Speed options. I had expected 600/4=150, but that’s just a wrong assumption.
The actual speed depends on fixed available clocks to get the chip running. The math is worked out as close as possible given integer divisions of the clocks.

Code in ...\arduino-1.8.19\hardware\teensy\avr\cores\teensy4\clockspeed.c :: uint32_t set_arm_clock(uint32_t frequency)
Something else to keep in mind is when you change F_CPU or call set_arm_clock(), you change both F_CPU_ACTUAL and F_BUS_ACTUAL, and the relationship between the two is not always the same. For example, if you call set_arm_clock(600), you get 600/150 (ratio of 4), but if you call set_arm_clock(300), you get 300/150, a ratio of only 2.

Still, it's pretty cool that you can change the CPU frequency on the fly and all of the peripherals continue to work.