Setting CPU Clock Speed
The first thing your C-based program should do is set the CPU to the correct speed. This speed should match the F_OSC variable in your Makefile.
Teensy defaults to only 2 MHz, for compatibility with lower voltage power supplies. To run at 16 MHz, you MUST set the speed. This setting affects the CPU and ALL periperals, except USB.
Symbol definitions
These macros make setting the clock prescaler easier.
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) #define CPU_16MHz 0x00 #define CPU_8MHz 0x01 #define CPU_4MHz 0x02 #define CPU_2MHz 0x03 #define CPU_1MHz 0x04 #define CPU_500kHz 0x05 #define CPU_250kHz 0x06 #define CPU_125kHz 0x07 #define CPU_62kHz 0x08
Interrupts MUST be disabled while setting the speed.
Simplest Method
The easiest way is to just set the speed at the beginning of your program. Interrupt aren't enabled yet, so you don't need to worry about them.
int main(void) { CPU_PRESCALE(CPU_16MHz); // rest of program
3.3 Volts = 8 MHz Maximum
If your Teensy is modified to run at 3.3 volts, 8 MHz is the maximum. Most Teensy boards will actually run at 16 MHz, at least a room temperature, but technically 16 MHz at 3.3 volts is overclocking. Setting to 8 MHz is safe.
int main(void) { CPU_PRESCALE(CPU_8MHz); // 3.3 volt compatible // rest of program
Slowly Starting Power Supplies
When Teensy is used with a power supply that features a "soft start", you may need wait for the voltage to reach 5 volts before switching to 16 MHz. This is easy, but remember the "_delay_ms()" function works with F_OSC, so it will delay longer.
int main(void) { CPU_PRESCALE(CPU_125kHz); // power supply still ramping up voltage _delay_ms(1); // actual delay 128 ms when F_OSC is 16000000 CPU_PRESCALE(CPU_16MHz); // rest of program
Running Slow To Save Power
You can save power by switching to a slower speed when the full 16 MHz isn't needed. Placing the CPU into an idle or sleep mode also helps. The idle mode, where the CPU is stopped but peripherals keep running, saves a lot of power when used together with reduced clock speed.However, all peripherals except USB depend on the clock prescaler. If you are using timers to generate waveforms, those outputs will slow down. If the UART is being used, the baud rate will change. Saving power with clock speed changes while peripherals are in use requires careful attention to configurations.
Here is a simple example of waiting for pushbuttons, using a slow clock.
char wait_pushbutton_press(void) { char retval=0; cli(); CPU_PRESCALE(CPU_125kHz); sei(); // pushbuttons connected to PC0, PC1, PC2 // those pins configured as input with pullup while (1) { if ((PINC & 1) == 0) { retval = 1; break; } if ((PINC & 2) == 0) { retval = 2; break; } if ((PINC & 4) == 0) { retval = 3; break; } } cli(); CPU_PRESCALE(CPU_16MHz); sei(); return retval; }
If interrupts may occur, they will run at the slow clock. If that is an issue, code can be added to switch the clock back to 16 MHz. Switching speeds while your program is running can add a number of complex issues, but it can also dramatically reduce power consumption, especially when USB is not in use and idle mode is used.