Read Fuse Bits via Arduino Software

Hi dude,
I’ve Arduino Mega board and would like to read the fuse bits by using Arduino IDE, is it possible to read? And if not, what is the default values of fuse bits for the board?

Best Regards,
pak

No way to read them from a user program.

Can be read with AVR Studio (on Windows) if you have a supported programmer.

Can be read with avrdude (on Windows, Linux or whatever...) if you have an Arduino bootloader installed on the ATmega or if you have a supported programmer.

The old Arduino Mega board with ATmega1280:


Low fuses      = 0xff
High fuses     = 0xda
Extended Fuses = 0xf5

The new Arduino Mega board with ATmega2560:


Low fuses      = 0xff
High Fuses     = 0xd8
Extended Fuses = 0xfd

Regards,

Dave

Maybe Arduino needs peek() and poke() functions.

Hummm, changing fuse setting on the fly. Sounds like a game played called Russian roulette. ;)

Actually I don't think you can change fuse bits on the fly without doing a chip erase function first to set all fuse bits to one before writing their proper value, but I'm not sure.

Lefty

The fuse registers do not reside in an address space that can be accessed from a program running on that device.

If the protect bits have not been programmed, you can access the fuse bits (for reading and for writing) in any program mode supported by that particular flavor of ATmega device and supported by the particular programmer being used.

Regards,

Dave

Footnote:

In my experience: For an ATmega chip with a "normal" Arduino bootloader, avrdude can read and write flash (program) memory and EEPROM memory (assuming an external programmer has not programmed protection bits), and it can read the device signature bytes but it can not access the fuse bits of that same device.

If AVRIsp is loaded on one ATmega chip and a second device is connected properly, you can write the fuse bits (and everything else) on the second device, assuming that the "ISP disable" fuse bit hasn't been programmed on the target device.

I could be wrong about the fuse bits with avrdude and the Arduino bootloader, and I would appreciate any corrections based on actual experience of others.

Hi dude,

I've just started using Arduino board and very new to this board.

Can be read with avrdude (on Windows, Linux or whatever...) if you have an Arduino bootloader installed on the ATmega or if you have a supported programmer.

I have an Arduino bootloader installed on my board and how can I read the fuse bits,

Maybe Arduino needs peek() and poke() functions.

How to use peek() and poke() function as well? Do you mean Serial.peek()? Can I use them to read fuse bits?

Regards, pak

@davekw7x:

...if you have an Arduino bootloader installed on the ATmega...

I misspoke. I don't know how to read (or write) the fuses without a programmer. The Arduino bootloader will not directly display or change the values of the fuses with avrdude.

Sorry.

Any one of a number of ISP programmers are able to do this.

Regards.

Dave

It's supposed to technically be possible to read the fuses from a running program, however I've only seen it done in IAR C.

read the fuses from a running program

Yes, I know how to do this with an ATXmega. But for ATmega???

I would like to find such a reference.

Regards,

Dave

Something I’ve been working on. “fusebytes.pde”
Sample output:

Compiled for ATmega328P
Your Serial Number is: UNO 1 4 B8 (66744)

Fuse bits (L/E/H): FF FD D6
Lock bits:         CF
Signature:         1E 95 F (ATmega328P)
Oscal:             9A

Fuse Low = 11111111 (FF)
           ||||++++______Low Power Crystal 8 - 16MHz
           ||++__________Start Up Time=11
           |+____________Clock Output Disabled
           +_____________(no divide)

Fuse High = 11010110 (D6)
            |||||||+______Reset to Bootstrap
            |||||++_______256 words (512 bytes)
            ||||+_________EEPROM Preserved on chip erase
            |||+__________Watchdog programmable
            ||+___________ISP programming enabled
            |+____________DebugWire off
            +_____________RST enabled

Fuse Extended = 11111101 (FD)
                |||||+++______Brownout at 2.7V

Lock Bits = 11001111 (CF)
            ||||||++______Read/Write to everywhere
            ||||++________R/W Application
            ||||++________No Write to Boot, no read from App

(split up because it’s … big.)
Also: not finished yet…

#include <Flash.h>
#include <avr/boot.h>
#include <EEPROM.h>
#include "cpuname.h"

