Phase Correct PWM library?

The Atmega328 has 3 timers all of which are capable of phase-correct PWM. Two are 8-bit timers, one is 16-bit.

I have some logic analyzer images of all the modes on Timer 0 here:

You can get very high frequency phase-correct PWM. It is just a trade-off between frequency and duty cycle resolution.

This image, for example shows 40 KHz:

Code to generate that:

#include <TimerHelpers.h>
// Timer 0
// output    OC0A   pin 12  (D6)
// output    OC0B   pin 11  (D5)

const byte timer0OutputA = 6;
const byte timer0OutputB = 5;
  
void setup() {
   pinMode (timer0OutputA, OUTPUT); 
   pinMode (timer0OutputB, OUTPUT); 
   TIMSK0 = 0;  // no interrupts
   Timer0::setMode (5, Timer0::PRESCALE_1, Timer0::CLEAR_A_ON_COMPARE | Timer0::CLEAR_B_ON_COMPARE);
   OCR0A = 200;    // number of counts for a cycle
   OCR0B = 150;    // duty cycle within OCR0A
}  // end of setup

void loop() {}

The 40 KHz is because of the frequency counter being 200, so with a clock period of 62.5 nS the frequency will be:

1 / (62.5e-9 * 200) / 2 = 40000

Just reduce the counter to get a higher frequency. eg. 75 would give approx 106 KHz. You divide by 2 because that is the way phase-correct works. It counts up and then counts down again.

The only drawback here is that since the "top" is 75, you only have 75 units of duty cycle. In other words, the duty cycle can be 1/75, 2/75 and so on. That is, increments of 1.33% each time.

I strongly recommend the hardware PWM. It will give jitter-free pulses without relying on interrupts or anything else, and you can have up to three of them at once (although you usually reserve Timer 0 for timing, like counting milliseconds).

You can change the duty cycle on-the-fly by merely writing a different number fo OCR0B (the duty cycle register).