Base frequency still 31250 Hz on pin3?

I'm trying to confirm the base frequency of pin 3 for Arduino Uno SMD / ATmega328

The data sheet results in a "This page isn't working". I got that link from the sales page here.

I'm not even sure the data I'm looking for is on that sheet. Looking at the data on the sales page, it says Clock Speed 16 MHz which i think is different but I don't know. The other code says its 31,250

I need to use setPwmFrequency from Arduino Playground - PwmFrequency to set the frequency to 108.7Hz. If i'm understanding what I'm reading, I'll need to set the following to achieve that:
setPwmFrequency(3, 287.48850046);

Edit:
Obviously I can't use 287......, must be one of the int specified in case. In general my question is still the same, and maybe with the help of how I could get closer to 287 instead of settling for 256 as a divisor.

Does this look correct? I do not have a working oscilloscope.

Browse Microchip's website to get the Atmega 328 datasheet.

The standard Arduino PWM frequency is about 490Hz. If you want to vary from that then you need to study the datasheet.

...R

You can set 31250 Hz frequency for PIN3 PWM, but you need to reduce system clock to 8MHz

For Timer/Counter2, the possible prescaled selections are: clkT2S/8, clkT2S/32, clkT2S/64,
clkT2S/128, clkT2S/256, and clkT2S/1024

Robin2:
Browse Microchip's website to get the Atmega 328 datasheet.

The standard Arduino PWM frequency is about 490Hz. If you want to vary from that then you need to study the datasheet.

...R

Got a link to the datasheet from support. Would be great if someone updated the broken link on the product page.

Product Sheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf

alesam:
You can set 31250 Hz frequency for PIN3 PWM, but you need to reduce system clock to 8MHz

For Timer/Counter2, the possible prescaled selections are: clkT2S/8, clkT2S/32, clkT2S/64,
clkT2S/128, clkT2S/256, and clkT2S/1024

I see the same information on page 161 of the datasheet. My goal is to set pin3 PWM to 125Hz or 108.7Hz. I'll study the setPwmFrequency info and product sheet

There are three ways to set the PWM frequency: Fast PWM, 'prescale' and 'TOP'.

Fast PWM just counts in one direction. The other PWM modes count up and down so they run at half the frequency.

There are very few choices of prescale (already mentioned above). You would start by picking the one that gives you the highest frequency below your desired frequency.

'TOP' is the maximum value to which the timer counts. You can increase the PWM frequency by decreasing TOP but that will also decrease the PWM range.

If you want 8-bit PWM you are stuck with:
16 MHz (clock) / 1024 (prescale) / 256 (TOP+1) = 61.03+ Hz Fast PWM
or
16 MHz (clock) / 256 (prescale) / 2 (PWM) / 256 (TOP+1) = 122.07+ Hz PWM

I think the closest you can get to 108.7 is:

16 MHz (clock) / 1024 (prescale) / 144 (TOP+1) = 108.50+ Hz Fast PWM.
In that case your PWM outputs will be limited to the range 0 to 143 instead of 0 to 255.

johnwasser:
There are three ways to set the PWM frequency: Fast PWM, 'prescale' and 'TOP'.

Fast PWM just counts in one direction. The other PWM modes count up and down so they run at half the frequency.

There are very few choices of prescale (already mentioned above). You would start by picking the one that gives you the highest frequency below your desired frequency.

'TOP' is the maximum value to which the timer counts. You can increase the PWM frequency by decreasing TOP but that will also decrease the PWM range.

If you want 8-bit PWM you are stuck with:
16 MHz (clock) / 1024 (prescale) / 256 (TOP+1) = 61.03+ Hz Fast PWM
or
16 MHz (clock) / 256 (prescale) / 2 (PWM) / 256 (TOP+1) = 122.07+ Hz PWM

I think the closest you can get to 108.7 is:

16 MHz (clock) / 1024 (prescale) / 144 (TOP+1) = 108.50+ Hz Fast PWM.
In that case your PWM outputs will be limited to the range 0 to 143 instead of 0 to 255.

Thanks you for the detail. I looked up some of the keywords and came to this link:

The following code snip:

pinMode(3, OUTPUT);
 pinMode(11, OUTPUT);
 TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
 TCCR2B = _BV(CS22);
 OCR2A = 180;
 OCR2B = 50;