/*
 * SIGRD is a "must be zero" bit on most Arduino CPUs; can we read the sig or not?
 */
#if (!defined(SIGRD))
#define SIGRD 5
#endif

unsigned char fuse_bits_low;
byte fuse_bits_extended;
byte fuse_bits_high;
byte lock_bits;
byte sig1, sig2, sig3;
byte oscal;

void setup()
{
  unsigned char xxx = fuse_bits_low>>4;
  Serial.begin(9600);
  Serial.print(xxx);
}

void space() {
  Serial.print(' ');
}

void print_serno(void)
{
  int i;
  int unoSerial[6];
  int startAddr=1018;
  unsigned long serno = 0;

  for (i = 0; i < 6; i++) {
    unoSerial[i] = EEPROM.read(startAddr + i);
  }
  if (unoSerial[0] == 'U' && unoSerial[1] == 'N' && unoSerial[2] == 'O') {

    Serial << F("Your Serial Number is: UNO");

    for (i = 3; i < 6; i = i + 1) {
      serno = serno*256 + unoSerial[i];
      Serial.print(" ");
      Serial.print(unoSerial[i], HEX);
    }
    Serial << F(" (") << serno << F(")");
  } 
  else {
    Serial << F("No Serial Number");
  }
  Serial.println();
}

void print_binary(byte b)
{
  for (byte i=0x80; i>0; i>>=1) {
    if (b&i) {
      Serial.print('1');
    } 
    else {
      Serial.print('0');
    }
  }
}

/*
 * Note that most fuses are active-low, and the the avr include files
 * define them as inverted bitmasks...
 */

void print_fuse_low(void)
{
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || \
  defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) ||  \
    defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__)
    /*
 * Fuse Low is same on 48/88/168/328
     */
    Serial << F("Fuse Low = ");
  print_binary(fuse_bits_low);
  Serial << F(" (");
  Serial.print(fuse_bits_low, HEX);
  Serial << F(")\n");
  Serial << F("           ||||++++______"); 
  switch (fuse_bits_low & 0xF) {
  case 0: 
    Serial << F("Reserved");
    break;
  case 1: 
    Serial << F("External Clock");
    break;
  case 2: 
    Serial << F("Calibrated 8MHz Internal Clock");
    break;
  case 3: 
    Serial << F("Internal 128kHz Clock");
    break;
  case 4: 
    Serial << F("LF Crystal, 1K CK Startup");
    break;
  case 5: 
    Serial << F("LF Crystal 32K CK Startup");
    break;
  case 6: 
    Serial << F("Full Swing Crystal ");
    break;
  case 7: 
    Serial << F("Full Swing Crystal");
    break;
  case 8:
  case 9:
    Serial << F("Low Power Crystal 0.4 - 0.8MHz");
    break;
  case 10:
  case 11:
    Serial << F("Low Power Crystal 0.9 - 3.0MHz");
    break;
  case 12:
  case 13:
    Serial << F("Low Power Crystal 3 - 8MHz");
    break;
  case 14:
  case 15:
    Serial << F("Low Power Crystal 8 - 16MHz");    
    break;
  }

  Serial.println();
  Serial << F("           ||++__________"); 
  Serial << F("Start Up Time=");
  Serial.print((fuse_bits_low >> 4) & 3, BIN);

  Serial.println();
  Serial << F("           |+____________"); 
  Serial << F("Clock Output ");
  if (fuse_bits_low & (~FUSE_CKOUT))
    Serial << F("Disabled");
  else
    Serial << F("Enabled");

  Serial.println();
  Serial << F("           +_____________");
  if (fuse_bits_low & (~FUSE_CKDIV8)) {
    Serial << F("(no divide)");
  } 
  else {
    Serial << F("Divide Clock by 8");
  }


#elif defined(__AVR_ATmega8__)
#endif
  Serial.println();
}

Part 2:

