16bit PWM Function

Hello,

Has anyone by chance created a function in any of their projects, which is similar to analogWrite(), but for the 16 bit PWM outputs of the mega?

Just curious as I have been looking at the datasheet for a while and so far are none the wiser, or at least struggling.

I have a board I have created, called 'The Brick', (http://arduino.cc/forum/index.php/topic,69358.0.html) which utillises 12 PWM channels of the atMega2560, and just wanting some assistance with understanding from other peoples experiences as to what needs to be set to change standard PWM to be 16bit.
Obviously not all of the outputs I have utilised are connected to 16 bit PWM outputs, but the ones that are I would like to utilise this.

Ideally I would like to be able to set the timers frequency, and then set the duty with the function - but direct register manipulation is fine for now.

Any assistance would be appreciated.

Regards
James

No one used 16 bit PWM on their mega then...

hmm

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

2 Likes