Executive Summary: the fuses need to be programmed correctly!
Notes:
- I used a super-cheap ‘usbasp’ programmer
- I used an old Mac which had the Arduino app on it
- In MacOSX, applications are a type of folder so in a command window: cd /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/
- That folder has the avrdude program in it
- I used these flags (upper case and lower case are different so type them exactly!):
- programmer (-c usbasp) and port (-P usb)
- avrdude.conf file explicitly with -C option
- correct part number -p m88 (NOT -p m88p like someone wrote somewhere)
- -B 1 something to do with timing
- -U efuse:w:0xF9:m -U hfuse:w:0xDF:m -U lfuse:w:0xFF:m to program the three fuses
- -u to tell it to ignore when the efuse doesn’t verify correctly (see below)
- -U flash:w:LZX-C1-SW-V1.0.bin to program the actual flash image (see below - this is not the .elf file!)
The biggest learning for me was that the .elf file is a container with various data inside it. Mostly it’s the actual flash binary, but my avrdude program couldn’t read .elf files directly, so I had to use avr-objcopy first to extract that binary image into another file.
These links were helpful:
https://helpmanual.io/help/avr-objdump/
As well as the binary the .elf file has the fuse settings in there. I used avr-objdump to dump out the entire contents of the .elf file to see what they should be set to.
When avrdude verifies the efuse values it has just written it gets back a different value. I program it as “0xff” but it gets back “0x01”. That’s apparently quite OK, which is why the -u flag is required to tell avrdude that it’s OK that it appears to have failed. This calculator was helpful: http://www.engbedded.com/fusecalc/
It says: " * Note that some numerical values refer to fuses containing undefined bits (set to ‘1’ here). Depending on the target device these fuse bits will be read either as ‘0’ or ‘1’. Verification errors will occur if the values are read back with undefined bits set to ‘0’. Everything is fine if the values read from the device are either the same as programmed, or the following values (undefined set to ‘0’): Extended: 0x01 ."
Also, I had the programmer plugged in backwards the first few times (doh!)
If you can use a GUI program instead of the command line I suspect things will be much easier and you won’t need to know all that stuff above, but sadly I don’t have a computer that I could install one on to.
Also note that you can program the fuses and flash separately, one at a time, with multiple calls to avrdude. That was helpful as I could see that hfuse and lfuse were successful, then work on efuse and the flash image separately until I got them to work.
Here are some command lines I used.
Change into the avrdude program folder:
cd /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/
I copied the LZX elf image file into that same folder, for convenience.
Dump the .elf file contents to see the fuse values:
./avr-objdump -s LZX-C1-SW-V1.0.elf
Extract the flash image into a separate file:
./avr-objcopy LZX-C1-SW-V1.0.elf -O binary LZX-C1-SW-V1.0.bin -j .text
Flash only:
./avrdude -c usbasp -p m88 -P usb -B 1 -U flash:w:LZX-C1-SW-V1.0.bin -C …/etc/avrdude.conf
Fuses:
./avrdude -c usbasp -p m88 -P usb -B 1 -U lfuse:w:0xFF:m -U hfuse:w:0xDF:m -U efuse:w:0xF9:m -u -C …/etc/avrdude.conf
Just the efuse on its own:
./avrdude -c usbasp -p m88 -P usb -B 1 -U efuse:w:0xF9:m -u -C …/etc/avrdude.conf
This shows the fuses being programmed, along with the efuse verification error which you can safely ignore:
avrdude: set SCK frequency to 750000 Hz
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e930a
avrdude: reading input file "0xFF"
avrdude: writing lfuse (1 bytes):
Writing | ################################################## | 100% 0.00s
avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xFF:
avrdude: load data lfuse data from input file 0xFF:
avrdude: input file 0xFF contains 1 bytes
avrdude: reading on-chip lfuse data:
Reading | ################################################## | 100% 0.00s
avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "0xDF"
avrdude: writing hfuse (1 bytes):
Writing | ################################################## | 100% 0.00s
avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xDF:
avrdude: load data hfuse data from input file 0xDF:
avrdude: input file 0xDF contains 1 bytes
avrdude: reading on-chip hfuse data:
Reading | ################################################## | 100% 0.00s
avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xF9"
avrdude: writing efuse (1 bytes):
Writing | | 0% 0.00s ***failed;
Writing | ################################################## | 100% 0.03s
avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xF9:
avrdude: load data efuse data from input file 0xF9:
avrdude: input file 0xF9 contains 1 bytes
avrdude: reading on-chip efuse data:
Reading | ################################################## | 100% 0.00s
avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0000
0x01 != 0xf9
avrdude: verification error; content mismatch
avrdude done. Thank you.
Thank you to everyone who helped, particularly transistorcat and csboling.