void print_fuse_high()
{
  Serial << F("\nFuse High = ");
  print_binary(fuse_bits_high);
  Serial << F(" (");
  Serial.print(fuse_bits_high, HEX);
  Serial << F(")\n");

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
  Serial << F("            |||||||+______");
  if (fuse_bits_high & bit(FUSE_BOOTRST)) {
    Serial << F("Reset to Start of memory\n");
  } 
  else {
    Serial << F("Reset to Bootstrap\n");
  }
  Serial << F("            |||||++_______");
  switch ((byte)(fuse_bits_high & ((~FUSE_BOOTSZ1)+(~FUSE_BOOTSZ0)))) {
    case (byte)((~FUSE_BOOTSZ1)+(~FUSE_BOOTSZ0)):
    Serial << F("256 words (512 bytes)\n"); 
    break;
    case (byte)((~FUSE_BOOTSZ1)):
    Serial << F("512 words (1024 bytes)\n"); 
    break;
    case (byte)((~FUSE_BOOTSZ0)):
    Serial << F("1024 words (2048 bytes)\n"); 
    break;
  case 0:
    Serial << F("2048 words (4096 bytes)\n"); 
    break;
  default:
    Serial.println(fuse_bits_high & ((~FUSE_BOOTSZ1)+(~FUSE_BOOTSZ0)), BIN);
  }
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || \
  defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__)
    Serial << F("            |||||+++______");
  switch ((byte)(fuse_bits_high & 7)) {
  case 7:
    Serial << F("Brownout Disabled\n"); 
    break;
  case 6:
    Serial << F("Brownout at 1.8V\n"); 
    break;
  case 5:
    Serial << F("Brownout at 2.7V\n"); 
    break;
  case 4:
    Serial << F("Brownout at 4.3V\n"); 
    break;
  default:    
    Serial << F("Brownout Reserved value");
    Serial.println(fuse_bits_high& 7, BIN);
    break;
  }

#elif defined(__AVR_ATmega8__)
#endif
  Serial << F("            ||||+_________");
  if (fuse_bits_high & ~(FUSE_EESAVE)) {
    Serial << F("EEPROM Erased on chip erase\n");
  } 
  else {
    Serial << F("EEPROM Preserved on chip erase\n");
  }
  Serial << F("            |||+__________");
  if (fuse_bits_high & ~(FUSE_WDTON)) {
    Serial << F("Watchdog programmable\n");
  } 
  else {
    Serial << F("Watchdog always on\n");
  }
  Serial << F("            ||+___________");
  if (fuse_bits_high & ~(FUSE_SPIEN)) {
    Serial << F("ISP programming disabled\n");
  } 
  else {
    Serial << F("ISP programming enabled\n");
  }
  Serial << F("            |+____________");
  if (fuse_bits_high & ~(FUSE_DWEN)) {
    Serial << F("DebugWire off\n");
  } 
  else {
    Serial << F("DebugWire enabled\n");
  }
  Serial << F("            +_____________");
  if (fuse_bits_high & ~(FUSE_RSTDISBL)) {
    Serial << F("RST enabled\n");
  } 
  else {
    Serial << F("RST disabled\n");
  }
}

void print_lock_bits()
{
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || \
  defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || \
    defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__)

    Serial << F("\nLock Bits = ");
  print_binary(lock_bits);
  Serial << F(" (");
  Serial.print(lock_bits, HEX);
  Serial << F(")\n");
  Serial << F("            ||||||++______");
  switch ((byte)(lock_bits & 3)) {
  case 3:
    Serial << F("Read/Write to everywhere\n"); 
    break;
  case 2:
    Serial << F("Programming of Flash/EEPROM disabled\n"); 
    break;
  case 0:
    Serial << F("No Read/Write of Flash/EEPROM\n"); 
    break;
  default:
    Serial.println();
  }
  Serial << F("            ||||++________");
  switch ((byte)(lock_bits & 0b1100)) {  //BLB0x
  case 0b1100:
    Serial << F("R/W Application\n"); 
    break;
  case 0b1000:
    Serial << F("No Write to App\n"); 
    break;
  case 0b0000:
    Serial << F("No Write to App, no read from Boot\n"); 
    break;
  case 0b0100:
    Serial << F("No Write to App, no read from Boot, no Ints to App\n"); 
    break;
  }

  Serial << F("            ||++__________");
  switch ((byte)(lock_bits & 0b110000)) {  //BLB0x
  case 0b110000:
    Serial << F("R/W Boot Section\n"); 
    break;
  case 0b100000:
    Serial << F("No Write to Boot Section\n"); 
    break;
  case 0b000000:
    Serial << F("No Write to Boot, no read from App\n"); 
    break;
  case 0b010000:
    Serial << F("No Write to Boot, no read from App, no Ints to Boot\n"); 
    break;
  }
