Fuses and lock bits???

I got some bare 328P chips with no bootloaders. They're going into a project that I program through SPI using a usbtiny programmer, so I don't need any bootloader.

I made the rookie mistake of putting my code on the chip and expecting results. OK, so I have to set the fuses. I think I know the standard settings for the chips on Arduino boards, and that appears to work as the chip I was using came out of an UNO. But would something else be more appropriate for me? Should I clear the BOOTRST since I am not using any bootloader? How do I set the bootloader space to 0? 256 bytes seems to be the lowest setting.

And I don't need it for this project because the code is pretty small, but for the future, how do I reclaim the bootloader space for code? Can I just write over it? I've tried to understand the lockbits but I'm having a hard time putting together where SPM and LPM instructions can and can't be called with where my code ends up going.

Are there any other recommended settings for different conditions? I've found the calculators, is there a good resource somewhere that can help me make sense of the hows and whys?

I'm also a little hazy on a lot of this. But I think the BOOTRST fuse you want to set to 1, which is its unprogrammed state. In that mode a reset results in execution starting at address zero, where the application sits. If you program the fuse (set it to zero), which is how it is in an Uno, execution will start at a high address determined by the BOOTSZ fuses where the bootloader is expected to be. But since there won't be a bootloader your processor will crash, assuming I understand this correctly.

One thing you would have to do to be able to upload the full 32K with the IDE is to create an entry in boards.txt where the entire flash size is specified. The Uno entry, for example, allows 32256 to be uploaded since it expects a 512 byte bootloader to be present. If you try to upload more the IDE will give you an error, even if there is no bootloader.

There are some finer points about when/where the code can program itself which I've ignored. The only things I've fiddled with are the oscillator sources.

Somebody else will explain all this much better, soon...

Is your 328 running at 16MHz with a crystal?

dmjlambert:
Is your 328 running at 16MHz with a crystal?

Yes.

And the IDE isn't involved at all. I'm compiling code from Eclipse and uploading via avrdude on command line with the usbtiny.

The Uno fuse settings...
https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/boards.txt#L65-L69

In a "fuse calculator"...

I recommend enabling Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0].

Disable Boot Reset vector Enabled (default address=$0000); [BOOTRST=0]. That fuse causes execution to start at the beginning of the bootloader section.

Unless you have a need to protect the application for overwriting itself I suggest setting both protection modes to 1.

That should leave you with...

Should I clear the BOOTRST since I am not using any bootloader?

Yes.

How do I set the bootloader space to 0?

Can't. But the settings above make the bootloader size irrelevant.

I've tried to understand the lockbits but I'm having a hard time putting together where SPM and LPM instructions can and can't be called with where my code ends up going.

Do you have a need to block SPM?

(LPM cannot be blocked otherwise Libc will fail to initialize, the F-macro will not work, and you will not be able to read from PROGMEM.)

The reason I ask about the clock is because I do like to use the IDE and set the board to UNO and do the "upload using programmer" option. If you set preferences to show verbose during upload you can see what fuses are being set. In this way I use the IDE and the choices made by the Arduino designers as a model for the fuse settings. Then I study their choices. The ultimate resource is the datasheet for the processor, and that is what I refer to as I study the choices made for the fuse settings. In this manner I feel I am learning the specifics of fuse settings pretty well.

This is a little confusing. I think you mean that this fuse should be set to "1".

I knew what he meant.

This is a little confusing. I think you mean that this fuse should be set to "1".

On the fuse calculator "checked" means the Boot Reset Vector is Enabled.

"Checked" means "burn the fuse".

"Burn the fuse" means "write a zero".

So, when BOOTRST is zero the Boot Reset Vector is Enabled and the fuse calculator shows that as a checkmark.

Basically, in fuse-land, zero = true / feature enabled, one = false / feature disabled.

Make sense?

It makes sense. But I find it confusing, the negative logic. It makes my brain do an extra cycle or two every time. But Delta_G sees it clearly.

I never really understood why fuses are "backwards" (or indeed, are called fuses) until I see this photo:

Credit: TI TL431 adjustable shunt regulator : weekend die-shot : ZeptoBars

Apparently when they make this chip (the TL431) they tweak it after manufacture by "blowing" a fuse. This is to get the voltage reference closer to the spec.

The fuse is in the center (circled) and you blow it by putting a high current through the two pads (left and right), thus melting it.

Clearly, the blowing is a one-way operation, and before it is blown it is "1" (that is, still intact) and afterwards it it "0" (blown away). So you call "programming the fuse" the operation of blowing it, that is breaking the link.

Now the Atmega chips may have fuses that can be reset, but the concept is the same. In the factory state, they are all 1 bits, and you "program" them by blowing the fuse, making them zero.

