Go Down

Topic: PWM2 (Digital Pin11) (Read 5648 times) previous topic - next topic


ATmega8 has got three PWMs and Arduino board has got PWM2 as well.

but in my case, I could not use digital pin11 as a PWM. Is there any way to use third pwm pin?


The third PWM pin will be enabled (using analogWrite()) in the next release of the Arduino software.  In the meantime, if you really need it, you could try the following code (which has been compiled, but not tested on the board).

Code: [Select]

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int i;

void timer2PWMOn()
  // configure timer 2 for normal (non-inverting) pwm operation
  // this attaches the timer to the pwm pin
  sbi(TCCR2, COM21);
  cbi(TCCR2, COM20);

void timer2PWMOff()
  // disconnect the timer from the pwm pin
  cbi(TCCR2, COM21);
  cbi(TCCR2, COM20);

void timer2PWMSet(unsigned char val)
  OCR2 = val;

void setup()

  // configure timer 2 for phase correct pwm
  // this is better for motors as it ensures an even waveform
  // note, however, that fast pwm mode can achieve a frequency of up
  // 8 MHz (with a 16 MHz clock) at 50% duty cycle
  cbi(TCCR2, WGM21);
  sbi(TCCR2, WGM20);
  pinMode(11, OUTPUT);

void loop()
  i = (i + 1) % 256;


Mar 08, 2006, 01:48 am Last Edit: Mar 08, 2006, 01:50 am by beltran Reason: 1
wow mellis!that is one wicked code syntax!!! full of functions I've never seen :-)
I've tried to track down the meaning of it all to better understand the guts of Arduino.
But I'm not sure If I got it all right...in the process I certainly learned a lot about C, Arduino, microprocessors in general and the ATmega8 working blocks, so this post is also to share this kind of discovery with the other designers like me willing to learn about these things...just 2-3 hour ago I couldn't understand your code :)
I guessed it would have been kind of long and complicated for you to explain all this so this is a short description of what I found, the notes I kept while finding things out step by step.
could you please tell me If I got it right or wrong..and maybe answer to the few open questions at the bottom?


cbi = clear bit in I/O register
sbi = set   bit in I/O register
sbi and cbi are 2 instruction specific of the Atmega8 that can be found in the datasheet under the sections
instruction set > Bit and bit test instructions (page 287)
I guess that "cbi" will set to 0 zero the specified bit
and "sbi" will set to 1 that specified bit (is that correct?)
I'll check what they are actually doing later on. (I've found the definitions inside tools/avr/avr/include/avr/sfr_defs.h)

you are passing to the cbi function 2 paramenters
sfr = stands for "Special Function Register"
bit = I guess it's the name of a bit inside that special function register

in fact looking inside the "Register Summary" in the Atmega 8 datasheet (page 284)
we can find the two parameters passed to the sbi func (inside the timer2PWMOn() )
sbi(TCCR2, COM21);
TCCR2 -> is the sfr or Special Function Register name ->look under address 0x25 (0x45)
COM21 -> is the name inside it's bit 5 column
the functions are explained in page 115 of the datasheet

in page 115 we discover that TCCR2 stands for TIMER/COUNTER CONTROL REGISTER
and that COM21(bit 5 of sfr TCCR2) and COM20 (bit 4 of sfr TCCR2)
(see section Bit 5:4 - COM21:0: Compare Match Output Mode)
are used for:
"These bits control the Output Compare Pin (OC2) behavior. If one or both of the
COM21:0 bits are set, the OC2 output overrides the normal port functionality of the I/O
pin it is connected to."
however there is a warning that is interesting for us:
"When OC2 is connected to the pin, the function of the COM21:0 bits depends on the
WGM21:0 bit setting."
and if we look in your code in the setup() function you are in fact setting values to those pins
cbi(TCCR2, WGM21); //sets to 0 the WGM21 bit of the TCCR2 register
sbi(TCCR2, WGM20); //sets to 1 the WGM20 bit of the TCCR2 register

this makes me understand that registers are in some extent similar to "preferences",
a set of behaviours that you set by making specific bits to 0 or 1
and that will modify the execution of specific functions or code inside the microprocessor
(I know this might be a very reducing definition :) and that registers might in fact be much much more)
so if we read the table 42 in the datasheet (page 115)

