Resettings Fuses And Lock Bits

I've been using Arduino for several years now and I'm just getting into the more hardcore aspects such as setting fuses and lock bits. I've done a lot of reading, but I'm still confused.

I'm sure this has been answered before, but here goes.

I'm working with 3.3V Pro Minis clocked at 8 MHz with the ATMega328p chips.

It looks like you can set the lock bits over the serial interface using AVRDUDE, but I'm not clear on a few things about what happens after that:

  1. If flash read and write are both disabled, then you can't use SPI to read or write the flash. However, can the arduino boot loader still do it? Meaning, the boot loader could still be used to upload sketches. Some sources say no, some suggest yes. I don't want to brick an MCU finding out.

  2. Once the lock bits are set, is the only way to clear them with the use of an additional device other than the FTDI breakout that I use to upload sketches? I.e. something like the USBtinyISP?

1 Like

It looks like you can set the lock bits over the serial interface using AVRDUDE,

No, you can only set the lock bits using the ISP interface and an external programmer. A bootloader CANNOT change the fuses or lock bits. (it might SAY that it has done so, for compatibility with programming SW. But it can't.)

If flash read and write are both disabled, then you can't use SPI to read or write the flash.

There are three sets of "lock bits." One controls access by the programming interface, one controls programatic access to the bootloader section, and one controls programatic access to the applications section. The way I read the documentation, the bootloader would work even if the SPI access is disabled. But you probably need to risk a chip to be sure...

There's another fuse that disables SPI programming, which would mean that you would need to connect the chip to a High Voltage Parallel Programmer in order to erase it.

1 Like

westfw:
No, you can only set the lock bits using the ISP interface and an external programmer. A bootloader CANNOT change the fuses or lock bits. (it might SAY that it has done so, for compatibility with programming SW. But it can't.)

Thanks for the reply. I think you're right about that it's faking compatibility with some of the AVRDUDE commands. While connected via FTDI to the normal programming interface on the Pro Mini, if I enter this command:

avrdude -patmega328p -carduino -PCOM3 -b57600 -Ulock:r:d:\hexfiles\lockbyte.txt:h

I get a text file out that reads:

0x0

If I'm reading the 328p data sheet right, that would mean that all the memory protections are turned on and the chip should not be able to accept a program. That's clearly not the case.

westfw:
There are three sets of "lock bits." One controls access by the programming interface, one controls programatic access to the bootloader section, and one controls programatic access to the applications section. The way I read the documentation, the bootloader would work even if the SPI access is disabled. But you probably need to risk a chip to be sure...

Maybe I'll risk a cheap clone. I treasure my genuine boards too much to risk them.

westfw:
There's another fuse that disables SPI programming, which would mean that you would need to connect the chip to a High Voltage Parallel Programmer in order to erase it.

Yeah, I'm not touching that one with a 10-foot pole!

Ok, so I'm guessing if I get the aforementioned USBtinyISP programmer, then wire it up something like this:

Then maybe I just might be able to use AVRDUDE to read and write fuses and lock bits properly.

To recover and make the chip writable again in the case I activate flash memory protection, I think I can recover by burning the bootloader from the arduino IDE. Right?

Assuming ISP is still connected as above, from within the Arduino IDE:

  1. Tools-->Board --> Arduino Pro or Pro Mini
  2. Tools-->Processor --> ATMega328 (3V, 8 MHz)
  3. Tools-->Programmer-->USBTinyISP
  4. Tools--> Burn Bootloader

As I understand it, part of the bootloader burning process is to perform a chip erase, which will reset the fuses and lock bits back to arduino defaults. I just have to be careful not to disable ISP programming by flipping that protection fuse. Am I getting any of this right?

I think you are heading the right direction. There are fuse calculators online which can help you figure out the fuse values to try. Have a look at the ATmega328P data sheet. Ask questions about any specific values you wonder about.

In the Arduino IDE preferences you can check show verbose output on upload. Then when you burn the bootloader (which also sets fuses) you will be shown the avrdude commands used during the process. Copy those commands to a notepad and use them as models.

Don't use the Raw pin of the Arduino during programming, just connect the 5V from the programmer to the VCC pin of the Arduino.

Ok, I think I'm figuring this stuff out. I've spent several hours studying the ATMega328p datasheet and the AVRDUDE documentation as well as various forum posts.

The fuse defaults for Arduino can be gleaned from boards.txt:

pro.name=Arduino Pro or Pro Mini

pro.upload.tool=avrdude
pro.upload.protocol=arduino

pro.bootloader.tool=avrdude
pro.bootloader.unlock_bits=0x3F
pro.bootloader.lock_bits=0x0F
...
## Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega328
menu.cpu.pro.8MHzatmega328=ATmega328 (3.3V, 8 MHz)

menu.cpu.pro.8MHzatmega328.upload.maximum_size=30720
menu.cpu.pro.8MHzatmega328.upload.speed=57600

menu.cpu.pro.8MHzatmega328.bootloader.low_fuses=0xFF
menu.cpu.pro.8MHzatmega328.bootloader.high_fuses=0xDA
menu.cpu.pro.8MHzatmega328.bootloader.extended_fuses=0x05
menu.cpu.pro.8MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex

I'm not sure what "unlock_bits" does, it's not mentioned in the ATMega328p data sheet, but the rest is pretty clear.

So, I whipped up a batch file to try when my Usbtiny ISP arrives (ordered it yesterday).

@rem Erase chip
avrdude -p atmega328p -c usbtiny -b57600 -e

@rem Upload the program
avrdude -p atmega328p -c usbtiny -b57600 -D -U flash:w:d:\hexfiles\MyProgram.hex:i

@rem Set Low Fuse byte exactly as Arduno does (all disabled, apparently)
avrdude -p atmega328p -c usbtiny -b57600 -D -u -U lfuse:w:0xFF:m

@rem Set High Fuse Byte to disable bootloader and just run the MyProgram directly
avrdude -p atmega328p -c usbtiny -b57600 -D -u -U hfuse:w:0xDF:m

@rem Set extended fuse to enable brownout detection at ~2.7V (Exactly the same as Arduino defaults)
avrdude -p atmega328p -c usbtiny -b57600 -D -u -U efuse:w:0x05:m

@rem Lock down the flash to disable read/write
avrdude -p atmega328p -c usbtiny -b57600 -D -u -U lock:w:0xFC:m

Now, I was careful to make sure the High fuse byte has SPIEN set to 0, meaning that serial programming is enabled.
The only other change in that byte was that I disabled the bootloader to allow my program run directly by clearing (setting to 1) the bits for BOOTRST (bit 0), BOOTSZ0 (bit 1), and BOOTSZ1 (bit 2).

So, the High fuse byte looks like this:
RSTDISBL = 1 (meaning external reset enabled)
DWEN = 1 (meaning debug wire disabled)
SPIEN = 0 (meaning serial programming is enabled)
WDTON = 1 (meaing watchdog timer is not always enabled)
EESAVE = 1 (meaning EEPROM will not be preserved during chip erase)
BOOTSZ1 = 1 (not needed since BOOTRST is not set to enable bootloader)
BOOTSZ2 = 1 (not needed since BOOTRST is not set to enable bootloader)
BOOTRST = 1 (meaning a bootloader is not used and program should start immeidately after reset)

I may first try to burn the bootloader first from the IDE as described earlier just to test the ISP is working.

I know this is a monster post, but I really want to make sure I've got my ducks in a row and there is a lot that needs to be right. I've done my homework, I just need it graded.

1 Like

B+, good job!

See also AVR® Fuse Calculator – The Engbedded Blog
Atmel Studio will also give you a nice GUI fuse calculator as part of the tools/device programming menu - you can use it with the 'simulator' even with no actual device attached, and no project open.
They seem to agree with your values!

I'm not sure what "unlock_bits" does, it's not mentioned in the ATMega328p data sheet

When you do a "burn bootloader" operation, the IDE uses avrdude in three steps:

  1. Erase the chip and set the the lock bits to the "unlock_bits" value.
  2. upload the bootloader code.
  3. Set the lock bits to the "lock_bits" value, to protect the bootloader from damaging itself, or being read by the application.
    Now, (1) is a bit overkill, since erasing the chip also erases the lock bits. And I don't see the value of preventing the application from reading the bootloader. But this is what it does.

Now, I few additional details:

avrdude -p atmega328p -c usbtiny -b57600 -D -u -U efuse:w:0x05:m

You probably don't need to specify the bitrate for a USB-connected programmer.
efuse has "unused" bits, and avrdude may want them set to "1" instead of "0", making the efuse value 0xFD instead of 5.
You can put multiple "-U" commands on a single line, and this might be a good idea, because some USB devices reset and re-enumerate between commands, and they might not be "available" for back-to-back commands in a batch file. (there's actually a bug open for the IDE when used with the Atmel Dragon programmer, because that three-step process can happen too fast for the dragon/windows combination.)

Thanks for the replies again, guys. I may have to try out that emulator. I didn't know there was such a thing. It would be nice to have a sandbox where I can try things out without risking a physical chip.

I made some updates based on the comments.

  • Agree that I probably don't need to specify a baud rate for a USB device.
  • Changed efuse to 0xFD to avoid setting unused upper bits.
@rem Erase chip
avrdude -p atmega328p -c usbtiny -e

@rem Upload the program
avrdude -p atmega328p -c usbtiny -D -U flash:w:d:\hexfiles\MyProgram.hex:i

@rem Set Low Fuse byte exactly as Arduno does (all disabled, apparently)
avrdude -p atmega328p -c usbtiny -D -u -U lfuse:w:0xFF:m

@rem Set High Fuse Byte to disable bootloader and just run the MyProgram directly
avrdude -p atmega328p -c usbtiny -D -u -U hfuse:w:0xDF:m

@rem Set extended fuse to enable brownout detection at ~2.7V (Exactly the same as Arduino defaults except upper two bits are not cleared to zero)
avrdude -p atmega328p -c usbtiny -D -u -U efuse:w:0xFD:m

@rem Lock down the flash to disable read/write
avrdude -p atmega328p -c usbtiny -D -u -U lock:w:0xFC:m

So, am I correct in my understanding that when a chip erase is performed, the lock byte get reset, but not the fuse bytes? So, unlike the lock byte, you can just set the Fuse bytes whenever you want willy-nilly?

Also, if I leave this as separate commands, I assume reset will be pulled low on the MCU for each command and then returned to high afterward. This would allow my program to potentially execute between commands. If my sketch used the programming pins for I/O, could this potentially damage the programmer if they were suddenly to go high, for example?

you can just set the Fuse bytes whenever you want willy-nilly?

Yes.

This would allow my program to potentially execute between commands.

Well, not if the first command was the chip erase. Erased memory on an AVR is a relative inconsequential near-noop.
If you use the programming pins for other purposes, you're supposed to include some isolation circuitry (documented in some app note) to make sure you can still do ISP programming.

westfw:
Well, not if the first command was the chip erase. Erased memory on an AVR is a relative inconsequential near-noop.
If you use the programming pins for other purposes, you're supposed to include some isolation circuitry (documented in some app note) to make sure you can still do ISP programming.

Hmm... I wonder if I could mitigate by using the -E option to specify that reset should stay low after programming. That would give me time to disconnect power from the MCU and unplug it from the programmer.

For example:

avrdude -p atmega328p -c usbtiny -D -E reset -U flash:w:d:\hexfiles\MyProgram.hex:i

Hi!

I am playing with ATmega chips for two weeks using Arduino IDE, Atmel Studio 7, CodeBlocks, Eclipse just to have fun. I also read datasheets and internet forums. After two weeks I finally realized that when you download bootloader from Arduino then it will set LB1 and LB2 to "0" that means you cannot write anything to flash. The only possibility is to erase the whole memory using avrdude or reload program via Arduino. The reason is to protect software from reverse engineering.
To play with fuses I use very good program AVR-burn-o-mat - http://avr8-burn-o-mat.brischalle.de - GNU license.

"when you download bootloader from Arduino then it will set LB1 and LB2 to "0""

I disagree. Look at boards.txt:

uno.bootloader.unlock_bits=0x3F

uno.bootloader.lock_bits=0x0F

That is the unlocked state.

0 means locked

Just check lock bits after downloading bootloader.

avrdude -p... -c... U:lock:r....

page 271 in datasheet
Bit 7 6 5 4 3 2 1 0
Rd – – BLB12 BLB11 BLB02 BLB01 LB2 LB1

"
ATmega88A/88PA/168A/168PA/328/328Pprovides six

Lock bits. These can be left unprogrammed (“1”) or can be programmed (“0”) to obtain the additional features

listed in Table 28-2. The Lock bits can only be erased to “1” with the Chip Erase command."
0x3F = 0011 1111 - so all 6 bits unlocked. I don't know what you have set up that is causing them to lock. A standard bootload using the IDE will not lock them.

i've got 0x0f in lock bits after loading bootloader from Arduino IDE and I was unable to load something to my ATmega328P from Atmel Studio. After erasing memory by avrdude lock bits have been 0x3f..

I think everything is OK. Just it is difficult to find problems when you play with different tools. If you are using only Arduino IDE evething is OK. If you want to play you must have fun to find something ...

avocadobeta:
i've got 0x0f in lock bits after loading bootloader from Arduino IDE and I was unable to load something to my ATmega328P from Atmel Studio. After erasing memory by avrdude lock bits have been 0x3f..

That much at least makes sense. The upper two lock bits aren't used anyway, so it probably doesn't matter what those are set to. It looks like the lower six bits are all "cleared" to their "unprogrammed" state after erase and set to 1. That seems to agree with the datasheet I've been reading.

Rd - - BLB12 BLB11 BLB02 BLB01 LB2 LB1

Right. And the "Burn Bootloader" command sets that byte to 0x0F (0b001111), which means that it has zero'ed (enabled)
BLB12 and BLB11 (not LB2/LB1)
Having BLB1 set to zero means "SPM is not allowed to write to the Boot Loader section, and LPM executing from the Application section is not allowed to read from the Boot Loader section." according to the data sheet,

BLB0 is 0b11, meaning "No restrictions for SPM or LPM accessing the Application section."
and LB is 0b11, meaning "No memory lock features enabled."