#elif defined(__AVR_ATmega8__)
#endif
}

void print_fuse_extended()
{
  Serial << F("\nFuse Extended = ");
  print_binary(fuse_bits_extended);
  Serial << F(" (");
  Serial.print(fuse_bits_extended, HEX);
  Serial << F(")\n");
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
  Serial << F("                |||||+++______");
  switch ((byte)(fuse_bits_extended & 7)) {
  case 7:
    Serial << F("Brownout Disabled\n"); 
    break;
  case 6:
    Serial << F("Brownout at 1.8V\n"); 
    break;
  case 5:
    Serial << F("Brownout at 2.7V\n"); 
    break;
  case 4:
    Serial << F("Brownout at 4.3V\n"); 
    break;
  default:    
    Serial << F("Brownout Reserved value");
    Serial.println(fuse_bits_extended & 7, BIN);
    break;
  }
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__)
  Serial << F("                |||||||+______");
  if (fuse_bits_extended & bit(FUSE_BOOTRST)) {
    Serial << F("Reset to Start of memory\n");
  } 
  else {
    Serial << F("Reset to Bootstrap\n");
  }
  Serial << F("                |||||++_______");
  switch ((byte)(fuse_bits_extended & ((~FUSE_BOOTSZ1)+(~FUSE_BOOTSZ0)))) {
    case (byte)((~FUSE_BOOTSZ1)+(~FUSE_BOOTSZ0)):
    Serial << F("128 words (256 bytes)\n"); 
    break;
    case (byte)((~FUSE_BOOTSZ1)):
    Serial << F("256 words (512 bytes)\n"); 
    break;
    case (byte)((~FUSE_BOOTSZ0)):
    Serial << F("512 words (1024 bytes)\n"); 
    break;
  case 0:
    Serial << F("1024 words (2048 bytes)\n"); 
    break;
  default:
    Serial.println(fuse_bits_extended & ((~FUSE_BOOTSZ1)+(~FUSE_BOOTSZ0)), BIN);
  }
#elif defined(__AVR_ATmega8__)
#endif
}

void print_signature()
{
  Serial << F("\nSignature:         ");
  Serial.print(sig1, HEX);
  space();
  Serial.print(sig2, HEX);
  space();
  Serial.print(sig3, HEX);
  if (sig1 == 0x1E) { /* Atmel ? */
    switch (sig2) {
    case 0x92:  /* 4K flash */
      if (sig3 == 0x0A) 
        Serial << F(" (ATmega48P)");
      else if (sig3 == 0x05)
        Serial << F(" (ATmega48A)");
      else if (sig3 == 0x09)
        Serial << F(" (ATmega48)");
      break;
    case 0x93:  /* 8K flash */
      if (sig3 == 0x0F) 
        Serial << F(" (ATmega88P)");
      else if (sig3 == 0x0A)
        Serial << F(" (ATmega88A)");
      else if (sig3 == 0x11)
        Serial << F(" (ATmega88)");
      else if (sig3 == 0x08)
        Serial << F(" (ATmega8)");
      break;
    case 0x94:  /* 16K flash */
      if (sig3 == 0x0B) 
        Serial << F(" (ATmega168P)");
      else if (sig3 == 0x06)
        Serial << F(" (ATmega168A)");
      break;
    case 0x95:  /* 32K flash */
      if (sig3 == 0x0F)
        Serial << F(" (ATmega328P)");
      else if (sig3 == 0x14)
        Serial << F(" (ATmega328)");
      break;
    }
  } 
  else {
#if defined (__AVR_ATmega168__) || defined(__AVR_ATmega8__)
    Serial << F(" (Fuses not readable on non-P AVR)");
#else
    Serial << F("????");
#endif
  }
}

