Arduino library to generate a fast PWM signal on an output pin at maximum frequency. Examples included.
FastPwmPin provides a means to generate a high frequency PWM signal on one specific output pin. Where the regular Arduino analogWrite() function allows for generating a fixed frequency signal, this library achieves frequencies as high as 4 MHz using fast timer manipulation. The library produces a PWM signal on a single output pin. The frequency and duty cycle can be selected. The library supports multiple MCU's. The capabilities depend on the specific MCU. While originally aimed at high frequencies, the library can now also generate very low frequencies; depending on the MCU used as low as 1 Hz.
This library supports generating a high frequency signal on different MCUs such as ATmega 328, 168 and ATtiny85. Depending on the MCU, it uses different timers and registers to produce the high frequency signal. The table below gives an overview:
MCU (Board) | Available pins | Timer used | Remarks |
---|---|---|---|
ATmega328 ATmega168 (Arduino Uno, Nano, Pro Mini) |
9,10 - 3,11 | 16-bit Timer1 - 8-bit Timer2 | Pins 9, 10 have 16-bit resolution, pins 3, 11 have 8-bit resolution. Pin 9, 11 only support toggle mode (50% PWM) |
LGT8F328P | 9,10 - 3,11 - 1*,2 | 16-bit Timer1 - 8-bit Timer2 - 16-bit Timer3 | Tested on QFP32 model. Pin 1 not supported on SSOP20. For Timer 3 fixed core github.com/LaZsolt/lgt8fx is required |
ATmega8A | 9,10 - 11 | Timer1 - Timer2 | Pins 9, 10 have 16-bit resolution, pin 11 has 8-bit resolution. Pins 9, 11 toggle mode only (50% PWM) |
ATtiny85 | 1,3 | Timer1 | Only 8-bit resolution. Pins 0, 4 can also be used, but only inverted (51%-99%) |
ATtiny44A ATtiny84A | 5,6 - 7,8 | Timer1 - Timer0 | Pins 5, 6 have 16-bit resolution, pins 7, 8 have 8-bit resolution. Pins 6 and 8 only support toggle mode (50% PWM) |
ATtiny13A | 0*, 1 | Timer0 | Pin 0 only supports toggle mode (50% PWM) |
ESP8266 | Minimal implementation using analogWriteFreq() and analogWrite() | ||
ESP32 | NOT SUPPORTED (YET) | ||
STM32 | NOT SUPPORTED (YET) |
This library has been tested on multiple MCU's under various condititions*. The generated signal frequency has been measured using different methods**. The table below lists frequencies measured:
MCU (Board) | Clock (voltage) | Highest frequency | Lowest frequency | Remarks |
---|---|---|---|---|
ATmega328 (Pro Mini) | 16 Mhz (3v3/5V) | 4 MHz | 1 Hz | Toggle only on pin 9, 11 and at highest frequencies. Lowest frequency is 40 and 80 Hz on pins 11 and 3 |
LGT8F328P | 32 Mhz (3v3) | 16 MHz | 1 Hz | Toggle only on pin 1, 9, 11 and at highest frequencies. Lowest frequency is 40 and 80 Hz on pins 11 and 3 (8-bit Timer2). Tested using QFP32 board. |
ATmega168 (Pro Mini) | 8 Mhz (3v3) | 4 MHz | Toggle only on pin 11 and at highest frequencies | |
ATmega8A | 8 MHz (5V) | 4 MHz | 1 Hz | best resolution on pins 9, 10 |
ATtiny85 | 1 MHz, 8 MHz (3v3), 16 MHz | 16 MHz | 1 Hz | when > 250 kHz fast PLL clock is activated, 1 Hz only on 1MHz clock |
ATtiny84A | 8 MHz (5V) | 4 MHz | 1 Hz | lowest frequency measured on pin 7 is 32 Hz, on pin 5 it is 1 Hz |
ATtiny44A | 8 MHz (3v3/5V) | 4 MHz | 1 Hz | lowest frequency measured on pin 7 is 32 Hz, on pin 5 it is 1 Hz |
ATtiny13A | 9.6 MHz (3v3) | 1.6 MHz | 38 Hz | frequencies > 1.6 MHz are instable |
* If you tested this library on a different board-setup, please send me your findings, so I can update the table.
** Frequency was measured using UT89C multimeter, DSO112 mini oscilloscope, Arduino FreqCount serial example on 16MHz Nano and a logic analyzer (@16MS/s).
The library can be downloaded from https://github.com/maxint-rd/FastPwmPin. It can be installed as an Arduino library using the Sketch|Library menu. Just add the zipfile library and the enclosed example should appear in the menu automatically.
Initialisation before Setup():
// include header
#include <FastPwmPin.h>
Then to initialize the high frequency signal, call the enablePwmPin() method in Setup():
FastPwmPin::enablePwmPin(11, 4000000L, 50);
The enablePwmPin() method has the following syntax:
int FastPwmPin::enablePwmPin(
const int nPreferredPin=0,
unsigned long ulFrequency=0L,
uint8_t nDutyPercentage=FASTPWMPIN_TOGGLE
);
Parameters:
nPreferredPin - prefered pin to generate the high frequency signal
ulFrequency - frequency in Hertz
nDutyPercentage - PWM percentage (duty cycle)
Return value:
When succesful the method returns the preferred pin as set. If unsuccesful -1 is returned.
Note: To switch a pin fully on or fully off, you must use digitalWrite(). Duty percentages of 100 and 0 result in -1 error return value.
See the enclosed example for more details.