maxint-rd / FastPwmPin

Arduino library to generate a fast PWM signal on an output pin at maximum frequency. Example included.
40 stars 14 forks source link

FastPwmPin

Arduino library to generate a fast PWM signal on an output pin at maximum frequency. Examples included.

Introduction

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.

Support for different MCUs

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)

Tested frequencies

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).

Installation/Usage

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.

Features & limitations

Credits

Links

Disclaimer