void loop()
{
  delay(2000);
  Serial << F("\nCompiled for " __CPUNAME "\n");
  print_serno();  
  cli();
  fuse_bits_low = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS);
  fuse_bits_extended = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS);
  fuse_bits_high = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
  lock_bits = boot_lock_fuse_bits_get(GET_LOCK_BITS);
  sig1 = boot_signature_byte_get(0);
  sig2 = boot_signature_byte_get(2);
  sig3 = boot_signature_byte_get(4);
  oscal = boot_signature_byte_get(1);
  sei();

  Serial << F("\nFuse bits (L/E/H): ");
  Serial.print(fuse_bits_low, HEX);
  space();
  Serial.print(fuse_bits_extended, HEX);
  space();
  Serial.print(fuse_bits_high, HEX);
  Serial << F("\nLock bits:         ");
  Serial.print(lock_bits, HEX);
  print_signature();
  Serial << F("\nOscal:             ");
  Serial.println(oscal, HEX);
  Serial.println();

  print_fuse_low();
  print_fuse_high();
  print_fuse_extended();
  print_lock_bits();

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || \
  defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__)
#elif defined(__AVR_ATmega8__)
#endif
    while (1) {
      if (Serial.read() > 0)
        break;
    }
}

oops. You'll need this (cpuname.h) too (contains lots of unneeded things, but it's generated via processing the existing io.h file...)

#ifndef _AVR_CPUNAME_H_
#define _AVR_CPUNAME_H_

