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
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
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:
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.
// 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);
}
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?
In order to use your code, should I supply the frequency in hertz, like '32000'?
Yes, the parameter to setFrequency is in Hz.
johnamon:
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().
johnamon:
I am using (what I believe is your) own arduino-tiny core,
Got it.
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?
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.
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.
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!
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...
Bear in mind, that changes the core. All your ATtinyX5 applications are affected.
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?
Thank you again, your depth of knowledge, and ability to communicate what you know is humbling!
I don't know why - but I thought you were in Australia.... It's past midnight here and I need to go to sleep! Anyway I have realised that you are donationware - I'll get on that right away!
Thank you again for 'babysitting' me through this.
What I need to do now is document all this, as I can see a lot of this information has already been posted and I think we've stitched a lot of it together here..
Thank you dc42 and Coding Badly. Due to the amount of information presented in the previous posts I thought I would summarise what I plan to do - if you guys let me know that the steps below are correct, then I will edit the first post in this thread to explain clearly how we got 32kHz frequency PWM from my ATtiny45.
Summary:
I would like the PWM output from an ATtiny45 to produce a variable voltage of 0v to 5v, via a RC low pass filter. I have calculated that a 32kHz PWM frequency would be ideal, the high frequency allows low ripply and relatively fast 'settle' time.
To achieve 32kHz, I need to divide the system 8MHz clock by 256 (prescaler of 1 in Fast Mode PWM). However the mills() and delay() programming functions utilise Timer1 - so to maintain programming functionality we will assign Timer0 to mills and delay (assigning Timer1 to PWM is dealt with later in the thread):
Execution:
Locate core_build_options.h in the Tiny Core directory
Open it in your favourite text editor (I like Visual StudioTextEdit.app :*)
Change FAVOR_PHASE_CORRECT_PWM to zero... #define FAVOR_PHASE_CORRECT_PWM 0
Save and close the file
Because we have favoured FAST PWM, OC1A is used to control PB1, and also PB0 - so Physical Pins 5 and 6 may be used to generate the PWM signal that is required.
As-yet Timer1 has not had it's frequency set to 32kHz - so in this step we do that...