Given that nobody has responded I figure this hasn't been covered already on the forum, so I had a bit of a look.
Every time I try to learn the AVR PWM modes I come away even more confused, nevertheless I decided to persevere and see if I could at least get something along the lines of 16-bit PWM working.
To reduce the options (and therefore the complexity) I started by concentrating on one pin (pin 7) and one mode, mode 3, aka "PWM, Phase Correct, 10-bit". This uses a hardcoded "TOP" value of 0x3FF or 1023 for the counter and therefore removes one variable. So, in (hopefully) plain English this is how it works
- Count up from BOTTOM
- When you hit the value in the OCR4C register set the output pin
- Continue counting
- When you hit the TOP value reverse and start counting down
- When you hit the value in the OCR4C register reset the output pin
- When you get to BOTTOM reverse and start counting up
- Repeat until golden brown
Note that the set/reset can be reversed by setting yet another option.
The Arduino analogWrite() func only allows values up to 256, write 260 and you get a pulse 256-260 or 4 counts wide. This is presumably because some counters are only 8 bits so the others have been dumbed down.
wiring_analog.c is not the culprit because if you look at the code it accepts an int and writes it to the OCR4C register, if you pass a value > 255 it will be correctly written into the compare register so that's not the problem.
The trail then led to wiring.c and the setup of the timer.
sbi(TCCR4A, WGM40);
Setting the WGM40 bit gives you mode 1 or "PWM, Phase Correct, 8-bit".
Changing this code to
sbi(TCCR4A, WGM40);
sbi(TCCR4A, WGM41);
Puts the timer into mode 3 or "PWM, Phase Correct, 10-bit" and hey presto we now have high(er) resolution PWM. For example
analogWrite (7, 921);
Gives a waveform approx 90% high and 10% low. Not 16 bits but a lot better that 10.
NOTE: As the counter now counts up to 1024 instead of 256 the waveform frequency is 1/4 the norm or about 125Hz. This can be sort of fixed because the timer prescaler is set to /64 in wiring.c, so that can be changed to /8 to give a frequency of 1kHz. I don't think it will be possible to get the standard 500Hz.
I might now have a look at using mode 11 to get 16-bit resolution.
Anyway I thought I'd write this up so there's some form of record for future searches and also maybe someone who knows more about this will comment.
Rob