Hello, it's my first post here btw. The problem I've came across is I want to have 1 output of Fast PWM on Attiny13 - particulary for controlling PC PWM fan, which requires frequency at around 25kHz. I searched for quite long time and still have problems, which are:
I have a piece of program that works on Arduino:
//const int controlPin= 3;
const int temp =A0;
void setup()
{
TCCR2A = 0x23;
TCCR2B = 0x09; // select clock
OCR2A = 79; // aiming for 25kHz
DDRD |= 1 << 3; // enable the PWM output (you now have a PWM signal on digital pin 3)
//same as pinMode(controlPin, OUTPUT); }
void loop(){
OCR2B = (analogRead(temp))/13;
delay(1000);
}
I try to make it compatible with Attiny13, and this is the closest version:
The values of the registers matches the info in datasheet of Attiny 13 I think
void setup()
{
TCCR0A = 2<<COM0A0 | 3<<WGM00; // clear 0c0a at compare match //enable fast pwm
TCCR0B = 0<<WGM02 | 1<<CS00; //enable fast pwm mode // not to use prescaler
OCR0A = 79; // aiming for desired frequency (only test values until it'll finally work)
DDRB = 0xFF; // all pins as outputs
OCR0B = 60; // set the PWM duty cycle
}
void loop()
{
OCR0B = 60;
delay(500);
OCR0B = 30;
delay(500);
}
Now: the strange think is that no matter what values are OCR0B/A it creates a 5.5kHz output at around 46% duty cycle (freq./voltage multimeter). As I am not an experienced MCU programmer (I know C and a little how to set values in registers but nothing more), I don't expect big accuracy and can even adjust values by testing - but it don't behave as I would love to.
Probably there's something wrong when setting Fast PWM Mode in first lines or I flipped somehow A/B registers. Please help who can set correct values for it to work as the first program on Arduino.
Thank you in advance, I appreciate your help on that.
Marek
Moderator edit: size tags removed
After reconfiguring timer 0, delay is very unlikely to work correctly. Use _delay_ms instead.
...the strange think is that no matter what values are OCR0B/A it creates a 5.5kHz output...
Are you certain? From the configuration it should be 1200000/256 = 4687.5 Hz.
Ok about delay function. The frequency could be a little less, it's measured with cheap multimeter I've bought for around 10$. Thank you for advice, I will let you know if that changed something
EDIT: OK so I did a little more tests and: frequency is closer to 4687 it's 4487 according to PC sound card oscilloscope so it's fine, but:
_delay_ms() behaves badly - it takes nearly 17s to make a 10s programmed change. MCU is clocked 9.6MHz (internal).
I created a program consisting of only 2 digitalWrites and it seems that MCU can't do more than these 4.7kHz.
Is it possible I've changed main clock? Looking now in documentation and I cannot see a mistake in bits assignments.
Coding Badly, can you explain why the clock is 1200000/256 as I suppose I don't use prescaler (CS bits)?
Also if anybody knows, why changing OCR0A doesn't affect frequency? (in Fast PWM it should be working)
This...
marekbawol:
EDIT: OK so I did a little more tests and: frequency is closer to 4687 it's 4487 according to PC sound card oscilloscope so it's fine
...and this...
MCU is clocked 9.6MHz (internal).
...and this...
I don't use prescaler (CS bits)?
...are mutually exclusive. The processor is not running at 9.6 MHz. It is running at 1.2 MHz. Which is why I used "1200000" instead of "9600000" when I calculated the PWM frequency.
After changing the board selection did you use Burn Bootloader to also change the fuses?
OK, so I understood a little bit:
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
//factory settings is to divide internal clock 9.6MHz by 8.
//don't, and just run at 8 MHz (set the clock divider to 1 so no effect)
CLKPR = (1<<CLKPCE);
CLKPR = 0; // Don't divide
//all pins go OUTPUT
DDRB = 0xFF;
TCCR0A = ((5<<WGM00) |(2<<COM0A0)) ; //mode Phase correct PWM
TCCR0B = ( (1<<CS00)); //clock input don't divide
OCR0A=253; //now it seems to be duty cycle - initial value
while (1==1){ //that while is changing duty cycle, signal freq is 18.75kHz
for (int i=0; i < 255; i ++){
OCR0A = i;
_delay_ms(120);
}
for (int i=0; i < 255; i ++){
OCR0A = 255-i;
_delay_ms(120);
}
}
}
So, let me comment it: Now the frequency is 9600000. I know why, because of factory fuse bits.
I changed mode to others but cannot acquire both frequency and duty cycle control.
Now in Phase Correct PWM I can control duty cycle, but again it'going always up to 256.
That gives 9600000(freq)/2(phase correct mode)/256(TOP value)= 18.75kHz
If it is possible to change freq by setting the TOP value a little less than 256 it will give 25kHz and both freq/duty control. But do you know how? In which mode it works and through what (OCR0B)?
Thanks in advance.
You just need to use mode 7 instead of mode 3 (one bit difference from the code you posted earlier)...
void setup()
{
TCCR0A = 2<<COM0A0 | 3<<WGM00; // clear 0c0a at compare match //enable fast pwm
TCCR0B = 1 <<WGM02 | 1<<CS00; //enable fast pwm mode // not to use prescaler
OCR0A = 79; // aiming for desired frequency (only test values until it'll finally work)
DDRB = 0xFF; // all pins as outputs
OCR0B = 60; // set the PWM duty cycle
}
To get an exact frequency of 25 kHz you will have to use a prescaler of 8 and a TOP of 47 (which makes the PWM rather coarse grained with only 48 steps).
9600000 / (8 * (47+1)) = 25000
Thank you, it's certainly what I've been looking for. Actually, for fan control 2% accuracy is fine.
Marek