Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Included -x option for Hx file with Fuses defined #70

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions device/device.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
DEFAULT_SIGROW_ADDRESS = 0x1100
DEFAULT_FUSES_ADDRESS = 0x1280
DEFAULT_USERROW_ADDRESS = 0x1300
DEFAULT_LOCKBIT_ADDRESS = 0x128a

class Device(object): # pylint: disable=too-few-public-methods
"""
Expand All @@ -37,6 +38,7 @@ def __init__(self, device_name):
self.nvmctrl_address = DEFAULT_NVMCTRL_ADDRESS
self.sigrow_address = DEFAULT_SIGROW_ADDRESS
self.fuses_address = DEFAULT_FUSES_ADDRESS
self.lockbit_address = DEFAULT_LOCKBIT_ADDRESS
self.userrow_address = DEFAULT_USERROW_ADDRESS

if device_name in DEVICE_AVR_D_SERIES:
Expand Down
55 changes: 52 additions & 3 deletions updi/application.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import updi.constants as constants
from updi.link import UpdiDatalink
from updi.timeout import Timeout
import time


class UpdiApplication(object):
Expand All @@ -22,6 +23,7 @@ def __init__(self, comport, baud, device=None):
self.write_nvm = self.write_nvm_v0
self.chip_erase = self.chip_erase_v0
self.write_fuse = self.write_fuse_v0
self.write_locks = self.write_locks_v0

def device_info(self):
"""
Expand All @@ -44,6 +46,7 @@ def device_info(self):
self.write_nvm = self.write_nvm_v1
self.chip_erase = self.chip_erase_v1
self.write_fuse = self.write_fuse_v1
self.write_locks = self.write_locks_v1
self.datalink.set_24bit_updi(True)

ocd = sib[11:14].strip()
Expand Down Expand Up @@ -101,10 +104,14 @@ def unlock(self):
self.datalink.key(constants.UPDI_KEY_64, constants.UPDI_KEY_CHIPERASE)

# Check key status
print("Getting Key Status")
self.logger.info("Getting Key Status")
key_status = self.datalink.ldcs(constants.UPDI_ASI_KEY_STATUS)
print("Key status = 0x{0:02X}".format(key_status))
self.logger.info("Key status = 0x{0:02X}".format(key_status))

if not key_status & (1 << constants.UPDI_ASI_KEY_STATUS_CHIPERASE):

if not (key_status & (1 << constants.UPDI_ASI_KEY_STATUS_CHIPERASE)):
raise Exception("Key not accepted")

# Insert NVMProg key as well
Expand Down Expand Up @@ -153,12 +160,17 @@ def enter_progmode(self):
self.reset(apply_reset=False)

# Wait for NVMPROG flag
print("Wait 60 secs for NVMPROG")
Now = time.time()
Timeout = 0
while True:
self.logger.info("Wait for NVMPROG")
self.logger.info("Wait 60 secs for NVMPROG")
sys_status = self.datalink.ldcs(constants.UPDI_ASI_SYS_STATUS)
if sys_status & (1 << constants.UPDI_ASI_SYS_STATUS_NVMPROG):
break

if time.time() > (Now + 60):
Timeout = 1
break
# TODO - add timeout

if not self.in_prog_mode():
Expand Down Expand Up @@ -435,6 +447,43 @@ def write_fuse_v1(self, fusenum, value):
"""
return self.write_eeprom_v1(fusenum, value)

def write_locks_v0(self, locknum, value):
"""
Writes one fuse value
"""
# Must be in prog mode
if not self.in_prog_mode():
raise Exception("Enter progmode first!")

if not self.wait_flash_ready():
raise Exception("Flash not ready for fuse setting")

lockbit_data = value
lockbit_address = self.device.lockbit_address + locknum

address = self.device.nvmctrl_address + constants.UPDI_NVMCTRL_ADDRL
data = [lockbit_address & 0xff]
self.write_data(address, data)

address = self.device.nvmctrl_address + constants.UPDI_NVMCTRL_ADDRH
data = [lockbit_address >> 8]
self.write_data(address, data)

address = self.device.nvmctrl_address + constants.UPDI_NVMCTRL_DATAL
self.write_data(address, lockbit_data)

address = self.device.nvmctrl_address + constants.UPDI_NVMCTRL_CTRLA
data = [constants.UPDI_V0_NVMCTRL_CTRLA_WRITE_FUSE]

self.write_data(address, data)

def write_locks_v1(self, locknum, value):
"""
Writes one fuse value
DA fuses are EEPROM-based
"""
return self.write_eeprom_v1(locknum, value)

def read_data(self, address, size):
"""
Reads a number of bytes of data from UPDI
Expand Down
1 change: 1 addition & 0 deletions updi/constants.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@

