Can't increase internal RC clock past ~1MHz

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, I'm on an ATmega48 (chip actually says ATmega48A-PU on it, not entirely sure what that entails).

 

I made a simple LED blinker test program which works, but I started digging into clock speed and wanted to see the micro actually run at 8MHz on the internal oscillator, since the datasheet claims it can. I cleared the CKDIV8 fuse first, to no avail, then tried fiddling with F_CPU before realizing it won't change how fast the CPU actually runs, it's just a hint to the delay module for figuring out how long a second should take.

 

Lastly, I tried setting the clock prescaler directly to make sure the 8MHz clock was being chosen. It still seems like things are running around 1MHz for me, though.

 

Here's the code. Modified lightly from the LED blinker example by riktronics.

 

//Simple code by riktronics to toogle an LED at 0.5Hz
//visit riktronics.wordpress.com
//LED is connected at PD6 of ATmega8
//Read datasheet of atmega8 for more details

#define F_CPU 8000000
/* If CPU is actually at 8MHz, this definition should cause _delay_ms(1000) to roughly take a second. */
/* What's actually happening is that it takes about 8 seconds, which indicates the CPU is at 1MHz. */

#include <avr/io.h>
#include <util/delay.h>

int main()
{
 DDRB |= (1 << PB1); // make PB1 an output

 CLKPR = (1 << CLKPCE); // Enable clock prescaler change
 CLKPR &= 0xF0; // Set prescaler bits to 0 (divide clock by 1)

 while(1)
 {
 PORTB |= (1 << PB1); // turn on led at PB1
 _delay_ms(1000); // delay for a second
 PORTB &= ~(1 << PB1); //turn off led at PB1
 _delay_ms(1000); // delay for a second

 }

 return 0; // the program executed successfully
}

 

The only thing I can think of that would be limiting the frequency to around 1MHz is some operation limitation, as insinuated by this ominous passage from the datasheet: "The Application software must ensure that a sufficient division factor is chosen if the selected clock source has a higher frequency than the maximum frequency of the device at the present operating conditions." I'm running at 5V with a dedicated supply so this seems strange to me, however.

 

Any advice?

Last Edited: Thu. Oct 26, 2017 - 08:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
Empty Set wrote:
CLKPR = (1 << CLKPCE); // Enable clock prescaler change CLKPR &= 0xF0; // Set prescaler bits to 0 (divide clock by 1)

try:

CLKPR = (1 << CLKPCE);
CLKPR = (0x00);

The "&=" is doing a read/modify/write of the register which causes the write to occur more than 4 cycles from when CLKPCE is set.

 

Edit quote format

David (aka frog_jr)

Last Edited: Thu. Oct 26, 2017 - 09:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The M48 will run at 8MHz, I have 100k in the field that do.  GCC is tricky in it will optimize your code so you can not be sure it will run the way you think it should.

There is a function for setting the the CLKPR you must use in order for it to work.  I don't use GCC, so someone else will have to tell you what the name of the function is.

 

Post you fuse settings, as that should also work.

use this website to find your fuse setting before you try to burn them...  http://www.engbedded.com/fusecalc/

or you may brick your AVR.

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have:

 CLKPR &= 0xF0; // Set prescaler bits to 0 (divide clock by 1)

It should be

 CLKPR = 0x00; // Set prescaler bits to 0 (divide clock by 1)

The CLKPR register must be written within 4 clock cycles.    Your statement involves LDS, ANDI, STS opcodes which exceed the 4 clock cycles.

 

God provided you with the "avr/power.h" header file.   You can use this to set CLKPR correctly.  (instead of having to worry about counting clock cycles and ASM opcodes)

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Empty Set wrote:
Any advice?
Tell more about how you
Empty Set wrote:
I cleared the CKDIV8 fuse

 

Did you set it to 0 (programmed), or to 1 (not programmed)?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

http://www.nongnu.org/avr-libc/u...

 

So:

#include <avr/io.h>
#include <avr/power.h>

int main(void) {
    clock_prescale_set(clock_div_1);
}

Job done.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the quick advice. clawson/david.prentice's advice to use the avr power command worked. frog_jr/david.prentice's register write suggestion also worked, but I'll probably avoid this with C in the future to stay on the safe side.

 

Regarding the fuses, I discovered the issue there while looking into it a bit. I was using the Makefile from riktronics' tutorial and thought the fuse setting would be applied every time, not as a special rule. I was already using the fuse calculator to set a fuse parameter, but not doing anything with it. After actually running that rule the speed changed to 8MHz as well (I confirmed this by removing the prescaler commands in the source code).

 

Thanks again. You've sped my progress (and clock speed) eightfold smiley

Last Edited: Fri. Oct 27, 2017 - 12:58 PM