1

I am programming an ATtiny85 with MS_Visual_Studio with extension Visual_Micro using an Arduino1.6/1.8 Gemma board definition. The programmer is Sparkfun Tiny Programmer.
Here is the very simple code utilized. ( Thanks to InsideGadgets YouTube channel " Change the ATtiny85 clock speed on the fly"). It couldn't get any simpler.

Yet, despite the fact that I change the #define F_CPU 1000000 to #define F_CPU 8000000, there is absolutely no effect on the LED flash cycling period, which is about 2 seconds.
The ATtiny85 act as if the clock was 1MHz, despite any changes to F_CPU.
I tested CLKPR = 3 over CLKPR = 0, which changes the prescaler from a factor of 1 to 8.
This should make the delay 8 times longer, which it does. I searched for some details about the F_CPU definition but could not find any explanation for this behavior.

The Question: Why is there no effect on the _delay_ms(1000) after the F_CPU has been defined from 1MHz to 8MHz?

#define F_CPU 1000000  
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int main(void) {
    DDRB |= (1 << PB0);

    while (1) {
        PORTB |= (1 << PB0);  //  Toggle LED 
        _delay_ms(1000);      //  delay 1 second
        PORTB &= ~(1 << PB0);
        _delay_ms(1000);      //  delay 1 second

        cli();
        CLKPR = (1 << CLKPCE); // set for changing prescaler
                               // Change clock prescaler to 0000
        CLKPR = 0;             // divider by 1
//      CLKPR = 3;             // divider by 8
        sei();
    }                          // complete Loop is a 2 seconds period
return 0;
}
Fred Cailloux
  • 175
  • 1
  • 7
  • Are you sure that the macro is actually used during compilation? Where do you define it? You could check the value during runtime and verify that it really is set to what you expect. – Rev Apr 03 '19 at 09:05
  • try #define F_CPU 8000000UL - note UL at the end. Without it probably functions are treating the value as 16-bit and truncating it, or replacing it with default – AterLux Apr 03 '19 at 11:53
  • Also, make sure the macro is not defined in the compiler options (i.e. there is no-DF_CPU=1000000UL or something like that) – AterLux Apr 03 '19 at 12:00

1 Answers1

3

The F_CPU just lets the _delay_ms() macro calculate how many cycles each second takes. You need this because the delay macros are very simple and do not know what the prescaller happens to be set to at the moment they are called at runtime.

So if you are going to be changing the prescaller on the fly, you might want to make two different delay functions so you can make it clear in your code what is going on.

It might look like...

#define F_CPU 1000000                   // We start with 8x prescaler on 8Mhz clock

#define delay_ms_1Mhz(x) (_delay_ms(x))   // Delay when prescaller set to 8x
#define delay_ms_8Mhz(x) (_delay_ms(x*8)) // Delay when prescaller set to 1x so we need to burn 8x as many cycles

...and then decide which to call depending on what the prescaler is set to at that point in your code.

bigjosh
  • 1,273
  • 13
  • 19
  • Makes sense. Still doesn't explain why F_CPU has no effect on the delay. Whether 1MHz or 8MHz the LED period remains 2 sec. If F_CPU had any effect, by changing F_CPU to 8MHz, the cycle period would be 16 sec, since each cycle would be presumed to be 8 time smaller but in reality would still be the same whether 1mhz or 8mhz clock. Keep in mind, on both F_CPU tried I am still using the same _delay_ms_(1000). Or, I get it all wrong, and by changing from 1MHz to 8MHz the compiler adjust the _delay_ms_ macro such that 1000ms remain always 1000ms ? (have I just answered my own question here?) – Fred Cailloux Apr 03 '19 at 02:25
  • Perhaps my question should have been: is #define F_CPU 1000000 only affect the _delay_ms_ macro or does it actually physically change the MCU real frequency ? – Fred Cailloux Apr 03 '19 at 02:28
  • 1
    The `#define F_CPU` does not do anything to the CPU. It does not change any registers. It just defines a number that is used in the calculations done by some other macros - most notably the `_delay_xx()` macros. They have a line in them like `delay_cycle_count = number_of_ms * F_CPU / 1000`. Make sense? – bigjosh Apr 04 '19 at 04:59
  • Now I am really confused. If F_CPU have no effect on the real CPU clock frequency then if I am changing the F_CPU value in the code and _delay_xx_() is using this F_CPU value to implement a time delay in code execution, why then changing F_CPU from 1MHz to 8MHz would have no effect on my code execution? If the real CPU frequency is not changes and the delay function is told otherwise shouldn't this impose an erroneous delay on the code execution ? – Fred Cailloux Apr 06 '19 at 21:53
  • 2
    Simplify your code so that it just blinks the LED every 1000ms. Use `#define F_CPU 1000000` and do not change the prescaller on the chip so that it is running at 1Mhz. Confirm that the LED blinks at the right rate. Now change the `F_CPU` define to `8000000` and recompile and run the code and confirm the LED blinks at the right rate (should be 8x slower than last try). If the LED blinks at the same rate both times, then something in your config is not as expected (has nothing to do with the chip itself, more likely with the build files or build environment, or even a spelling error someplace). – bigjosh Apr 09 '19 at 02:58
  • tried your simplified code. Result: The cycle period is still 15.6 seconds where it should have been 2 seconds ( an 8 times factor ? ) whether I use C_CPU 1000000 or F_CPU 8000000. So, I guess there is something wrong is the way Visual Studio Visual Micro is coding this ATtiny85. Any suggestions as to where I may start my search ? – Fred Cailloux Apr 09 '19 at 19:42
  • Next I would try moving the `#define F_CPU 1000000 `down to be right before the `#include ` and keeping the `#include ` as the last `#include`. If this fixes it, then maybe `F_CPU` is getting redefined inside one of the other header files, prob `io.h`. – bigjosh Apr 12 '19 at 15:14