#if defined (__AVR_AT94K__)
#  define __CPUNAME "AT94K"
#elif defined (__AVR_AT43USB320__)
#  define __CPUNAME "AT43USB320"
#elif defined (__AVR_AT43USB355__)
#  define __CPUNAME "AT43USB355"
#elif defined (__AVR_AT76C711__)
#  define __CPUNAME "AT76C711"
#elif defined (__AVR_AT86RF401__)
#  define __CPUNAME "AT86RF401"
#elif defined (__AVR_AT90PWM1__)
#  define __CPUNAME "AT90PWM1"
#elif defined (__AVR_AT90PWM2__)
#  define __CPUNAME "AT90PWM2"
#elif defined (__AVR_AT90PWM2B__)
#  define __CPUNAME "AT90PWM2B"
#elif defined (__AVR_AT90PWM3__)
#  define __CPUNAME "AT90PWM3"
#elif defined (__AVR_AT90PWM3B__)
#  define __CPUNAME "AT90PWM3B"
#elif defined (__AVR_AT90PWM216__)
#  define __CPUNAME "AT90PWM216"
#elif defined (__AVR_AT90PWM316__)
#  define __CPUNAME "AT90PWM316"
#elif defined (__AVR_ATmega32C1__)
#  define __CPUNAME "ATmega32C1"
#elif defined (__AVR_ATmega32M1__)
#  define __CPUNAME "ATmega32M1"
#elif defined (__AVR_ATmega32U4__)
#  define __CPUNAME "ATmega32U4"
#elif defined (__AVR_ATmega32U6__)
#  define __CPUNAME "ATmega32U6"
#elif defined (__AVR_ATmega128__)
#  define __CPUNAME "ATmega128"
#elif defined (__AVR_ATmega1280__)
#  define __CPUNAME "ATmega1280"
#elif defined (__AVR_ATmega1281__)
#  define __CPUNAME "ATmega1281"
#elif defined (__AVR_ATmega1284P__)
#  define __CPUNAME "ATmega1284P"
#elif defined (__AVR_ATmega2560__)
#  define __CPUNAME "ATmega2560"
#elif defined (__AVR_ATmega2561__)
#  define __CPUNAME "ATmega2561"
#elif defined (__AVR_AT90CAN32__)
#  define __CPUNAME "AT90CAN32"
#elif defined (__AVR_AT90CAN64__)
#  define __CPUNAME "AT90CAN64"
#elif defined (__AVR_AT90CAN128__)
#  define __CPUNAME "AT90CAN128"
#elif defined (__AVR_AT90USB82__)
#  define __CPUNAME "AT90USB82"
#elif defined (__AVR_AT90USB162__)
#  define __CPUNAME "AT90USB162"
#elif defined (__AVR_AT90USB646__)
#  define __CPUNAME "AT90USB646"
#elif defined (__AVR_AT90USB647__)
#  define __CPUNAME "AT90USB647"
#elif defined (__AVR_AT90USB1286__)
#  define __CPUNAME "AT90USB1286"
#elif defined (__AVR_AT90USB1287__)
#  define __CPUNAME "AT90USB1287"
#elif defined (__AVR_ATmega64__)
#  define __CPUNAME "ATmega64"
#elif defined (__AVR_ATmega640__)
#  define __CPUNAME "ATmega640"
#elif defined (__AVR_ATmega644__)
#  define __CPUNAME "ATmega644"
#elif defined (__AVR_ATmega644P__)
#  define __CPUNAME "ATmega644P"
#elif defined (__AVR_ATmega645__)
#  define __CPUNAME "ATmega645"
#elif defined (__AVR_ATmega6450__)
#  define __CPUNAME "ATmega6450"
#elif defined (__AVR_ATmega649__)
#  define __CPUNAME "ATmega649"
#elif defined (__AVR_ATmega6490__)
#  define __CPUNAME "ATmega6490"
#elif defined (__AVR_ATmega103__)
#  define __CPUNAME "ATmega103"
#elif defined (__AVR_ATmega32__)
#  define __CPUNAME "ATmega32"
#elif defined (__AVR_ATmega323__)
#  define __CPUNAME "ATmega323"
#elif defined (__AVR_ATmega324P__)
#  define __CPUNAME "ATmega324P"
#elif defined (__AVR_ATmega325__)
#  define __CPUNAME "ATmega325"
#elif defined (__AVR_ATmega325P__)
#  define __CPUNAME "ATmega325P"
#elif defined (__AVR_ATmega3250__)
#  define __CPUNAME "ATmega3250"
#elif defined (__AVR_ATmega3250P__)
#  define __CPUNAME "ATmega3250P"
#elif defined (__AVR_ATmega328P__)
#  define __CPUNAME "ATmega328P"
#elif defined (__AVR_ATmega329__)
#  define __CPUNAME "ATmega329"
#elif defined (__AVR_ATmega329P__)
#  define __CPUNAME "ATmega329P"
#elif defined (__AVR_ATmega3290__)
#  define __CPUNAME "ATmega3290"
#elif defined (__AVR_ATmega3290P__)
#  define __CPUNAME "ATmega3290P"
#elif defined (__AVR_ATmega32HVB__)
#  define __CPUNAME "ATmega32HVB"
#elif defined (__AVR_ATmega406__)
#  define __CPUNAME "ATmega406"
#elif defined (__AVR_ATmega16__)
#  define __CPUNAME "ATmega16"
#elif defined (__AVR_ATmega161__)
#  define __CPUNAME "ATmega161"
#elif defined (__AVR_ATmega162__)
#  define __CPUNAME "ATmega162"
#elif defined (__AVR_ATmega163__)
#  define __CPUNAME "ATmega163"
#elif defined (__AVR_ATmega164P__)
#  define __CPUNAME "ATmega164P"
#elif defined (__AVR_ATmega165__)
#  define __CPUNAME "ATmega165"
#elif defined (__AVR_ATmega165P__)
#  define __CPUNAME "ATmega165P"
#elif defined (__AVR_ATmega168__)
#  define __CPUNAME "ATmega168"
#elif defined (__AVR_ATmega168P__)
#  define __CPUNAME "ATmega168P"
#elif defined (__AVR_ATmega169__)
#  define __CPUNAME "ATmega169"
#elif defined (__AVR_ATmega169P__)
#  define __CPUNAME "ATmega169P"
#elif defined (__AVR_ATmega8HVA__)
#  define __CPUNAME "ATmega8HVA"
#elif defined (__AVR_ATmega16HVA__)
#  define __CPUNAME "ATmega16HVA"
#elif defined (__AVR_ATmega8__)
#  define __CPUNAME "ATmega8"
#elif defined (__AVR_ATmega48__)
#  define __CPUNAME "ATmega48"
#elif defined (__AVR_ATmega48P__)
#  define __CPUNAME "ATmega48P"
#elif defined (__AVR_ATmega88__)
#  define __CPUNAME "ATmega88"
#elif defined (__AVR_ATmega88P__)
#  define __CPUNAME "ATmega88P"
#elif defined (__AVR_ATmega8515__)
#  define __CPUNAME "ATmega8515"
#elif defined (__AVR_ATmega8535__)
#  define __CPUNAME "ATmega8535"
#elif defined (__AVR_AT90S8535__)
#  define __CPUNAME "AT90S8535"
#elif defined (__AVR_AT90C8534__)
#  define __CPUNAME "AT90C8534"
#elif defined (__AVR_AT90S8515__)
#  define __CPUNAME "AT90S8515"
#elif defined (__AVR_AT90S4434__)
#  define __CPUNAME "AT90S4434"
#elif defined (__AVR_AT90S4433__)
#  define __CPUNAME "AT90S4433"
#elif defined (__AVR_AT90S4414__)
#  define __CPUNAME "AT90S4414"
#elif defined (__AVR_ATtiny22__)
#  define __CPUNAME "ATtiny22"
#elif defined (__AVR_ATtiny26__)
#  define __CPUNAME "ATtiny26"
#elif defined (__AVR_AT90S2343__)
#  define __CPUNAME "AT90S2343"
#elif defined (__AVR_AT90S2333__)
#  define __CPUNAME "AT90S2333"
#elif defined (__AVR_AT90S2323__)
#  define __CPUNAME "AT90S2323"
#elif defined (__AVR_AT90S2313__)
#  define __CPUNAME "AT90S2313"
#elif defined (__AVR_ATtiny2313__)
#  define __CPUNAME "ATtiny2313"
#elif defined (__AVR_ATtiny13__)
#  define __CPUNAME "ATtiny13"
#elif defined (__AVR_ATtiny13A__)
#  define __CPUNAME "ATtiny13A"
#elif defined (__AVR_ATtiny25__)
#  define __CPUNAME "ATtiny25"
#elif defined (__AVR_ATtiny45__)
#  define __CPUNAME "ATtiny45"
#elif defined (__AVR_ATtiny85__)
#  define __CPUNAME "ATtiny85"
#elif defined (__AVR_ATtiny24__)
#  define __CPUNAME "ATtiny24"
#elif defined (__AVR_ATtiny44__)
#  define __CPUNAME "ATtiny44"
#elif defined (__AVR_ATtiny84__)
#  define __CPUNAME "ATtiny84"
#elif defined (__AVR_ATtiny261__)
#  define __CPUNAME "ATtiny261"
#elif defined (__AVR_ATtiny461__)
#  define __CPUNAME "ATtiny461"
#elif defined (__AVR_ATtiny861__)
#  define __CPUNAME "ATtiny861"
#elif defined (__AVR_ATtiny43U__)
#  define __CPUNAME "ATtiny43U"
#elif defined (__AVR_ATtiny48__)
#  define __CPUNAME "ATtiny48"
#elif defined (__AVR_ATtiny88__)
#  define __CPUNAME "ATtiny88"
#elif defined (__AVR_ATtiny167__)
#  define __CPUNAME "ATtiny167"
/* avr1: the following only supported for assembler programs */
#elif defined (__AVR_ATtiny28__)
#  define __CPUNAME "ATtiny28"
#elif defined (__AVR_AT90S1200__)
#  define __CPUNAME "AT90S1200"
#elif defined (__AVR_ATtiny15__)
#  define __CPUNAME "ATtiny15"
#elif defined (__AVR_ATtiny12__)
#  define __CPUNAME "ATtiny12"
#elif defined (__AVR_ATtiny11__)
#  define __CPUNAME "ATtiny11"
#elif defined (__AVR_ATxmega64A1__)
#  define __CPUNAME "ATxmega64A1"
#elif defined (__AVR_ATxmega64A3__)
#  define __CPUNAME "ATxmega64A3"
#elif defined (__AVR_ATxmega128A1__)
#  define __CPUNAME "ATxmega128A1"
#elif defined (__AVR_ATxmega128A3__)
#  define __CPUNAME "ATxmega128A3"
#elif defined (__AVR_ATxmega256A3__)
#  define __CPUNAME "ATxmega256A3"
#elif defined (__AVR_ATxmega256A3B__)
#  define __CPUNAME "ATxmega256A3B"
#else
#  if !defined(__COMPILING_AVR_LIBC__)
#    warning "device type not defined"
#  endif
#endif

