From 06f6bd03cc091d05d84ecb7bbae96fc2f01ca31d Mon Sep 17 00:00:00 2001 From: Sergey Shchelkanov Date: Mon, 27 Mar 2023 18:03:20 +0300 Subject: [PATCH] updates --- .gitignore | 3 +- mik32_parsing.py | 126 ++++++++++++++++++++++++++++++++++ mik32_ram.py | 11 +++ mik32_upload.py | 174 ++++++++++------------------------------------- tclrpc.py | 2 +- 5 files changed, 176 insertions(+), 140 deletions(-) create mode 100644 mik32_parsing.py create mode 100644 mik32_ram.py diff --git a/.gitignore b/.gitignore index 7b62f12..4f5c3d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ __pycache__ -.vscode \ No newline at end of file +.vscode +openocd \ No newline at end of file diff --git a/mik32_parsing.py b/mik32_parsing.py new file mode 100644 index 0000000..44aa0b3 --- /dev/null +++ b/mik32_parsing.py @@ -0,0 +1,126 @@ + +def parse_hex(file: str) -> dict: + """ + TODO: Implement support for more record types + """ + with open(file, + "r", encoding='utf-8') as f: + lines = f.readlines() + + memory_blocks = {} + bytes = [] + block_offset = -1 + + def add_memory_block(): + memory_blocks[block_offset] = bytes[:] + + is_error = False + byte_len = 0 + + next_line_offset = -1 + + for i in range(lines.__len__()): + line = lines[i] + if line[0] != ':': + print("Error: unexpected record mark on line %i, expect \':\', get \'%c\'" % ( + i+1, line[0])) + is_error = True + break + + reclen = int(line[1:3], base=16) # Record length + load_offset = int(line[3:7], base=16) # Initial address of data byte + rectype = int(line[7:9], base=16) # Record type + data_bytes: list[str] = [] + + data_bytes_line = line[9:reclen*2 + 9] + for i in range(reclen): + data_bytes.append(data_bytes_line[i*2:i*2+2]) + byte_len += 1 + + if rectype == 0: # Data Record + if next_line_offset == -1: + next_line_offset = load_offset + block_offset = load_offset + + if next_line_offset != load_offset: + add_memory_block() + bytes.clear() + block_offset = load_offset + next_line_offset = load_offset + + for i in range(reclen): + byte = data_bytes[i] + byte = int(f"0x{byte}", base=16) + bytes.append(byte) + + next_line_offset += reclen + + # for i in range(data_len//4): + # data_bytes = word_bytes.reverse() + # print("data words: ", data_words) + elif rectype == 1: # End of File Record + # print("End of File") + add_memory_block() + elif rectype == 2: # Extended Segment Address Record + print("Record 2: Extended Segment Address Record") + print("ERROR: unimplemented record type 2 on line %i" % (i+1)) + is_error = True + break + elif rectype == 3: # Start Segment Address Record + print("Start Segment Address Record") + print("ERROR: unimplemented record type 3 on line %i" % (i+1)) + is_error = True + elif rectype == 4: # Extended Linear Address Record + print("Extended Linear Address Record") + print("ERROR: unimplemented record type 4 on line %i" % (i+1)) + is_error = True + elif rectype == 5: # Start Linear Address Record + print("Start Linear Address is 0x%s (line %i)" % + (data_bytes_line, (i+1))) + print("MIK32 MCU does not support arbitrary start address") + else: + print("ERROR: unexpected record type %i on line %i" % + (rectype, i+1)) + is_error = True + break + # print("line %i data_bytes=%i line_addr=%i" % (i+1, data_bytes, line_addr)) + + # for word in memory_blocks[0]: + # print(f"{word:#0x}") + + if is_error: + print("ERROR: error while parsing") + exit() + + return memory_blocks + + +def parse_bin(filename: str) -> list[int]: + arr: list[int] = [] + with open(filename, "rb") as f: + while byte := f.read(1): + arr.append(byte[0]) + return arr + + +def bytes2words(arr: list[int]) -> list[int]: + word = [] + words = [] + for byte in arr: + word.append(byte) + if word.__len__() == 4: + words.append(word[0]+2**8*word[1]+2**16*word[2]+2**24*word[3]) + word = [] + return words + +def get_content(filename: str) -> list[int]: + content: list[int] = [] + + if filename.endswith(".bin"): + content = parse_bin(filename) + elif filename.endswith(".hex"): + content = parse_hex(filename)[0] + else: + raise Exception("Unsupported file format") + + return content diff --git a/mik32_ram.py b/mik32_ram.py new file mode 100644 index 0000000..bc758fe --- /dev/null +++ b/mik32_ram.py @@ -0,0 +1,11 @@ +from tclrpc import TclException +from tclrpc import OpenOcdTclRpc +from pathlib import Path + +def write_file(filename): + + with OpenOcdTclRpc() as openocd: + openocd.halt() + print(openocd.run("load_image {%s} 0x0" % Path(filename))) + openocd.resume(0) + print("RAM write file maybe done") diff --git a/mik32_upload.py b/mik32_upload.py index 928d69f..d88e8cc 100644 --- a/mik32_upload.py +++ b/mik32_upload.py @@ -5,6 +5,9 @@ import sys import subprocess import mik32_eeprom import mik32_spifi +import mik32_ram +from mik32_parsing import * +import os from typing import Iterable @@ -16,121 +19,17 @@ from typing import Iterable # BOLD = '\033[1m' # UNDERLINE = '\033[4m' - -def parse_hex(file: str) -> dict: - """ - TODO: Implement support for more record types - """ - with open(file, - "r", encoding='utf-8') as f: - lines = f.readlines() - - memory_blocks = {} - bytes = [] - block_offset = -1 - - def add_memory_block(): - memory_blocks[block_offset] = bytes[:] - - is_error = False - byte_len = 0 - - next_line_offset = -1 - - for i in range(lines.__len__()): - line = lines[i] - if line[0] != ':': - print("Error: unexpected record mark on line %i, expect \':\', get \'%c\'" % ( - i+1, line[0])) - is_error = True - break - - reclen = int(line[1:3], base=16) # Record length - load_offset = int(line[3:7], base=16) # Initial address of data byte - rectype = int(line[7:9], base=16) # Record type - data_bytes: list[str] = [] - - data_bytes_line = line[9:reclen*2 + 9] - for i in range(reclen): - data_bytes.append(data_bytes_line[i*2:i*2+2]) - byte_len += 1 - - match rectype: - case 0: # Data Record - if next_line_offset == -1: - next_line_offset = load_offset - block_offset = load_offset - - if next_line_offset != load_offset: - add_memory_block() - bytes.clear() - block_offset = load_offset - next_line_offset = load_offset - - for i in range(reclen): - byte = data_bytes[i] - byte = int(f"0x{byte}", base=16) - bytes.append(byte) - - next_line_offset += reclen - - # for i in range(data_len//4): - # data_bytes = word_bytes.reverse() - # print("data words: ", data_words) - case 1: # End of File Record - # print("End of File") - add_memory_block() - case 2: # Extended Segment Address Record - print("Record 2: Extended Segment Address Record") - print("ERROR: unimplemented record type 2 on line %i" % (i+1)) - is_error = True - break - case 3: # Start Segment Address Record - print("Start Segment Address Record") - print("ERROR: unimplemented record type 3 on line %i" % (i+1)) - is_error = True - case 4: # Extended Linear Address Record - print("Extended Linear Address Record") - print("ERROR: unimplemented record type 4 on line %i" % (i+1)) - is_error = True - case 5: # Start Linear Address Record - print("Start Linear Address is 0x%s (line %i)" % - (data_bytes_line, (i+1))) - print("MIK32 MCU does not support arbitrary start address") - case _: - print("ERROR: unexpected record type %i on line %i" % - (rectype, i+1)) - is_error = True - break - # print("line %i data_bytes=%i line_addr=%i" % (i+1, data_bytes, line_addr)) - - # for word in memory_blocks[0]: - # print(f"{word:#0x}") - - if is_error: - print("ERROR: error while parsing") - exit() - - return memory_blocks +DEFAULT_OPENOCD_EXEC_FILE_PATH = os.path.join("openocd", "bin", "openocd.exe") +DEFAULT_OPENOCD_SCRIPTS_PATH = os.path.join("openocd", "share", "openocd", "scripts") -def parse_bin(filename: str) -> list[int]: - arr: list[int] = [] - with open(filename, "rb") as f: - while byte := f.read(1): - arr.append(byte[0]) - return arr - - -def bytes2words(arr: list[int]) -> list[int]: - word = [] - words = [] - for byte in arr: - word.append(byte) - if word.__len__() == 4: - words.append(word[0]+2**8*word[1]+2**16*word[2]+2**24*word[3]) - word = [] - return words +def test_connection(): + output = "" + with OpenOcdTclRpc() as openocd: + output = openocd.run(f"capture \"reg\"") + + if output == "": + raise Exception("ERROR: no regs found, check MCU connection") def upload_file(filename: str, boot_source: str = "eeprom"): @@ -138,29 +37,34 @@ def upload_file(filename: str, boot_source: str = "eeprom"): Write ihex or binary file into MIK32 EEPROM or external flash memory @filename: full path to the file with hex or bin file format - @boot_source: boot source, eeprom or spifi, define memory block mapped to boot memory area (0x0 offset) + @boot_source: boot source, eeprom, ram or spifi, define memory block mapped to boot memory area (0x0 offset) TODO: Implement error handling """ - if filename.endswith(".bin"): - content = parse_bin(filename) - elif filename.endswith(".hex"): - content = parse_hex(filename) - else: - raise Exception("Unsupported file format") - if boot_source == "eeprom": - if type(content) is list: - mik32_eeprom.write_words(bytes2words(content)) - elif type(content) is dict: - mik32_eeprom.write_words(bytes2words(content[0])) - elif boot_source == "spifi": - if type(content) is list: - mik32_spifi.spifi_write_file(content) - elif type(content) is dict: - mik32_spifi.spifi_write_file(content[0]) - else: - raise Exception("Unsupported boot source, use eeprom or spifi") + print("Boot mode %s" % boot_source) + + print("Running OpenOCD...") + + print(DEFAULT_OPENOCD_EXEC_FILE_PATH) + print(DEFAULT_OPENOCD_SCRIPTS_PATH) + + if not os.path.exists(filename): + print("ERROR: File %s does not exist" % filename) + exit(1) + + cmd = shlex.split("%s -s %s -f interface/ftdi/m-link.cfg -f target/mcu32.cfg" % (DEFAULT_OPENOCD_EXEC_FILE_PATH, DEFAULT_OPENOCD_SCRIPTS_PATH), posix=0) + with subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL) as proc: + if boot_source == "eeprom": + mik32_eeprom.write_words(bytes2words(get_content(filename))) + elif boot_source == "spifi": + mik32_spifi.spifi_write_file(get_content(filename)) + elif boot_source == "ram": + mik32_ram.write_file(filename) + else: + raise Exception("Unsupported boot source, use eeprom or spifi") + proc.kill() + def show_file(filename: str, boot_source: str = "eeprom"): @@ -198,9 +102,3 @@ if __name__ == '__main__': upload_file(namespace.filepath, namespace.boot_mode) else: print("Nothing to upload") - - -# cmd = shlex.split("C://Users//shche//Desktop//MK32_Burner//openocd//bin//openocd.exe -s C://Users//shche//Desktop//MK32_Burner//openocd//share//openocd//scripts -f interface/ftdi/m-link.cfg -f target/mcu32.cfg") -# subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL) -# upload_file("C://Users//shche//Documents//PlatformIO//Projects//irq_test_compare//.pio//build//mik32-bluepill-v0//firmware.hex", "spifi") -# show_file("C://Users//shche//Documents//PlatformIO//Projects//irq_test_compare//.pio//build//mik32-bluepill-v0//firmware.hex", "spifi") diff --git a/tclrpc.py b/tclrpc.py index cc8b7d6..99437b4 100644 --- a/tclrpc.py +++ b/tclrpc.py @@ -95,7 +95,7 @@ class OpenOcdTclRpc: """Halt MCU and raise an error if it returns an error""" return self.run("capture \"halt\"") - def resume(self, address:int|None=None): + def resume(self, address=None): """Resume the target at its current code position, or the optional address if it is provided. OpenOCD will wait 5 seconds for the target to resume."""