Mode    WGM21    WGM20    Timer/Counter Mode  
  0   0   0   Normal 0xFF Immediate MAX
  1   0   1   PWM, Phase Correct 0xFF TOP BOTTOM
  2   1   0   CTC OCR2 Immediate MAX
  3   1   1   Fast PWM


we understand that in the setup() func you are actually setting the TCCR2 Register to MODE1 (WGM21 to 0 and WGM20 to 1)
that means to the Timer/counter Mode: PWM, Phase Correct

if we now go back to the COM21 and COM20 bits explanation in the datasheet (page 115-116) we see that there is a
clarifying table for the specific mode -> Table 45. Compare Output Mode, Phase Correct PWM Mode

  0   0  Normal port operation, OC2 disconnected.
  0   1  Reserved
  1   0 Clear OC2 on Compare Match when up-counting. Set OC2 on Compare Match when downcounting
  1   1 Set OC2 on Compare Match when up-counting. Clear OC2 on Compare Match when downcounting

... continues in next post ...


Mar 08, 2006, 01:48 am Last Edit: Mar 08, 2006, 01:52 am by beltran Reason: 1
... continues from previous post

so by writing
sbi(TCCR2, COM21); //sets to 1 the COM21 bit inside the TCCR2 register
cbi(TCCR2, COM20); //sets to 0 the COM20 bit inside the TCCR2 register
you are performing the third option "Clear OC2 on Compare Match when up-counting. Set OC2 on Compare Match when downcounting."

now comes the difficult part...what the hell does that mean?? :)
I'm not sure if I got it right...I read "Modes of Operation" (page 107-109)
and "Phase Correct PWM Mode" (page 111) and its diagrams, and I understood that, as you write in the comments
the Phase Correct PWM Mode is a safer mode for motors :) (hehehe not much ;) hey)

I also found the OCR2 register quoted in this explanation...
the OCR2 that you set inside the timer2PWMSet() func
by reading the OCR2 definition - Output Compare Register in page 117 you discover that:
"The Output Compare Register contains an 8-bit value that is continuously compared
with the counter value (TCNT2). A match can be used to generate an Output Compare
interrupt, or to generate a waveform output on the OC2 pin."

This makes me think that (more or less :) ) the PWM function works by comparing a desired output value stored in the OCR2 register
with the value of the Timer TTCR2...is that right?
and that TTCR2 and OCR2 are reserved for the specific PWM2 pin
in fact that is more or less what you are doing in the analogWrite Function inside lib/targets/arduino/wiring.c:
analogWrite(int pin, int val) {
timer1PWMAOn();//activate the mode for pwm to the pwm specific pin (pin10 PWM1)
timer1PWMASet(val);//set the desired value to the pwm specific pin

in the loop you write
 i = (i+1) % 256;
the % symbol is called "modulo" and it's a C operator that is used here to loop the values from zero to maximum 256, once reached the maximum value the count starts again from 0.

from Wikipedia "Modulo operation" - http://en.wikipedia.org/wiki/Modulo_operation
Given two numbers, a and n, a modulo n (abbreviated as a mod n) is the remainder, on division of a by n.
10 % 6 = 4  -> read 10 modulo 6 = 4
this is because 6 into 10 stays 1 time with the remainder of 4 :) (sorry for the italian version of it :) )

but the cool thing is that "Some programming languages, such as ANSI C, don't define a result if either of n or a is negative" (quote from Wikipedia).
this means that if you write
 i = (i+1) % 256;
for any i<256 the %256 part of the expression won't return any value,
but for i=256 the operation will return 0   (i = the remainder of 256/256 = 1 remainder 0 --> i=0;)
hence starting again the loop.
that is one cool function :D I whished I'd knew that before :D

in the loop you are basically storing in the OCR2 register values from 0 to 255 increasing 1 every 10 milliseconds.

this is where I'm getting a bit lost...
I tracked down a few things...but I'm still missing the inner working of the _SFR_BYTE(sfr) function...