UPDI_KEY_NVM = b"NVMProg "
UPDI_KEY_CHIPERASE = b"NVMErase"
#UPDI_KEY_CHIPERASE = 0x4E564D4572617365

UPDI_ASI_STATUSA_REVID = 4
UPDI_ASI_STATUSB_PESIG = 0
Expand Down
27 changes: 27 additions & 0 deletions updi/nvm.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,33 @@ def write_fuse(self, fusenum, value):

return self.application.write_fuse(fusenum, fuse_data)

def read_locks(self, locsnum):
"""
Reads one fuse value
"""
# Must be in prog mode
if not self.progmode:
raise Exception("Enter progmode first!")

address = self.device.fuses_address + locsnum
data = self.application.datalink.ld(address)
return data

def write_locks(self, locksnum, value):
"""
Writes one fuse value
"""
# Must be in prog mode
if not self.progmode:
raise Exception("Enter progmode first!")

if not self.application.wait_flash_ready():
raise Exception("Flash not ready for fuse setting")

locks_data = [value]

return self.application.write_locks(locksnum, locks_data)

def pad_data(self, data, blocksize, character=0xFF):
"""
Pads data so that there are full pages
Expand Down
153 changes: 142 additions & 11 deletions updi/pyupdi.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import re
import logging

from io import StringIO
from device.device import Device
from updi.nvm import UpdiNvmProgrammer
"""
Expand Down Expand Up @@ -55,6 +56,7 @@


def _main():
ExecuteLeave = 1
if sys.version_info[0] < 3:
print("WARNING: for best results use Python3")

