From 9bec497601a23c3f5ea7f4dc47bb6370942e6fba Mon Sep 17 00:00:00 2001 From: sh-sergey Date: Thu, 16 Jan 2025 16:21:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=20eeprom=20=D0=B8=20spifi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit функции сгруппированы в классы, для spifi улучшено разделение функционала между контроллерами интерфейса и флеш памяти --- flash_drivers/generic_flash.py | 544 +++++++++++++++++++++--------- mik32_check.py | 13 +- mik32_debug_hal/eeprom.py | 566 ++++++++++++++----------------- mik32_debug_hal/spifi.py | 592 ++++++++++----------------------- mik32_upload.py | 15 +- 5 files changed, 828 insertions(+), 902 deletions(-) diff --git a/flash_drivers/generic_flash.py b/flash_drivers/generic_flash.py index 2dccacf..847dcae 100644 --- a/flash_drivers/generic_flash.py +++ b/flash_drivers/generic_flash.py @@ -1,212 +1,452 @@ from enum import Enum +import os +import pathlib +import sys import time -from typing import List, Union +from typing import Dict, List, Union from tclrpc import OpenOcdTclRpc -import mik32_debug_hal.spifi as spifi +from mik32_debug_hal.spifi import SPIFI +# import mik32_debug_hal.spifi as spifi import mik32_debug_hal.dma as dma -# -------------------------- -# Commands -# -------------------------- -SREG1_BUSY = 1 +class GenericFlash(): + # -------------------------- + # Commands + # -------------------------- + SREG1_BUSY = 1 -READ_LEN = 256 + READ_LEN = 256 -ENABLE_RESET_COMMAND = 0x66 -RESET_COMMAND = 0x99 + ENABLE_RESET_COMMAND = 0x66 + RESET_COMMAND = 0x99 -CHIP_ERASE_COMMAND = 0xC7 -SECTOR_ERASE_COMMAND = 0x20 + CHIP_ERASE_COMMAND = 0xC7 + SECTOR_ERASE_COMMAND = 0x20 -WRITE_ENABLE_COMMAND = 0x06 -WRITE_DISABLE_COMMAND = 0x04 + WRITE_ENABLE_COMMAND = 0x06 + WRITE_DISABLE_COMMAND = 0x04 -MEM_CONFIG_COMMAND = 0x61 -MEM_CONFIG_VALUE = 0x7F + MEM_CONFIG_COMMAND = 0x61 + MEM_CONFIG_VALUE = 0x7F -READ_DATA_COMMAND = 0x03 + READ_DATA_COMMAND = 0x03 -FAST_READ_QUAD_OUTPUT_COMMAND = 0x6B + FAST_READ_QUAD_OUTPUT_COMMAND = 0x6B -READ_SREG1_COMMAND = 0x05 -READ_SREG2_COMMAND = 0x35 -WRITE_SREG_COMMAND = 0x01 + READ_SREG1_COMMAND = 0x05 + READ_SREG2_COMMAND = 0x35 + WRITE_SREG_COMMAND = 0x01 -SREG2_QUAD_ENABLE = 9 -SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8) -SREG2_QUAD_ENABLE_M = 1 << SREG2_QUAD_ENABLE_S + SREG2_QUAD_ENABLE = 9 + SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8) + SREG2_QUAD_ENABLE_M = 1 << SREG2_QUAD_ENABLE_S -PAGE_PROGRAM_COMMAND = 0x02 + PAGE_PROGRAM_COMMAND = 0x02 -QUAD_PAGE_PROGRAM_COMMAND = 0x32 + QUAD_PAGE_PROGRAM_COMMAND = 0x32 -JEDEC_ID_COMMAND = 0x9F + JEDEC_ID_COMMAND = 0x9F + class FlashError(Exception): + def __init__(self, value): + self.value = value -class FlashError(Exception): - def __init__(self, value): - self.value = value + def __str__(self): + return ("ERROR: " + repr(self.value)) - def __str__(self): - return ("ERROR: " + repr(self.value)) + class SREG_Num(Enum): + SREG1 = 0x00 + SREG2 = 0x30 + openocd: OpenOcdTclRpc + spifi: SPIFI -class SREG_Num(Enum): - SREG1 = 0x00 - SREG2 = 0x30 + def __init__(self, spifi: SPIFI): + self.spifi = spifi + self.openocd = self.spifi.openocd + # self.init() -def write_enable(openocd: OpenOcdTclRpc): - spifi.send_command(openocd, WRITE_ENABLE_COMMAND, - spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL) + def write_enable(self): + self.spifi.send_command(self.WRITE_ENABLE_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL) + def read_sreg(self, sreg: SREG_Num) -> int: + return self.spifi.send_command( + self.READ_SREG1_COMMAND | sreg.value, + self.spifi.Frameform.OPCODE_NOADDR, + self.spifi.Fieldform.ALL_SERIAL, + byte_count=1 + )[0] -def read_sreg(openocd: OpenOcdTclRpc, sreg: SREG_Num) -> int: - return spifi.send_command( - openocd, - READ_SREG1_COMMAND | sreg.value, - spifi.Frameform.OPCODE_NOADDR, - spifi.Fieldform.ALL_SERIAL, - byte_count=1 - )[0] + def write_sreg(self, sreg1: int, sreg2: int): + self.write_enable() + self.spifi.send_command( + self.WRITE_SREG_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, + self.spifi.Fieldform.ALL_SERIAL, + byte_count=2, + direction=self.spifi.Direction.WRITE, + data=[sreg1, sreg2] + ) + self.wait_busy() + def wait_busy(self): + while 1: + sreg1 = self.read_sreg(self.SREG_Num.SREG1) + if not (sreg1 & self.SREG1_BUSY): + break -def write_sreg(openocd: OpenOcdTclRpc, sreg1: int, sreg2: int): - write_enable(openocd) - spifi.send_command( - openocd, - WRITE_SREG_COMMAND, - spifi.Frameform.OPCODE_NOADDR, - spifi.Fieldform.ALL_SERIAL, - byte_count=2, - direction=spifi.Direction.WRITE, - data=[sreg1, sreg2] - ) - wait_busy(openocd) + RESET_DELAY = 0.001 + def chip_reset(self): + self.spifi.send_command(self.ENABLE_RESET_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL) + self.spifi.send_command(self.RESET_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL) + time.sleep(self.RESET_DELAY) -def wait_busy(openocd: OpenOcdTclRpc): - while 1: - sreg1 = read_sreg(openocd, SREG_Num.SREG1) - if not (sreg1 & SREG1_BUSY): - break + def chip_reset_qpi(self): + self.spifi.send_command(self.ENABLE_RESET_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_PARALLEL) + self.spifi.send_command(self.RESET_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_PARALLEL) + time.sleep(self.RESET_DELAY) + def chip_erase(self): + print("Chip erase...", flush=True) + self.spifi.send_command(self.CHIP_ERASE_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL) -RESET_DELAY = 0.001 + def sector_erase(self, address: int): + print(f"Erase sector {address:#010x}...", flush=True) + self.spifi.send_command(self.SECTOR_ERASE_COMMAND, + self.spifi.Frameform.OPCODE_3ADDR, self.spifi.Fieldform.ALL_SERIAL, address=address) + def read_data(self, address: int, byte_count: int, bin_data: List[int], dma: Union[dma.DMA, None] = None, use_quad_spi=False) -> int: + read_data: List[int] = [] -def chip_reset(openocd: OpenOcdTclRpc): - spifi.send_command(openocd, ENABLE_RESET_COMMAND, - spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL) - spifi.send_command(openocd, RESET_COMMAND, - spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL) - time.sleep(RESET_DELAY) + if (use_quad_spi): + read_data = self.spifi.send_command(self.FAST_READ_QUAD_OUTPUT_COMMAND, self.spifi.Frameform.OPCODE_3ADDR, + self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=address, idata_length=1, dma=dma) + else: + read_data = self.spifi.send_command(self.READ_DATA_COMMAND, self.spifi.Frameform.OPCODE_3ADDR, + self.spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=address, dma=dma) + for i in range(byte_count): + if read_data[i] != bin_data[i]: + print( + f"DATA[{i+address}] = {read_data[i]:#0x} expect {bin_data[i]:#0x}", flush=True) -def chip_reset_qpi(openocd: OpenOcdTclRpc): - spifi.send_command(openocd, ENABLE_RESET_COMMAND, - spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_PARALLEL) - spifi.send_command(openocd, RESET_COMMAND, - spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_PARALLEL) - time.sleep(RESET_DELAY) + return 1 + return 0 -def chip_erase(openocd: OpenOcdTclRpc): - print("Chip erase...", flush=True) - spifi.send_command(openocd, CHIP_ERASE_COMMAND, - spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL) + def page_program( + self, + ByteAddress: int, + data: List[int], + byte_count: int, + progress: str = "", + dma: Union[dma.DMA, None] = None + ): + print( + f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True) + if byte_count > 256: + raise self.FlashError("Byte count more than 256") + self.write_enable() + self.spifi.send_command(self.PAGE_PROGRAM_COMMAND, self.spifi.Frameform.OPCODE_3ADDR, + self.spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=ByteAddress, + idata=0, cache_limit=0, direction=self.spifi.Direction.WRITE, data=data, dma=dma) + self.wait_busy() -def sector_erase(openocd: OpenOcdTclRpc, address: int): - print(f"Erase sector {address:#010x}...", flush=True) - spifi.send_command(openocd, SECTOR_ERASE_COMMAND, - spifi.Frameform.OPCODE_3ADDR, spifi.Fieldform.ALL_SERIAL, address=address) + class EraseType(Enum): + CHIP_ERASE = 0 + SECTOR_ERASE = 1 + def erase(self, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []): + if erase_type == self.EraseType.CHIP_ERASE: + self.write_enable() + self.chip_erase() + self.wait_busy() + elif erase_type == self.EraseType.SECTOR_ERASE: + for sector in sectors: + self.write_enable() + self.sector_erase(sector) + self.wait_busy() -def read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: List[int], dma: Union[dma.DMA, None] = None, use_quad_spi=False) -> int: - read_data: List[int] = [] - - if (use_quad_spi): - read_data = spifi.send_command(openocd, FAST_READ_QUAD_OUTPUT_COMMAND, spifi.Frameform.OPCODE_3ADDR, - spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=address, idata_length=1, dma=dma) - else: - read_data = spifi.send_command(openocd, READ_DATA_COMMAND, spifi.Frameform.OPCODE_3ADDR, - spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=address, dma=dma) - - for i in range(byte_count): - if read_data[i] != bin_data[i]: - print( - f"DATA[{i+address}] = {read_data[i]:#0x} expect {bin_data[i]:#0x}", flush=True) - - return 1 - - return 0 - - -def page_program( - openocd: OpenOcdTclRpc, + def quad_page_program( + self, ByteAddress: int, data: List[int], byte_count: int, progress: str = "", dma: Union[dma.DMA, None] = None -): - print(f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True) - if byte_count > 256: - raise FlashError("Byte count more than 256") + ): + print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True) + if byte_count > 256: + raise self.FlashError("Byte count more than 256") - write_enable(openocd) - spifi.send_command(openocd, PAGE_PROGRAM_COMMAND, spifi.Frameform.OPCODE_3ADDR, - spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=ByteAddress, - idata=0, cache_limit=0, direction=spifi.Direction.WRITE, data=data, dma=dma) - wait_busy(openocd) + self.write_enable() + self.spifi.send_command(self.QUAD_PAGE_PROGRAM_COMMAND, self.spifi.Frameform.OPCODE_3ADDR, + self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=ByteAddress, + idata=0, cache_limit=0, direction=self.spifi.Direction.WRITE, data=data, dma=dma) + self.wait_busy() + def quad_enable(self): + if (self.check_quad_enable(self.openocd) != True): + self.write_sreg( + self.read_sreg(self.SREG_Num.SREG1), + self.read_sreg(self.SREG_Num.SREG2) | self.SREG2_QUAD_ENABLE_M + ) -class EraseType(Enum): - CHIP_ERASE = CHIP_ERASE_COMMAND - SECTOR_ERASE = SECTOR_ERASE_COMMAND + def check_quad_enable(self): + return (self.read_sreg(self.SREG_Num.SREG2) & self.SREG2_QUAD_ENABLE_M) != 0 + def check_pages(self, pages: Dict[int, List[int]], use_quad_spi=False, use_chip_erase=False): + result = 0 -def erase(openocd, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []): - if erase_type == EraseType.CHIP_ERASE: - write_enable(openocd) - chip_erase(openocd) - wait_busy(openocd) - elif erase_type == EraseType.SECTOR_ERASE: - for sector in sectors: - write_enable(openocd) - sector_erase(openocd, sector) - wait_busy(openocd) + self.openocd.halt() + # self.init() + # Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим. + self.chip_reset_qpi() -def quad_page_program( - openocd: OpenOcdTclRpc, - ByteAddress: int, - data: List[int], - byte_count: int, - progress: str = "", - dma: Union[dma.DMA, None] = None -): - print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True) - if byte_count > 256: - raise FlashError("Byte count more than 256") + # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим. + self.chip_reset() - write_enable(openocd) - spifi.send_command(openocd, QUAD_PAGE_PROGRAM_COMMAND, spifi.Frameform.OPCODE_3ADDR, - spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=ByteAddress, - idata=0, cache_limit=0, direction=spifi.Direction.WRITE, data=data, dma=dma) - wait_busy(openocd) + JEDEC_ID = self.spifi.send_command(self.JEDEC_ID_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3) + print( + f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}") -def quad_enable(openocd): - if (check_quad_enable(openocd) != True): - write_sreg( - openocd, - read_sreg(openocd, SREG_Num.SREG1), - read_sreg(openocd, SREG_Num.SREG2) | SREG2_QUAD_ENABLE_M - ) + dma_instance = self.spifi.dma_config() + if (use_quad_spi): + print("Using Quad SPI") + self.quad_enable(self.openocd) + else: + print("Using Single SPI") + # spifi_quad_disable(openocd) -def check_quad_enable(openocd): - return (read_sreg(openocd, SREG_Num.SREG2) & SREG2_QUAD_ENABLE_M) != 0 + pages_offsets = list(pages) + + for index, page_offset in enumerate(pages_offsets): + print( + f"Check page {page_offset:#010x}... {(index*100)//pages_offsets.__len__()}%", flush=True) + page_bytes = pages[page_offset] + + result = self.read_data( + self.openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi) + + if result == 1: + print("Data error") + # if (use_quad_spi): + # spifi_quad_disable(openocd) + return result + + if result == 0: + print("SPIFI pages checking completed", flush=True) + return 0 + + def write_pages(self, pages: Dict[int, List[int]], use_quad_spi=False, use_chip_erase=False): + result = 0 + + self.openocd.halt() + # self.init() + + # Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим. + self.chip_reset_qpi() + + # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим. + self.chip_reset() + + JEDEC_ID = self.spifi.send_command(self.JEDEC_ID_COMMAND, + self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3) + + print( + f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}") + + dma_instance = self.spifi.dma_config() + + if use_chip_erase: + self.erase( + self.openocd, self.EraseType.CHIP_ERASE) + else: + self.erase(self.openocd, self.EraseType.SECTOR_ERASE, + self.get_segments_list(list(pages), 4*1024)) + + print("Quad Enable", self.check_quad_enable(self.openocd)) + + if (use_quad_spi): + print("Using Quad SPI") + self.quad_enable(self.openocd) + else: + print("Using Single SPI") + # spifi_quad_disable(openocd) + + # print("SREG1", spifi_read_sreg(openocd, SREG_Num.SREG1)) + # print("SREG2", spifi_read_sreg(openocd, SREG_Num.SREG2)) + + pages_offsets = list(pages) + + for index, page_offset in enumerate(pages_offsets): + page_bytes = pages[page_offset] + + if (use_quad_spi): + self.quad_page_program( + self.openocd, page_offset, page_bytes, 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance) + else: + self.page_program(self.openocd, page_offset, page_bytes, + 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance) + + result = self.read_data( + self.openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi) + + if result == 1: + print("Data error") + return result + + if result == 0: + # Прошивка страниц флеш памяти по SPIFI была завершена + print( + "Flashing of flash memory pages via SPIFI has been completed", flush=True) + return 0 + + def wait_halted(self, timeout_seconds: float = 2): + self.openocd.run(f'wait_halt {int(timeout_seconds * 1000)}') + + def write_pages_by_sectors(self, pages: Dict[int, List[int]], + driver_path: str, + use_quad_spi=False, + use_chip_erase=False, + ): + result = 0 + + self.openocd.halt() + # Отключение прерываний + self.openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") + + # self.init() + # openocd.run("rwp") + + # Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим. + self.chip_reset_qpi() + + # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим. + self.chip_reset() + + JEDEC_ID = self.spifi.send_command( + 0x9F, self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3) + print( + f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}") + + sectors_list = self.get_segments_list(list(pages), 4*1024) + + self.openocd.halt() + pathname = os.path.dirname(sys.argv[0]) + + self.openocd.run("wp 0x2003000 4 w") + + print("Uploading driver... ", end="", flush=True) + self.openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}") + print("OK!", flush=True) + + self.openocd.resume(0x2000000) + self.wait_halted() + + print("Writing Flash by sectors...", flush=True) + + for i, sector in enumerate(sectors_list): + ByteAddress = sector + progress = f"{(i*100)//len(sectors_list)}%" + print(f" {ByteAddress:#010x} {progress:>4}", end="", flush=True) + bytes_list: List[int] = [] + for page in range(16): + page = pages.get(page * 256 + sector) + if page is not None: + bytes_list.extend(page) + else: + bytes_list.extend([0]*256) + + result = self.openocd.write_memory(0x02002000, 8, bytes_list) + if result: + print("ERROR!", flush=True) + print("An error occurred while writing data to the buffer area!") + print("Aborting...", flush=True) + return 1 + + self.openocd.run(f"set_reg {{t6 {sector}}}") + self.openocd.resume() + self.wait_halted(10) # ждем, когда watchpoint сработает + # watchpoint ловит до изменения слова + # делаем шаг, чтобы прочитать новое слово + self.openocd.run("step") + + result = self.openocd.read_memory(0x2003000, 32, 1)[0] + + if result == 0: + print(" OK!", flush=True) + else: + print(" FAIL!", flush=True) + print("result =", result) + break + if result == 0: + print(f" {sectors_list[-1]:#010x} 100% OK!", flush=True) + + self.openocd.run("rwp 0x02003000") + self.spifi.init_memory() + + if result == 0: + # Прошивка страниц флеш памяти по SPIFI была завершена + print("SPIFI writing successfully completed!", flush=True) + else: + print(f"SPIFI writing failed!", flush=True) + return 1 + + return result + + def write(self, address: int, data: List[int], data_len: int): + if data_len > 256: + raise self.SpifiError("Byte count more than 256") + + self.page_program(self.openocd, address, data, data_len) + + print("written") + + def write_file(self, bytes: List[int]): + # print(bytes) + print(f"Write {len(bytes)} bytes") + + self.openocd.halt() + # self.init() + self.erase() + print("bin_data_len = ", len(bytes)) + address = 0 + + for address in range(0, len(bytes), 256): + if ((address + 256) > len(bytes)): + break + print("address = ", address) + self.write(address, bytes, 256) + if self.read_data(address, 256, bytes) == 1: + return 1 + + if (len(bytes) % 256) != 0: + print( + f"address = {address}, +{len(bytes) - address-1}[{address + len(bytes) - address-1}]") + self.write(address, bytes, len(bytes) - address) + if self.read_data(address, len(bytes) - address, bytes) == 1: + return 1 + print("end") + + return 0 + + def get_segments_list(self, pages_offsets: List[int], segment_size: int) -> List[int]: + segments = set() + for offset in pages_offsets: + segments.add(offset & ~(segment_size - 1)) + return sorted(list(segments)) diff --git a/mik32_check.py b/mik32_check.py index 97a6e4b..3af2c68 100644 --- a/mik32_check.py +++ b/mik32_check.py @@ -9,11 +9,12 @@ from typing import List, Union from mik32_debug_hal.power_manager import pm_init from mik32_upload import BootMode, Pages, form_pages, openocd_exec_path, openocd_scripts_path, openocd_interface_path, openocd_target_path, adapter_default_speed, run_openocd, default_post_action, default_log_path, default_openocd_host, mik32_sections, OpenOCDError, adapter_speed_not_supported, memory_page_size from mik32_debug_hal.gpio import MIK32_Version, gpio_init, gpio_deinit -import mik32_debug_hal.eeprom as eeprom -import mik32_debug_hal.spifi as spifi import mik32_debug_hal.ram as ram from hex_parser import FirmwareFile, MemoryType, Segment from tclrpc import OpenOcdTclRpc, TclException +from mik32_debug_hal.eeprom import EEPROM +from mik32_debug_hal.spifi import SPIFI +from flash_drivers.generic_flash import GenericFlash def upload_file( @@ -78,6 +79,8 @@ def upload_file( logging.debug("PM configured!") if (pages.pages_eeprom.__len__() > 0): + eeprom = EEPROM(openocd) + start_time = time.perf_counter() result |= eeprom.check_pages( @@ -90,10 +93,12 @@ def upload_file( f"Check {write_size} bytes in {write_time:.2f} seconds (effective {(write_size/(write_time*1024)):.1f} kbyte/s)") if (pages.pages_spifi.__len__() > 0): gpio_init(openocd, mik_version) + spifi = SPIFI(openocd) + flash = GenericFlash(spifi) start_time = time.perf_counter() - result |= spifi.check_pages( - pages.pages_spifi, openocd, use_quad_spi=use_quad_spi) + result |= flash.check_pages( + pages.pages_spifi, use_quad_spi=use_quad_spi) write_time = time.perf_counter() - start_time write_size = pages.pages_spifi.__len__( diff --git a/mik32_debug_hal/eeprom.py b/mik32_debug_hal/eeprom.py index 1df01ea..fdbeea2 100644 --- a/mik32_debug_hal/eeprom.py +++ b/mik32_debug_hal/eeprom.py @@ -1,9 +1,8 @@ -import datetime from enum import Enum import os import pathlib import sys -from typing import Dict, List, Tuple +from typing import Dict, List import time from tclrpc import OpenOcdTclRpc, TclException from utils import bytes2words @@ -12,262 +11,6 @@ import mik32_debug_hal.registers.memory_map as mem_map import mik32_debug_hal.registers.bitfields.eeprom as eeprom_fields -def eeprom_sysinit(openocd: OpenOcdTclRpc): - print("MCU clock init...", flush=True) - - -class EEPROM_Operation(Enum): - READ = eeprom_fields.OP_RD - ERASE = eeprom_fields.OP_ER - PROGRAM = eeprom_fields.OP_PR - - -class EEPROM_AffectedPages(Enum): - SINGLE = 0 - EVEN = eeprom_fields.BEH_EVEN - ODD = eeprom_fields.BEH_ODD - GLOBAL = eeprom_fields.BEH_GLOB - - -def eeprom_execute_operation(openocd: OpenOcdTclRpc, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]): - # buffer write enable and select affected pages - openocd.write_memory(mem_map.EEPROM_REGS_EEA, 32, [offset, (1 << eeprom_fields.EECON_BWE_S) - | (affected_pages.value << eeprom_fields.EECON_WRBEH_S)]) - - if buffer.__len__() > 32: - return - for word in buffer: - openocd.write_word(mem_map.EEPROM_REGS_EEDAT, word) - # start operation - openocd.write_word(mem_map.EEPROM_REGS_EECON, ( - (1 << eeprom_fields.EECON_EX_S) | (1 << eeprom_fields.EECON_BWE_S) | - (op.value << eeprom_fields.EECON_OP_S) | ( - affected_pages.value << eeprom_fields.EECON_WRBEH_S) - )) - - -def eeprom_configure_cycles(openocd: OpenOcdTclRpc, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500): - openocd.write_word(mem_map.EEPROM_REGS_NCYCRL, LD << eeprom_fields.NCYCRL_N_LD_S | - R_1 << eeprom_fields.NCYCRL_N_R_1_S | R_2 << eeprom_fields.NCYCRL_N_R_2_S) - openocd.write_word(mem_map.EEPROM_REGS_NCYCEP1, CYCEP1) - openocd.write_word(mem_map.EEPROM_REGS_NCYCEP2, CYCEP2) - - -def eeprom_global_erase(openocd: OpenOcdTclRpc): - print("EEPROM global erase...", flush=True) - # configure cycles duration - eeprom_execute_operation( - openocd, EEPROM_Operation.ERASE, EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32) - - -def eeprom_global_erase_check(openocd: OpenOcdTclRpc): - print("EEPROM global erase check through APB...", flush=True) - print(" Read Data at ...", flush=True) - ex_value = 0x00000000 - openocd.write_word(mem_map.EEPROM_REGS_EEA, 0x00000000) - for i in range(0, 64): - print(f" Row={i+1}/64") - for j in range(0, 32): - value = openocd.read_memory(mem_map.EEPROM_REGS_EEDAT, 32, 1)[0] - if ex_value != value: - print( - f"Unexpect value at Row {i}, Word {j}, expect {ex_value:#0x}, {value:#0x}", flush=True) - - -def eeprom_write_word(openocd: OpenOcdTclRpc, address: int, word: int): - eeprom_execute_operation( - openocd, EEPROM_Operation.PROGRAM, EEPROM_AffectedPages.SINGLE, address, [word]) - time.sleep(0.001) - - -def eeprom_write_page(openocd: OpenOcdTclRpc, address: int, data: List[int]): - eeprom_execute_operation( - openocd, EEPROM_Operation.PROGRAM, EEPROM_AffectedPages.SINGLE, address, data) - time.sleep(0.001) - - -def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int: - if print_progress: - print("EEPROM check through APB...", flush=True) - # address load - openocd.write_word(mem_map.EEPROM_REGS_EEA, offset) - word_num = 0 - progress = 0 - if print_progress: - print("[", end="", flush=True) - for word in words: - value: int = openocd.read_word(mem_map.EEPROM_REGS_EEDAT) - if words[word_num] != value: - print( - f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}", flush=True) - return 1 - word_num += 1 - curr_progress = int((word_num * 50) / len(words)) - if print_progress and (curr_progress > progress): - print("#"*(curr_progress - progress), end="", flush=True) - progress = curr_progress - if print_progress: - print("]", flush=True) - print("EEPROM check through APB done!", flush=True) - return 0 - - -def eeprom_check_data_ahb_lite(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int: - if print_progress: - print("EEPROM check through AHB-Lite...", flush=True) - mem_array = openocd.read_memory(0x01000000 + offset, 32, len(words)) - if len(words) != len(mem_array): - print("ERROR: Wrong number of words in read_memory output!") - return 1 - progress = 0 - if print_progress: - print("[", end="", flush=True) - for word_num in range(len(words)): - if words[word_num] != mem_array[word_num]: - print(f"Unexpect value at {word_num} word, expect {words[word_num]:#0x}, " - f"get {mem_array[word_num]:#0x}", flush=True) - return 1 - curr_progress = int((word_num * 50) / len(words)) - if print_progress and (curr_progress > progress): - print("#"*(curr_progress - progress), end="", flush=True) - progress = curr_progress - if print_progress: - print("]", flush=True) - print("EEPROM check through APB done!", flush=True) - return 0 - - -def eeprom_check_data(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True, read_through_apb=False) -> int: - if read_through_apb: - return eeprom_check_data_apb(openocd, words, offset, print_progress) - else: - return eeprom_check_data_ahb_lite(openocd, words, offset, print_progress) - - -def write_words(words: List[int], openocd: OpenOcdTclRpc, write_by_word=False, read_through_apb=False) -> int: - """ - Write words in MIK32 EEPROM through APB bus - - @words: list of words to write at offset 0x0 - @write_by_word: if True, write every word in separete page flash operation - @read_through_apb: if True, check written words through APB instead of AHB-Lite - - TODO: implement setting byte array offset, add error handling, - improve progress visualization, add option check page immidiately after writing - - @return: return 0 if successful, 1 if failed - """ - print(f"Write {len(words*4)} bytes", flush=True) - - openocd.halt() - eeprom_sysinit(openocd) - eeprom_global_erase(openocd) - # eeprom_global_erase_check(openocd) - # configure cycles duration - eeprom_configure_cycles(openocd, 1, 3, 1, 100000, 1000) - time.sleep(0.1) - word_num: int = 0 - progress: int = 0 - print("EEPROM writing...", flush=True) - print("[", end="", flush=True) - if write_by_word: - for word in words: - eeprom_write_word(openocd, word_num*4, word) - word_num += 1 - curr_progress = int((word_num * 50) / len(words)) - if curr_progress > progress: - print("#"*(curr_progress - progress), end="", flush=True) - progress = curr_progress - else: - page = [] - page_num = 0 - page_size = 32 - while word_num < len(words): - if word_num < page_size*(page_num+1): - page.append(words[word_num]) - word_num += 1 - else: - # print(list(map(lambda word: f"{word:#0x}", page))) - eeprom_write_page(openocd, page_num*page_size*4, page) - page_num += 1 - page.clear() - curr_progress = int((word_num * 50) / len(words)) - if curr_progress > progress: - print("#"*(curr_progress - progress), end="", flush=True) - progress = curr_progress - eeprom_write_page(openocd, page_num*page_size*4, page) - print("]", flush=True) - if read_through_apb: - result = eeprom_check_data_apb(openocd, words, 0) - else: - result = eeprom_check_data_ahb_lite(openocd, words, 0) - - if result == 0: - print("EEPROM write file done!", flush=True) - return result - - -def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc) -> int: - openocd.halt() - eeprom_sysinit(openocd) - # configure cycles duration - eeprom_configure_cycles(openocd, 1, 3, 1, 100000, 1000) - time.sleep(0.1) - print("EEPROM checking...", flush=True) - - pages_offsets = list(pages) - - for index, page_offset in enumerate(pages_offsets): - page_words = bytes2words(pages[page_offset]) - - print( - f"Check page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True) - - if eeprom_check_data(openocd, page_words, page_offset, False): - print("Page mismatch!", flush=True) - return 1 - - print("EEPROM page check completed", flush=True) - return 0 - - -def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc) -> int: - openocd.halt() - eeprom_sysinit(openocd) - eeprom_global_erase(openocd) - if eeprom_check_data_ahb_lite(openocd, [0]*2048, 0, False): - print("EEPROM global erase failed, try again", flush=True) - eeprom_global_erase(openocd) - - if eeprom_check_data_ahb_lite(openocd, [0]*2048, 0, False): - print("EEPROM global erase failed", flush=True) - return 1 - # configure cycles duration - eeprom_configure_cycles(openocd, 1, 3, 1, 100000, 1000) - time.sleep(0.1) - print("EEPROM writing...", flush=True) - - pages_offsets = list(pages) - - for index, page_offset in enumerate(pages_offsets): - page_words = bytes2words(pages[page_offset]) - - print( - f"Writing page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True) - eeprom_write_page(openocd, page_offset, page_words) - - if eeprom_check_data(openocd, page_words, page_offset, False): - print("Page mismatch!", flush=True) - return 1 - - print("EEPROM page recording completed", flush=True) - return 0 - - -def wait_halted(openocd: OpenOcdTclRpc, timeout_seconds: float = 2): - openocd.run(f'wait_halt {int(timeout_seconds * 1000)}') - - def combine_pages(pages: Dict[int, List[int]]) -> List[int]: """ Объединить страницы в последовательность байт с заполнением промежутков @@ -287,83 +30,270 @@ def combine_pages(pages: Dict[int, List[int]]) -> List[int]: return bytes_list -def write_memory(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, driver_path: str) -> int: - """ - Записать всю память с использованием драйвера. +class EEPROM(): + openocd: OpenOcdTclRpc - pages: Dict[int, List[int]] -- страница - список байт, ключ - адрес в EEPROM - """ + def __init__(self, openocd: OpenOcdTclRpc): + self.openocd = openocd - # TODO: добавить проверку на версию mik32 - текущий драйвер поддерживает - # только версию mik32v2 + self.eeprom_sysinit() - RAM_OFFSET = 0x02000000 - RAM_BUFFER_OFFSET = 0x02001800 - RAM_DRIVER_STATUS = 0x02003800 + def eeprom_sysinit(self): + print("MCU clock init...", flush=True) - bytes_list = combine_pages(pages) - openocd.halt() - openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний + class EEPROM_Operation(Enum): + READ = eeprom_fields.OP_RD + ERASE = eeprom_fields.OP_ER + PROGRAM = eeprom_fields.OP_PR - STATUS_CODE_M = 0xFF + class EEPROM_AffectedPages(Enum): + SINGLE = 0 + EVEN = eeprom_fields.BEH_EVEN + ODD = eeprom_fields.BEH_ODD + GLOBAL = eeprom_fields.BEH_GLOB - max_address = len(bytes_list) // 128 - openocd.write_memory(RAM_DRIVER_STATUS, 32, [1 | (max_address << 8)]) + def eeprom_execute_operation(self, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]): + # buffer write enable and select affected pages + self.openocd.write_memory(mem_map.EEPROM_REGS_EEA, 32, [offset, (1 << eeprom_fields.EECON_BWE_S) + | (affected_pages.value << eeprom_fields.EECON_WRBEH_S)]) - pathname = os.path.dirname(sys.argv[0]) + if buffer.__len__() > 32: + return + for word in buffer: + self.openocd.write_word(mem_map.EEPROM_REGS_EEDAT, word) + # start operation + self.openocd.write_word(mem_map.EEPROM_REGS_EECON, ( + (1 << eeprom_fields.EECON_EX_S) | (1 << eeprom_fields.EECON_BWE_S) | + (op.value << eeprom_fields.EECON_OP_S) | ( + affected_pages.value << eeprom_fields.EECON_WRBEH_S) + )) - print("Uploading driver... ", end="", flush=True) - openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}") - print("OK!", flush=True) + def eeprom_configure_cycles(self, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500): + self.openocd.write_word(mem_map.EEPROM_REGS_NCYCRL, LD << eeprom_fields.NCYCRL_N_LD_S | + R_1 << eeprom_fields.NCYCRL_N_R_1_S | R_2 << eeprom_fields.NCYCRL_N_R_2_S) + self.openocd.write_word(mem_map.EEPROM_REGS_NCYCEP1, CYCEP1) + self.openocd.write_word(mem_map.EEPROM_REGS_NCYCEP2, CYCEP2) - print("Uploading data... ", end="", flush=True) - result = openocd.write_memory(RAM_BUFFER_OFFSET, 8, bytes_list) - if result: - print("ERROR!", flush=True) - print("An error occurred while writing data to the buffer area!") - print("Aborting...", flush=True) - return 1 - else: + def eeprom_global_erase(self): + print("EEPROM global erase...", flush=True) + # configure cycles duration + self.eeprom_execute_operation( + self.EEPROM_Operation.ERASE, self.EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32) + + def eeprom_global_erase_check(self): + print("EEPROM global erase check through APB...", flush=True) + print(" Read Data at ...", flush=True) + ex_value = 0x00000000 + self.openocd.write_word(mem_map.EEPROM_REGS_EEA, 0x00000000) + for i in range(0, 64): + print(f" Row={i+1}/64") + for j in range(0, 32): + value = self.openocd.read_memory( + mem_map.EEPROM_REGS_EEDAT, 32, 1)[0] + if ex_value != value: + print( + f"Unexpect value at Row {i}, Word {j}, expect {ex_value:#0x}, {value:#0x}", flush=True) + + def eeprom_write_word(self, address: int, word: int): + self.eeprom_execute_operation( + self.EEPROM_Operation.PROGRAM, self.EEPROM_AffectedPages.SINGLE, address, [word]) + time.sleep(0.001) + + def eeprom_write_page(self, address: int, data: List[int]): + self.eeprom_execute_operation( + self.EEPROM_Operation.PROGRAM, self.EEPROM_AffectedPages.SINGLE, address, data) + time.sleep(0.001) + + def eeprom_check_data_apb(self, words: List[int], offset: int, print_progress=True) -> int: + if print_progress: + print("EEPROM check through APB...", flush=True) + # address load + self.openocd.write_word(mem_map.EEPROM_REGS_EEA, offset) + word_num = 0 + progress = 0 + if print_progress: + print("[", end="", flush=True) + for word in words: + value: int = self.openocd.read_word(mem_map.EEPROM_REGS_EEDAT) + if words[word_num] != value: + print( + f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}", flush=True) + return 1 + word_num += 1 + curr_progress = int((word_num * 50) / len(words)) + if print_progress and (curr_progress > progress): + print("#"*(curr_progress - progress), end="", flush=True) + progress = curr_progress + if print_progress: + print("]", flush=True) + print("EEPROM check through APB done!", flush=True) + return 0 + + def eeprom_check_data_ahb_lite(self, words: List[int], offset: int, print_progress=True) -> int: + if print_progress: + print("EEPROM check through AHB-Lite...", flush=True) + mem_array = self.openocd.read_memory( + 0x01000000 + offset, 32, len(words)) + if len(words) != len(mem_array): + print("ERROR: Wrong number of words in read_memory output!") + return 1 + progress = 0 + if print_progress: + print("[", end="", flush=True) + for word_num in range(len(words)): + if words[word_num] != mem_array[word_num]: + print(f"Unexpect value at {word_num} word, expect {words[word_num]:#0x}, " + f"get {mem_array[word_num]:#0x}", flush=True) + return 1 + curr_progress = int((word_num * 50) / len(words)) + if print_progress and (curr_progress > progress): + print("#"*(curr_progress - progress), end="", flush=True) + progress = curr_progress + if print_progress: + print("]", flush=True) + print("EEPROM check through APB done!", flush=True) + return 0 + + def eeprom_check_data(self, words: List[int], offset: int, print_progress=True, read_through_apb=False) -> int: + if read_through_apb: + return self.eeprom_check_data_apb(words, offset, print_progress) + else: + return self.eeprom_check_data_ahb_lite(words, offset, print_progress) + + def check_pages(self, pages: Dict[int, List[int]]) -> int: + self.openocd.halt() + self.eeprom_sysinit() + # configure cycles duration + self.eeprom_configure_cycles(1, 3, 1, 100000, 1000) + time.sleep(0.1) + print("EEPROM checking...", flush=True) + + pages_offsets = list(pages) + + for index, page_offset in enumerate(pages_offsets): + page_words = bytes2words(pages[page_offset]) + + print( + f"Check page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True) + + if self.eeprom_check_data(page_words, page_offset, False): + print("Page mismatch!", flush=True) + return 1 + + print("EEPROM page check completed", flush=True) + return 0 + + def write_pages(self, pages: Dict[int, List[int]]) -> int: + self.openocd.halt() + self.eeprom_sysinit() + self.eeprom_global_erase() + + if self.eeprom_check_data_ahb_lite([0]*2048, 0, False): + print("EEPROM global erase failed, try again", flush=True) + self.eeprom_global_erase() + + if self.eeprom_check_data_ahb_lite([0]*2048, 0, False): + print("EEPROM global erase failed", flush=True) + return 1 + + # configure cycles duration + self.eeprom_configure_cycles(1, 3, 1, 100000, 1000) + time.sleep(0.1) + print("EEPROM writing...", flush=True) + + pages_offsets = list(pages) + + for index, page_offset in enumerate(pages_offsets): + page_words = bytes2words(pages[page_offset]) + + print( + f"Writing page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True) + self.eeprom_write_page(page_offset, page_words) + + if self.eeprom_check_data(page_words, page_offset, False): + print("Page mismatch!", flush=True) + return 1 + + print("EEPROM page recording completed", flush=True) + return 0 + + def wait_halted(self, timeout_seconds: float = 2): + self.openocd.run(f'wait_halt {int(timeout_seconds * 1000)}') + + def write_memory(self, pages: Dict[int, List[int]], driver_path: str) -> int: + """ + Записать всю память с использованием драйвера. + + pages: Dict[int, List[int]] -- страница - список байт, ключ - адрес в EEPROM + """ + + # TODO: добавить проверку на версию mik32 - текущий драйвер поддерживает + # только версию mik32v2 + + RAM_OFFSET = 0x02000000 + RAM_BUFFER_OFFSET = 0x02001800 + RAM_DRIVER_STATUS = 0x02003800 + + bytes_list = combine_pages(pages) + self.openocd.halt() + # Отключение прерываний + self.openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") + + STATUS_CODE_M = 0xFF + + max_address = len(bytes_list) // 128 + self.openocd.write_memory(RAM_DRIVER_STATUS, 32, [ + 1 | (max_address << 8)]) + + pathname = os.path.dirname(sys.argv[0]) + + print("Uploading driver... ", end="", flush=True) + self.openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}") print("OK!", flush=True) - # mem = openocd.read_memory(0x01000000, 8, len(bytes_list)) - # print(f"total bytes read {len(bytes_list)}") + print("Uploading data... ", end="", flush=True) + result = self.openocd.write_memory(RAM_BUFFER_OFFSET, 8, bytes_list) + if result: + print("ERROR!", flush=True) + print("An error occurred while writing data to the buffer area!") + print("Aborting...", flush=True) + return 1 + else: + print("OK!", flush=True) - # for i in range(len(bytes_list)): - # if bytes_list[i] != mem[i]: - # print(f"RAM data mismatch at address 0x{i:08x};" - # f"expect 0x{bytes_list[i]:08x} get 0x{mem[i]:08x}!", flush=True) - # return 1 + # готовимся поймать результат записи + self.openocd.run(f"wp 0x{RAM_DRIVER_STATUS:08x} 4 w") - openocd.run(f"wp 0x{RAM_DRIVER_STATUS:08x} 4 w") # готовимся поймать результат записи + print("Run driver...", flush=True) + self.openocd.resume(RAM_OFFSET) - print("Run driver...", flush=True) - openocd.resume(RAM_OFFSET) + try: + # ждем, когда watchpoint сработает + self.wait_halted(10) + except TclException: + print("Timeout!", flush=True) + # return 1 - try: - # ждем, когда watchpoint сработает - wait_halted(openocd, 10) - except TclException: - print("Timeout!", flush=True) - # return 1 + # watchpoint ловит до изменения слова + self.openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}") + # делаем шаг, чтобы прочитать новое слово + self.openocd.run("step") - openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}") # watchpoint ловит до изменения слова - openocd.run("step") # делаем шаг, чтобы прочитать новое слово + result = self.openocd.read_memory(RAM_DRIVER_STATUS, 32, 1)[0] - result = openocd.read_memory(RAM_DRIVER_STATUS, 32, 1)[0] + if (result & STATUS_CODE_M) == 0: + print(f"EEPROM writing successfully completed!", flush=True) + else: + miss_page = (result >> 8) & (64 - 1) + miss_byte = (result >> 16) & (128 - 1) + expected_byte = pages[miss_page*128][miss_byte] + miss_byte = (result >> 24) & 0xFF - if (result & STATUS_CODE_M) == 0: - print(f"EEPROM writing successfully completed!", flush=True) - else: - miss_page = (result >> 8) & (64 - 1) - miss_byte = (result >> 16) & (128 - 1) - expected_byte = pages[miss_page*128][miss_byte] - miss_byte = (result >> 24) & 0xFF + print(f"EEPROM writing failed!", flush=True) + print(f"First mismatched byte in page {miss_page},") + print( + f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}") - print(f"EEPROM writing failed!", flush=True) - print(f"First mismatched byte in page {miss_page},") - print(f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}") + return 1 - return 1 - - return 0 + return 0 diff --git a/mik32_debug_hal/spifi.py b/mik32_debug_hal/spifi.py index f0267d5..69acf96 100644 --- a/mik32_debug_hal/spifi.py +++ b/mik32_debug_hal/spifi.py @@ -1,466 +1,214 @@ -import datetime from enum import Enum -import os -import pathlib -import sys -from typing import Dict, List, Union +from typing import List, Union import time -from tclrpc import TclException from tclrpc import OpenOcdTclRpc import mik32_debug_hal.registers.memory_map as mem_map import mik32_debug_hal.registers.bitfields.spifi as spifi_fields import mik32_debug_hal.dma as dma -import flash_drivers.generic_flash as generic_flash -class SpifiError(Exception): - def __init__(self, value): - self.value = value +class SPIFI(): - def __str__(self): - return ("ERROR: " + repr(self.value)) + DEFAULT_READ_DATA_COMMAND = 0x03 + class SpifiError(Exception): + def __init__(self, value): + self.value = value -def spifi_intrq_clear(openocd: OpenOcdTclRpc): - openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | - spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) + def __str__(self): + return ("ERROR: " + repr(self.value)) + class Frameform(Enum): + RESERVED = 0 + OPCODE_NOADDR = 1 + OPCODE_1ADDR = 2 + OPCODE_2ADDR = 3 + OPCODE_3ADDR = 4 + OPCODE_4ADDR = 5 + NOOPCODE_3ADDR = 6 + NOOPCODE_4ADDR = 7 -INIT_DELAY = 0.001 + class Fieldform(Enum): + ALL_SERIAL = 0 + DATA_PARALLEL = 1 + OPCODE_SERIAL = 2 + ALL_PARALLEL = 3 -TIMEOUT = 1.0 + class Direction(Enum): + READ = 0 + WRITE = 1 + INIT_DELAY = 0.001 -def init_periphery(openocd: OpenOcdTclRpc): - openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | - # SPIFI_CONFIG_STAT_INTRQ_M | - spifi_fields.SPIFI_CONFIG_STAT_RESET_M) - # openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word( - # SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)) - openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00) - openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00) - openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00) + TIMEOUT = 1.0 - time.sleep(INIT_DELAY) + openocd: OpenOcdTclRpc + def __init__(self, openocd: OpenOcdTclRpc): + self.openocd = openocd -def init(openocd: OpenOcdTclRpc): + self.init() - init_periphery(openocd) + def intrq_clear(self): + self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | + spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) - control = openocd.read_word(mem_map.SPIFI_CONFIG_CTRL) - control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M - openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control) + def init_periphery(self): + self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | + # SPIFI_CONFIG_STAT_INTRQ_M | + spifi_fields.SPIFI_CONFIG_STAT_RESET_M) + # openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word( + # SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)) + self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00) + self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00) + self.openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00) - time.sleep(INIT_DELAY) + time.sleep(self.INIT_DELAY) + def init(self): -def init_memory(openocd: OpenOcdTclRpc): - openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | - spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M | - spifi_fields.SPIFI_CONFIG_STAT_RESET_M) - # openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word( - # SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)) - openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00) - openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00) - openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00) - openocd.write_word(mem_map.SPIFI_CONFIG_MCMD, (0 << spifi_fields.SPIFI_CONFIG_MCMD_INTLEN_S) | - (spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << spifi_fields.SPIFI_CONFIG_MCMD_FIELDFORM_S) | - (spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << spifi_fields.SPIFI_CONFIG_MCMD_FRAMEFORM_S) | - (generic_flash.READ_DATA_COMMAND << spifi_fields.SPIFI_CONFIG_MCMD_OPCODE_S)) + self.init_periphery() - time.sleep(INIT_DELAY) + control = self.openocd.read_word(mem_map.SPIFI_CONFIG_CTRL) + control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M + self.openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control) + time.sleep(self.INIT_DELAY) -def spifi_wait_intrq_timeout(openocd: OpenOcdTclRpc, error_message: str): - time_end = time.perf_counter() + TIMEOUT - while time.perf_counter() < time_end: - if (openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0: - return - raise SpifiError(error_message) + def init_memory(self): + self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | + spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M | + spifi_fields.SPIFI_CONFIG_STAT_RESET_M) + # openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word( + # SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)) + self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00) + self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00) + self.openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00) + self.openocd.write_word(mem_map.SPIFI_CONFIG_MCMD, (0 << spifi_fields.SPIFI_CONFIG_MCMD_INTLEN_S) | + (spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << spifi_fields.SPIFI_CONFIG_MCMD_FIELDFORM_S) | + (spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << spifi_fields.SPIFI_CONFIG_MCMD_FRAMEFORM_S) | + (self.DEFAULT_READ_DATA_COMMAND << spifi_fields.SPIFI_CONFIG_MCMD_OPCODE_S)) + time.sleep(self.INIT_DELAY) -class Frameform(Enum): - RESERVED = 0 - OPCODE_NOADDR = 1 - OPCODE_1ADDR = 2 - OPCODE_2ADDR = 3 - OPCODE_3ADDR = 4 - OPCODE_4ADDR = 5 - NOOPCODE_3ADDR = 6 - NOOPCODE_4ADDR = 7 + def spifi_wait_intrq_timeout(self, error_message: str): + time_end = time.perf_counter() + self.TIMEOUT + while time.perf_counter() < time_end: + if (self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0: + return + raise self.SpifiError(error_message) + def send_command( + self, + cmd: int, + frameform: Frameform, + fieldform: Fieldform, + byte_count=0, + address=0, + idata=0, + cache_limit=0, + idata_length=0, + direction=Direction.READ, + data: List[int] = [], + dma: Union[dma.DMA, None] = None + ) -> List[int]: + if (dma is not None) and (direction == self.Direction.WRITE): + self.openocd.write_memory(0x02003F00, 8, data) -class Fieldform(Enum): - ALL_SERIAL = 0 - DATA_PARALLEL = 1 - OPCODE_SERIAL = 2 - ALL_PARALLEL = 3 + dma.channels[0].start( + 0x02003F00, + mem_map.SPIFI_CONFIG_DATA32, + 255 + ) + elif (dma is not None) and (direction == self.Direction.READ): + dma.channels[1].start( + mem_map.SPIFI_CONFIG_DATA32, + 0x02003F00, + 255 + ) + self.openocd.write_memory( + mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata]) -class Direction(Enum): - READ = 0 - WRITE = 1 + cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) | + (frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) | + (fieldform.value << spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_S) | + (byte_count << spifi_fields.SPIFI_CONFIG_CMD_DATALEN_S) | + (idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) | + (direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S)) + self.openocd.write_memory( + mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value]) -def send_command( - openocd: OpenOcdTclRpc, - cmd: int, - frameform: Frameform, - fieldform: Fieldform, - byte_count=0, - address=0, - idata=0, - cache_limit=0, - idata_length=0, - direction=Direction.READ, - data: List[int] = [], - dma: Union[dma.DMA, None] = None -) -> List[int]: - if (dma is not None) and (direction == Direction.WRITE): - openocd.write_memory(0x02003F00, 8, data) + if direction == self.Direction.READ: + out_list = [] + if dma is not None: + dma.dma_wait(dma.channels[1], 0.1) + out_list.extend(self.openocd.read_memory( + 0x02003F00, 8, byte_count)) - dma.channels[0].start( - 0x02003F00, - mem_map.SPIFI_CONFIG_DATA32, - 255 - ) - elif (dma is not None) and (direction == Direction.READ): - dma.channels[1].start( - mem_map.SPIFI_CONFIG_DATA32, - 0x02003F00, - 255 - ) - - openocd.write_memory(mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata]) - - cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) | - (frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) | - (fieldform.value << spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_S) | - (byte_count << spifi_fields.SPIFI_CONFIG_CMD_DATALEN_S) | - (idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) | - (direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S)) - - openocd.write_memory(mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value]) - - if direction == Direction.READ: - out_list = [] - if dma is not None: - dma.dma_wait(dma.channels[1], 0.1) - out_list.extend(openocd.read_memory(0x02003F00, 8, byte_count)) - - return out_list - else: - for i in range(byte_count): - out_list.append(openocd.read_memory( - mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0]) - return out_list - - if direction == Direction.WRITE: - if dma is not None: - dma.dma_wait(dma.channels[0], 0.1) - else: - if (byte_count % 4) == 0: - for i in range(0, byte_count, 4): - openocd.write_memory(mem_map.SPIFI_CONFIG_DATA32, 32, [ - data[i] + data[i+1] * 256 + data[i+2] * 256 * 256 + data[i+3] * 256 * 256 * 256]) + return out_list else: for i in range(byte_count): - openocd.write_memory( - mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]]) + out_list.append(self.openocd.read_memory( + mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0]) + return out_list - return [] - - -def write(openocd: OpenOcdTclRpc, address: int, data: List[int], data_len: int): - if data_len > 256: - raise SpifiError("Byte count more than 256") - - generic_flash.page_program(openocd, address, data, data_len) - - print("written") - - -def write_file(bytes: List[int], openocd: OpenOcdTclRpc): - # print(bytes) - print(f"Write {len(bytes)} bytes") - - openocd.halt() - init(openocd) - generic_flash.erase(openocd) - print("bin_data_len = ", len(bytes)) - address = 0 - - for address in range(0, len(bytes), 256): - if ((address + 256) > len(bytes)): - break - print("address = ", address) - write(openocd, address, bytes, 256) - if generic_flash.read_data(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}]") - write(openocd, address, bytes, len(bytes) - address) - if generic_flash.read_data(openocd, address, len(bytes) - address, bytes) == 1: - return 1 - print("end") - - return 0 - - -def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]: - segments = set() - for offset in pages_offsets: - segments.add(offset & ~(segment_size - 1)) - return sorted(list(segments)) - - -def dma_config(openocd: OpenOcdTclRpc) -> dma.DMA: - dma_instance = dma.DMA(openocd) - dma_instance.init() - - dma_instance.channels[0].write_buffer = 0 - - dma_instance.channels[0].channel = dma.ChannelIndex.CHANNEL_0 - dma_instance.channels[0].priority = dma.ChannelPriority.VERY_HIGH - - dma_instance.channels[0].read_mode = dma.ChannelMode.MEMORY - dma_instance.channels[0].read_increment = dma.ChannelIncrement.ENABLE - dma_instance.channels[0].read_size = dma.ChannelSize.WORD - dma_instance.channels[0].read_burst_size = 2 - dma_instance.channels[0].read_request = dma.ChannelRequest.SPIFI_REQUEST - dma_instance.channels[0].read_ack = dma.ChannelAck.DISABLE - - dma_instance.channels[0].write_mode = dma.ChannelMode.PERIPHERY - dma_instance.channels[0].write_increment = dma.ChannelIncrement.DISABLE - dma_instance.channels[0].write_size = dma.ChannelSize.WORD - dma_instance.channels[0].write_burst_size = 2 - dma_instance.channels[0].write_request = dma.ChannelRequest.SPIFI_REQUEST - dma_instance.channels[0].write_ack = dma.ChannelAck.DISABLE - - dma_instance.channels[1].write_buffer = 0 - - dma_instance.channels[1].channel = dma.ChannelIndex.CHANNEL_1 - dma_instance.channels[1].priority = dma.ChannelPriority.VERY_HIGH - - dma_instance.channels[1].write_mode = dma.ChannelMode.MEMORY - dma_instance.channels[1].write_increment = dma.ChannelIncrement.ENABLE - dma_instance.channels[1].write_size = dma.ChannelSize.WORD - dma_instance.channels[1].write_burst_size = 2 - dma_instance.channels[1].write_request = dma.ChannelRequest.SPIFI_REQUEST - dma_instance.channels[1].write_ack = dma.ChannelAck.DISABLE - - dma_instance.channels[1].read_mode = dma.ChannelMode.PERIPHERY - dma_instance.channels[1].read_increment = dma.ChannelIncrement.DISABLE - dma_instance.channels[1].read_size = dma.ChannelSize.WORD - dma_instance.channels[1].read_burst_size = 2 - dma_instance.channels[1].read_request = dma.ChannelRequest.SPIFI_REQUEST - dma_instance.channels[1].read_ack = dma.ChannelAck.DISABLE - - return dma_instance - - -def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False): - result = 0 - - openocd.halt() - init(openocd) - - # Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим. - generic_flash.chip_reset_qpi(openocd) - - # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим. - generic_flash.chip_reset(openocd) - - JEDEC_ID = send_command(openocd, generic_flash.JEDEC_ID_COMMAND, - Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3) - - print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}") - - dma_instance = dma_config(openocd) - - if (use_quad_spi): - print("Using Quad SPI") - generic_flash.quad_enable(openocd) - else: - print("Using Single SPI") - # spifi_quad_disable(openocd) - - pages_offsets = list(pages) - - for index, page_offset in enumerate(pages_offsets): - print( - f"Check page {page_offset:#010x}... {(index*100)//pages_offsets.__len__()}%", flush=True) - page_bytes = pages[page_offset] - - result = generic_flash.read_data( - openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi) - - if result == 1: - print("Data error") - # if (use_quad_spi): - # spifi_quad_disable(openocd) - return result - - if result == 0: - print("SPIFI pages checking completed", flush=True) - return 0 - - -def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False): - result = 0 - - openocd.halt() - init(openocd) - - # Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим. - generic_flash.chip_reset_qpi(openocd) - - # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим. - generic_flash.chip_reset(openocd) - - JEDEC_ID = send_command(openocd, generic_flash.JEDEC_ID_COMMAND, - Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3) - - print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}") - - dma_instance = dma_config(openocd) - - if use_chip_erase: - generic_flash.erase(openocd, generic_flash.EraseType.CHIP_ERASE) - else: - generic_flash.erase(openocd, generic_flash.EraseType.SECTOR_ERASE, - get_segments_list(list(pages), 4*1024)) - - print("Quad Enable", generic_flash.check_quad_enable(openocd)) - - if (use_quad_spi): - print("Using Quad SPI") - generic_flash.quad_enable(openocd) - else: - print("Using Single SPI") - # spifi_quad_disable(openocd) - - # print("SREG1", spifi_read_sreg(openocd, SREG_Num.SREG1)) - # print("SREG2", spifi_read_sreg(openocd, SREG_Num.SREG2)) - - pages_offsets = list(pages) - - for index, page_offset in enumerate(pages_offsets): - page_bytes = pages[page_offset] - - if (use_quad_spi): - generic_flash.quad_page_program( - openocd, page_offset, page_bytes, 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance) - else: - generic_flash.page_program(openocd, page_offset, page_bytes, - 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance) - - result = generic_flash.read_data( - openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi) - - if result == 1: - print("Data error") - return result - - if result == 0: - # Прошивка страниц флеш памяти по SPIFI была завершена - print("Flashing of flash memory pages via SPIFI has been completed", flush=True) - return 0 - - -def wait_halted(openocd: OpenOcdTclRpc, timeout_seconds: float = 2): - openocd.run(f'wait_halt {int(timeout_seconds * 1000)}') - - -def write_pages_by_sectors(pages: Dict[int, List[int]], - openocd: OpenOcdTclRpc, - driver_path: str, - use_quad_spi=False, - use_chip_erase=False, - ): - result = 0 - - openocd.halt() - openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний - - init(openocd) - # openocd.run("rwp") - - # Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим. - generic_flash.chip_reset_qpi(openocd) - - # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим. - generic_flash.chip_reset(openocd) - - JEDEC_ID = send_command( - openocd, 0x9F, Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3) - print(f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}") - - dma_instance = dma_config(openocd) - - sectors_list = get_segments_list(list(pages), 4*1024) - - openocd.halt() - pathname = os.path.dirname(sys.argv[0]) - - openocd.run("wp 0x2003000 4 w") - - print("Uploading driver... ", end="", flush=True) - openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}") - print("OK!", flush=True) - - openocd.resume(0x2000000) - wait_halted(openocd) - - print("Writing Flash by sectors...", flush=True) - - for i, sector in enumerate(sectors_list): - ByteAddress = sector - progress = f"{(i*100)//len(sectors_list)}%" - print(f" {ByteAddress:#010x} {progress:>4}", end="", flush=True) - bytes_list: List[int] = [] - for page in range(16): - page = pages.get(page * 256 + sector) - if page is not None: - bytes_list.extend(page) + if direction == self.Direction.WRITE: + if dma is not None: + dma.dma_wait(dma.channels[0], 0.1) else: - bytes_list.extend([0]*256) + if (byte_count % 4) == 0: + for i in range(0, byte_count, 4): + self.openocd.write_memory(mem_map.SPIFI_CONFIG_DATA32, 32, [ + data[i] + data[i+1] * 256 + data[i+2] * 256 * 256 + data[i+3] * 256 * 256 * 256]) + else: + for i in range(byte_count): + self.openocd.write_memory( + mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]]) - result = openocd.write_memory(0x02002000, 8, bytes_list) - if result: - print("ERROR!", flush=True) - print("An error occurred while writing data to the buffer area!") - print("Aborting...", flush=True) - return 1 - - openocd.run(f"set_reg {{t6 {sector}}}") - openocd.resume() - wait_halted(openocd, 10) # ждем, когда watchpoint сработает - # watchpoint ловит до изменения слова - openocd.run("step") # делаем шаг, чтобы прочитать новое слово + return [] - result = openocd.read_memory(0x2003000, 32, 1)[0] - - if result == 0: - print(" OK!", flush=True) - else: - print(" FAIL!", flush=True) - print("result =", result) - break - if result == 0: - print(f" {sectors_list[-1]:#010x} 100% OK!", flush=True) + def dma_config(self) -> dma.DMA: + dma_instance = dma.DMA(self.openocd) + dma_instance.init() - openocd.run("rwp 0x02003000") - init_memory(openocd) + dma_instance.channels[0].write_buffer = 0 - if result == 0: - # Прошивка страниц флеш памяти по SPIFI была завершена - print("SPIFI writing successfully completed!", flush=True) - else: - print(f"SPIFI writing failed!", flush=True) - return 1 - - return result + dma_instance.channels[0].channel = dma.ChannelIndex.CHANNEL_0 + dma_instance.channels[0].priority = dma.ChannelPriority.VERY_HIGH + + dma_instance.channels[0].read_mode = dma.ChannelMode.MEMORY + dma_instance.channels[0].read_increment = dma.ChannelIncrement.ENABLE + dma_instance.channels[0].read_size = dma.ChannelSize.WORD + dma_instance.channels[0].read_burst_size = 2 + dma_instance.channels[0].read_request = dma.ChannelRequest.SPIFI_REQUEST + dma_instance.channels[0].read_ack = dma.ChannelAck.DISABLE + + dma_instance.channels[0].write_mode = dma.ChannelMode.PERIPHERY + dma_instance.channels[0].write_increment = dma.ChannelIncrement.DISABLE + dma_instance.channels[0].write_size = dma.ChannelSize.WORD + dma_instance.channels[0].write_burst_size = 2 + dma_instance.channels[0].write_request = dma.ChannelRequest.SPIFI_REQUEST + dma_instance.channels[0].write_ack = dma.ChannelAck.DISABLE + + dma_instance.channels[1].write_buffer = 0 + + dma_instance.channels[1].channel = dma.ChannelIndex.CHANNEL_1 + dma_instance.channels[1].priority = dma.ChannelPriority.VERY_HIGH + + dma_instance.channels[1].write_mode = dma.ChannelMode.MEMORY + dma_instance.channels[1].write_increment = dma.ChannelIncrement.ENABLE + dma_instance.channels[1].write_size = dma.ChannelSize.WORD + dma_instance.channels[1].write_burst_size = 2 + dma_instance.channels[1].write_request = dma.ChannelRequest.SPIFI_REQUEST + dma_instance.channels[1].write_ack = dma.ChannelAck.DISABLE + + dma_instance.channels[1].read_mode = dma.ChannelMode.PERIPHERY + dma_instance.channels[1].read_increment = dma.ChannelIncrement.DISABLE + dma_instance.channels[1].read_size = dma.ChannelSize.WORD + dma_instance.channels[1].read_burst_size = 2 + dma_instance.channels[1].read_request = dma.ChannelRequest.SPIFI_REQUEST + dma_instance.channels[1].read_ack = dma.ChannelAck.DISABLE + + return dma_instance diff --git a/mik32_upload.py b/mik32_upload.py index 57d40bc..f186afc 100644 --- a/mik32_upload.py +++ b/mik32_upload.py @@ -9,8 +9,9 @@ from typing import List, Dict, NamedTuple, Union from hex_parser import FirmwareFile, MemorySection, MemoryType, Segment from tclrpc import OpenOcdTclRpc, TclException, TclPortError from mik32_debug_hal.gpio import MIK32_Version, gpio_init, gpio_deinit -import mik32_debug_hal.eeprom as eeprom -import mik32_debug_hal.spifi as spifi +from mik32_debug_hal.eeprom import EEPROM +from mik32_debug_hal.spifi import SPIFI +from flash_drivers.generic_flash import GenericFlash import mik32_debug_hal.ram as ram import mik32_debug_hal.power_manager as power_manager from _version import applicaton_version @@ -261,12 +262,13 @@ def upload_file( logging.debug("PM configured!") if (pages.pages_eeprom.__len__() > 0): + eeprom = EEPROM(openocd) + start_time = time.perf_counter() if use_driver: result |= eeprom.write_memory( pages.pages_eeprom, - openocd, os.path.join( default_drivers_path, 'jtag-eeprom', @@ -290,12 +292,13 @@ def upload_file( f"[{current_time}] Wrote {write_size} bytes in {write_time:.2f} seconds (effective {(write_size/(write_time*1024)):.1f} kbyte/s)") if (pages.pages_spifi.__len__() > 0): gpio_init(openocd, mik_version) + spifi = SPIFI(openocd) + flash = GenericFlash(spifi) start_time = time.perf_counter() if use_driver: - result |= spifi.write_pages_by_sectors( + result |= flash.write_pages_by_sectors( pages.pages_spifi, - openocd, os.path.join( default_drivers_path, 'jtag-spifi', @@ -304,7 +307,7 @@ def upload_file( ) ) else: - result |= spifi.write_pages( + result |= flash.write_pages( pages.pages_spifi, openocd, use_quad_spi=use_quad_spi