Since I spend the last two days trying to get the clock prescaler to
work I wanted to share my results. Everything I write here has been
tested with an attiny2313. Anyway this problem exists with other AVR
microcontrollers as well.
To set for clock prescaling factor it is necessary to access the CLKPR
twice within 4 clock cycles. First you set the highest bit (CLKPCE) to 1
and all others to 0. Then you write the actual value for CLKPR. avr-gcc
code could look like this:
CLKPR = (1<<CLKPCE);
CLKPR = 1;
As long as code optimizatin is used (gcc option -Os) everything works as
expected. If no optimization is used (-O0), the above code has no
effect. The clock prescaling factor isn't changed. The reason for this
can be found in the respective assembler code.
With optimization you get:
ldi r24,lo8(-128) ; tmp44,
out 70-32,r24; ,, tmp44
ldi r24,lo8(1) ; tmp46,
out 70-32,r24; ,, tmp46
Obviously the register access (the lines with "st Z,r18") is not done
within 4 clock cycles.
If you do not want to use code optimization, you can circumvent the
problem by using an inline assembler statement like this one:
"st Z,%1""\n\t""st Z,%2"
"r" ((uint8_t) (1<<CLKPCE)),
"r" ((uint8_t) 1) // new CLKPR value
> Since I spend the last two days trying to get the clock prescaler to> work I wanted to share my results.
Since you've spent two days senselessly, as you either forgot to, or you
don't know how to read the documentation, there's a certain chance
you'll do it next time more clever.
Anyway, it doesn't make you look smarter, if you post the same proof
that you had blinders on, in English too.
Beitrag "AVR clock prescaler (CLKPR) und gcc-Codeoptimierung"
The solution is simple: use clock_prescale_set(x) from power.h
I am new to ATMEL and found your posting here very helpful. I do not
bash people for not reading documentation or missing some particular
part of the documentation. I would not have known to go to a seemingly
unrelated file like "power.h" to find out about setting the clock
Keep up your good work here. I look forward to seeing what you discover.
Thank you for this. I had also the same problem, as I was in debug mode
and the prescaler would not change.
@MWS I am gratefull he posted it in English as wel. Also not everyone
uses the libraries provided by Arduino.
RT wrote:> Also not everyone uses the libraries provided by Arduino.
The header file mentioned is part of avr-libc (and thus in no relation
to "Arduino libraries"), and this particular inline function has been
provided there for exactly the purpose the TO tried to solve with his
own inline asm macro: being independent of the compiler optimization.
Of course, everyone is free to roll their own … and making their own
mistakes (like, in this case, not thinking about whether interrupts need
to be disabled - the inline function in avr/power.h takes care about
Jörg W. wrote:> The header file mentioned is part of avr-libc (and thus in no relation> to "Arduino libraries"), and this particular inline function has been> provided there for exactly the purpose the TO tried to solve with his> own inline asm macro: being independent of the compiler optimization.
Yes, that's the truth. But it is NOT PORTABLE.
> Of course, everyone is free to roll their own
Those guys are the guys, who're REALLY know, what they're doing. The
advantage is: they drop any dependencies to any specific compiler.
That's the only way to get really free. Gain own knowledge regarding the
target. Don't become a stupid slave of one specific compiler.
> and making their own> mistakes
Of course. Making the own mistakes is the only way to generate foundated
This is a very widely accepted fact.
c-hater wrote:> Those guys are the guys, who're REALLY know, what they're doing. The> advantage is: they drop any dependencies to any specific compiler.
Inline assembly is compiler specific and not portable at all. For
example, the original code contains "asm volatile (...". This is, in
fact, invalid C syntax, and will not compile with a standard-compliant
compiler (e.g. GCC when specifying -std=c99). The compiler will think
that "asm" is a function or type name and will indicate a syntax error.
By changing it to "__asm__ __volatile__", as in avr/power.h, it becomes
correct C, as now the compiler-specific keyword "__asm__" is used, which
the standard allows. Of course, it's still not portable, but at least
not invalid C.