#endif /* _AVR_CPUNAME_H_ */

not finished yet

I would simply (or even not-so-simply) like to see how you are going to to read your variables "fuse_bits_high" and "fuse_bits_low" and "fuse_bits_extended" from a program running on a given ATmega processor, say an ATmega1280.

The Original Post asked if there is a way to read the fuse bits from a Mega board, and my response was that there is no way to read them from a user program. I think I know how to read them in a programming mode (using an external device connected as a programmer), but not from a running program.

I would love to see how to do it and to be able to retract my statement.

Regards,

Dave

I would love to see how to do it

The fuses are readable from software as a “special case” of the “load program memory.” See “24.8.9 Reading the Fuse and Lock Bits from Software” (atmega328p data sheet) or Section 29.6.9 of the ATmega1280 data sheet. The AVR-gcc compiler includes macros that read (and sometimes write!) these bits and handle the special cases of “set this bit and do an LPM instruction within 5 cpu cycles” sort of thing. They’re in <avr/boot.h> (and described here: avr-libc: <avr/boot.h>: Bootloader Support Utilities )

My sketch isn’t finished in that it only has code for ATmega168x and ATmega328x, and I was going to extend it to at least ATmega8. (I had forgotten about 1280/2560. Sigh.) It does seem to work on 168 and 328 boards.

