Overclocking ATMega328P

Overclocking ATMega328P / Atmega2560 to 20 MHz and 24 MHz

Please read Liability Disclaimer and License Agreement CAREFULLY

Recently I hit the wall of speed in my application for a remote controlled DSLR Camera.

In this project I use a custom board based on Arduino UNO and like Arduino a16MHz XTAL.

When I’ve read the data sheet with more care I saw that the ATMega328 can run at 20MHz

(someone on the Arduino forum said that the first revision of the data sheet mentioned

the maximum frequency to be 24MHz – I can’t find this version, so I can’t say for sure if is true).

In order to make DSLR Camera Remote Control with Touch Shield Slide run at 20MHz I’ve decided to change the 16MHz XTAL

with a 20MHz one. In order to make it work with Arduino IDE I’ve added this section in the boards.txt

at the top after I’ve read this article Optiboot Upload Performance

gvi20.name=GVI High Speed (5V-20MHz-500k Baud)
gvi20.upload.protocol=arduino
gvi20.upload.maximum_size=32256
gvi20.upload.speed=500000
gvi20.bootloader.low_fuses=0xf7
gvi20.bootloader.high_fuses=0xd6
gvi20.bootloader.extended_fuses=0x05
gvi20.bootloader.path=optiboot
gvi20.bootloader.file=optiboot_atmega328__20MHz.hex
gvi20.bootloader.unlock_bits=0x3F
gvi20.bootloader.lock_bits=0x0F
gvi20.build.mcu=atmega328p
gvi20.build.f_cpu=20000000L
gvi20.build.core=arduino
gvi20.build.variant=standard

In order to make this work we will also need a new boot loader and fortunately for me it is quite easy to do it by editing

the Makefile stored in \hardware\arduino\bootloaders\optiboot\ where I added these lines

#
# lines added by GVI for testing ATMega328P @ 20MHZ
#
atmega328_20MHz: TARGET = atmega328__20MHz
atmega328_20MHz: MCU_TARGET = atmega328p
atmega328_20MHz: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=500000'
atmega328_20MHz: AVR_FREQ = 20000000L
atmega328_20MHz: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_20MHz: $(PROGRAM)_atmega328__20MHz.hex
atmega328_20MHz: $(PROGRAM)_atmega328__20MHz.lst
atmega328_20MHz_isp: atmega328_20MHz
atmega328_20MHz_isp: TARGET = atmega328__20MHz
atmega328_20MHz_isp: MCU_TARGET = atmega328p
# 512 byte boot, SPIEN
atmega328_20MHz_isp: HFUSE = D6
# Low power xtal (16MHz) 16KCK/14CK+65ms
atmega328_20MHz_isp: LFUSE = F7
# 2.7V brownout
atmega328_20MHz_isp: EFUSE = 05
atmega328_20MHz_isp: isp

after i saved the change to Make file  I had to generate the bootloader using this line in a command prompt window:

omake  atmega328_20MHz

After the command is executed in the optiboot folder I had

optiboot_atmega328__20MHz.hex and

optiboot_atmega328__20MHz.lst

added in folder.

By using ATMega328P - Burning bootloader I uploaded the boot loader to my 328P and test it using the attached sketch.

I was pleased by the results so I decided to make this page and publish it.

Regarding the 24MHz speed I have to test it more because seems to be problems with writing/reading the EEPROM, but when I will finish these tests i will publish the results here.

 

ATMega328P at 16MHz, 20MHz, 24MHz

 

 

The full optiboot archived folder can be downloaded Optiboot 20MHz 24MHz and the test sketch GVI Overclockd Arduino Uno Speed test.

Below is the entry for 24 MHz board - Only for enthusiast's

gvi24.name=GVI High Speed (5V-24MHz-500k Baud)
gvi24.upload.protocol=arduino
gvi24.upload.maximum_size=32256
gvi24.upload.speed=500000
gvi24.bootloader.low_fuses=0xf7
gvi24.bootloader.high_fuses=0xd6
gvi24.bootloader.extended_fuses=0x05
gvi24.bootloader.path=optiboot
gvi24.bootloader.file=optiboot_atmega328__24MHz.hex
gvi24.bootloader.unlock_bits=0x3F
gvi24.bootloader.lock_bits=0x0F
gvi24.build.mcu=atmega328p
gvi24.build.f_cpu=24000000L
gvi24.build.core=arduino
gvi24.build.variant=standard

To conclude, you can find all these informations on Arduino Forum.

UPDATE 

