skip navigational linksPJRC
Shopping Cart Checkout Shipping Cost Download Website
Home MP3 Player 8051 Tools All Projects PJRC Store Site Map
You are here: Teensy Teensyduino PWM & Tone

PJRC Store
Teensy 3.1, $19.80
Teensy 2.0, $16.00
Teensy++ 2.0, $24.00
USB Cable, $4.00
Teensy
Main Page
Teensy 3.1
Getting Started
How-To Tips
Code Library
Projects
Teensyduino
Reference

Pulsed Output: PWM & Tone

Teensy can output pulses digital signals that are useful for many projects.

Pulse Width Modulation

PWM creates an output with analog-like properties, where you can control the intensity in fine steps, even though the signal is really a digital pin rapidly pulsing.

BoardPWM Capable Pins
Teensy 3.13, 4, 5, 6, 9, 10, 20, 21, 22, 23, 25, 32
Teensy 3.03, 4, 5, 6, 9, 10, 20, 21, 22, 23
Teensy 2.04, 5, 9, 10, 12, 14, 15
Teensy 1.00, 15, 17, 18
Teensy++ 2.0 0, 1, 14, 15, 16, 24, 25, 26, 27
Teensy++ 1.00, 1, 14, 15, 16, 24, 25, 26, 27

PWM is controlled with the analogWrite(pin, value) function.

  analogWrite(3, 50);
  analogWrite(5, 140);
Here are the actual waveforms this code creates on pins 3 and 5:


PWM Waveforms, values 50 and 140

The value is between 0 to 255, where the higher the value, the more time the signal remains high. The value is referred to in perentage terms as "duty cycle". A value of 128 is 50% duty cycle.

PWM for LED Brightness

PWM is useful for controlling the brightness of LEDs. In this photo, 3 of the LEDs are driven by different PWM signals.


LED Dimming, with PWM values 10, 50, and 120

These LEDs are actually blinking very rapidly. Because the blinking happens much faster than the human eye can perceive, and much faster than the camera's shutter time for this photo, the result looks like a LED that is partially illuminated.

Most LEDs decrease in efficieny as you approach their maximum output. The human eye is less sensitive to differences between brightly lit objects. As you can see in the photo above, these 2 factors cause the LED with PWM value 120 to appear almost as bright as the right-most LED connected directly to the power. The PWM-driven LED really is using only 47% of the power.

When creating animated LED fading, consider changing the PWM value in larger steps when the value is larger, to achieve a more natural-looking result.

PWM for Motors

Pulse Width Modulation for controlling DC motors. The Teensy pins can not directly power a motor, so a transistor is used.

    TODO: photo: teensy3, motor, transistor, etc

    TODO: schematic diagram, NPN transistor, arrows showing charge and discharge currents

TODO: talk about average current, charge and discharge paths and current ramps

Filtering PWM for Analog Output

PWM waveforms can turned into analog signals with a low pass filter. The simplest filter uses only a resistor and capacitor, for a very simple and low cost way to obtain an analog signal.


Filtering PWM with a Resistor and Capacitor

Analog signals from PWM have caveats. If the power supply voltage changes or has noise, perhaps due to other devices that greatly vary in their power usage, the PWM high voltage varies, which in turn becomes a change to the filtered analog output.

Choosing the filter involves a trade-off between response speed and removing the PWM frequency. The lower the filter's corner frequency, the more steady the output becomes, but the slower it changes when you use analogWrite(). A more sophisticated filter can offer faster response and cleaner output, but at the cost of more components and complexity.

In the tests below, this code was used to create a PWM output which changes between 20% to 78% duty cycle.

void loop() {
  analogWrite(9, 50);
  delay(250);
  analogWrite(9, 200);
  delay(250);
}
Using a 1K resistor and 10µF capacitor gives a filter which leaves a substantial amount of the PWM frequency, but the output responds quickly when the PWM value changes.


PWM Filtered by 1K Resistor & 10µF Capacitor

Increasing the capacitor to 47µF results in a much smoother output, but the response is 5 times slower. Even this output has some of the PWM frequency present, so an even slower response would be needed to reduce it further.


PWM Filtered by 1K Resistor & 47µF Capacitor

A more complex filter can give faster response and smoother output, but such filters usually require opamp chips and many parts.

