The source code for the analogWrite function looks like this:

void analogWrite(uint8_t pin, int val) {
    sbi(TCCRnA, COM0x);
    OCRnx = val;

Where n is which timer (0, 1, 2...) and x is which pin is controlled by that timer (A, B).

This doesn't make sense to me, because the ATmega328P datasheet says that the bits TCCRnA.WGM0[1:0], and TCCRnB.WGM0 need to be set up as well.


Obviously the above code works, but how, with the missing bit settings?

  • Look in init(). All that stuff gets set up ahead of time. All they're doing here is setting the one COM bit to enable the pwm on that pin. – Delta_G Oct 5 '17 at 2:22
  • Thanks. I suspected that, but I couldn't find where it was set up. If you want to write that as an answer I will accept it. – Ember Oct 5 '17 at 5:01
  • Your statement “the Compare Match Interrupt for the pin [...] is required for the Waveform Generator to function” is incorrect. – Edgar Bonet Oct 5 '17 at 11:25
  • @EdgarBonet You're right. I edited the question. – Ember Oct 6 '17 at 0:29

Look at the init() function in wiring.c. All of the timers get set up there depending on which chip is selected. I don't know if some might also be done by initVariant(). But all it leaves for analogWrite to do is set the bit in the COM register to enable the PWM.


because the ATmega328P datasheet says that the bits TCCRnA.WGM0[1:0], TCCRnB.WGM02, and TIMSKn.OCIEx all need to be set as well.

they use different meanings for the word "set".

  1. the datasheet is saying that you need to SET UP those bits for the appropriate mode. "SET" here means both set or clear, as appropriate.

  2. the code, poorly written actually, sets those bits that need to be set, and let the rest is in their default / reset state, presumably cleared. a more robust way would have been to explicitly clear those bits.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.