mirror of
https://github.com/MikronMIK32/mik32-uploader.git
synced 2026-01-01 13:37:03 +03:00
переработка eeprom и spifi
функции сгруппированы в классы, для spifi улучшено разделение функционала между контроллерами интерфейса и флеш памяти
This commit is contained in:
parent
d55a5242a8
commit
9bec497601
@ -1,212 +1,452 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import List, Union
|
from typing import Dict, List, Union
|
||||||
from tclrpc import OpenOcdTclRpc
|
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
|
import mik32_debug_hal.dma as dma
|
||||||
|
|
||||||
|
|
||||||
# --------------------------
|
class GenericFlash():
|
||||||
# Commands
|
# --------------------------
|
||||||
# --------------------------
|
# Commands
|
||||||
SREG1_BUSY = 1
|
# --------------------------
|
||||||
|
SREG1_BUSY = 1
|
||||||
|
|
||||||
READ_LEN = 256
|
READ_LEN = 256
|
||||||
|
|
||||||
ENABLE_RESET_COMMAND = 0x66
|
ENABLE_RESET_COMMAND = 0x66
|
||||||
RESET_COMMAND = 0x99
|
RESET_COMMAND = 0x99
|
||||||
|
|
||||||
CHIP_ERASE_COMMAND = 0xC7
|
CHIP_ERASE_COMMAND = 0xC7
|
||||||
SECTOR_ERASE_COMMAND = 0x20
|
SECTOR_ERASE_COMMAND = 0x20
|
||||||
|
|
||||||
WRITE_ENABLE_COMMAND = 0x06
|
WRITE_ENABLE_COMMAND = 0x06
|
||||||
WRITE_DISABLE_COMMAND = 0x04
|
WRITE_DISABLE_COMMAND = 0x04
|
||||||
|
|
||||||
MEM_CONFIG_COMMAND = 0x61
|
MEM_CONFIG_COMMAND = 0x61
|
||||||
MEM_CONFIG_VALUE = 0x7F
|
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_SREG1_COMMAND = 0x05
|
||||||
READ_SREG2_COMMAND = 0x35
|
READ_SREG2_COMMAND = 0x35
|
||||||
WRITE_SREG_COMMAND = 0x01
|
WRITE_SREG_COMMAND = 0x01
|
||||||
|
|
||||||
SREG2_QUAD_ENABLE = 9
|
SREG2_QUAD_ENABLE = 9
|
||||||
SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8)
|
SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8)
|
||||||
SREG2_QUAD_ENABLE_M = 1 << SREG2_QUAD_ENABLE_S
|
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 __str__(self):
|
||||||
def __init__(self, value):
|
return ("ERROR: " + repr(self.value))
|
||||||
self.value = value
|
|
||||||
|
|
||||||
def __str__(self):
|
class SREG_Num(Enum):
|
||||||
return ("ERROR: " + repr(self.value))
|
SREG1 = 0x00
|
||||||
|
SREG2 = 0x30
|
||||||
|
|
||||||
|
openocd: OpenOcdTclRpc
|
||||||
|
spifi: SPIFI
|
||||||
|
|
||||||
class SREG_Num(Enum):
|
def __init__(self, spifi: SPIFI):
|
||||||
SREG1 = 0x00
|
self.spifi = spifi
|
||||||
SREG2 = 0x30
|
self.openocd = self.spifi.openocd
|
||||||
|
|
||||||
|
# self.init()
|
||||||
|
|
||||||
def write_enable(openocd: OpenOcdTclRpc):
|
def write_enable(self):
|
||||||
spifi.send_command(openocd, WRITE_ENABLE_COMMAND,
|
self.spifi.send_command(self.WRITE_ENABLE_COMMAND,
|
||||||
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
|
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:
|
def write_sreg(self, sreg1: int, sreg2: int):
|
||||||
return spifi.send_command(
|
self.write_enable()
|
||||||
openocd,
|
self.spifi.send_command(
|
||||||
READ_SREG1_COMMAND | sreg.value,
|
self.WRITE_SREG_COMMAND,
|
||||||
spifi.Frameform.OPCODE_NOADDR,
|
self.spifi.Frameform.OPCODE_NOADDR,
|
||||||
spifi.Fieldform.ALL_SERIAL,
|
self.spifi.Fieldform.ALL_SERIAL,
|
||||||
byte_count=1
|
byte_count=2,
|
||||||
)[0]
|
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):
|
RESET_DELAY = 0.001
|
||||||
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)
|
|
||||||
|
|
||||||
|
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):
|
def chip_reset_qpi(self):
|
||||||
while 1:
|
self.spifi.send_command(self.ENABLE_RESET_COMMAND,
|
||||||
sreg1 = read_sreg(openocd, SREG_Num.SREG1)
|
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_PARALLEL)
|
||||||
if not (sreg1 & SREG1_BUSY):
|
self.spifi.send_command(self.RESET_COMMAND,
|
||||||
break
|
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):
|
if (use_quad_spi):
|
||||||
spifi.send_command(openocd, ENABLE_RESET_COMMAND,
|
read_data = self.spifi.send_command(self.FAST_READ_QUAD_OUTPUT_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
|
||||||
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
|
self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=address, idata_length=1, dma=dma)
|
||||||
spifi.send_command(openocd, RESET_COMMAND,
|
else:
|
||||||
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
|
read_data = self.spifi.send_command(self.READ_DATA_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
|
||||||
time.sleep(RESET_DELAY)
|
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):
|
return 1
|
||||||
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 0
|
||||||
|
|
||||||
def chip_erase(openocd: OpenOcdTclRpc):
|
def page_program(
|
||||||
print("Chip erase...", flush=True)
|
self,
|
||||||
spifi.send_command(openocd, CHIP_ERASE_COMMAND,
|
ByteAddress: int,
|
||||||
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
|
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):
|
class EraseType(Enum):
|
||||||
print(f"Erase sector {address:#010x}...", flush=True)
|
CHIP_ERASE = 0
|
||||||
spifi.send_command(openocd, SECTOR_ERASE_COMMAND,
|
SECTOR_ERASE = 1
|
||||||
spifi.Frameform.OPCODE_3ADDR, spifi.Fieldform.ALL_SERIAL, address=address)
|
|
||||||
|
|
||||||
|
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:
|
def quad_page_program(
|
||||||
read_data: List[int] = []
|
self,
|
||||||
|
|
||||||
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,
|
|
||||||
ByteAddress: int,
|
ByteAddress: int,
|
||||||
data: List[int],
|
data: List[int],
|
||||||
byte_count: int,
|
byte_count: int,
|
||||||
progress: str = "",
|
progress: str = "",
|
||||||
dma: Union[dma.DMA, None] = None
|
dma: Union[dma.DMA, None] = None
|
||||||
):
|
):
|
||||||
print(f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True)
|
print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
|
||||||
if byte_count > 256:
|
if byte_count > 256:
|
||||||
raise FlashError("Byte count more than 256")
|
raise self.FlashError("Byte count more than 256")
|
||||||
|
|
||||||
write_enable(openocd)
|
self.write_enable()
|
||||||
spifi.send_command(openocd, PAGE_PROGRAM_COMMAND, spifi.Frameform.OPCODE_3ADDR,
|
self.spifi.send_command(self.QUAD_PAGE_PROGRAM_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
|
||||||
spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=ByteAddress,
|
self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=ByteAddress,
|
||||||
idata=0, cache_limit=0, direction=spifi.Direction.WRITE, data=data, dma=dma)
|
idata=0, cache_limit=0, direction=self.spifi.Direction.WRITE, data=data, dma=dma)
|
||||||
wait_busy(openocd)
|
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):
|
def check_quad_enable(self):
|
||||||
CHIP_ERASE = CHIP_ERASE_COMMAND
|
return (self.read_sreg(self.SREG_Num.SREG2) & self.SREG2_QUAD_ENABLE_M) != 0
|
||||||
SECTOR_ERASE = SECTOR_ERASE_COMMAND
|
|
||||||
|
|
||||||
|
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] = []):
|
self.openocd.halt()
|
||||||
if erase_type == EraseType.CHIP_ERASE:
|
# self.init()
|
||||||
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)
|
|
||||||
|
|
||||||
|
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
|
||||||
|
self.chip_reset_qpi()
|
||||||
|
|
||||||
def quad_page_program(
|
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
|
||||||
openocd: OpenOcdTclRpc,
|
self.chip_reset()
|
||||||
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")
|
|
||||||
|
|
||||||
write_enable(openocd)
|
JEDEC_ID = self.spifi.send_command(self.JEDEC_ID_COMMAND,
|
||||||
spifi.send_command(openocd, QUAD_PAGE_PROGRAM_COMMAND, spifi.Frameform.OPCODE_3ADDR,
|
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3)
|
||||||
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)
|
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
||||||
|
|
||||||
def quad_enable(openocd):
|
dma_instance = self.spifi.dma_config()
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
|
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):
|
pages_offsets = list(pages)
|
||||||
return (read_sreg(openocd, SREG_Num.SREG2) & SREG2_QUAD_ENABLE_M) != 0
|
|
||||||
|
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))
|
||||||
|
|||||||
@ -9,11 +9,12 @@ from typing import List, Union
|
|||||||
from mik32_debug_hal.power_manager import pm_init
|
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_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
|
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
|
import mik32_debug_hal.ram as ram
|
||||||
from hex_parser import FirmwareFile, MemoryType, Segment
|
from hex_parser import FirmwareFile, MemoryType, Segment
|
||||||
from tclrpc import OpenOcdTclRpc, TclException
|
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(
|
def upload_file(
|
||||||
@ -78,6 +79,8 @@ def upload_file(
|
|||||||
logging.debug("PM configured!")
|
logging.debug("PM configured!")
|
||||||
|
|
||||||
if (pages.pages_eeprom.__len__() > 0):
|
if (pages.pages_eeprom.__len__() > 0):
|
||||||
|
eeprom = EEPROM(openocd)
|
||||||
|
|
||||||
start_time = time.perf_counter()
|
start_time = time.perf_counter()
|
||||||
|
|
||||||
result |= eeprom.check_pages(
|
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)")
|
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):
|
if (pages.pages_spifi.__len__() > 0):
|
||||||
gpio_init(openocd, mik_version)
|
gpio_init(openocd, mik_version)
|
||||||
|
spifi = SPIFI(openocd)
|
||||||
|
flash = GenericFlash(spifi)
|
||||||
start_time = time.perf_counter()
|
start_time = time.perf_counter()
|
||||||
|
|
||||||
result |= spifi.check_pages(
|
result |= flash.check_pages(
|
||||||
pages.pages_spifi, openocd, use_quad_spi=use_quad_spi)
|
pages.pages_spifi, use_quad_spi=use_quad_spi)
|
||||||
|
|
||||||
write_time = time.perf_counter() - start_time
|
write_time = time.perf_counter() - start_time
|
||||||
write_size = pages.pages_spifi.__len__(
|
write_size = pages.pages_spifi.__len__(
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import datetime
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List
|
||||||
import time
|
import time
|
||||||
from tclrpc import OpenOcdTclRpc, TclException
|
from tclrpc import OpenOcdTclRpc, TclException
|
||||||
from utils import bytes2words
|
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
|
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]:
|
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
|
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 - текущий драйвер поддерживает
|
self.eeprom_sysinit()
|
||||||
# только версию mik32v2
|
|
||||||
|
|
||||||
RAM_OFFSET = 0x02000000
|
def eeprom_sysinit(self):
|
||||||
RAM_BUFFER_OFFSET = 0x02001800
|
print("MCU clock init...", flush=True)
|
||||||
RAM_DRIVER_STATUS = 0x02003800
|
|
||||||
|
|
||||||
bytes_list = combine_pages(pages)
|
class EEPROM_Operation(Enum):
|
||||||
openocd.halt()
|
READ = eeprom_fields.OP_RD
|
||||||
openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний
|
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
|
def eeprom_execute_operation(self, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]):
|
||||||
openocd.write_memory(RAM_DRIVER_STATUS, 32, [1 | (max_address << 8)])
|
# 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)
|
def eeprom_configure_cycles(self, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500):
|
||||||
openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
|
self.openocd.write_word(mem_map.EEPROM_REGS_NCYCRL, LD << eeprom_fields.NCYCRL_N_LD_S |
|
||||||
print("OK!", flush=True)
|
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)
|
def eeprom_global_erase(self):
|
||||||
result = openocd.write_memory(RAM_BUFFER_OFFSET, 8, bytes_list)
|
print("EEPROM global erase...", flush=True)
|
||||||
if result:
|
# configure cycles duration
|
||||||
print("ERROR!", flush=True)
|
self.eeprom_execute_operation(
|
||||||
print("An error occurred while writing data to the buffer area!")
|
self.EEPROM_Operation.ERASE, self.EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32)
|
||||||
print("Aborting...", flush=True)
|
|
||||||
return 1
|
def eeprom_global_erase_check(self):
|
||||||
else:
|
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)
|
print("OK!", flush=True)
|
||||||
|
|
||||||
# mem = openocd.read_memory(0x01000000, 8, len(bytes_list))
|
print("Uploading data... ", end="", flush=True)
|
||||||
# print(f"total bytes read {len(bytes_list)}")
|
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]:
|
self.openocd.run(f"wp 0x{RAM_DRIVER_STATUS:08x} 4 w")
|
||||||
# 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
|
|
||||||
|
|
||||||
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)
|
try:
|
||||||
openocd.resume(RAM_OFFSET)
|
# ждем, когда watchpoint сработает
|
||||||
|
self.wait_halted(10)
|
||||||
|
except TclException:
|
||||||
|
print("Timeout!", flush=True)
|
||||||
|
# return 1
|
||||||
|
|
||||||
try:
|
# watchpoint ловит до изменения слова
|
||||||
# ждем, когда watchpoint сработает
|
self.openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}")
|
||||||
wait_halted(openocd, 10)
|
# делаем шаг, чтобы прочитать новое слово
|
||||||
except TclException:
|
self.openocd.run("step")
|
||||||
print("Timeout!", flush=True)
|
|
||||||
# return 1
|
|
||||||
|
|
||||||
openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}") # watchpoint ловит до изменения слова
|
result = self.openocd.read_memory(RAM_DRIVER_STATUS, 32, 1)[0]
|
||||||
openocd.run("step") # делаем шаг, чтобы прочитать новое слово
|
|
||||||
|
|
||||||
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 failed!", flush=True)
|
||||||
print(f"EEPROM writing successfully completed!", flush=True)
|
print(f"First mismatched byte in page {miss_page},")
|
||||||
else:
|
print(
|
||||||
miss_page = (result >> 8) & (64 - 1)
|
f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}")
|
||||||
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)
|
return 1
|
||||||
print(f"First mismatched byte in page {miss_page},")
|
|
||||||
print(f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}")
|
|
||||||
|
|
||||||
return 1
|
return 0
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|||||||
@ -1,466 +1,214 @@
|
|||||||
import datetime
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import os
|
from typing import List, Union
|
||||||
import pathlib
|
|
||||||
import sys
|
|
||||||
from typing import Dict, List, Union
|
|
||||||
import time
|
import time
|
||||||
from tclrpc import TclException
|
|
||||||
from tclrpc import OpenOcdTclRpc
|
from tclrpc import OpenOcdTclRpc
|
||||||
import mik32_debug_hal.registers.memory_map as mem_map
|
import mik32_debug_hal.registers.memory_map as mem_map
|
||||||
import mik32_debug_hal.registers.bitfields.spifi as spifi_fields
|
import mik32_debug_hal.registers.bitfields.spifi as spifi_fields
|
||||||
import mik32_debug_hal.dma as dma
|
import mik32_debug_hal.dma as dma
|
||||||
import flash_drivers.generic_flash as generic_flash
|
|
||||||
|
|
||||||
|
|
||||||
class SpifiError(Exception):
|
class SPIFI():
|
||||||
def __init__(self, value):
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
def __str__(self):
|
DEFAULT_READ_DATA_COMMAND = 0x03
|
||||||
return ("ERROR: " + repr(self.value))
|
|
||||||
|
|
||||||
|
class SpifiError(Exception):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
def spifi_intrq_clear(openocd: OpenOcdTclRpc):
|
def __str__(self):
|
||||||
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
|
return ("ERROR: " + repr(self.value))
|
||||||
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M)
|
|
||||||
|
|
||||||
|
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):
|
TIMEOUT = 1.0
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
def init_periphery(self):
|
||||||
control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M
|
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
|
||||||
openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control)
|
# 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):
|
self.init_periphery()
|
||||||
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))
|
|
||||||
|
|
||||||
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):
|
def init_memory(self):
|
||||||
time_end = time.perf_counter() + TIMEOUT
|
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
|
||||||
while time.perf_counter() < time_end:
|
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M |
|
||||||
if (openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0:
|
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
|
||||||
return
|
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
|
||||||
raise SpifiError(error_message)
|
# 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):
|
def spifi_wait_intrq_timeout(self, error_message: str):
|
||||||
RESERVED = 0
|
time_end = time.perf_counter() + self.TIMEOUT
|
||||||
OPCODE_NOADDR = 1
|
while time.perf_counter() < time_end:
|
||||||
OPCODE_1ADDR = 2
|
if (self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0:
|
||||||
OPCODE_2ADDR = 3
|
return
|
||||||
OPCODE_3ADDR = 4
|
raise self.SpifiError(error_message)
|
||||||
OPCODE_4ADDR = 5
|
|
||||||
NOOPCODE_3ADDR = 6
|
|
||||||
NOOPCODE_4ADDR = 7
|
|
||||||
|
|
||||||
|
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):
|
dma.channels[0].start(
|
||||||
ALL_SERIAL = 0
|
0x02003F00,
|
||||||
DATA_PARALLEL = 1
|
mem_map.SPIFI_CONFIG_DATA32,
|
||||||
OPCODE_SERIAL = 2
|
255
|
||||||
ALL_PARALLEL = 3
|
)
|
||||||
|
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):
|
cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||||
READ = 0
|
(frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||||
WRITE = 1
|
(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(
|
if direction == self.Direction.READ:
|
||||||
openocd: OpenOcdTclRpc,
|
out_list = []
|
||||||
cmd: int,
|
if dma is not None:
|
||||||
frameform: Frameform,
|
dma.dma_wait(dma.channels[1], 0.1)
|
||||||
fieldform: Fieldform,
|
out_list.extend(self.openocd.read_memory(
|
||||||
byte_count=0,
|
0x02003F00, 8, byte_count))
|
||||||
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)
|
|
||||||
|
|
||||||
dma.channels[0].start(
|
return out_list
|
||||||
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])
|
|
||||||
else:
|
else:
|
||||||
for i in range(byte_count):
|
for i in range(byte_count):
|
||||||
openocd.write_memory(
|
out_list.append(self.openocd.read_memory(
|
||||||
mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]])
|
mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0])
|
||||||
|
return out_list
|
||||||
|
|
||||||
return []
|
if direction == self.Direction.WRITE:
|
||||||
|
if dma is not None:
|
||||||
|
dma.dma_wait(dma.channels[0], 0.1)
|
||||||
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)
|
|
||||||
else:
|
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)
|
return []
|
||||||
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") # делаем шаг, чтобы прочитать новое слово
|
|
||||||
|
|
||||||
result = openocd.read_memory(0x2003000, 32, 1)[0]
|
def dma_config(self) -> dma.DMA:
|
||||||
|
dma_instance = dma.DMA(self.openocd)
|
||||||
if result == 0:
|
dma_instance.init()
|
||||||
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)
|
|
||||||
|
|
||||||
openocd.run("rwp 0x02003000")
|
dma_instance.channels[0].write_buffer = 0
|
||||||
init_memory(openocd)
|
|
||||||
|
|
||||||
if result == 0:
|
dma_instance.channels[0].channel = dma.ChannelIndex.CHANNEL_0
|
||||||
# Прошивка страниц флеш памяти по SPIFI была завершена
|
dma_instance.channels[0].priority = dma.ChannelPriority.VERY_HIGH
|
||||||
print("SPIFI writing successfully completed!", flush=True)
|
|
||||||
else:
|
dma_instance.channels[0].read_mode = dma.ChannelMode.MEMORY
|
||||||
print(f"SPIFI writing failed!", flush=True)
|
dma_instance.channels[0].read_increment = dma.ChannelIncrement.ENABLE
|
||||||
return 1
|
dma_instance.channels[0].read_size = dma.ChannelSize.WORD
|
||||||
|
dma_instance.channels[0].read_burst_size = 2
|
||||||
return result
|
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
|
||||||
|
|||||||
@ -9,8 +9,9 @@ from typing import List, Dict, NamedTuple, Union
|
|||||||
from hex_parser import FirmwareFile, MemorySection, MemoryType, Segment
|
from hex_parser import FirmwareFile, MemorySection, MemoryType, Segment
|
||||||
from tclrpc import OpenOcdTclRpc, TclException, TclPortError
|
from tclrpc import OpenOcdTclRpc, TclException, TclPortError
|
||||||
from mik32_debug_hal.gpio import MIK32_Version, gpio_init, gpio_deinit
|
from mik32_debug_hal.gpio import MIK32_Version, gpio_init, gpio_deinit
|
||||||
import mik32_debug_hal.eeprom as eeprom
|
from mik32_debug_hal.eeprom import EEPROM
|
||||||
import mik32_debug_hal.spifi as spifi
|
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.ram as ram
|
||||||
import mik32_debug_hal.power_manager as power_manager
|
import mik32_debug_hal.power_manager as power_manager
|
||||||
from _version import applicaton_version
|
from _version import applicaton_version
|
||||||
@ -261,12 +262,13 @@ def upload_file(
|
|||||||
logging.debug("PM configured!")
|
logging.debug("PM configured!")
|
||||||
|
|
||||||
if (pages.pages_eeprom.__len__() > 0):
|
if (pages.pages_eeprom.__len__() > 0):
|
||||||
|
eeprom = EEPROM(openocd)
|
||||||
|
|
||||||
start_time = time.perf_counter()
|
start_time = time.perf_counter()
|
||||||
|
|
||||||
if use_driver:
|
if use_driver:
|
||||||
result |= eeprom.write_memory(
|
result |= eeprom.write_memory(
|
||||||
pages.pages_eeprom,
|
pages.pages_eeprom,
|
||||||
openocd,
|
|
||||||
os.path.join(
|
os.path.join(
|
||||||
default_drivers_path,
|
default_drivers_path,
|
||||||
'jtag-eeprom',
|
'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)")
|
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):
|
if (pages.pages_spifi.__len__() > 0):
|
||||||
gpio_init(openocd, mik_version)
|
gpio_init(openocd, mik_version)
|
||||||
|
spifi = SPIFI(openocd)
|
||||||
|
flash = GenericFlash(spifi)
|
||||||
start_time = time.perf_counter()
|
start_time = time.perf_counter()
|
||||||
|
|
||||||
if use_driver:
|
if use_driver:
|
||||||
result |= spifi.write_pages_by_sectors(
|
result |= flash.write_pages_by_sectors(
|
||||||
pages.pages_spifi,
|
pages.pages_spifi,
|
||||||
openocd,
|
|
||||||
os.path.join(
|
os.path.join(
|
||||||
default_drivers_path,
|
default_drivers_path,
|
||||||
'jtag-spifi',
|
'jtag-spifi',
|
||||||
@ -304,7 +307,7 @@ def upload_file(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
result |= spifi.write_pages(
|
result |= flash.write_pages(
|
||||||
pages.pages_spifi,
|
pages.pages_spifi,
|
||||||
openocd,
|
openocd,
|
||||||
use_quad_spi=use_quad_spi
|
use_quad_spi=use_quad_spi
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user