Expand All @@ -72,6 +74,10 @@ def _main():
help="Reset")
parser.add_argument("-i", "--info", action="store_true",
help="Info")
parser.add_argument("-x", "--integratedHex", action="store_true",
help="Intel HEX file that include fuses definition.")
parser.add_argument("-l", "--lockbits", action="append", nargs="*",
help="LockBits to set (syntax: lockbyte_nr:0xvalue)")
parser.add_argument("-fs", "--fuses", action="append", nargs="*",
help="Fuse to set (syntax: fuse_nr:0xvalue)")
parser.add_argument("-fr", "--readfuses", action="store_true",
Expand Down Expand Up @@ -106,11 +112,79 @@ def _main():

print("Device info: {0:s}".format(str(nvm.get_device_info())))

if not _process(nvm, args):
if _process(nvm, args) == 0:
print("Error during processing")
else:
ExecuteLeave = 0

# Reset only needs this.
nvm.leave_progmode()
if ExecuteLeave:
nvm.leave_progmode()


def _GetLockBitFromHexLine(lLock):
LockString = []
NumOfBytes = int(lLock[1:3], 16)
FLocks = lLock[9:-2]
Crc = lLock[:-2]
if len(FLocks) == NumOfBytes * 2:
# ok, seem good
i = 0
while i < NumOfBytes:
bPos = i*2
lLock = '%d:0x%s' % (i, FLocks[bPos:bPos+2])
LockString.append(lLock)
i = i+1
return LockString


def _GetFusesFromHexLine(lFuses):
FusesString = []
NumOfBytes = int(lFuses[1:3], 16)
FFuses = lFuses[9:-2]
Crc = lFuses[:-2]
if len(FFuses) == NumOfBytes * 2:
# ok, seem good
i = 0
while i < NumOfBytes:
bPos = i*2
fFuse = '%d:0x%s' % (i, FFuses[bPos:bPos+2])
FusesString.append(fFuse)
i = i+1
return FusesString


def _SplitHexFile(filein):
FileHex = StringIO()
FusesString = []
LockBitString = []
fhex = open(filein, 'r').read().split('\n')
GetFuses = 0
GetLockBit = 0
for lhex in fhex:
# search records of tyoe 0x04
# records are at position7,8
recordId = lhex[7:9]
if recordId == '04':
# found an address record. Get the address:
AddressBase = lhex[9:13]
if AddressBase == '0082':
# found the fuses string
GetFuses = 1
elif AddressBase == '0083':
# found lockbit string
GetLockBit = 1
elif GetFuses == 1:
FusesString = _GetFusesFromHexLine(lhex)
GetFuses = 0
elif GetLockBit == 1:
LockBitString = _GetLockBitFromHexLine(lhex)
GetLockBit = 0
else:
FileHex.write('%s\n' % lhex)
FileHex.seek(0)

return FileHex, FusesString, LockBitString


def _process(nvm, args):
Expand All @@ -119,8 +193,34 @@ def _process(nvm, args):
nvm.chip_erase()
except:
return False
if args.fuses is not None:
for fslist in args.fuses:
FileHex = None
FusesString = None
LockString = None
if args.integratedHex:
if args.flash is not None:
filename = args.flash
FileHex, FusesString, LockString = _SplitHexFile(filename)
FusesString = [FusesString]
LockString = [LockString]
else:
print("Needs to specify FileIn with flag -f")
sys.exit(1)

if args.flash is not None:
if FileHex is None:
FileHex = args.flash
ret = _flash_file(nvm, FileHex)
if args.integratedHex is None:
if ret == True:
return 1
else:
return 0

if FusesString is None:
FusesString = args.fuses
if FusesString is not None:
print(FusesString)
for fslist in FusesString:
for fsarg in fslist:
if not re.match("^[0-9]+:0x[0-9a-fA-F]+$", fsarg):
print("Bad fuses format {}. Expected fuse_nr:0xvalue".format(fsarg))
Expand All @@ -129,13 +229,24 @@ def _process(nvm, args):
fusenum = int(lst[0])
value = int(lst[1], 16)
if not _set_fuse(nvm, fusenum, value):
return False
if args.flash is not None:
return _flash_file(nvm, args.flash)
if args.readfuses:
if not _read_fuses(nvm):
return False
return True
return 0
if LockString is None:
LockString = args.lockbits
if LockString is not None:
print(LockString)
for fslist in LockString:
for fsarg in fslist:
if not re.match("^[0-9]+:0x[0-9a-fA-F]+$", fsarg):
print("Bad fuses format {}. Expected fuse_nr:0xvalue".format(fsarg))
continue
lst = fsarg.split(":0x")
fusenum = int(lst[0])
value = int(lst[1], 16)
if not _set_locks(nvm, fusenum, value):
return 0
else:
return 2
return 1


def _flash_file(nvm, filename):
Expand Down Expand Up @@ -169,6 +280,26 @@ def _set_fuse(nvm, fusenum, value):
print("Fuse {0} set to 0x{1:02X} successfully".format(fusenum, value))
return ret

def _set_locks(nvm, locksnum, value):
ret = 0
actual_val = nvm.read_locks(locksnum)
print("LockBits {0}: Actual Val: 0x{1:02X}".format(locksnum, actual_val))
nvm.write_locks(locksnum, value)
# now exit program mode
# check if the lock is programmed exiting and entring programm mode
nvm.leave_progmode()
try:
nvm.enter_progmode()
except:
print("Device is locked.")
ret = 1
# ret = actual_val == value
# if not ret:
# print("Verify error for LockBits {0}, expected 0x{1:02X} read 0x{2:02X}".format(locksnum, value, actual_val))
# else:
# print("LockBits {0} set to 0x{1:02X} successfully".format(locksnum, value))
return ret


def _read_fuses(nvm):
print("Fuse:Value")
Expand Down