Closed MRezaNasirloo closed 2 years ago
As you presumably noticed, the Timer1 clock source tools menu option doesn't work (never has, and people didnt complain about it - but many people complain about the number of menus - so it is being dropped from 2.0.0)
What I'd probably do is in setup first switch timer1 to the PLL If the clock source is the 16 MHz internal PLL, the PLL is already running. Otherwise you need to do
PLLCSR = (1 << PLLE)
Either way you need to then set it as the clock source for timer1
while (!(PLLCSR & (1 << PLOCK) )); //wait until the PLOCK bit is set
PLLCSR = (1<< PLLE | 1 << PLCKE );
Timer1 will now be clocked from a 64 MHz timebase instead of an 8 or 16 MHz one (Depending on which clock source you are using) - but it will still be divided down to a lower frequency by the prescaler.
So that needs to be changed as well. At full 8-bit resolution, there are 256 counts per timer cycle. Assuming you have it counting to the full 255 maximum, the fastest pwm possible is with no prescaling. 64 MHz / 256 counts per cycle gives 250 kHz; far faster than your requirement.
Assuming you want to keep it in that specified 10-30 range, dividing by 8 gives you 31.25 kHz, and dividing by 16 would give 15.625 kHz - both with full 8-bit resolution (which is helpful for a non-obvious reason which I'll to, in addition to the obvious one). Pescale division on Timer1 is controlled by TCCR1, specifically the 4 low bits. fom table 12-5 we see than we want CS13:CS10 to be 0b0101 (5) - or 0b0100 (4).
uint8_t tccr = TCCR1; // reading to a local variable doesn't have a size/speed penalty, and is more readable
tccr &= 0xF0; // we want to preserve the 4 high bits, but will replace the 4 low bits
tccr |= 0x05; // Now OR the new value for the low bits with the old high bits
TCCR1 = tccr; // and assign back to the register
(copying to a temporary variable is helpful because modifying registers in ways that happen in multiple steps is ugly to write on a single line - those 4 lines have the same effect and size as TCCR1 = (TCCR1 & 0x0F) | 0x05 - but that's harder to explain in comments line by line - and unlike directly operating on the register (which is "volatile"), it isn't forced to reread it every time (the above code is 4 words 4 clocks - in, andi, ori, out (same as TCCR1 = (TCCR1 & 0x0F) | 0x05) , while TCCR1 &= 0xF0; TCCR1 |= 0x05;
is 6 clocks and 6 words - in andi out in ori out)
Once the PLL is set as clock source, and the prescaler is set, as long as you don't need to more precisely adjust the frequency (Which would come at the expense of the full 8-bit resolution, you can then proceed to use analogWrite() like normal (it doesn't go back and adjust the timer prescaler or other settings). Two pins are available: PB1 and PB4 (the other PWM pin is generated from Timer0 adjusting that time will break the millis() and delay() timekeeping functions
Closing issue as it does not represent a defect in the core, I will still see comments
This was the best explanation I could ever get, it works like a charm.
Thank you very much for your time 🥇
Hi @SpenceKonde , first, thanks for the great library and the tremendous work you have done here! I came across this issue as I was trying to use the Timer1 clock option in the IDE menu noticing that it doesn't have any effect on the timer. I have the requirement to control a DC Motor using the ATTiny85 and a mosfet. For this to be not in the acoustically noticeable range, I need at least 33 kHz if not 66 kHz. The code example above sets the PWM frequency to 15.625 kHz is that correct? How would I assign the TCCR1 if I want it to be 33khz or 66khz?
Any help would be much appreciated. Thank you very much!
After scratching my head for a few hours and reading the Datasheet of the ATTiny85 I think I figured this out myself. To keep 8-bit resolution the 4 low bits of the TCCR1 registry can be changed to the following to get a PWM frequency of 62.5 Mhz :
uint8_t tccr = TCCR1;
tccr &= 0xF0;
tccr |= 0x03; // <- changed
TCCR1 = tccr;
For a frequency of 31.25 Mhz:
uint8_t tccr = TCCR1;
tccr &= 0xF0;
tccr |= 0x04; // <- changed
TCCR1 = tccr;
Hi,
I've been trying to config attiny85 to get a high PWM frequency (10-30 Khz) on one of its pins, there are a few ways to achieve this:
I wanted to know what is the recommended way to achieve this in ATTinyCore with minimum side effects?
Thanks