How to achieve to PWM, maximum frequency and variable duty cycle of at least 8 bit

Interesting indeed!
Now, I have verified that the TCCR1A and TCCR1B registers are to be reset to 0s
and then the analogWrite(DPin, dutyCycle); function will come into affect.

That statement cannot be true. I haven't cleared the TCCR1A and TCCR1B registers to 0, just tweaked the timers' prescaler bitfields and yet the analogWrite() function outputs at a PWM frequency of 31.25kHz.

In my edited post I have removed the phrase "if and only if"!

Hi @GolamMostafa

At the end of the day, it's just easier to continue using analogWrite() rather than playing with the timers' registers.

The small change to their prescalers simply multiplies up the frequency by 64, so that 488.28Hz, becomes 31.25kHz (outside of audible range).

While generating high frequency PWM manipulating registers, I would prefer not to use analogWrite() at the end to avoid confusion.

Hi @GolamMostafa

Confusion for whom?

For myself.

If it's that easy, why is it not standard? Surely every PWM application could benefit from it?

488.28 x 64 = 31,249.92 ==> 31.24992 kHz and NOT 31.25 kHz

If using TC1 and fast PWM (fpwm = 16000000/(N*(1+ICR1)) with N=1 or 8 or 64 or 256 or 1024, is there any possible combination of N and ICR1 that will produce 488.28 Hz signal? (In practical application, does any scheme go fraction of a Hertz?)

Hi @aarg

I think that's a question only Arduino can answer.

A less judgemental plea - couldn't they provide a way to change it in the API, similar to the way analog resolution can be changed on some hardware?

I guess they could and still provide backward compatibility, but to be honest, I can't imagine that happening.

Hi @GolamMostafa

Yes, if you set N to 256 and ICR1 to 127.

Really close. 488.28125 Hz. You get the same frequency with prescale of 1 and ICR1 = 32767

It gives 488.28125 and NOT 488.28 and that was the reason for @anon57585045 to make the comment in post #28.

@johnwasser Thanks, that's a better suggestion than mine, as it also gives a 15-bit resolution as well.

@GolamMostafa Anyway, I hopefully answered the OP's original question, since the changes I suggested do allow analogWrite() to operate at 31.25000kHz :smiley:.

In case you want to use existing code on an Atmel processor you can have a look at this library (https://github.com/MajicDesigns/MD_PWM) and the blog post at https://arduinoplusplus.wordpress.com/2021/04/06/pwm-on-any-i-o-pin/.

This library is probably not fast enough for what you need, but he code to manage TIMER1 and TIMER2 is all in there.

Guys, thanks a million for all the responses. I think the discussion between @GolamMostafa and @MartinL is very constructive. I agree with @anon57585045 that it'd be awesome if Arduino provided an easier way to handle this. After all, now that I kind of understand how the timers and the prescalers relate to one another, it doesn't look like very difficult math. However, for this particular project, I'm going with @MartinL's suggestion of just setting the timers and then keep on using analogWrite() (you certainly did answer the question!). The code stays much cleaner that way and, like I said, I didn't need a specific frequency, only one fast enough.

@marco_c it is interesting and I guess it might be useful to people trying to drive many things with different things and are fine with slower frequencies.

There are cases where the PWM must be slow. To support PWM properly, the controlled device must be able to switch on/off rapidly enough that the switching interval is much, much less than the cycle time. The low default frequency could be a conservative way to make "everything" work.

The disappointing aspect of this, however, is that there exists a trade off between frequency and resolution. It means, if operated at a much lower frequency than possible, the opportunity to increase the PWM resolution is ignored.

Because, at the low frequency, the prescaler can also run at a higher frequency, while using a larger cycle count value.