Another approach to smoother output is to increase the PWM frequency, so the filter can more easily remove it.

PWM Frequency

The PWM signals are created by hardware timers. PWM pins common to each timer always have the same frequency, so if you change one pin's PWM frequency, all other pins for the same timer change.

BoardTimerPWM PinsDefault Frequency
Teensy 3.105, 6, 9, 10, 20, 21, 22, 23488.28 Hz
13, 4488.28 Hz
225, 32488.28 Hz
Teensy 3.005, 6, 9, 10, 20, 21, 22, 23488.28 Hz
13, 4488.28 Hz
Teensy 2.005976.56 Hz
14, 14, 153921.57 Hz
393921.57 Hz
410, 123921.57 Hz
Teensy++ 2.0 00976.56 Hz
125, 26, 273921.57 Hz
21, 243921.57 Hz
314, 15, 163921.57 Hz

Teensy 3.0 supports the analogWriteFrequency(pin, frequency) function to easily configure the PWM.

    void setup() {
      analogWriteFrequency(4, 375000); // Teensy 3.0 pin 3 also changes to 375 kHz
    }

For Teensy 2.0 and Teensy++ 2.0, the TimerOne & TimerThree libraries can be used to control the PWM frequency.

PWM Resolution (Teensy 3.0)

Normally analogWrite(pin, value) is used with the value between 0 to 255, which corresponds to 8 bit resolution. Teensy 3.0 supports an analogWriteResolution(bits) function, to reconfigure analogWrite.

    void setup() {
      analogWriteResolution(12);  // analogWrite value 0 to 4095
    }

This function only configures the analogWrite value range, which is mapped to the hardware's capability. The actual resolution available depends on the PWM frequency, where slower frequencies have higher resolution.

For example, if you set the PWM frequency to 375 kHz and the resolution to 10 bits, analogWrite will automatically map the 0-1023 values to the available 0-127 range. Your code can write values from 0 to 1023, but groups of 8 consecutive values will produce the same output.

To configure both frequency and resolution for matching performance, use the values from this table:

BoardResolution
(# of bits)
PWM ValueIdeal Frequency
CPU Speed: 48 or 96 MHz
Ideal Frequency
CPU Speed: 24 MHz
Teensy 3.0160 - 65535732 Hz366 Hz
150 - 327671464 Hz732 Hz
140 - 163832929 Hz1464 Hz
130 - 81915859 Hz2929 Hz
120 - 409511718 Hz5859 Hz
110 - 204723437 Hz11718 Hz
100 - 102346875 Hz23437 Hz
90 - 51193750 Hz46875 Hz
80 - 255187500 Hz93750 Hz
70 - 127375000 Hz187500 Hz
60 - 63750000 Hz375000 Hz
50 - 311500000 Hz750000 Hz
40 - 153000000 Hz1500000 Hz
30 - 76000000 Hz3000000 Hz
20 - 312000000 Hz6000000 Hz

Tone

The tone() function is useful for simple audio. It outputs a square wave at the frequency you specify. There are generally 2 ways to use tone:

    tone(pin, frequency);       // Begin the tone
    delay(300);
    noTone(pin);                // manually stop it
    
    tone(pin, frequency, 300);  // Begin a tone which automatically stops

Either way, the tone() function returns quickly and your code continues to run while the pin outputs the specified frequency. An example can be opened from File > Examples > 02.Digital > toneMelody.

When playing a sequence of tones, sometimes it is easier to start and stop the tone. For other uses, especially output of a beep for user feedback, the automatic stop is very convenient.

To connect a speaker, a 330 ohm resistor and 100 µF capacitor are recommended. The negative terminal of the capacitor connects to the speaker.


Speaker with tone(), using 330 Ohm Resistor & 100µF Capacitor

Teensy 2.0 has a known issue where tone() will not play if you call the tone() function repetitively at high speed, restarting the tone over and over before it can begin. A future version of Teensyduino will correct this issue. As a workaround, do not call tone() again while the previous tone is still playing.

Tone uses a timer interrupt. If libraries that use interrupts create excessive interrupt latency, tone's pulsing can be delayed, creating an incorrect frequency. SoftwareSerial and OneWire are libraries known to potentially interfere with tone().