Pages: [1] 2   Go Down
Author Topic: ATtiny45 PWM Frequency Selection  (Read 3946 times)
0 Members and 1 Guest are viewing this topic.
Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Guys,

I am not experienced in the under-the-hood details of microcontrollers and I wondered if anyone could help me?  I have settled on a nice RC filter arrangement to produce a 'true analogue' voltage, with the RC calcs based on 32kHz PWM frequency.

I would like to set my 8MHz ATtiny45's PWM frequency to approximately 32kHz, but I'm not sure if a guide that I have found is quite correct....

Reading the guide below, the author suggests that he has achieved 32kHz PWM with the following like

http://nicknorton.net/?q=node/7

TCCR0B = TCCR0B & 0b11111000 | 0b001

That all looks great, but the post here suggests that the line above will only result in a PWM frequency of 15.6kHz...  Unfortunately I don't have access to an oscilloscope to perform my own confirmation  smiley-sad

I also don't understand why there is a 'b' at the end of the Timer set line (my lack of understanding showing through).  By looking at the datasheet I'd have thought that the Timer select line should read something like:

TCCR0B = TCCR0B & 0b11111000 | 1001

Does anyone have a definative answer?

Thanks in advance

John
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I also don't understand why there is a 'b' at the end of the Timer set line (my lack of understanding showing through).

The "b" informs the compiler that the constant is to be treated as a binary value (as opposed to decimal or hexadecimal).

Quote
By looking at the datasheet I'd have thought that the Timer select line should read something like:
TCCR0B = TCCR0B & 0b11111000 | 1001

"1001" is one-thousand and one in decimal.  "0b1001" is nine in decimal.
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Which core are you using?
Logged

Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Coding Badly,

I am using (what I believe is your) own arduino-tiny core, and your knock-bang debugging too - I am in your debt already!  smiley-roll

Thank you for the replies smiley
« Last Edit: January 26, 2013, 11:26:43 am by johnamon » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is the code I use for setting a given frequency on the ATtiny45. I developed it originally for IR remote control at a variable frequency.

Code:
// Set the frequency that we will get on pin OCR1A but don't turn it on
void setFrequency(uint16_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;

  uint16_t prescalerVal = 1;
  uint8_t prescalerBits = 1;
  while ((requiredDivisor + prescalerVal/2)/prescalerVal > 256)
  {
    ++prescalerBits;
    prescalerVal <<= 1;
  }
  
  uint8_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1 = (1 << CTC1) | prescalerBits;
  GTCCR = 0;
  OCR1C = top;
}

// Turn the frequency on
void on()
{
  TCNT1 = 0;
  TCCR1 |= (1 << COM1A0);
}

// Turn the frequency off and turn off the IR LED.
// We let the counter continue running, we just turn off the OCR1A pin.
void off()
{
  TCCR1 &= ~(1 << COM1A0);
}
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for your reply dc42,

In order to use your code, should I supply the frequency in hertz, like '32000'?

Also, your Off function appears to turn the pin off, whereas I would like variable PWM duty cycle, it is a throttle that I am programming and the idea is that I can set 0v to 5v over PWM using analogWrite() - is it still possible to use analogueWrite with 255 representing 5v after i've used your code to turn the pin on?

Thanks again for your help smiley

John
« Last Edit: January 26, 2013, 01:37:30 pm by johnamon » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for your reply dc42,

In order to use your code, should I supply the frequency in hertz, like '32000'?

Yes, the parameter to setFrequency is in Hz.

Also, your Off function appears to turn the pin off, whereas I would like variable PWM duty cycle, it is a throttle that I am programming and the idea is that I can set 0v to 5v over PWM using analogWrite() - is it still possible to use analogueWrite with 255 representing 5v after i've used your code to turn the pin on?