I've tracked down the functions inside
and the numeric values for the TCCR2 WGM20 WGM21 COM21 COM20 constants

I've gotten down the expression line to find out that _SFR_BYTE() does the following:
#define _SFR_BYTE(sfr)  (*(volatile uint8_t *)((uint16_t) &((sfr+0x20))))
I'm not sure if that's right though :)

I've tryed different compiling combinations, trying to rewrite the SFR_BYTE func like that (including typedefs for uint8_t and uint16_t) but couldn't make it work

- can you please explain us how it is making what it does? or at least its general pourpose and usage that we can apply in the future.
the _SFR_BYTE is all over also in the DMX tutorial
and i think it could help everybody understand it better.

- is cbi setting a bit to 0 and sbi setting a bit to 1 in a specific register?
(I got a bit lost in all that ANDing &=, inverting ~, and shifting (1<<COM21) )

I know that all this trascends the pourpose of the forum...but I'm trying to learn C and microprocessors workings a bit better...it's such a fascinating world :)

thanks in advance


It works great!!!
Thanks mellis, and beltran's analysis was really helpful.


Hi beltran,

from what I can say all your assumptions are right.
Generally the whole memory of a micro/processor can be called "the registers". The SFRs are in that way "special function" regsiters, that they control a certain setting in a micro and cannot be used as programm storage (flash) or RAM.
So, like you suggested, they can be seen as nothing else but simple preferences.
SBI, CBI and _SFR_BYTE are so called preprocessor macros. The DMX Master example could have also used the sbi() and cbi() macros instead of using _SFR_BYTE directly. _SFR_BYTE simply applies an Offset (+ 0x20 !) to a register number (like e.g. TCCR2). The actual reason fot that, I dont know.
But what all 3 macros are used for,  is setting/unsetting a certain bit in a certain (special function) register - again just like you guessed! :-)

You should take a closer look at "bit manipulation" and the logical operators in C. It's not that hard, really! It will be a big benefit for understanding micros in all.
Shiffting (like 1<< WGM21) is necessary because C has no binary variable type.
Usually, to simplify things, SFRs and their Bits are defined with just the same decimal value like in the datasheet of the micro (as you found in /tools/avr/avr/include/avr/iom8.h).

For all german language aware people I can recommend this very good tutorial about bit toggling: http://www.mikrocontroller.net/articles/Bitmanipulation
(maybe you can translate it with google)



thanks Oliver :)

I got down to the bit manipulation part...
but that didn't produce any good result
I've read this very clarifying article on BitManipulation

and I will try to read yours...unfortunately the english translation isn't very clear und meine deutch ist nicht so gut ;-)

I've understood that:
_BV(COM21) (1<<COM21)
COM21 = 5
1 << 5   means in binary 100000
but then there is the ~ inverse (inside cbi) so that
~_BV(COM21)     returns    011111

this means that by ANDing ( &= ) to the register address bits
we are actually setting to 0 the value of the 5th bit and leaving untouched all the others

ex register   1000101 = TCCR2 = 0x25+0x20 = 0x45
~_BV(COM21)    011111
&= result   1000101

and that is exactly what cbi is doing...that is clear :)
I also understood that by ORing ( |= ) _BV(COM21)
(100000 in binary) will change to 1 the 5th bit of the register...

what really screws my mind up is the _SFR_BYTE part
_SFR_BYTE(sfr)  (*(volatile uint8_t *)((uint16_t) &((sfr+0x20))))
when I try to compile it I get some errors...even if I try to carefully include or define all the needed macros and teypefs

the 8-bit and 16-bit unsigned types
(found inside tools/avr/avr/include/stdint.h)
typedef unsigned char uint8_t;
typedef unsigned long uint16_t;
are not very clear...

are they simply an empty byte
uint8_t = 00000000
and two empty bytes
uint16_t = 0000000000000000
used in conjunction with the pointers *
to address the specific memory address??

it's not that important after all :)
I can simply keep in mind that it is addressing the specific memory location...but there will always be an itchy thing in the back of my mind saying that I haven't got it all :) hehehe I'm a pain in my own ass!

well thanks anyways...
this all is starting to get interesting :)

Go Up