Above that code, the following was posted:
"Fast PWM Mode
The following code fragment sets up fast PWM on pins 3 and 11 (Timer 2). To summarize the register settings, setting the waveform generation mode bits WGM to 011 selects fast PWM. Setting the COM2A bits and COM2B bits to 10 provides non-inverted PWM for outputs A and B. Setting the CS bits to 100 sets the prescaler to divide the clock by 64. (Since the bits are different for the different timers, consult the datasheet for the right values.) The output compare registers are arbitrarily set to 180 and 50 to control the PWM duty cycle of outputs A and B. (Of course, you can modify the registers directly instead of using pinMode, but you do need to set the pins to output.)"

I'm missing some very basic stuff somewhere. When i see "summarize the register settings, setting the waveform generation mode bits WGM to 011 selects fast PWM", I expected to see that somewhere in the code example, but I don't.

Looking back at your post, this section "16 MHz (clock) / 1024 (prescale) / 144 (TOP+1) = 108.50+ Hz Fast PWM.", the math is clear but the "why" isn't. I'm guessing you choose 1024 because it's the largest prescale dividor and we need to divide by a prescale value...only guessing. The 144, i'm not sure where it came from. I looked for 143 and could not find it or that TOP was 143.

I see the bitwise or operator in the example code, but i'm not sure how to convert that if I want to achieve a result. Is there a way to figure out what to put where in that code to achieve 108.5 Hz for example?

testing001:
I see the bitwise or operator in the example code, but i'm not sure how to convert that if I want to achieve a result. Is there a way to figure out what to put where in that code to achieve 108.5 Hz for example?

See Section 18.11 of the ATMega328P Datasheet.

testing001:
I'm missing some very basic stuff somewhere. When i see "summarize the register settings, setting the waveform generation mode bits WGM to 011 selects fast PWM", I expected to see that somewhere in the code example, but I don't.

Explanation in text and code your quoted is cristall clear. Just read a chapters about timers counters at Atmega 328 datasheet.

testing001:

 TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);

TCCR2B = _BV(CS22);



I'm missing some very basic stuff somewhere. When i see "summarize the register settings, setting the waveform generation mode bits WGM to 011 selects fast PWM", I expected to see that somewhere in the code example, but I don't.

The "Waveform Generation Mode" (WGM) field for Timer2 has three bits, named WGM22, WGM21 and WGM20. Setting the mode to 3 (0b011) means setting the bottom two bits: WGM21 and WGM20 and leaving the top bit (WGM22) at zero. You can see how that is done in the code above.

From the WGM table in the datasheet you can see that Mode 3 is Fast PWM with TOP fixed at 0xFF (256).

IF YOU WANT TO USE A DIFFERENT VALUE FOR 'TOP' your only Fast PWM choice is Mode 7 where the 'TOP' value is stored in the OCR2A register. This means that the PWM output pin connected to OCR2A can't be used for PWM. You have to use the OCR2B pin for PWM.

Warning: If you use Timer1, it has four WGM bits. The tricky part is that WGM11 and WGM10 are in register TCCR1A while WGM13 and WGM12 are in TCCR1B. This can be confusing.

Thank you

johnwasser:
The "Waveform Generation Mode" (WGM) field for Timer2 has three bits, named WGM22, WGM21 and WGM20. Setting the mode to 3 (0b011) means setting the bottom two bits: WGM21 and WGM20 and leaving the top bit (WGM22) at zero. You can see how that is done in the code above.

From the WGM table in the datasheet you can see that Mode 3 is Fast PWM with TOP fixed at 0xFF (256).

IF YOU WANT TO USE A DIFFERENT VALUE FOR 'TOP' your only Fast PWM choice is Mode 7 where the 'TOP' value is stored in the OCR2A register. This means that the PWM output pin connected to OCR2A can't be used for PWM. You have to use the OCR2B pin for PWM.

Warning: If you use Timer1, it has four WGM bits. The tricky part is that WGM11 and WGM10 are in register TCCR1A while WGM13 and WGM12 are in TCCR1B. This can be confusing.

I'm still very lost and haven't been able to get any frequency I'm looking for. Assuming i want a PWM of 125Hz on pin3 at 25% duty cycle, can anybody help me break down how to make this code work?

int ledPin = 3;

void setup()
{ 
 pinMode(ledPin, OUTPUT);
 TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
 TCCR2B = _BV(CS22); //bit value of clock select bit description? if 1 /64 from prescaler?
 // 16000000/64000/2 = 125
 OCR2A = 64000; // prescale? but i can't use this because i'm limited to none,8,32,64,128,256,1024 clock select bit descriptions? 
 OCR2B = 2; // ?
 }



