I noted some online discussions where some people had troubles using an ISP programmer to program the MCU.
I do not have a (tr)uSDX (trusdx), but inspection of the schematic does hint what those users are doing wrong.
Loading the SCK, MOSI and MISO lines risks problems with operation of the SPI protocol used, but the effect depends to some extent on the driver, length and type of interconnecting cable etc.
Here are some measurements of a USBasp driving an Arduino board with 5V Atmega328P 16MHz chip using about 200mm of ribbon cable… AND the MOSI line is loaded with a 0.01µF capacitor (as in the (tr)uSDX schematic).
As mentioned, ISCP uses an SPI protocol and the capture above uses blue for SCK and cyan for MOSI.
Note that the MOSI rise time is about 1µS, and recall that MOSI is sampled at the rising edge of SCK. The very first rising transition of SCK probably samples MOSI to be logical 1 (since it is more than about 1V)… but in fact it is slowly on its way to logical 0, and has been for 0.5µs. As mentioned, different cable types and lengths, and different programmers are likely to give different results, and some might resolve this bit correctly, others might not.
But that is not what digital systems are about!
Above is the same scenario WITHOUT the 0.1µ capacitor on MOSI. There is no confusion about the value of MOSI around the rising edge of SCK… it works reliably.
The (tr)uSDX shares the MOSI pin with the external PA control jack J9 and filters the line with a 0.1µF capacitor, the work around is to slow the programmer bit rate down so that the slowed MOSI rise and fall do not cause errors, a bit clock rate of 100kHz or less (AVRDUDE -B8 command line option with USBasp) should be reliable… though of course slower to program the chip.
Above is a datastream clocked at 93.75kHz, it can be seen that the rise time is now acceptable for the SCK rate.
The default rate for AVRDUDE and USBasp is 375kHz. It would probably work most of the time in my test setup… but digital systems are about stuff that works ALL the time.
Some software and programmers may not provide a convenient way to slow the clock rate, for example the recommended ArduinoISP may require you adjust source code, the source code default is 167kHz, change to #define SPI_CLOCK (100000)
. Again, the default probably works MOST of the time, but reducing speed will make it more reliable (given the heavy MOSI filtering discussed above).
My own practice with these type of systems is to use a bat file to invoke AVRDUDE with the correct fuse settings (see WriteOptiBoot.bat), and to erase / unlock / lock the boot region to protect the boot loader from accidental damage. The bat file serves to document to required settings, and reduces the risk of accidental writing of wrong fuse values that is so easy with a GUI such as AVRDUDESS.
Above, the default fuse settings when AVRDUDESS is opened. Hitting the Write button may make changes that are very difficult to recover.
Far and away, the most common cause of unreliability in ISP is wrong / unreliable connections or unstable / insufficient power. Don’t power the target from the programmer unless you are sure there is sufficient capacity.
Learn to read and properly interpret the AVRDUDE log, checking carefully the verify steps for sizes. Look for and check EACH verification, check for both size and success.
The ‘fix’ proposed by some to remove the 0.1µF capacitor might solve the ISP issue, but create other problems, particularly if J9 is used for an external connection.
At the end of the day, this is a user problem, perhaps fueled by a lack of documentation of reliable programming speeds.
Scripts
My own practice would be to perform the bootloader and application programming using a script file (.bat) with all the relevant settings in the file to minimise the risk of programming incorrect fuses or lock bits at a later time.
Here is a bat file:
@echo off echo Copyright: Owen Duffy 2022, all rights reserved. echo. echo Processing echo. if not *%2==* ( set SERIAL=%2 echo SERIAL=%SERIAL% set FL=truSDX_%SERIAL%_Firmware.hex ) rem set defaults here if *%PORT%==* set PORT=COM25 if *%FL%==* set FL=truSDX_default-serial_Firmware.hex if *%1==*BOOT goto boot if *%1==*APP goto app :usage echo %0 BOOT ^| APP [serial] goto end :boot if *%BOOT%==* set BOOT=truSDX-initial_Bootloader.hex echo BOOT=%BOOT% set PRG=usbasp set PRG=avrisp2 set PORTB=usb set OPTS=-B 8& rem (tr)uSDX has MOSI loaded with 0.1uF rem set OPTS= set DEVICE=atmega328p set AVRDUDE=avrdude rem AVRDUDE now likes unused fuse bits set to 1 set EFUSE=0xFD& rem 0xFE for 1.8V BOD, 0xFD for 2.7V, CFD enabled (328P) set HFUSE=0xD6& rem HFUSE=0xD6 (std Optiboot 512B boot sector), HFUSE=0xD4 1kB boot sector set LFUSE=0xFF set LOCK=0xCF& rem protect boot sector echo. echo Write boot loader (%BOOT%)... echo. echo on @echo Unlock and set default HFUSE so that EEPROM can be erased %AVRDUDE% %OPTS% -c %PRG% -P %PORTB% -p %DEVICE% -e -Uhfuse:w:0xD9:m @timeout /nobreak /t 1 >nul @echo Erase FLASH and EEPROM, set FUSES %AVRDUDE% %OPTS% -c %PRG% -P %PORTB% -p %DEVICE% -e -Uefuse:w:%EFUSE%:m -Uhfuse:w:%HFUSE%:m -Ulfuse:w:%LFUSE%:m @timeout /nobreak /t 1 >nul @echo Write FLASH and LOCK bits %AVRDUDE% %OPTS% -c %PRG% -P %PORTB% -p %DEVICE% -U flash:w:"%BOOT%":i -Ulock:w:%LOCK%:m @echo off set PORTB= set BOOT= goto cleanup :app echo FL=%FL% set PRG=arduino set DEVICE=m328p set OPTS=-b 115200 rem set OPTS=-b 92160& rem fudge for testing on 16MHz board set AVRDUDE=avrdude echo. echo Write application flash (%FL%)... echo. echo on %AVRDUDE% %OPTS% -c %PRG% -P %PORT% -p %DEVICE% -U flash:w:"%FL%":i @echo off goto cleanup :cleanup echo. :end pause exit /b
Here is the console log from writing the bootloader using a USBasp:
D:\project\trusdx>prog BOOT Copyright: Owen Duffy 2022, all rights reserved. Processing BOOT=truSDX-initial_Bootloader.hex Write boot loader (truSDX-initial_Bootloader.hex)... Unlock and set default HFUSE so that EEPROM can be erased D:\project\trusdx>avrdude -B 8 -c avrisp2 -P usb -p atmega328p -e -Uhfuse:w:0xD9:m avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.01s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: erasing chip avrdude: reading input file "0xD9" avrdude: writing hfuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of hfuse written avrdude: verifying hfuse memory against 0xD9: Reading | ################################################## | 100% 0.00s avrdude: 1 bytes of hfuse verified avrdude done. Thank you. Erase FLASH and EEPROM, set FUSES D:\project\trusdx>avrdude -B 8 -c avrisp2 -P usb -p atmega328p -e -Uefuse:w:0xFD:m -Uhfuse:w:0xD6:m -Ulfuse:w:0xFF:m avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: erasing chip avrdude: reading input file "0xFD" avrdude: writing efuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of efuse written avrdude: verifying efuse memory against 0xFD: Reading | ################################################## | 100% 0.00s avrdude: 1 bytes of efuse verified avrdude: reading input file "0xD6" avrdude: writing hfuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of hfuse written avrdude: verifying hfuse memory against 0xD6: Reading | ################################################## | 100% 0.00s avrdude: 1 bytes of hfuse verified avrdude: reading input file "0xFF" avrdude: writing lfuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of lfuse written avrdude: verifying lfuse memory against 0xFF: Reading | ################################################## | 100% 0.00s avrdude: 1 bytes of lfuse verified avrdude done. Thank you. Write FLASH and LOCK bits D:\project\trusdx>avrdude -B 8 -c avrisp2 -P usb -p atmega328p -U flash:w:"truSDX-initial_Bootloader.hex":i -Ulock:w:0xCF:m avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: reading input file "truSDX-initial_Bootloader.hex" avrdude: writing flash (32768 bytes): Writing | ################################################## | 100% 9.93s avrdude: 32768 bytes of flash written avrdude: verifying flash memory against truSDX-initial_Bootloader.hex: Reading | ################################################## | 100% 9.42s avrdude: 32768 bytes of flash verified avrdude: reading input file "0xCF" avrdude: writing lock (1 bytes): Writing | ################################################## | 100% 0.02s avrdude: 1 bytes of lock written avrdude: verifying lock memory against 0xCF: Reading | ################################################## | 100% 0.00s avrdude: 1 bytes of lock verified avrdude done. Thank you. Press any key to continue . . .
If there is any reason to doubt the bootloader writing process (flash and FUSES), redo it. Experience reported by some users is that if application firmware won’t load or run properly, starting again by writing the bootloader then application firmware has resolved their problem.
A check list of things to increase the probability of success writing the bootloader and FUSES:
- use and ISP programmer connected to the ISP header with short wires;
- make sure the connections are correct and reliable;
- power the target independently of the programmer
- use a low resistance / short USB cable;
- be very very very careful specifying FUSES (you can make the chip very difficult to program if you program incompatible FUSES);
- set the bit clock to less than 100kHz (in source code for the ArduinoISP sketch);
- make sure you have specified the bootloader hex file;
- save the AVRDUDE log, and check it very carefully for 4 separate write commands (-U) followed by their verify report, and check the verify is for the data source and data length you expected.
Erasing EEPROM
If there is a need to erase EEPROM, it can become a bit tricky.
Whilst the -e switch erased EEPROM on a new from factory ATmega328P (which already has an erased EEPROM), if the preserve EEPROM FUSE is programmed, then -e does not erase the EEPROM. Be aware that (tr)uSDX programs that FUSE, so if the FUSES have been programmed for (tr)uSDX, you need to change the fuses (with an ISP programmer) to not preserve EEPROM, or simply write the file 1k-FF.bin contained in 1k-FF.7z which is raw binary to the EEPROM (it should damage the existing bootloader and application code in FLASH or the FUSES.
Be very very careful messing with FUSES, you may render the chip very hard to reprogram.
The bat file above takes care of the detail of erasing EEPROM.
Going forward
Good luck, it should be very straightforward, but not everyone finds it so.