mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
376 lines
13 KiB
Python
Executable File
376 lines
13 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
MRAM (NVM) burning / writing utility
|
|
Support
|
|
- APPLICATION TOC package writing
|
|
- image write at any address in NVM (MRAM)
|
|
- image erase of any | range of addresses in NVM (MRAM)
|
|
|
|
__author__ = ""
|
|
__copyright__ = "ALIF Seminconductor"
|
|
__version__ = "0.16.0"
|
|
__status__ = "Dev" "
|
|
"""
|
|
import os
|
|
import sys
|
|
import signal
|
|
import argparse
|
|
from utils.discover import getValues, getJlinkSN
|
|
import utils.config
|
|
from utils.config import *
|
|
from utils.user_validations import validateArgList
|
|
from _ast import Or
|
|
from _operator import or_
|
|
from cgitb import handler
|
|
sys.path.append("./isp")
|
|
from serialport import serialPort
|
|
from serialport import COM_BAUD_RATE_MAXIMUM
|
|
#import ispcommands
|
|
from isp_core import *
|
|
from isp_util import *
|
|
import pylink
|
|
import datetime
|
|
#from array import array
|
|
|
|
# Version Feature
|
|
# 0.22.000 Added support for MAC OS (J-Link not included yet)
|
|
# 0.21.000 get baudrate from DBs
|
|
# 0.20.007 Added padding option for binaries not multiple of 16
|
|
# 0.20.006 Added Python error exit code
|
|
# 0.20.005 Fixed J-Link+Pylink issue writing binaries
|
|
# 0.20.004 REV_A0 dynamic baud rate support
|
|
# 0.20.003 remove maintenance mode output unless -v is used)
|
|
# 0.20.002 Reset option set as default
|
|
# 0.20.001 Added Erase option
|
|
# 0.20.000 Added option to skip user managed images
|
|
# 0.19.000 Removed JTAG access
|
|
# 0.16.000 Addition of baud rate increase for bulk transfer
|
|
# 0.15.000 Fixes for Block sizes and left overs
|
|
TOOL_VERSION ="0.22.000" # Define Version constant for each separate tool
|
|
|
|
EXIT_WITH_ERROR = 1
|
|
|
|
def readImageList(dsFile):
|
|
"""
|
|
readImageList = read images from arm-ds command file
|
|
"""
|
|
try:
|
|
f = open(dsFile, 'r')
|
|
imageList = f.read()
|
|
f.close()
|
|
# search for image list
|
|
start = imageList.find('args')
|
|
end = imageList.find('continue')
|
|
if start == -1 or end == -1:
|
|
print('[ERROR] There is a problem with the Debug Script information')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
imageList = imageList[start + 5: end]
|
|
except:
|
|
print('[ERROR] opening Debug Script file',dsFile)
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
return imageList
|
|
|
|
def app_mram_erase(isp,args, ALIF_BASE_ADDRESS, ALIF_MRAM_SIZE):
|
|
"""
|
|
app_mram_erase
|
|
- erase the Application are of MRAM
|
|
args
|
|
argv[0] 'erase' Operation, can be ignored
|
|
argv[1] <address> Starting address
|
|
argv{2] <size> Length of bytes to erase
|
|
argv[3] <pattern> Optional pattern to erase with
|
|
argc Checked before this is called
|
|
"""
|
|
argv = args.split()
|
|
argc = len(argv)
|
|
|
|
# nombres magiques, maybe not needed?
|
|
address = 0x80000000
|
|
erase_len = 16
|
|
pattern = 0x00000000
|
|
|
|
if argc >= 3:
|
|
address = int(argv[1],base=16)
|
|
erase_len = int(argv[2],base=16)
|
|
erase_len_fmt = "{:,}".format(erase_len)
|
|
|
|
if argc == 4:
|
|
pattern = int(argv[3],base=16)
|
|
print("[INFO] %s 0x%x %d (%s)" %(argv[0],address,erase_len,
|
|
erase_len_fmt))
|
|
|
|
# Validate user request for erasing is in OEM
|
|
if (address > ALIF_BASE_ADDRESS or
|
|
address + erase_len > ALIF_BASE_ADDRESS):
|
|
|
|
if address + erase_len > ALIF_BASE_ADDRESS:
|
|
print("[ERROR] illegal address " + hex(address+erase_len) +
|
|
" (" + hex(address) + " + " + hex(erase_len) + ")")
|
|
else:
|
|
print("[ERROR] illegal address " + hex(address))
|
|
return
|
|
|
|
isp_mram_erase(isp,address,erase_len,pattern)
|
|
|
|
def main():
|
|
if sys.version_info.major == 2:
|
|
print("[ERROR] You need Python 3 for this application!")
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
# Deal with Command Line
|
|
parser = argparse.ArgumentParser(description=
|
|
'NVM Burner for Application TOC Package')
|
|
parser.add_argument("-d" , "--discover", action='store_true', \
|
|
default=False, help="COM port discovery")
|
|
parser.add_argument("-b", "--baudrate", help="serial port baud rate",
|
|
type=int)
|
|
parser.add_argument("-e", "--erase", type=str,
|
|
help='ERASE [APP | <start address> <size> [<pattern>] ]')
|
|
# creating a mutually exclusive group for -i IMAGES and -S
|
|
# (skip option doesn't make sense in a user provided list...)
|
|
group = parser.add_mutually_exclusive_group()
|
|
group.add_argument("-i", "--images", type=str,
|
|
default="Application TOC Package",
|
|
help='images list to burn into NVM \
|
|
("/path/image1.bin 0x80001000 /path/image2.bin 0x80003000")')
|
|
parser.add_argument("-a", "--auth_image", action='store_true',
|
|
help="authenticate the image by sending its signature file",
|
|
default=False)
|
|
parser.add_argument("-m", "--method", type=str,
|
|
help="loading method [JTAG | ISP]")
|
|
group.add_argument("-S", "--skip",
|
|
help='write ATOC only - skip user managed images',
|
|
action="store_true")
|
|
parser.add_argument("-s", "--switch",
|
|
help="dynamic baud rate switch toggle, default=on",
|
|
action="store_false")
|
|
parser.add_argument("-p", "--pad",
|
|
help="pad the binary if size is not multiple of 16", action="store_true")
|
|
parser.add_argument("-nr", "--no_reset", default=False,
|
|
help="do not reset target before operation", action="store_true")
|
|
parser.add_argument("-V" , "--version",
|
|
help="Display Version Number", action="store_true")
|
|
parser.add_argument("-v" , "--verbose",
|
|
help="verbosity mode", action="store_true")
|
|
|
|
args = parser.parse_args()
|
|
if args.version:
|
|
print(TOOL_VERSION)
|
|
sys.exit()
|
|
|
|
# memory defines for Alif/OEM MRAM Addresses and Sizes
|
|
load_global_config()
|
|
DEVICE_PART_NUMBER = utils.config.DEVICE_PART_NUMBER
|
|
DEVICE_REVISION = utils.config.DEVICE_REVISION
|
|
DEVICE_REV_BAUD_RATE = utils.config.DEVICE_REV_BAUD_RATE
|
|
MRAM_BASE_ADDRESS = utils.config.MRAM_BASE_ADDRESS
|
|
ALIF_BASE_ADDRESS = utils.config.ALIF_BASE_ADDRESS
|
|
OEM_BASE_ADDRESS = utils.config.APP_BASE_ADDRESS
|
|
MRAM_SIZE = utils.config.MRAM_SIZE
|
|
ALIF_MRAM_SIZE = utils.config.ALIF_MRAM_SIZE
|
|
OEM_MRAM_SIZE = utils.config.APP_MRAM_SIZE
|
|
MRAM_BURN_INTERFACE = utils.config.MRAM_BURN_INTERFACE
|
|
JTAG_ADAPTER = utils.config.JTAG_ADAPTER
|
|
|
|
os.system('') # Help MS-DOS window with ESC sequences
|
|
|
|
print('Writing MRAM with parameters:')
|
|
print('Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
|
|
print('- Available MRAM: ' + str(OEM_MRAM_SIZE) + ' bytes')
|
|
|
|
# baud_rate = args.baudrate
|
|
# if DEVICE_REVISION == 'A0':
|
|
# """
|
|
# For REV_A0 we need to change the default used by ALL other devices
|
|
# """
|
|
# default_baud_rate = COM_BAUD_RATE_REV_A0
|
|
# if baud_rate == COM_BAUD_RATE_DEFAULT:
|
|
# baud_rate = default_baud_rate
|
|
# else:
|
|
# default_baud_rate = COM_BAUD_RATE_DEFAULT
|
|
# baud_rate = args.baudrate
|
|
|
|
# if baud_rate != default_baud_rate:
|
|
# dynamic_baud_rate_switch = False
|
|
# else:
|
|
# dynamic_baud_rate_switch = args.switch
|
|
|
|
baud_rate = DEVICE_REV_BAUD_RATE[DEVICE_REVISION]
|
|
if args.baudrate is not None:
|
|
baud_rate = args.baudrate
|
|
|
|
dynamic_baud_rate_switch = args.switch
|
|
|
|
argList = ''
|
|
action = 'Burning: '
|
|
method = None
|
|
|
|
if args.method == None:
|
|
method = MRAM_BURN_INTERFACE
|
|
elif args.method.upper() == 'ISP':
|
|
method = 'isp'
|
|
elif args.method.upper() == 'JTAG':
|
|
method = 'jtag'
|
|
else:
|
|
print("[ERROR] Unknown connection method", args.method)
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
if args.erase:
|
|
action = 'Erasing: '
|
|
argList = 'erase '
|
|
if args.erase.upper() == 'APP':
|
|
argList += hex(OEM_BASE_ADDRESS) + ' ' + hex(OEM_MRAM_SIZE)
|
|
else:
|
|
if args.erase.strip() == '':
|
|
print("[ERROR] erase arguments are empty")
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
argList += args.erase
|
|
elif args.images != "Application TOC Package":
|
|
argList = args.images
|
|
else:
|
|
dsFile = 'bin/application_package.ds'
|
|
argList = readImageList(dsFile)
|
|
|
|
if args.skip:
|
|
idx = argList.find('../build/AppTocPackage.bin 0x')
|
|
argList = argList[idx: idx + 37]
|
|
|
|
# validate all parameters
|
|
argList = validateArgList(action, argList.strip(), args.pad)
|
|
|
|
if sys.platform == "linux" or sys.platform == "darwin":
|
|
argList = argList.replace('../','')
|
|
|
|
print("[INFO]", action + argList)
|
|
|
|
|
|
if method == 'jtag' and not args.erase: # erase via jtag not yet supported!
|
|
jlinkSN = getJlinkSN()
|
|
if jlinkSN == -1:
|
|
print('J-Link device not found!')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
print('J-Link SN: ' + jlinkSN)
|
|
|
|
jlink = pylink.JLink()
|
|
jlink.open(serial_no=int(jlinkSN))
|
|
print(jlink.product_name)
|
|
if not jlink.opened():
|
|
print('Error opening J-Link')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
if not jlink.connected():
|
|
print('Error connecting J-Link')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
print("about to connect to M0+..")
|
|
jlink.connect("CORTEX-M0+", verbose=True)
|
|
#jlink.connect('AC302F8A82562_HE', verbose=True)
|
|
if not jlink.target_connected():
|
|
print('Error connecting target')
|
|
print('Please, power-cycle the board')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
argParams = argList.strip().split(" ")
|
|
lenParams = len(argParams)
|
|
i = 0
|
|
while i < lenParams:
|
|
f = argParams[i][3:]
|
|
if sys.platform == "linux":
|
|
f = argParams[i][:]
|
|
|
|
print('File name: ' + f)
|
|
file_size = os.path.getsize(f)
|
|
print("File Size is :", file_size, "bytes")
|
|
print('MRAM starting address: ' + argParams[i+1])
|
|
addr = globalToLocalAddress(argParams[i+1])
|
|
print("Writing the file to MRAM...")
|
|
# read the file
|
|
f = open(f,"rb")
|
|
#fileData = array("I")
|
|
#fileData.fromfile(f, int(file_size/4))
|
|
fileData = list(f.read(file_size))
|
|
f.close()
|
|
|
|
# write the data to MRAM
|
|
t1 = datetime.datetime.now()
|
|
#jlink.memory_write32(int(addr, 16), fileData)
|
|
jlink.memory_write8(int(addr, 16), fileData)
|
|
t2 = datetime.datetime.now()
|
|
print('Done in ' + str(t2-t1))
|
|
i += 2
|
|
|
|
#jlink.reset() # the reset causes an issue and the board will need to power cycle...
|
|
|
|
return # end jlink tests
|
|
|
|
if method == 'jtag' and args.erase: # erase via jtag not yet supported!
|
|
print('[INFO] Erase is only supported via ISP')
|
|
|
|
dynamic_string = "Enabled" if dynamic_baud_rate_switch else "Disabled"
|
|
print("[INFO] baud rate ", baud_rate)
|
|
print("[INFO] dynamic baud rate change ", dynamic_string)
|
|
|
|
handler = CtrlCHandler()
|
|
isp = serialPort(baud_rate) # Serial dabbling open up port.
|
|
|
|
if args.discover: # discover the COM ports if requested
|
|
isp.discoverSerialPorts()
|
|
|
|
errorCode = isp.openSerial()
|
|
if errorCode is False:
|
|
print("[ERROR] isp openSerial failed for %s" %isp.getPort())
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
print("[INFO] %s open Serial port success" %isp.getPort())
|
|
|
|
isp.setBaudRate(baud_rate)
|
|
isp.setVerbose(args.verbose)
|
|
|
|
if not args.no_reset:
|
|
put_target_in_maintenance_mode(isp, baud_rate, args.verbose)
|
|
|
|
if sys.platform == "linux" or sys.platform == "darwin":
|
|
argList = argList.replace('\\','/')
|
|
else:
|
|
argList = argList.replace('/','\\')
|
|
|
|
items = argList.split(' ')
|
|
|
|
isp_start(isp) # Start ISP Sequence
|
|
|
|
if args.erase:
|
|
app_mram_erase(isp,argList,ALIF_BASE_ADDRESS, ALIF_MRAM_SIZE)
|
|
else:
|
|
if dynamic_baud_rate_switch:
|
|
isp_set_baud_rate(isp,COM_BAUD_RATE_MAXIMUM) # Jack up Baud rate
|
|
isp.setBaudRate(COM_BAUD_RATE_MAXIMUM) # Sets the HOST baud rate
|
|
|
|
# issue enquiry command to check if SERAM is in Maintenance Mode
|
|
mode = isp_get_maintenance_status(isp)
|
|
isp_show_maintenance_mode(isp, mode)
|
|
|
|
for e in range(1, len(items),2):
|
|
addr = items[e]
|
|
address = int(addr,base=16)
|
|
fileName = items[e-1]
|
|
fileName = fileName.replace('..\\','')
|
|
|
|
if burn_mram_isp(isp, handler, fileName, address,
|
|
args.verbose, args.auth_image) == False:
|
|
break
|
|
|
|
# Restore the default Baud rate
|
|
if dynamic_baud_rate_switch:
|
|
isp_set_baud_rate(isp,baud_rate)
|
|
isp.setBaudRate(baud_rate)
|
|
|
|
isp_stop(isp) # Stop ISP Sequence
|
|
isp_reset(isp)
|
|
|
|
isp.closeSerial()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|