Burn Bootloader for a custom Atmega328P board

Hello,

I have some custom atmega328P board that have no bootloader on. I am using arduino IDE to burn a new bootloader with a UNO board.
Now, I want to use the burn bootloader of platformIO but I am not able to make it work even if I got a success message after burn bootloader.

What i don’t understand is that i have a success message whereas I am still unable to upload a simple program to my board. When I do the same operation with arduino ide. I don’t have those issue.

I don’t really understand if it is possible to burn bootloader whithout using a script suggest in this warning message :

Warning: The custom upload protocol is used! The upload and fuse flags may conflict!

I am just using the programmer “arduino as isp” used in arduino IDE too : Atmel AVR — PlatformIO latest documentation
With some extra argument such as :

board_hardware.oscillator = external ; added
board_build.f_cpu = 4000000L ;added 4 MHz

I got the following platformio.ini configuration

platformio.ini
[common_env_data]
platform = atmelavr
framework = arduino
src_filter = ${env.src_filter}  +<bootloader.cpp>


[env:uno]
platform = atmelavr
board = uno
framework = arduino

[env:program_via_ArduinoISP]
platform = ${common_env_data.platform}
framework =${common_env_data.framework}
board = atmega328p
board_hardware.oscillator = external ; added
board_build.f_cpu = 4000000L ;added 4 MHz
upload_protocol = custom
upload_port = COM10 
upload_speed = 19200
upload_flags =
    -C
    ; use "tool-avrdude-megaavr" for the atmelmegaavr platform
    $PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
    -p
    $BOARD_MCU
    -P
    $UPLOAD_PORT
    -b
    $UPLOAD_SPEED
    -c
    stk500v1
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i
src_filter =${common_env_data.src_filter}
lib_extra_dirs = 
    /lib

If I try to understand what is doing burn bootloader:

  • it first recognize the target device with its signature
  • then it check the fuses
  • finally it upload the bootloader
result after burn bootloader platformio
Executing task in folder bootloader: C:\Users\name_user\.platformio\penv\Scripts\platformio.exe run --target bootloader --environment p

Processing program_via_ArduinoISP (platform: atmelavr; framework: arduino; board: atmega328p)
------------------------------------------------------------------------------------------------------------------------------------------------CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/atmega328p.html
PLATFORM: Atmel AVR (3.3.0) > ATmega328P/PA
HARDWARE: ATMEGA328P 4MHz, 2KB RAM, 32KB Flash       
DEBUG: Current (avr-stub) On-board (avr-stub, simavr)
PACKAGES:
 - framework-arduino-avr-minicore 2.1.1
 - toolchain-atmelavr 1.70300.191015 (7.3.0)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 19 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <SPI> (C:\Users\name_user\Documents\Code\platform\project\bootloader\lib\SPI)
|-- <Wire> 1.0 (C:\Users\name_user\.platformio\packages\framework-arduino-avr-minicore\libraries\Wire)
Building in release mode

TARGET CONFIGURATION:
---------------------
Target = atmega328p
Clock speed = 4000000L
Oscillator = external
BOD level = 2.7v
Save EEPROM = yes
UART port = uart0
Clock output = no
---------------------
Warning: The `custom` upload protocol is used! The upload and fuse flags may conflict!
More information: https://docs.platformio.org/en/latest/platforms/atmelavr.html#overriding-default-fuses-command


Selected fuses: [lfuse = 0xf7, hfuse = 0xd6, efuse = 0xfd]
Warning: The `custom` upload protocol is used! The upload and fuse flags may conflict!
More information: https://docs.platformio.org/en/latest/platforms/atmelavr.html#overriding-default-bootloader-command

avrdude -p atmega328p -C "C:\Users\name_user\.platformio\packages\tool-avrdude\avrdude.conf" -e -C C:\Users\name_user\.platformio\d6:m -Ulfuse:w:0xf7:m -Uefuse:w:0xfd:m

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: erasing chip
avrdude: reading input file "0x3F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x3F:
avrdude: load data lock data from input file 0x3F:
avrdude: input file 0x3F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lock 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:
avrdude: load data hfuse data from input file 0xd6:
avrdude: input file 0xd6 contains 1 bytes
avrdude: reading on-chip hfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xf7"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xf7:
avrdude: load data lfuse data from input file 0xf7:
avrdude: input file 0xf7 contains 1 bytes
avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
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:
avrdude: load data efuse data from input file 0xfd:
avrdude: input file 0xfd contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of efuse verified

avrdude: safemode: Fuses OK (E:FD, H:D6, L:F7)

avrdude done.  Thank you.

avrdude -p atmega328p -C "C:\Users\name_user\.platformio\packages\tool-avrdude\avrdude.conf" -C C:\Users\name_user\.platformio\pacigeon\.platformio\packages\framework-arduino-avr-minicore\bootloaders\optiboot_flash\bootloaders\atmega328p\4000000L\optiboot_flash_atmega328p_U

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

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 "C:\Users\name_user\.platformio\packages\framework-arduino-avr-minicore\bootloaders\optiboot_flash\bootloader
avrdude: writing flash (32768 bytes):

Writing | ################################################## | 100% -0.00s

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against C:\Users\name_user\.platformio\packages\framework-arduino-avr-minicore\bootloaders\optiboot_flash
avrdude: load data flash data from input file C:\Users\name_user\.platformio\packages\framework-arduino-avr-minicore\bootloaders\optiboot
avrdude: input file C:\Users\name_user\.platformio\packages\framework-arduino-avr-minicore\bootloaders\optiboot_flash\bootloaders\atmega3
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 32768 bytes of flash verified
avrdude: reading input file "0x0F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x0F:
avrdude: load data lock data from input file 0x0F:
avrdude: input file 0x0F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lock verified

avrdude: safemode: Fuses OK (E:FD, H:D6, L:F7)

avrdude done.  Thank you.

=============================================================================================================== [SUCCESS] Took 4.01 seconds ====
Environment             Status    Duration
----------------------  --------  ------------
program_via_ArduinoISP  SUCCESS   00:00:04.014
=============================================================================================================== 1 succeeded in 00:00:04.014 ====
arduino IDE burn bootloader
C:\Users\name_user\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino18/bin/avrdude -CC:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/avrdude.conf -v -patmega328p -cstk500v1 -PCOM10 -b19200 -Uflash:w:C:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/bootloaders/optiboot_flash/bootloaders/atmega328p/4000000L/optiboot_flash_atmega328p_UART0_9600_4000000L_B5.hex:i -Ulock:w:0x0f:m 

avrdude: Version 6.3-20201216
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/avrdude.conf"

         Using Port                    : COM10
         Using Programmer              : stk500v1
         Overriding Baud Rate          : 19200
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : STK500
         Description     : Atmel STK500 Version 1.x firmware
         Hardware Version: 2
         Firmware Version: 1.18
         Topcard         : Unknown
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

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 "C:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/bootloaders/optiboot_flash/bootloaders/atmega328p/4000000L/optiboot_flash_atmega328p_UART0_9600_4000000L_B5.hex"
avrdude: writing flash (32768 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against C:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/bootloaders/optiboot_flash/bootloaders/atmega328p/4000000L/optiboot_flash_atmega328p_UART0_9600_4000000L_B5.hex:
avrdude: load data flash data from input file C:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/bootloaders/optiboot_flash/bootloaders/atmega328p/4000000L/optiboot_flash_atmega328p_UART0_9600_4000000L_B5.hex:
avrdude: input file C:\Users\name_user\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2/bootloaders/optiboot_flash/bootloaders/atmega328p/4000000L/optiboot_flash_atmega328p_UART0_9600_4000000L_B5.hex contains 32768 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% -0.00s

avrdude: verifying ...
avrdude: 32768 bytes of flash verified
avrdude: reading input file "0x0f"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.03s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x0f:
avrdude: load data lock data from input file 0x0f:
avrdude: input file 0x0f contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lock verified

avrdude done.  Thank you.

Have a nice day :slight_smile:

Is there someone who was successful with platformio burn bootloader ?
Or any idea how I could debug my config to burn a bootloader correctly with platformio ?

I am not really famillar with bootloader. I am starting to understand a bit how avrdude works.

It appears that you might not be burning a bootloader? In the output, I see this avrdude command – which I’ve split over a few lines for clarity:

avrdude -p atmega328p 
-C "C:\Users\USER_NAME\.platformio\packages\tool-avrdude\avrdude.conf" 
-C C:\Users\USER_NAME\.platformio\pacigeon\.platformio\packages\framework-arduino-avr-minicore\bootloaders\optiboot_flash\bootloaders\atmega328p\4000000L\optiboot_flash_atmega328p_U

The weird thing here is, as far as I can see, you are specifying the avrdude config file twice using the -C option. The first is the (correct) config file but the second is this:

C:\Users\USER_NAME\.platformio\pacigeon\
.platformio\packages\framework-arduino-avr-minicore\
bootloaders\optiboot_flash\bootloaders\atmega328p
\4000000L\optiboot_flash_atmega328p_U

Again, I’ve split the line to make it a bit more readable. I see what looks like bits of the command line and bits of the bootloader file all mixed in there - is that path correct?

I would expect to see a command something like:

avrdude -p atmega328p
-C "C:\Users\USER_NAME\.platformio\packages\tool-avrdude\avrdude.conf" 
-c <upload protocol of some kind>
-Uflash:w:<your bootloader hex file>:i
-Ulock:w:<atmega328p lock byte address>:m

Just for “fun” I connected up an Uno and burned the default bootloader. Obviously, using an ICSP to actually burn it:

pio run -t bootloader

Using the command line there by the way. My platformio.ini looks like this:

[env:uno]
platform = atmelavr
board = uno
framework = arduino

board_bootloader.file = /home/norman/.platformio/packages/framework-arduino-avr/bootloaders/optiboot/optiboot_atmega328.hex
board_bootloader.lfuse = 0xFF
board_bootloader.hfuse = 0xDE
board_bootloader.efuse = 0xFD
board_bootloader.lock_bits = 0x0F
board_bootloader.unlock_bits = 0x3F

upload_protocol = custom
upload_flags =
    -C
    ; use "tool-avrdude-megaavr" for the atmelmegaavr platform
    $PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
    -p
    $BOARD_MCU
    -c
    usbtiny
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i

the full output was this:

pio run -t bootloader
Processing uno (platform: atmelavr; board: uno; framework: arduino)
--------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/uno.html
PLATFORM: Atmel AVR (3.3.0) > Arduino Uno
HARDWARE: ATMEGA328P 16MHz, 2KB RAM, 31.50KB Flash
DEBUG: Current (avr-stub) On-board (avr-stub, simavr)
PACKAGES: 
 - framework-arduino-avr 5.1.0 
 - toolchain-atmelavr 1.70300.191015 (7.3.0)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 5 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Warning: The `custom` upload protocol is used! The upload and fuse flags may conflict!
More information: https://docs.platformio.org/en/latest/platforms/atmelavr.html#overriding-default-fuses-command


Selected fuses: [lfuse = 0xFF, hfuse = 0xDE, efuse = 0xFD]
Warning: The `custom` upload protocol is used! The upload and fuse flags may conflict!
More information: https://docs.platformio.org/en/latest/platforms/atmelavr.html#overriding-default-bootloader-command

Setting fuses

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 "0x3F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x3F:
avrdude: load data lock data from input file 0x3F:
avrdude: input file 0x3F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of lock verified
avrdude: reading input file "0xDE"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xDE:
avrdude: load data hfuse data from input file 0xDE:
avrdude: input file 0xDE 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 "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 "0xFD"
avrdude: writing efuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xFD:
avrdude: load data efuse data from input file 0xFD:
avrdude: input file 0xFD contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of efuse verified

avrdude: safemode: Fuses OK (E:FD, H:DE, L:FF)

avrdude done.  Thank you.

Uploading bootloader

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

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 "/home/norman/.platformio/packages/framework-arduino-avr/bootloaders/optiboot/optiboot_atmega328.hex"
avrdude: writing flash (32768 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against /home/norman/.platformio/packages/framework-arduino-avr/bootloaders/optiboot/optiboot_atmega328.hex:
avrdude: load data flash data from input file /home/norman/.platformio/packages/framework-arduino-avr/bootloaders/optiboot/optiboot_atmega328.hex:
avrdude: input file /home/norman/.platformio/packages/framework-arduino-avr/bootloaders/optiboot/optiboot_atmega328.hex contains 32768 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 32768 bytes of flash verified
avrdude: reading input file "0x0F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x0F:
avrdude: load data lock data from input file 0x0F:
avrdude: input file 0x0F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of lock verified

avrdude: safemode: Fuses OK (E:FD, H:DE, L:FF)

avrdude done.  Thank you.

========================= [SUCCESS] Took 1.60 seconds

I think you also have fuse problems. At the end of the burn, I see that your fuses are set to:

avrdude: safemode: Fuses OK (E:FD, H:D6, L:F7)
  • Low: F7 => 1111 0111 = CKSEL3
  • High: D6 => 1101 0110 = SPIEN, EESAVE, BOOTRST
  • Extended: FD => 1111 1101 = BODLEVEL1

a 1 bit means unprogrammed while a zero bit is programmed.

In your low fuse setting, CKSEL3 means that the four CKSEL bits are 1000 and means that you are using an external crystal attached to pins 9 and 10 of the ATmeag328P.

Unfortunately, CKSEL bits 3, 2 and 1 are 100 here, and those define an oscillator speed of 0.4 to 0.9 MHz. You need to have those bits set to 110 to get a frequency between 3 and 8 MHz. (You wanted 4 MHz I believe?)

So, your low fuse needs to be CKSEL3 and CKSEL2 at the very least, this is a value of F3 for the low fuse. Plus you might need to play with SUT1 and SUT0 to get a decent startup delay to allow the power and oscillator to stabilise. The data sheet has the gory details.

Your extended fuse value is set to BODLEVEL1 on it’s own which gives a system reset by the Brown Out Detector at 2.7V. If you are intending to run with a 4MHz crystal, then your operating voltages are from 1.8V to 5.5V so this might be applicable. However, with a VCC of 2.7V or below, the BOD will constantly reset the device!

HTH

Cheers,
Norm.

1 Like

Thanks you a lot. I know where to look now.
I didn’t precise in my explanation but I am using an external clock at 4Mhz and my board is at 1.8V.
So I need to disable BOD and fix baudrate.

I found a really good example for avrdude with Platformio here in this doc in the arduino folder : C:\Users\username\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.1.2

Edit :
This is my new config which is working now !

[env:fuses_bootloader]
platform = ${common_env_data.platform}
framework =${common_env_data.framework}
board = atmega328p
board_build.f_cpu = 4000000L ;added 4 MH
board_hardware.oscillator = external ; Oscillator type
board_hardware.uart = uart0          ; Set UART0 to use for serial upload
board_bootloader.speed = 9600      ; Set bootloader baud rate
board_hardware.bod = disabled            ; Set brown-out detection
board_hardware.eesave = yes          ; Preserve EEPROM when uploading using programmer
upload_protocol = custom 
upload_port = COM10 
upload_speed = 19200 ;
upload_flags =
  -C
  ; use "tool-avrdude-megaavr" for the atmelmegaavr platform
  $PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
  -p
  $BOARD_MCU
  -P
  $UPLOAD_PORT
  -b
  $UPLOAD_SPEED
  -c
  stk500v1
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i

Thanks for the fuses calculator @NormanDunbar, I found another one but it was no longer hosted

1 Like

This web site is a decent AVR fuse calculator, if you need one.

I use it all the time when checking or messing around with fuse settings.

Cheers,
Norm.