HI Cy
The only 3 options I am aware of are:
A: using the inbuilt PWM features of the AVR which are currently being used in both libraries (IRremote & IRlib). This of course limits output on only the supported PWM pins of each MCU & as you said they are different on many models.The inbuilt PWM function always gives you the cleanest signal. (Any other method could potentially result in an occasional stretch/distortion of the modulated signal because of other interrupts. I have seen situations where this confuses some IR receivers, resulting in a corrupted demodulated signal)
B: The other option would be to configure your own timer, with an associated ISR which toggles the desired output pin (or pins). This would give the ultimate flexibility. However, for 56kHz modulation (17.8 uSec period) you would be toggling twice per period which is equal to 8.9 uSecs @ 50% duty cycle or circa 5.95uSecs @ 33% duty cycle. Maybe do-able at 16Mhz but less so at 8Mhz or 1MHz.
C: Use a standard code loop to generate your own PWM by toggling the output pin as required. To do this you need to use delayMicroseconds rather than the Timer0 (Timer0 is only 4usecs granularity), but delayMicroseconds is close to 1 uSec granularity. Even better would be to generate your own ASM loops to exactly match the timings required for each standard modulation frequency & supported duty cycles. You would also have to use direct port access for toggling. delayMicroseconds has an example of an ASM loop to get a fixed delay, based on MCU cycles. An oscilloscope or LA would help in calibrating any new code.
I have also seen discussions about using the SPI & USART clocks to generate the IR PWM as already mentioned, but I suspect you are likely to run into similar isues to the ones you raised.
So my immediate guess would be to invest your effort into making the existing approach (A) more configurable between the different timers on each of the models. Reserve Timer0 for Arduino millis() and then allow users to configure Timer1 or Timer2 etc (if available). Once the first few are implemented (in a generic manner) it should be easier adding more models to the mix via conditional "#defines". . You should also consider adding in a way to configure duty cycle from 10->50%. BTW: A lot of the Arduino Core is implemented this way (#define's).
You could also look at the Timer1 (or Timerone) library which supports PWM & ISRs etc. - but will have the same issues as mentioned above.
Finally, inbuilt PWM (A) is the most accurate approach, with no CPU overhead while generating the PWM.
Keep up the great work & thanks for making IRLib available to the community ![]()