I know that. It dates back to the days of programmable ROMs and PALs. Then we got UV erasable versions. Then electrically erasable. But at this point, couldn't they could call a "0" a "1" if they wanted to?

Might be a bit late to change. :slight_smile:

OK, so I came up with the same thing as @Coding Badly. FF D7 05. But I had already set the chip to FF DE 05 like a stock arduino and it still works even without the bootloader in there. I did a little digging, and it seems that it fills that section with FF, so it works like a big nop slide right to the start of the code.

Next time I have the programmer out, I’ll fix the bits.

One last question. Should I bother with the lock bits if I don’t need to? As I understand it, they get erased every time anyway. Does that mean I have to write them every time if I want anything other than default behavior? Should I bother with them at all until I actually need the last 256 bytes of program space (probably never)?

I wouldn’t fiddle with the lock bits myself. And if you have the fuse set to “no bootloader” I don’t know whether or not the lock bits will affect it.

Delta_G:
I got some bare 328P chips with no bootloaders. They're going into a project that I program through SPI using a usbtiny programmer, so I don't need any bootloader.

I made the rookie mistake of putting my code on the chip and expecting results. OK, so I have to set the fuses. I think I know the standard settings for the chips on Arduino boards, and that appears to work as the chip I was using came out of an UNO. But would something else be more appropriate for me? Should I clear the BOOTRST since I am not using any bootloader? How do I set the bootloader space to 0? 256 bytes seems to be the lowest setting.

And I don't need it for this project because the code is pretty small, but for the future, how do I reclaim the bootloader space for code? Can I just write over it? I've tried to understand the lockbits but I'm having a hard time putting together where SPM and LPM instructions can and can't be called with where my code ends up going.

Are there any other recommended settings for different conditions? I've found the calculators, is there a good resource somewhere that can help me make sense of the hows and whys?

The BOOTRST bit in the 328p, when programmed (that is, set to 0) makes the processor jump to the first byte of the bootloader address space which, in turn, is determined by BOOTSZ1 and BOOTSZ0 bits.

It's terribly confusing because of two things:

(1) Atmel defines the boodloader address in WORDS, not BYTES
(2) When a feature is set, usually it's bit is PROGRAMMED which means it's ZERO.

Now, an example: Say you have a bootloader which is 1024 BYTES in size. You would want to use BOOTSZ bits as follows:

BOOTSZ1 = NOT PROGRAMMED = 1
BOOTSZ0 = PROGRAMMED = 0
Therefore the bootloader resides in 512 WORDS of space beginning at 0x3E00 (15872 words) or 0x7C00 (31744 bytes) which is 32768 - 1024 = 31744.

So, with BOOTSZ1 = 1 and BOOTSZ0 = 0 and BOOTRST = 0, the processor will jump to 0x7C00 upon reset.

If BOOTRST is set to 1 (that is, NOT PROGRAMMED), then the processor will jump to 0x0000 upon reset, regardless of what BOOTSZ1 and 0 are set to.

One thing to always remember with the bass-ackwards fuse terminology Atmel uses:

FEATURE ACTIVE = CONTROL BIT PROGRAMMED = BIT is ZERO.... and
FEATURE DISABLED = CONTROL BIT NOT PROGRAMMED = BIT is ONE.

Hope this helps.

In the “old days” integrated circuits with programmable features had ACTUAL fuses on the silicon (very thin metalization which shorted two pads together). To change a feature, you would connect (usually) the VPP (programming voltage) pin to something like 12 volts with a decent capacitor in parallel with it and literally BLOW the fuse (burn away the metalization) to un-short the pads and enable/disable a feature.

This was also used with old EEPROM and OTPROM chips where once they were programmed you would blow the security fuse to prevent read access or to prevent changes (depending on what the fuse did). Obviously, this was not reversible.

Atmel simply replaced physical fuses with EEPROM or FLASH cells so that the fuses could be “blown” or “unblown” at will.

I just wish they had chosen to reverse the logic in their chips so that a “1” enabled things rather than a “0”. It’s counter intuitive and makes figuring out feature bit settings a lot harder than it needs to be.

Delta_G:
But I had already set the chip to FF DE 05 like a stock arduino and it still works even without the bootloader in there. I did a little digging, and it seems that it fills that section with FF, so it works like a big nop slide right to the start of the code.

Nope...

Next time I have the programmer out, I'll fix the bits.

Excellent choice.

There is a more serious problem lurking. If the upload image ever gets large enough to spill into the bootloader area and BOOTRST is enabled ... well ... I suspect you get the idea.

Delta_G:
Should I bother with them at all until I actually need the last 256 bytes of program space (probably never)?

The smallest bootloader size is 512 bytes. But I don't think it's relevant when programming serially. You should be able to access that space. I've had a sketch briefly skirt within 100 bytes of 32K.