import sys
import os
from SCons.Script import ARGUMENTS, COMMAND_LINE_TARGETS, Import, Return
Import("env")
def get_WDTCFG_fuse():
return 0x00
def get_BODCFG_fuse(bod):
if bod == "4.3v":
return 0xF4
elif bod == "2.6v":
return 0x54
elif bod == "1.8v":
return 0x14
else: # bod disabled
return 0x00
def get_OSCCFG_fuse(f_cpu, oscillator):
if (f_cpu == "20000000L" or f_cpu == "10000000L" or f_cpu == "5000000L") and oscillator == "internal":
return 0x02
else:
return 0x01
def get_TCD0CFG_fuse():
return 0x00
def get_SYSCFG0_fuse(eesave, rstpin, uart):
eesave_bit = 1 if eesave == "yes" else 0
if rstpin == "gpio":
if uart == "no_bootloader":
rstpin_bit = 0
else:
rstpin_bit = 1
else:
rstpin_bit = 1
return 0xC0 | rstpin_bit << 3 | eesave_bit
def get_SYSCFG1_fuse():
return 0x06
def get_APPEND_fuse():
return 0x00
def get_BOOTEND_fuse(uart):
if uart == "no_bootloader":
return 0x00
else:
return 0x02
def get_LOCKBIT_fuse():
return 0xC5
def print_fuses_info(fuse_values, fuse_names, lock_fuse):
print("\nSelected fuses:")
print("------------------------")
for idx, value in enumerate(fuse_values):
if value:
print("[fuse%d / %s = 0x%s]" % (idx, fuse_names[idx], value))
if lock_fuse:
print("[lfuse / LOCKBIT = %s]" % lock_fuse)
print("------------------------\n")
board = env.BoardConfig()
platform = env.PioPlatform()
core = board.get("build.core", "")
target = (
board.get("build.mcu").lower()
if board.get("build.mcu", "")
else env.subst("$BOARD").lower()
)
fuses_section = "fuse_values"
if "bootloader" in COMMAND_LINE_TARGETS or "UPLOADBOOTCMD" in env:
fuses_section = "bootloader"
board_fuses = board.get(fuses_section, {})
# Note: the index represents the fuse number
fuse_values = [
board_fuses.get("WDTCFG", ""),
board_fuses.get("BODCFG", ""),
board_fuses.get("OSCCFG", ""),
"", # reserved
board_fuses.get("TCD0CFG", ""),
board_fuses.get("SYSCFG0", ""),
board_fuses.get("SYSCFG1", ""),
board_fuses.get("APPEND", ""),
board_fuses.get("BOOTEND", ""),
]
fuse_names = (
"WDTCFG ",
"BODCFG ",
"OSCCFG ",
" ",
"TCD0CFG",
"SYSCFG0",
"SYSCFG1",
"APPEND ",
"BOOTEND",
"LOCKBIT"
)
lock_fuse = board_fuses.get("LOCKBIT", "0xC5")
if not board_fuses and "FUSESFLAGS" not in env and core not in ("MegaCoreX"):
sys.stderr.write(
"Error: Dynamic fuses generation for %s / %s is not supported."
" Please specify fuses in platformio.ini\n" % (target, env.subst("$BOARD"))
)
env.Exit(1)
if core in ("MegaCoreX"):
f_cpu = board.get("build.f_cpu", "16000000L").upper()
oscillator = board.get("hardware.oscillator", "internal").lower()
bod = board.get("hardware.bod", "2.6v").lower()
uart = board.get("hardware.uart", "no_bootloader").lower()
eesave = board.get("hardware.eesave", "yes").lower()
rstpin = board.get("hardware.rstpin", "reset").lower()
# Guard that prevents the user from turning the reset pin
# into a GPIO while using a bootloader
if uart != "no_bootloader":
rstpin = "reset"
print("\nTARGET CONFIGURATION:")
print("------------------------")
print("Target = %s" % target)
print("Clock speed = %s" % f_cpu)
print("Oscillator = %s" % oscillator)
print("BOD level = %s" % bod)
print("Save EEPROM = %s" % eesave)
print("Reset pin mode = %s" % rstpin)
print("------------------------")
fuse_values[0] = fuse_values[0] or '%.2X' % get_WDTCFG_fuse()
fuse_values[1] = fuse_values[1] or '%.2X' % get_BODCFG_fuse(bod)
fuse_values[2] = fuse_values[2] or '%.2X' % get_OSCCFG_fuse(f_cpu, oscillator)
fuse_values[4] = fuse_values[4] or '%.2X' % get_TCD0CFG_fuse()
fuse_values[5] = fuse_values[5] or '%.2X' % get_SYSCFG0_fuse(eesave, rstpin, uart)
fuse_values[6] = fuse_values[6] or '%.2X' % get_SYSCFG1_fuse()
fuse_values[7] = fuse_values[7] or '%.2X' % get_APPEND_fuse()
fuse_values[8] = fuse_values[8] or '%.2X' % get_BOOTEND_fuse(uart)
env.Append(
FUSESUPLOADER="avrdude",
FUSESUPLOADERFLAGS=[
"-p",
"$BOARD_MCU",
"-C",
'"%s"'
% os.path.join(env.PioPlatform().get_package_dir(
"tool-avrdude-megaavr") or "", "avrdude.conf"),
],
SETFUSESCMD="$FUSESUPLOADER $FUSESUPLOADERFLAGS $UPLOAD_FLAGS $FUSESFLAGS",
)
env.Append(
FUSESFLAGS=[
"-Ufuse%d:w:0x%s:m" % (idx, value) for idx, value in enumerate(fuse_values) if value
]
)
if lock_fuse:
env.Append(FUSESFLAGS=["-Ulock:w:%s:m" % lock_fuse])
if int(ARGUMENTS.get("PIOVERBOSE", 0)):
env.Append(FUSESUPLOADERFLAGS=["-v"])
if not env.BoardConfig().get("upload", {}).get("require_upload_port", False):
# upload methods via USB
env.Append(FUSESUPLOADERFLAGS=["-P", "usb"])
else:
env.AutodetectUploadPort()
env.Append(FUSESUPLOADERFLAGS=["-P", '"$UPLOAD_PORT"'])
if env.subst("$UPLOAD_PROTOCOL") != "custom":
env.Append(FUSESUPLOADERFLAGS=["-c", "$UPLOAD_PROTOCOL"])
else:
print(
"Warning: The `custom` upload protocol is used! The upload and fuse flags may "
"conflict!\nMore information: "
"https://docs.platformio.org/en/latest/platforms/atmelavr.html"
"#overriding-default-fuses-command\n"
)
print_fuses_info(fuse_values, fuse_names, lock_fuse)
fuses_action = env.VerboseAction("$SETFUSESCMD", "Setting fuses...")
Return("fuses_action")