diff --git a/mik32_spifi.py b/mik32_spifi.py index 96a7a66..e9162e0 100644 --- a/mik32_spifi.py +++ b/mik32_spifi.py @@ -3,6 +3,7 @@ from typing import Dict, List import time from tclrpc import TclException from tclrpc import OpenOcdTclRpc +import config # -------------------------- # PM register offset @@ -306,11 +307,13 @@ def spifi_sector_erase(openocd: OpenOcdTclRpc, address: int): spifi_wait_intrq_timeout(openocd, "Timeout executing chip erase command") -def spifi_read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: List[int]) -> int: +def spifi_read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int) -> List[int]: read_data: List[int] = [] openocd.write_word(SPIFI_CONFIG_ADDR, address) - spifi_intrq_clear(openocd) + # spifi_intrq_clear(openocd) + openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word( + SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M) openocd.write_word(SPIFI_CONFIG_CMD, (READ_DATA_COMMAND << SPIFI_CONFIG_CMD_OPCODE_S) | (SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << SPIFI_CONFIG_CMD_FRAMEFORM_S) | (SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_CMD_FIELDFORM_S) | @@ -319,11 +322,33 @@ def spifi_read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_d for i in range(byte_count): data8 = openocd.read_memory(SPIFI_CONFIG_DATA32, 8, 1)[0] read_data.append(data8) - # print(f"DATA[{i+address}] = {read_data[i]:#0x}") + if config.is_verbose: + print(f"DATA[{i+address}] = {read_data[i]:#0x}") + + return read_data + + +def spifi_check_erase(openocd: OpenOcdTclRpc, address: int, byte_count: int): + print(f"Checking erase from {address:#0x} to {(byte_count-1):#0x}") + read_data: List[int] = spifi_read_data(openocd, address, byte_count) + + for i in range(byte_count): + if read_data[i] != 0: + print(f"DATA[{(i+address):#0x}] = {read_data[i]:#0x}, expected {0:#0x}") + return 1 + + return 0 + + +def spifi_check_program(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: List[int]) -> int: + read_data: List[int] = spifi_read_data(openocd, address, byte_count) + + if read_data.__len__ != byte_count: + return 1 for i in range(byte_count): if read_data[i] != bin_data[i]: - print(f"DATA[{i+address}] = {read_data[i]:#0x} - ошибка") + print(f"DATA[{(i+address):#0x}] = {read_data[i]:#0x}, expected {bin_data[i]:#0x}") return 1 return 0 @@ -333,9 +358,8 @@ def spifi_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: List[int] if byte_count > 256: raise Exception("Byte count more than 256") - # spifi_intrq_clear(openocd) - openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word( - SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M) + print("Writing page %s..." % hex(ByteAddress)) + spifi_intrq_clear(openocd) openocd.write_word(SPIFI_CONFIG_ADDR, ByteAddress) openocd.write_word(SPIFI_CONFIG_IDATA, 0x00) openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00000000) @@ -360,15 +384,20 @@ class EraseType(Enum): def spifi_erase(openocd, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []): + result = 0 if erase_type == EraseType.CHIP_ERASE: spifi_write_enable(openocd) spifi_chip_erase(openocd) spifi_wait_busy(openocd) + result |= spifi_check_erase(openocd, 0, 4096) elif erase_type == EraseType.SECTOR_ERASE: for sector in sectors: spifi_write_enable(openocd) spifi_sector_erase(openocd, sector) spifi_wait_busy(openocd) + result |= spifi_check_erase(openocd, sector, sector + 0x800) + + return result def spifi_write(openocd: OpenOcdTclRpc, address: int, data: List[int], data_len: int): @@ -397,14 +426,14 @@ def spifi_write_file(bytes: List[int], openocd: OpenOcdTclRpc, is_resume=True): break print("address = ", address) spifi_write(openocd, address, bytes, 256) - if spifi_read_data(openocd, address, 256, bytes) == 1: + if spifi_check_program(openocd, address, 256, bytes) == 1: return 1 if (len(bytes) % 256) != 0: print( f"address = {address}, +{len(bytes) - address-1}[{address + len(bytes) - address-1}]") spifi_write(openocd, address, bytes, len(bytes) - address) - if spifi_read_data(openocd, address, len(bytes) - address, bytes) == 1: + if spifi_check_program(openocd, address, len(bytes) - address, bytes) == 1: return 1 print("end") if is_resume: @@ -417,6 +446,7 @@ def spifi_quad_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: List if byte_count > 256: raise Exception("Byte count more than 256") + print("Writing page %s..." % hex(ByteAddress)) # spifi_intrq_clear(openocd) openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word( SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M) @@ -481,18 +511,26 @@ def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]: return list(segments) -def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, is_resume=True, use_quad_spi=False): +def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, is_resume=True, use_quad_spi=False, use_chip_erase=False): result = 0 openocd.halt() spifi_init(openocd) - spifi_erase(openocd, EraseType.SECTOR_ERASE, get_segments_list(list(pages), 4*1024)) - address = 0 + + if use_chip_erase: + erase_type = EraseType.CHIP_ERASE + else: + erase_type = EraseType.SECTOR_ERASE + + result = spifi_erase(openocd, erase_type, get_segments_list(list(pages), 4*1024)) + + if result == 1: + print("Erase error") + return result spifi_quad_enable(openocd) for page_offset in list(pages): - print("Writing page %s..." % hex(page_offset)) page_bytes = pages[page_offset] spifi_write_enable(openocd) @@ -502,10 +540,10 @@ def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, is_resume=T spifi_page_program(openocd, page_offset, page_bytes, 256) spifi_wait_busy(openocd) - result = spifi_read_data(openocd, page_offset, 256, page_bytes) + result = spifi_check_program(openocd, page_offset, 256, page_bytes) if result == 1: - print("Data error") + print("Program error") return result spifi_quad_disable(openocd) diff --git a/mik32_upload.py b/mik32_upload.py index c2baf7a..19d4e9a 100644 --- a/mik32_upload.py +++ b/mik32_upload.py @@ -3,12 +3,13 @@ import argparse import subprocess import os from enum import Enum -from typing import List, Dict, NamedTuple +from typing import List, Dict, NamedTuple, Union from tclrpc import OpenOcdTclRpc import mik32_eeprom import mik32_spifi import mik32_ram from mik32_parsers import * +import config # class bcolors(Enum): @@ -26,6 +27,8 @@ DEFAULT_OPENOCD_SCRIPTS_PATH = os.path.join( supported_formats = [".hex"] +is_verbose = False + def test_connection(): output = "" @@ -50,8 +53,11 @@ class MemorySection(NamedTuple): length: int # Memory section length in bytes +MEMORY_SECTION_BOOT = MemorySection(MemoryType.BOOT, 0x0, 16 * 1024) + + mik32v0_sections: List[MemorySection] = [ - MemorySection(MemoryType.BOOT, 0x0, 16 * 1024), + MEMORY_SECTION_BOOT, MemorySection(MemoryType.EEPROM, 0x01000000, 8 * 1024), MemorySection(MemoryType.RAM, 0x02000000, 16 * 1024), MemorySection(MemoryType.SPIFI, 0x80000000, 8 * 1024 * 1024), @@ -61,7 +67,7 @@ mik32v0_sections: List[MemorySection] = [ @dataclass class Segment: offset: int - memory: MemorySection | None + memory: Union[MemorySection, None] data: List[int] @@ -74,7 +80,7 @@ def belongs_memory_section(memory_section: MemorySection, offset: int) -> bool: return True -def find_memory_section(offset: int) -> MemorySection | None: +def find_memory_section(offset: int) -> Union[MemorySection, None]: for section in mik32v0_sections: if belongs_memory_section(section, offset): return section @@ -94,7 +100,7 @@ def read_file(filename: str) -> List[Segment]: with open(filename, "rb") as f: contents = list(f.read()) segments.append( - Segment(offset=0, memory=find_memory_section(0), data=contents)) + Segment(offset=0, memory=MEMORY_SECTION_BOOT, data=contents)) else: raise Exception("Unsupported file format: %s" % (file_extension)) @@ -107,8 +113,10 @@ def read_file(filename: str) -> List[Segment]: drlo: int = record.address # Data Record Load Offset if (expect_address != lba+drlo) or (segments.__len__() == 0): expect_address = lba+drlo - segments.append(Segment( - offset=expect_address, memory=find_memory_section(expect_address), data=[])) + section = find_memory_section(expect_address) + if section is not None: + segments.append(Segment( + offset=expect_address, memory=section, data=[])) for byte in record.data: segments[-1].data.append(byte) @@ -126,7 +134,7 @@ def read_file(filename: str) -> List[Segment]: def segment_to_pages(segment: Segment, page_size: int, pages: Dict[int, List[int]]): if segment.memory is None: return - + internal_offset = segment.offset - segment.memory.offset for i, byte in enumerate(segment.data): @@ -136,7 +144,7 @@ def segment_to_pages(segment: Segment, page_size: int, pages: Dict[int, List[int if (page_offset) not in pages.keys(): pages[page_offset] = [0] * page_size - + pages[page_offset][byte_offset - page_offset] = byte @@ -145,11 +153,22 @@ def segments_to_pages(segments: List[Segment], page_size: int) -> Dict[int, List for segment in segments: segment_to_pages(segment, page_size, pages) - + return pages -def upload_file(filename: str, host: str = '127.0.0.1', port: int = OpenOcdTclRpc.DEFAULT_PORT, is_resume=True, run_openocd=False, use_quad_spi=False) -> int: +def upload_file( + filename: str, + openocd_path: str, + scripts_path: str, + adapter_speed: str, + host: str = '127.0.0.1', + port: int = OpenOcdTclRpc.DEFAULT_PORT, + is_resume=True, + run_openocd=False, + use_quad_spi=False, + use_chip_erase=False, +) -> int: """ Write ihex or binary file into MIK32 EEPROM or external flash memory @@ -165,6 +184,7 @@ def upload_file(filename: str, host: str = '127.0.0.1', port: int = OpenOcdTclRp result = 0 + print(filename) if not os.path.exists(filename): print("ERROR: File %s does not exist" % filename) exit(1) @@ -181,10 +201,10 @@ def upload_file(filename: str, host: str = '127.0.0.1', port: int = OpenOcdTclRp raise Exception("ERROR: segment with offset %s and length %s overflows section %s" % ( hex(segment.offset), segment.data.__len__(), segment.memory.type.name)) - proc: subprocess.Popen | None = None + proc: Union[subprocess.Popen, None] = None if run_openocd: - 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=False) + cmd = shlex.split("%s -s %s -f interface/ftdi/m-link.cfg -f target/mik32.cfg" % ( + openocd_path, scripts_path), posix=False) proc = subprocess.Popen( cmd, creationflags=subprocess.CREATE_NEW_CONSOLE | subprocess.SW_HIDE) @@ -195,12 +215,14 @@ def upload_file(filename: str, host: str = '127.0.0.1', port: int = OpenOcdTclRp lambda segment: (segment.memory is not None) and (segment.memory.type == MemoryType.SPIFI), segments)), 256) segments_ram = list(filter( lambda segment: (segment.memory is not None) and (segment.memory.type == MemoryType.RAM), segments)) - + if (pages_eeprom.__len__() > 0): - result |= mik32_eeprom.write_pages(pages_eeprom, openocd, is_resume) + result |= mik32_eeprom.write_pages( + pages_eeprom, openocd, is_resume) if (pages_spifi.__len__() > 0): # print(pages_spifi) - result |= mik32_spifi.write_pages(pages_spifi, openocd, is_resume, use_quad_spi) + result |= mik32_spifi.write_pages( + pages_spifi, openocd, is_resume, use_quad_spi, use_chip_erase) if (segments_ram.__len__() > 0): mik32_ram.write_segments(segments_ram, openocd, is_resume) result |= 0 @@ -214,6 +236,12 @@ def upload_file(filename: str, host: str = '127.0.0.1', port: int = OpenOcdTclRp def createParser(): parser = argparse.ArgumentParser() parser.add_argument('filepath', nargs='?') + parser.add_argument('--openocd-path', dest='openocd_path', + default=DEFAULT_OPENOCD_EXEC_FILE_PATH) + parser.add_argument('--scripts-path', dest='scripts_path', + default=DEFAULT_OPENOCD_SCRIPTS_PATH) + parser.add_argument('--adapter-speed', dest='adapter_speed', + default=500) parser.add_argument('--run-openocd', dest='run_openocd', action='store_true', default=False) parser.add_argument('--use-quad-spi', dest='use_quad_spi', @@ -224,6 +252,10 @@ def createParser(): default=OpenOcdTclRpc.DEFAULT_PORT) parser.add_argument('--keep-halt', dest='keep_halt', action='store_true', default=False) + parser.add_argument('-v', '--verbose', dest='is_verbose', + action='store_true', default=False) + parser.add_argument('--use-chip-erase', dest='use_chip_erase', + action='store_true', default=False) # parser.add_argument('-b', '--boot-mode', default='undefined') return parser @@ -232,9 +264,20 @@ def createParser(): if __name__ == '__main__': parser = createParser() namespace = parser.parse_args() + config.is_verbose = namespace.is_verbose if namespace.filepath: - upload_file(namespace.filepath, namespace.openocd_host, - namespace.openocd_port, is_resume=(not namespace.keep_halt), run_openocd=namespace.run_openocd, use_quad_spi=namespace.use_quad_spi) + upload_file( + namespace.filepath, + namespace.openocd_path, + namespace.scripts_path, + namespace.adapter_speed, + host=namespace.openocd_host, + port=namespace.openocd_port, + is_resume=(not namespace.keep_halt), + run_openocd=namespace.run_openocd, + use_quad_spi=namespace.use_quad_spi, + use_chip_erase=namespace.use_chip_erase, + ) else: print("Nothing to upload")