Hi dude, I've never tried to read fuse bits by mean of bootloader software before. Usually I use AVR Dragon or STK500 or even pony2000 to read these bits, i.e by mean of ISP.

The fuses are readable from software as a "special case" of the "load program memory."

thanks, westfw for sharing this useful info.

I think it's ok to read these bit s but a bit risk to write via bootloader or software because I've some experiences of losing ISP corruption and finally end up with HV parallel programing to recover.

So, thank you very much all for sharing your advice and information,

Best regards, pak

See "24.8.9 Reading the Fuse and Lock Bits from Software" (atmega328p data sheet)

Thanks for the pointer.

Here's where I went wrong...

In the current data sheet, doc8271.pdf, Rev. 8271C–AVR–08/10, chapter 24 only goes up to section 24.6.1.

Chapter 25, is titled "Self-Programming the Flash, ATmega 48A/48PA," and I could find no mention of "self-programming" any other ATmega chips. I was basing my opinion on that. I should have kept reading. It is spelled out in Chapter 27, but wasn't exactly clear to me until I saw your code. (See Footnote.)

I'll do some more investigation.

Regards,

Dave

Footnote:

Maybe someday I will learn not to say that something, "can't be done," since proving a negative is sometimes not so easy, and maybe it's even (gasp) wrong.

Maybe, just maybe, I will remember to say, "As far as I know..." or "In my opinion..." or some such thing. (And then hope for enlightenment from Someone Who Knows.)

Anyhow... Now I got it! Thank you very much for the information. Your sketch reads 328p stuff perfectly. After adding a couple of lines to cpuname.h and with minor mods for signature and the upper two bits of the high fuse byte, it works with my Mega1280 board also.

Finally:

Thank you for your patience and your code. My experience with ATmega chips is (obviously) limited.

I get a flash.h no such... error

I searched the arduino install... not anywhere i can see...

I fig'd it out - it's a 3rd party lib...

looks cool... and the fuse read thing looks like a great piece of useful code.

I need to verify the brnout settings...

I could find no mention of "self-programming" any other ATmega chips.

Ah yes, the difference between "self programming" and "bootloader support"; not the clearest of distinctions!

I think that the "self programming" ability implies that you could actually put a bootloader onto a mega48 as well (and with optiboot being only 512 bytes, it might even be useful.) It wouldn't have all the capabilities and protections of a bootloader running on one of the bigger chips, and it might have to do things like spoof the reset vector, but it might be enough for Arduino...

Works greaton my newer UNO - c/p the text from the message ended up with tabs in it tho.. and it seems to only line up correctly in monitor... other comm programs like superterm and teraterm mangle it a bit.

still a great piece of coding...thanks much!!!