void loop()
{
//int duty_cycle = 64; // 25% duty cycle
//analogWrite(ledPin, duty_cycle);
}

The above is wrong, but i'm trying to find out what need to happen to make it right with a full example. The spec sheet assumes so much more in known by the reader. All i'm sure of so far (and even this might be wrong)

  • _BV() get the bit value of the value passed in (COM2A1, COM2B1, etc) (it would be great to know the place to find the bit value in case i wanted to test/try manual shifting the bit values. I don't see COM2A1=???BV anywhere)

  • The | is the C++ "bitwise OR" function and takes two numbers and does a or on every bit like:
    0101

0011

0111

  • The manual says "Waveform Generation Mode Bit Description" and where TOP is mode 7 (fast PWM) TOP is OCRA instead of the hexadecimal representation of the decimal number 255 (0xFF)

The rest I'm still lost trying to figure out what values to change if all I know is the frequency needs to be X (say 125Hz for example) and needs to operate at y (25% for example).

_BV() is a function macro defined in sfr_defs.h. You'll have to dig around in your Arduino installation to find it. It's simply defined as:

#define _BV(bit) (1 << (bit))

I personally just prefer to use the regular C language shift operator rather than wrapping it in a macro. YMMV.

COM2A1 and the like are constants defined in iom328p.h. For example:

#define WGM20 0
#define WGM21 1
#define COM2B0 4
#define COM2B1 5
#define COM2A0 6
#define COM2A1 7

You'll note the names are defined as values that EXACTLY match their bit positions in the registers as shown in the ATMega328P datasheet.

So, this:

TCCR2A |= 1 << COM2A1;

sets COM2A1 (bit 7) in the TCCR2A register while leaving the others unchanged.

Pin 3 is OCR2B (Timer2, channel B). To get 125 Hz PWM on a 16 MHz Arduino your have to set 'prescale' to 1024 and OCR2A (TOP) to 124 and use WGM 7 (Fast PWM with 'TOP' set in OCR2A). Then to get 25% duty cycle you would set OCR2B to 124 * 0.25 = 31.25 so 31.

This is what i gathered from that and it's not working:

int ledPin = 3;

void setup()
{ 
 pinMode(ledPin, OUTPUT);
 TCCR2A |= 1 << COM2A1; //use WGM 7 (Fast PWM with 'TOP' set in OCR2A)
 OCR2A = 124; // OCR2A (TOP) to 124?
 OCR2B = 31; // 25% duty cycle OCR2B to 124 * 0.25 = 31.25 so 31.
 }

set 'prescale' to 1024 and OCR2A (TOP) to 124

Where do i set prescale to be 1024 if OCR2A set to 124?

Tried to use this code to set prescaler but got error:

/tmp/ccglPiYg.ltrans0.ltrans.o: In function `main':
/Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/main.cpp:43: undefined reference to `setup'
/Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/main.cpp:46: undefined reference to `loop'
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino/Genuino Uno

testing001:
Tried to use this code to set prescaler but got error:

/tmp/ccglPiYg.ltrans0.ltrans.o: In function `main':

/Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/main.cpp:43: undefined reference to setup' /Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/main.cpp:46: undefined reference to loop'
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino/Genuino Uno

The compiler message is pretty clear. Did the code you just tried have setup() and loop() functions?

It did but with it in there, i got a lot more errors

sketch_feb27b:67:24: error: variable or field 'setClockPrescaler' declared void
 inline void setClockPrescaler(uint8_t clockPrescaler) {
                        ^
sketch_feb27b:67:24: error: 'uint8_t' was not declared in this scope
sketch_feb27b:87:1: error: 'uint8_t' does not name a type
 inline uint8_t getClockPrescaler() {
 ^
sketch_feb27b:91:1: error: 'uint16_t' does not name a type
 inline uint16_t getClockDivisionFactor() {
 ^
/home/testing/Arduino/sketch_feb27b/sketch_feb27b.ino: In function 'void setup()':
sketch_feb27b:5:18: error: 'OUTPUT' was not declared in this scope
  pinMode(ledPin, OUTPUT);
                  ^
sketch_feb27b:5:24: error: 'pinMode' was not declared in this scope
  pinMode(ledPin, OUTPUT);
                        ^
sketch_feb27b:7:2: error: 'TCCR2B' was not declared in this scope
  TCCR2B = _BV(CS22);
  ^
sketch_feb27b:7:15: error: 'CS22' was not declared in this scope
  TCCR2B = _BV(CS22);
               ^
sketch_feb27b:7:19: error: '_BV' was not declared in this scope
  TCCR2B = _BV(CS22);
                   ^
sketch_feb27b:9:2: error: 'OCR2A' was not declared in this scope
  OCR2A = 124; // new TOP?
  ^
sketch_feb27b:10:2: error: 'OCR2B' was not declared in this scope
  OCR2B = 31; // duty cycle will be (50+1)/256 = 19.9%
  ^
/home/testing/Arduino/sketch_feb27b/sketch_feb27b.ino: In function 'void loop()':
sketch_feb27b:18:31: error: 'analogWrite' was not declared in this scope
 analogWrite(ledPin, duty_cycle);
                               ^
In file included from /home/testing/Arduino/sketch_feb27b/sketch_feb27b.ino:49:0:
/home/testing/Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/Arduino.h: At global scope:
/home/testing/Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/Arduino.h:153:16: error: conflicting declaration of 'void setup()' with 'C' linkage
 void setup(void);
                ^
/home/testing/Arduino/sketch_feb27b/sketch_feb27b.ino:3:6: note: previous declaration with 'C++' linkage
 void setup()
      ^
In file included from /home/testing/Arduino/sketch_feb27b/sketch_feb27b.ino:49:0:
/home/testing/Downloads/arduino-1.8.8/hardware/arduino/avr/cores/arduino/Arduino.h:154:15: error: conflicting declaration of 'void loop()' with 'C' linkage
 void loop(void);
               ^
/home/testing/Arduino/sketch_feb27b/sketch_feb27b.ino:15:6: note: previous declaration with 'C++' linkage
 void loop()
      ^
exit status 1
variable or field 'setClockPrescaler' declared void

Looks like the code i found should have been at the top of the code. But it looks like that doesn't have a 1024 prescaler. Only 1,2,4,16,32,128 and 256

from https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

Setting the CS bits to 100 sets the prescaler to divide the clock by 64.
// TCCR2B = _BV(CS22);

I don't see how "TCCR2B = _BV(CS22)" sets prescale to divde by 64. Table 18-9 in data sheet shows 100 for 64 but the logic seems like magic because from my lack of understanding "TCCR2B = _BV(CS22)" can set prescale to 111 too. What i guess is throwing me is these variables with hidden values. Can't i just do "TCCR2B = 0100"?

gfvalvo:
The compiler message is pretty clear. Did the code you just tried have setup() and loop() functions?

 TCCR2A |= 1 << COM2A1; //use WGM 7 (Fast PWM with 'TOP' set in OCR2A)

I don't see you setting the WGM2 bits (WGM22=1, WGM21=1, WGM20=1 to get WGM 7)

TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);

The "COM2B1" bit sets the PWM mode for Pin 3 (OC2B) to "Clear OC2B on Compare Match". That means the pin gets turned on at BOTTOM (0) and turned off when the count reaches the value n the OCR2B register.

(OOPS, I had CS 4 instead of CS 7. Fixed now)
(OOPS again. I forgot that WGM22 was in TCCR2B, not in TCCR2A like the other two bits.)

The prescale is set in TCCR2B. For 1024 you set the CS22, CS21, and CS20 bits.

 TCCR2B = _BV(WGM22) | _BV(CS22) | _BV(CS21) | _BV(CS20);
const byte ledPin = 3;

void setup()
{ 
  pinMode(ledPin, OUTPUT);
  // Set WGM 7 and enable PWM on Pin 3
  TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  // Set clock prescale to 1024
  TCCR2B =_BV(WGM22) | _BV(CS22) | _BV(CS21) | _BV(CS20);;
  OCR2A = 124; // OCR2A (TOP) to 124 for 125 counts per cycle
  OCR2B = 31; // 25% duty cycle OCR2B  (124 * 0.25 = 31.25 so 31)
 }

void loop() {}

testing001:
I don't see how "TCCR2B = _BV(CS22)" sets prescale to divde by 64. Table 18-9 in data sheet shows 100 for 64 but the logic seems like magic because from my lack of understanding "TCCR2B = _BV(CS22)" can set prescale to 111 too. What i guess is throwing me is these variables with hidden values.

I already told you in Reply #12 what the definition of the _BV() macro was and where to find the "hidden values" for the various bit fields. Go back and read it.