Change the file wiring.c so that delayMicroseconds will look like:

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us){
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 24000000L
   // for the 24 MHz clock for the aventurous ones, trying to overclock
    // for a one-microsecond delay, simply wait 6 cycles and return. The overhead
   // of the function call yields a delay of exactly one microsecond.
   __asm__ __volatile__ (
     "nop" "\n\t"
     "nop" "\n\t"
     "nop" "\n\t"
     "nop" "\n\t"
     "nop" "\n\t"
     "nop"); //just waiting 6 cycles
   if (--us == 0)
     return;
    // the following loop takes a 1/6 of a microsecond (4 cycles)
   // per iteration, so execute it six times for each microsecond of
   // delay requested.
   us *= 6; // x6 us
    // account for the time taken in the preceeding commands.
   us -= 2;
#elif F_CPU >= 20000000L
// for the 20 MHz clock on rare Arduino boards
// for a one-microsecond delay, simply wait 2 cycle and return. The overhead
// of the function call yields a delay of exactly a one microsecond.
__asm__ __volatile__ (
"nop" "\n\t"
"nop"); //just waiting 2 cycle
if (--us == 0)
return;
// the following loop takes a 1/5 of a microsecond (4 cycles)
// per iteration, so execute it five times for each microsecond of
// delay requested.
us = (us<<2) + us; // x5 us
// account for the time taken in the preceeding commands.
us -= 2;
#elif F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return.  the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
#else
// for the 8 MHz internal clock on the ATmega168
// for a one- or two-microsecond delay, simply return.  the overhead of
// the function calls takes more than two microseconds.  can't just
// subtract two, since us is unsigned; we'd overflow.
if (--us == 0)
return;
if (--us == 0)
return;
// the following loop takes half of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1;
// partially compensate for the time taken by the preceeding commands.
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}

In SoftwareSerial.cpp add the following

const int XMIT_START_ADJUSTMENT = 6;// starting from this line
#elif F_CPU == 24000000
// 20MHz support courtesy of the good people at macegr.com.
// Thanks, Garrett!
static const DELAY_TABLE PROGMEM table[] =
{
  //  baud    rxcenter    rxintra    rxstop  tx
  { 115200,   6,          24,        24,     25,     },
  { 57600,    34,         46,        46,     48,     },
  { 38400,    49,         89,        89,     86,     },
  { 31250,    60,         108,       108,    108,    },
  { 28800,    58,         119,       119,    116,    },
  { 19200,    88,         179,       179,    176,    },
  { 14400,    118,        238,       238,    235,    },
  { 9600,     178,        358,       358,    355,    },
  { 4800,     360,        716,       716,    713,    },
  { 2400,     713,        1428,      1428,   1425,   },
  { 1200,     1427,       2856,      2856,   2853,   },
  { 600,      2856,       5714,      5714,   5710,   },
  { 300,      5714,       11429,     11429,  11426,  },
};
const int XMIT_START_ADJUSTMENT = 7;
#else
#error This version of SoftwareSerial supports only 24, 20, 16 and 8MHz processors
#endif

I finally had time to try to increase the frequency to ATMega2560. After several failed attempts to use the default files that comes with the Arduino IDE, I found this Arduino stk500v2 bootloader  version.
I had changed the CPU frequency in both Makefile and stk500boot.c 20MHz respectively 24MHz, in both cases the processor works well, for 24MHz the MCU requires 5V power supply and it heats slightly.
in stk500boot.c change line 232 #define F_CPU 20000000UL or #define F_CPU 24000000UL
in Makefile add or edit the defaut entry for ATMega2560

############################################################
#March 6,2014<GVI> Adding ATMega2560 support @ 20MHz and 24MHz
mega2560:MCU = atmega2560
mega2560:F_CPU = 24000000
mega2560:BOOTLOADER_ADDRESS = 3E000
mega2560:CFLAGS += -D_MEGA_BOARD_
mega2560:begin gccversion sizebefore build sizeafter end 
mv $(TARGET).hex stk500boot_v2_mega2560_24.hex
############################################################

Click to download the ATMega2560 20MHz 24MHz archive (Intel format HEX files for ATMega2560 at 20MHz and 24MHz included)
Don't forget to add a new entry in the boards.txt of your Arduino (tested on arduino-1.0.4 and arduino-1.0.5-r2)

##############################################################
gvimega256020.name=GVI Mega 2560 24MHz
gvimega256020.upload.protocol=wiring
gvimega256020.upload.maximum_size=258048
gvimega256020.upload.speed=115200
gvimega256020.bootloader.low_fuses=0xFF
gvimega256020.bootloader.high_fuses=0xD8
gvimega256020.bootloader.extended_fuses=0xFD
gvimega256020.bootloader.path=stk500v2
gvimega256020.bootloader.file=stk500boot_v2_gvibot24.hex
gvimega256020.bootloader.unlock_bits=0x3F
gvimega256020.bootloader.lock_bits=0x0F
gvimega256020.build.mcu=atmega2560
gvimega256020.build.f_cpu=24000000L
gvimega256020.build.core=arduino
gvimega256020.build.variant=mega
##############################################################

Comments powered by CComment