I'm sorry, I didn't read your original post properly. The code I supplied is intended to provide a variable frequency square wave from timer 1 rather than for PWM. If you are already using Coding Badly's core, then I think all you need to do is to set the prescaler of the timer you are using for the PWM output to 128. That should give you a PWM frequency of 8MHz/256 = 31.25kHz. However, if the timer you are using for PWM is the same one used for the micros() function, then this would mess up the values returned by micros().
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks again dc42,

I can see from the datasheet that I want to set the prescaler bits to 1001 or something equivalent:


Do you know how I correctly write that 1001 row into the prescaler instruction?
« Last Edit: January 26, 2013, 02:28:51 pm by johnamon » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using (what I believe is your) own arduino-tiny core,

Got it.

Quote
and your knock-bang debugging too - I am in your debt already!

Excellent.


By default, millis is on timer 1.  If you alter the timer 1 prescaler, millis (and its ilk) will not work correctly.  Does your application use millis, micros, delay, or delayMicroseconds?

The millis timer is configured for "fast PWM".  The other timer is configured for "phase-correct PWM".  This detail is important when calculating the output frequency.  Fast PWM is much more appropriate for a regulator.

How easily can you change the the output pin?  Do you have a circuit board made?  Are you working on a bread board?
Logged

Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Coding Badly,

Thanks for taking another look.  I am using millis for button debouncing, but I can adjust the software timings to suit if I end up speeding up / slowing down the timer clock.

I am currently working on a breadboard, so pins are completely flexible.

Thanks again,

John
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Of the two timer/counters, only #1 has a prescaler option of 128. So one option is to use timer 1 to generate your PWM signal and move the millis function to timer 0. Alternatively, switch timer 0 to Fast PWM mode and set its prescaler to 256.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

wow, I don't know how to do any of that!

32kHz is roughly 8MHz/256 - so I believe that I want a prescaler of 256??  Or is there a halving of the frequency going on somewhere that I'm not aware of which means I require a prescaler of 128?

If there is the option to have fast mode PWM running at 32kHz and maintain millis and delay working normally, I'd sure be grateful for the how-to! smiley
« Last Edit: January 26, 2013, 05:15:00 pm by johnamon » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


In addition to what @dc42 said, timer 1 on the X5 family is designed for doing what you are trying to do.  It has lots more prescaler options and the base clock can be changed to 64 MHz (or 32 MHz).

I suggest swapping the timers so timer 1 is available to use as you please...
http://arduino.cc/forum/index.php/topic,142948.msg1073712.html#msg1073712

Bear in mind, that changes the core.  All your ATtinyX5 applications are affected.
« Last Edit: January 26, 2013, 06:15:26 pm by Coding Badly » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13039
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


The Tiny Core includes a (partial) hardware veneer that should make changing the "user timer" a bit easier.  Give this a try...

Code:
#include <UserTimer.h>

void setup( void )
{
  UserTimer_SetToPowerup();
  UserTimer_SetWaveformGenerationMode( UserTimer_(Fast_PWM_FF) );
  UserTimer_ClockSelect( UserTimer_(Prescale_Value_1) );
  // Frequency is F_CPU / (1 * (0xFF+1))
  // (8 megahertz) / 256 = 31.25 kilohertz
}

void loop( void )
{
}

The code changes timer 0 when millis is on timer 1 and vice versa.
Logged

Aberdeen, United Kingdom
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you very much Coding Badly - I really appreciate your help.  

So to be clear, I should change Prescale_Value_1 in your code below to 255 (255+1 = 256)?

How does the timer change affect the pin mapping?  I was (arbitrarily) going to use physical Pin5 (or Pin0) for my PWM source, would this still be the pin to use?  The datasheet shows all the PWM pins having a OC0A or 0C0B reference making it not clear to my inexperienced eyes as to which PWM timers are mapped to which pins?  
« Last Edit: January 26, 2013, 07:01:14 pm by johnamon » Logged

Pages: [1] 2   Go Up
Jump to: