espefuse

Angus Gratton edited this page Jun 8, 2017 · 5 revisions

espefuse.py

espefuse.py is a tool for communicating with an ESP32 and reading/writing ("burning") the one-time-programmable efuses values.

IMPORTANT: Because efuse is one-time-programmable, it is possible to permanently damage or "brick" your ESP32 using this tool. Use it with great care.

For more details about ESP32 efuse features, see the Technical Reference Manual.

espefuse.py is installed alongside esptool.py, so if esptool.py (v2.0 or newer) is available on the PATH then espefuse.py should be as well.

Display efuse summary

espefuse.py --port /dev/ttyUSB1 summary

The options --port and --before can be supplied, and are identical to the equivalent esptool.py options.

Output from the summary command will look like this:

espefuse.py v2.0-beta1
Connecting....
Security fuses:
FLASH_CRYPT_CNT        Flash encryption mode counter                     = 0 R/W (0x0)
FLASH_CRYPT_CONFIG     Flash encryption config (key tweak bits)          = 0 R/W (0x0)
CONSOLE_DEBUG_DISABLE  Disable ROM BASIC interpreter fallback            = 0 R/W (0x0)
ABS_DONE_0             secure boot enabled for bootloader                = 0 R/W (0x0)
ABS_DONE_1             secure boot abstract 1 locked                     = 0 R/W (0x0)
JTAG_DISABLE           Disable JTAG                                      = 0 R/W (0x0)
DISABLE_DL_ENCRYPT     Disable flash encryption in UART bootloader       = 0 R/W (0x0)
DISABLE_DL_DECRYPT     Disable flash decryption in UART bootloader       = 0 R/W (0x0)
DISABLE_DL_CACHE       Disable flash cache in UART bootloader            = 0 R/W (0x0)
BLK1                   Flash encryption key
  = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLK2                   Secure boot key
  = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLK3                   Variable Block 3
  = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W

Efuse fuses:
WR_DIS                 Efuse write disable mask                          = 0 R/W (0x0)
RD_DIS                 Efuse read disablemask                            = 0 R/W (0x0)
CODING_SCHEME          Efuse variable block length scheme                = 0 R/W (0x0)
KEY_STATUS             Usage of efuse block 3 (reserved)                 = 0 R/W (0x0)

Config fuses:
XPD_SDIO_FORCE         Ignore MTDI pin (GPIO12) for VDD_SDIO on reset    = 0 R/W (0x0)
XPD_SDIO_REG           If XPD_SDIO_FORCE, enable VDD_SDIO reg on reset   = 0 R/W (0x0)
XPD_SDIO_TIEH          If XPD_SDIO_FORCE & XPD_SDIO_REG, 1=3.3V 0=1.8V   = 0 R/W (0x0)
SPI_PAD_CONFIG_CLK     Override SD_CLK pad (GPIO6/SPICLK)                = 0 R/W (0x0)
SPI_PAD_CONFIG_Q       Override SD_DATA_0 pad (GPIO7/SPIQ)               = 0 R/W (0x0)
SPI_PAD_CONFIG_D       Override SD_DATA_1 pad (GPIO8/SPID)               = 0 R/W (0x0)
SPI_PAD_CONFIG_HD      Override SD_DATA_2 pad (GPIO9/SPIHD)              = 0 R/W (0x0)
SPI_PAD_CONFIG_CS0     Override SD_CMD pad (GPIO11/SPICS0)               = 0 R/W (0x0)
DISABLE_SDIO_HOST      Disable SDIO host                                 = 0 R/W (0x0)

Identity fuses:
MAC                    MAC Address                                       = c4:xx:xx:xx:xx:xx R/W

On relatively new chip, most efuses are unburned (value 0).

For details on the meaning of each efuse value, refer to the Technical Reference Manual.

Dump raw efuse registers

To display raw efuse register values, use the dump subcommand:

espefuse.py --port /dev/ttyUSB1 dump
espefuse.py v2.0-dev
Connecting....
EFUSE block 0:
00000000 c40042xx xxxxxxxx 00000000 00000033 00000000 00000000
EFUSE block 1:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE block 2:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE block 3:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

Output corresponds directly to efuse register values in the register space.

Burning an efuse

This command can brick your ESP32

To burn an efuse to a new value, use the burn_efuse command:

espefuse.py --port /dev/DONOTDOTHIS burn_efuse JTAG_DISABLE 1

The arguments to burn_efuse are the name of the efuse (as shown in summary output) and the new value.

New values can be a numeric value in decimal or hex (with 0x prefix). Efuse bits can only be burned from to 0 to 1, attempting to set any back to 0 will have no effect. Most efuses have a limited bit width (many are only 1-bit flags).

Longer efuses (MAC addresses, keys) cannot be set via this command.

By default, espefuse.py will ask you to type BURN before it permanently sets an efuse. The --do-not-confirm option allows you to bypass this.

Setting Flash Voltage (VDD_SDIO)

After reset, the default ESP32 behaviour is to enable and configure the flash voltage regulator (VDD_SDIO) based on the level of the MTDI pin (GPIO12).

The default behaviour on reset is:

MTDI (GPIO12) Pin VDD_SDIO Internal Regulator
Low or unconnected Enabled at 3.3V
High Enabled at 1.8V

Consult ESP32 Technical Reference Manual chapter 4.8.1 "VDD_SDIO Power Domain" for details.

A combination of 3 efuses (XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH) can be burned in order to override this behaviour and disable VDD_SDIO regulator, or set it to a fixed voltage. These efuses can be burned with individual burn_efuse commands, but the set_flash_voltage command makes it easier:

Disable VDD_SDIO regulator

espefuse.py set_flash_voltage OFF

Once set:

  • VDD_SDIO regulator always disabled.
  • MTDI pin (GPIO12) is ignored.
  • Flash must be powered externally and voltage supplied to VDD_SDIO pin of ESP32.
  • Efuse XPD_SDIO_FORCE is burned.

Fixed 1.8V VDD_SDIO

espefuse.py set_flash_voltage 1.8V

Once set:

  • VDD_SDIO regulator always enables at 1.8V.
  • MTDI pin (GPIO12) is ignored.
  • External voltage should not be supplied to VDD_SDIO.
  • Efuses XPD_SDIO_FORCE and XPD_SDIO_REG are burned.

Fixed 3.3V VDD_SDIO

espefuse.py set_flash_voltage 3.3V

Once set:

  • VDD_SDIO regulator always enables at 3.3V.
  • MTDI pin (GPIO12) is ignored.
  • External voltage should not be supplied to VDD_SDIO.
  • Efuses XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH are burned.

Subsequent changes

Once an efuse is burned it cannot be un-burned. However, changes can be made by burning additional efuses:

  • set_flash_voltage OFF can be changed to 1.8V or 3.3V.
  • set_flash_voltage 1.8V can be changed to 3.3V

Burning a key

This command can brick your ESP32

The efuse key blocks BLK1, BLK2 and BLK3 can all hold encryption keys. The burn_key subcommand loads a key (stored as a raw binary file, 32 bytes long) and burns it to a key block.

"flash_encryption" can be used as an alias for BLK1, and "secure_boot" can be used as an alias for BLK2.

By default, when an encryption key block is burned it is also read and write protected. The --no-protect-key option will disable this behaviour (you can separately read- or write-protect the key later.) Note that leaving a key unprotected may compromise its use as a security feature.

espefuse.py --port /dev/DONOTDOTHIS burn_key secure_boot keyfile.bin

Normally, a key will only be burned if the efuse block has not been previously written to. The --force-write-always option can be used to ignore this and burn the key anyhow.

The --do-not-confirm option can be used with burn_key, otherwise a manual confirmation step is required.

SPI flash pins

The following efuses configure the SPI flash pins which are used to boot:

SPI_PAD_CONFIG_CLK     Override SD_CLK pad (GPIO6/SPICLK)                = 0 R/W (0x0)
SPI_PAD_CONFIG_Q       Override SD_DATA_0 pad (GPIO7/SPIQ)               = 0 R/W (0x0)
SPI_PAD_CONFIG_D       Override SD_DATA_1 pad (GPIO8/SPID)               = 0 R/W (0x0)
SPI_PAD_CONFIG_HD      Override SD_DATA_2 pad (GPIO9/SPIHD)              = 0 R/W (0x0)
SPI_PAD_CONFIG_CS0     Override SD_CMD pad (GPIO11/SPICS0)               = 0 R/W (0x0)

On ESP32 chips without integrated SPI flash, these efuses are set to zero in the factory. This causes the default GPIO pins (shown in the summary output above) to be used for the SPI flash.

On ESP32 chips with integrated internal SPI flash, these efuses are burned in the factory to the GPIO numbers where the flash is connected. These values override the defaults on boot.

In order to change the SPI flash pin configuration, these efuses can be burned to the GPIO numbers where the flash is connected. If at least one of these efuses is burned, all of of them must be set to the correct values.

If these efuses are burned, GPIO1 (U0TXD pin) is no longer consulted to set the boot mode from SPI to HSPI flash on reset.

These pins can be set to any GPIO number in the range 0-29, 32 or 33. Values 30 and 31 cannot be set. The "raw" hex value for pins 32,33 is 30,31 (this is visible in the summary output if these pins are configured for any SPI I/Os.)

ie:

SPI_PAD_CONFIG_CS0     Override SD_CMD pad (GPIO11/SPICS0)               = 32 R/W (0x1e)

If using the burn_efuse command to configure these pins, always specify the actual GPIO number you wish to set.

Read- and Write- protecting efuses

This command can severely limit your ESP32 options

Some efuses can be read- or write-protected, preventing further changes. burn_key subcommand read and write protects new keys by default, but other efuses can be protected iwth the read_protect_efuse and write_protect_efuse commands.

The R/W output in the summary display will change to indicate protected efuses:

  • -/W indicates read protected (value will always show all-zeroes, even though hardware may use the correct value.)
  • R/- shows write protected (no further bits can be set),
  • -/- means read and write protected.

Sample:

espefuse.py --port /dev/SOMEPORT read_protect_efuse KEY_STATUS

The --do-not-confirm option can be used with burn_key, otherwise a manual confirmation step is required.

NOTE that efuses are often read/write protected as a group, so protecting one will cause some related efuses to become protected. espefuse.py will confirm the full list of efuses that will become protected.

The following efuses can be read protected:

  • FLASH_CRYPT_CONFIG
  • CODING_SCHEME
  • KEY_STATUS
  • BLK1
  • BLK2
  • BLK3

The following efuses can be write protected:

  • WR_DIS,RD_DIS
  • FLASH_CRYPT_CNT
  • MAC
  • XPD_SDIO_FORCE
  • XPD_SDIO_REG
  • XPD_SDIO_TIEH
  • SPI_PAD_CONFIG_CLK
  • SPI_PAD_CONFIG_Q
  • SPI_PAD_CONFIG_D
  • SPI_PAD_CONFIG_HD
  • SPI_PAD_CONFIG_CS0
  • FLASH_CRYPT_CONFIG
  • CODING_SCHEME
  • CONSOLE_DEBUG_DISABLE
  • DISABLE_SDIO_HOST
  • ABS_DONE_0
  • ABS_DONE_1
  • JTAG_DISABLE
  • DISABLE_DL_ENCRYPT
  • DISABLE_DL_DECRYPT
  • DISABLE_DL_CACHE
  • KEY_STATUS
  • BLK1
  • BLK2
  • BLK3
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.