Been a while since I did any work on these - I have a whole bunch in the "unfinished project" pile that needed to be programmed. This time decided to use my Mac. Notes dump as follows
First off installed the Arduino IDE from here.
https://www.arduino.cc/en/software
Then added the minicore here
https://github.com/MCUdude/MiniCore
Then remembered that I hated the Arduino IDE and decided to do as much as possible from the command line
Then installed brew
https://brew.sh
Then used Brew to install AVR Dude
https://formulae.brew.sh/formula/avrdude#default
Then followed the instructions from the brew output to ad AVRdude to the path
If this was windows I would have needed to fix the USBasp driver (which is way harder than you would imagine!) but on Mac it is already installed
So from here I was ready to verify that my toolchain (AVRdude to ASP programer to SAT2NEO QPB to SAT2NEO device) could talk to the target device by reading the fuses off the ATmega. Something like this will read the lower fuse
avrdude -CC:\Users\hatmoose\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.3/avrdude.conf -v -patmega328pb -cusbasp -Pusb -U lfuse:r:-:i -v
-C is the location of the minicore config file (mini core has the advanced settings for ATmega chips)
-v means verbose (so it will tell me what's going on)
-p is the kind of chip we want to program (for me it was a 328pb)
-c is the programer type (its an ASP with USB interface)
-P is the port (USB is the port we'll be using)
-U is the memory operation (read the LFUSE and print the output to stdout)
-v means ever more verbose (so it will tell me exactly what's going on)
Because we are just reading in this operation we don’t really need the config file, so you could shorten it to something like this
Avrdude -v -patmega328pb -cusbasp -Pusb -U lfuse:r:-:i -v
Which should output this for LFUSE, assuming it’s a brand new chip and no-one has already set the LFUSE
Avrdude: writing output file "<stdout>"
:01000000621D
:00000001FF
We need to change this from :01000000621D to :01000000E21D which we will do in a bit, but for a fresh chip 62 is the correct default
Avrdude -v -patmega328pb -cusbasp -Pusb -U hfuse:r:-:i -v
Which should output this for HFUSE, assuming it’s a brand new chip and no-one has already set the HFUSE
Avrdude: writing output file "<stdout>"
:01000000D926
:00000001FF
We don’t need to change this
Avrdude -v -patmega328pb -cusbasp -Pusb -U efuse:r:-:i -v
Which should output this for EFUSE, assuming it’s a brand new chip and no-one has already set the EFUSE
Avrdude: writing output file "<stdout>"
:01000000F708
:00000001FF
We don’t need to change this either
So then I knew that my toolchain was good and that my target device was good, time to write the code and set the fuses
Its good opec to compile your own code from source when avaIlable - in this case its a tiny embedded device that talks to a Saturn controller and a Supergun so the risk is pretty low - but good practise is good practise.
So I jumped back into the IDE loaded the sketch source (.ino) and compiled it into a binary (.hex) - I called it SAT2NEO.hex which in hindsight was confusing AF, I should have called it “freshly compiled and ready to deploy.hex” or something.
Then I used the IDE to export the binary
Then I remembered that I had not compiled it for the 328pb, so back into the IDE set the "board" to mini core -> ATMEGA328.
Im pretty sure that none of the other settings matter, but just in case I also set the clock to external 8mhz and the variant to 328pb as well
Then I compiled and exported again
At that point I was ready to push the code to the device
You could use something like this to push the code
avrdude -v -patmega328pb -cusbasp -Pusb -Uflash:w:/Users/hatmoose/Downloads/SAT2NEO/Code/saturn_controller_demux_RMAF_RBF_SLFI

SAT2NEO.hex:i -v
This is actually two operations, first it clears the flash memory, then it writes the new code. If there is existing code on there and the lock bit is set you may get “target does not answer” in which case you can add the -F flag to force it.
avrdude -v -patmega328pb -cusbasp -Pusb -Uflash:w:/Users/hatmoose/Downloads/SAT2NEO/Code/saturn_controller_demux_RMAF_RBF_SLFI

SAT2NEO.hex:i -v -F
Once the code is pushed you can use this to set Lower Fuse to 8mhz external to the ATmega can run the code independently
Avrdude -v -patmega328pb -cusbasp -Pusb -U lfuse:w:0xe2:m -v
In a lot of cases you only get one chance to set the Lower Fuse, if you set it incorreclty (for example to internal) then the SAT2NEO does not have any of the circuitry required to generate an internal clock signal so your ASP will no longer be able to see the chip to re-write the LFUSE setting. At this point you’ll need to unsolder the ATmega, put it on a development board which can generate an internal clock signal, then use that so the ASP can re-write the fuses.
It’s also possible to set it just plan wrong, for example if you do your hex calculation wrong it’s possible to set the fuses to something that make no sense at all, in that case it’s probably best to toss the chip and start again.
Anyhoo at that point if we re-run this to check LFUSE we should get
Avrdude -v -patmega328pb -cusbasp -Pusb -U lfuse:r:-:i -v
Which should output this for LFUSE, assuming it’s a brand new chip and no-one has already set the LFUSE
Avrdude: writing output file "<stdout>"
:01000000E21D
:00000001FF
Note that :01000000621D has been changed to to :01000000E21D
E2 is Hex for “8 MHz internal” so at this point we are ready to start testing.
If you want to know more about fuse bits this site has a good description - it assumes you have a degree in computer science and can calculate your own Hex and offset from Binary
https://binaryupdates.com/setting-avr-fuse-bits/
but its important to note that this site shows the defaults are the defaults for the ATMEGA on a prebuilt development board (E1 and 99) - Because we’re using bare chips our defaults are going to be factory (62 and D9)

