mirror of
https://github.com/MikronMIK32/mik32-uploader.git
synced 2026-01-01 13:37:03 +03:00
821 lines
27 KiB
Python
821 lines
27 KiB
Python
from enum import Enum
|
|
import os
|
|
import pathlib
|
|
import sys
|
|
from typing import Dict, List, Union
|
|
import time
|
|
from tclrpc import TclException
|
|
from tclrpc import OpenOcdTclRpc
|
|
from mik32_dma import DMA, ChannelMode, ChannelIndex, ChannelAck, ChannelIncrement, ChannelPriority, ChannelRequest, ChannelSize
|
|
|
|
|
|
# --------------------------
|
|
# SPIFI register offset
|
|
# --------------------------
|
|
SPIFI_REGS_BASE_ADDRESS = 0x00070000
|
|
|
|
SPIFI_CONFIG_CTRL = SPIFI_REGS_BASE_ADDRESS + 0x000
|
|
SPIFI_CONFIG_CMD = SPIFI_REGS_BASE_ADDRESS + 0x004
|
|
SPIFI_CONFIG_ADDR = SPIFI_REGS_BASE_ADDRESS + 0x008
|
|
SPIFI_CONFIG_IDATA = SPIFI_REGS_BASE_ADDRESS + 0x00C
|
|
SPIFI_CONFIG_CLIMIT = SPIFI_REGS_BASE_ADDRESS + 0x010
|
|
SPIFI_CONFIG_DATA32 = SPIFI_REGS_BASE_ADDRESS + 0x014
|
|
SPIFI_CONFIG_MCMD = SPIFI_REGS_BASE_ADDRESS + 0x018
|
|
SPIFI_CONFIG_STAT = SPIFI_REGS_BASE_ADDRESS + 0x01C
|
|
|
|
# --------------------------
|
|
# SPIFI register fields
|
|
# --------------------------
|
|
# CTRL
|
|
SPIFI_CONFIG_CTRL_TIMEOUT_S = 0
|
|
SPIFI_CONFIG_CTRL_TIMEOUT_M = (0xFFFF << SPIFI_CONFIG_CTRL_TIMEOUT_S)
|
|
|
|
|
|
def SPIFI_CONFIG_CTRL_TIMEOUT(v):
|
|
return (((v) << SPIFI_CONFIG_CTRL_TIMEOUT_S) & SPIFI_CONFIG_CTRL_TIMEOUT_M)
|
|
|
|
|
|
SPIFI_CONFIG_CTRL_CSHIGH_S = 16
|
|
SPIFI_CONFIG_CTRL_CSHIGH_M = (0xF << SPIFI_CONFIG_CTRL_CSHIGH_S)
|
|
|
|
|
|
def SPIFI_CONFIG_CTRL_CSHIGH(v):
|
|
return (((v) << SPIFI_CONFIG_CTRL_CSHIGH_S) & SPIFI_CONFIG_CTRL_CSHIGH_M)
|
|
|
|
|
|
SPIFI_CONFIG_CTRL_CACHE_EN_S = 20
|
|
SPIFI_CONFIG_CTRL_CACHE_EN_M = (0x1 << SPIFI_CONFIG_CTRL_CACHE_EN_S)
|
|
SPIFI_CONFIG_CTRL_D_CACHE_DIS_S = 21
|
|
SPIFI_CONFIG_CTRL_D_CACHE_DIS_M = (0x1 << SPIFI_CONFIG_CTRL_D_CACHE_DIS_S)
|
|
SPIFI_CONFIG_CTRL_INTEN_S = 22
|
|
SPIFI_CONFIG_CTRL_INTEN_M = (0x1 << SPIFI_CONFIG_CTRL_INTEN_S)
|
|
SPIFI_CONFIG_CTRL_MODE3_S = 23
|
|
SPIFI_CONFIG_CTRL_MODE3_M = (0x1 << SPIFI_CONFIG_CTRL_MODE3_S)
|
|
SPIFI_CONFIG_CTRL_SCK_DIV_S = 24
|
|
SPIFI_CONFIG_CTRL_SCK_DIV_M = (0x7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)
|
|
|
|
|
|
def SPIFI_CONFIG_CTRL_SCK_DIV(v):
|
|
return (((v) << SPIFI_CONFIG_CTRL_SCK_DIV_S) & SPIFI_CONFIG_CTRL_SCK_DIV_M)
|
|
|
|
|
|
SPIFI_CONFIG_CTRL_PREFETCH_DIS_S = 27
|
|
SPIFI_CONFIG_CTRL_PREFETCH_DIS_M = (0x1 << SPIFI_CONFIG_CTRL_PREFETCH_DIS_S)
|
|
SPIFI_CONFIG_CTRL_DUAL_S = 28
|
|
SPIFI_CONFIG_CTRL_DUAL_M = (0x1 << SPIFI_CONFIG_CTRL_DUAL_S)
|
|
SPIFI_CONFIG_CTRL_RFCLK_S = 29
|
|
SPIFI_CONFIG_CTRL_RFCLK_M = (0x1 << SPIFI_CONFIG_CTRL_RFCLK_S)
|
|
SPIFI_CONFIG_CTRL_FBCLK_S = 30
|
|
SPIFI_CONFIG_CTRL_FBCLK_M = (0x1 << SPIFI_CONFIG_CTRL_FBCLK_S)
|
|
SPIFI_CONFIG_CTRL_DMAEN_S = 31
|
|
SPIFI_CONFIG_CTRL_DMAEN_M = (0x1 << SPIFI_CONFIG_CTRL_DMAEN_S)
|
|
|
|
# CMD
|
|
SPIFI_CONFIG_CMD_DATALEN_S = 0
|
|
SPIFI_CONFIG_CMD_DATALEN_M = (0x3FFF << SPIFI_CONFIG_CMD_DATALEN_S)
|
|
|
|
|
|
def SPIFI_CONFIG_CMD_DATALEN(v):
|
|
return (((v) << SPIFI_CONFIG_CMD_DATALEN_S) & SPIFI_CONFIG_CMD_DATALEN_M)
|
|
|
|
|
|
SPIFI_CONFIG_CMD_POLL_S = 14
|
|
SPIFI_CONFIG_CMD_POLL_M = (0x1 << SPIFI_CONFIG_CMD_POLL_S)
|
|
SPIFI_CONFIG_CMD_DOUT_S = 15
|
|
SPIFI_CONFIG_CMD_DOUT_M = (0x1 << SPIFI_CONFIG_CMD_DOUT_S)
|
|
SPIFI_CONFIG_CMD_INTLEN_S = 16
|
|
SPIFI_CONFIG_CMD_INTLEN_M = (0x7 << SPIFI_CONFIG_CMD_INTLEN_S)
|
|
SPIFI_CONFIG_CMD_FIELDFORM_S = 19
|
|
SPIFI_CONFIG_CMD_FIELDFORM_M = (0x3 << SPIFI_CONFIG_CMD_FIELDFORM_S)
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_S = 21
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_M = (0x7 << SPIFI_CONFIG_CMD_FRAMEFORM_S)
|
|
SPIFI_CONFIG_CMD_OPCODE_S = 24
|
|
SPIFI_CONFIG_CMD_OPCODE_M = (0xFF << SPIFI_CONFIG_CMD_OPCODE_S)
|
|
|
|
SPIFI_CONFIG_CMD_DATALEN_BUSY_INDEX_S = 0
|
|
SPIFI_CONFIG_CMD_DATALEN_BUSY_DONE_VALUE_S = 3
|
|
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_RESERVED = 0
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR = 1
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_1ADDR = 2
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_2ADDR = 3
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR = 4
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_4ADDR = 5
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_NOOPCODE_3ADDR = 6
|
|
SPIFI_CONFIG_CMD_FRAMEFORM_NOOPCODE_4ADDR = 7
|
|
|
|
SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL = 0
|
|
SPIFI_CONFIG_CMD_FIELDFORM_DATA_PARALLEL = 1
|
|
SPIFI_CONFIG_CMD_FIELDFORM_OPCODE_SERIAL = 2
|
|
SPIFI_CONFIG_CMD_FIELDFORM_ALL_PARALLEL = 3
|
|
|
|
# MCMD
|
|
SPIFI_CONFIG_MCMD_POLL_S = 14
|
|
SPIFI_CONFIG_MCMD_POLL_M = (0x1 << SPIFI_CONFIG_MCMD_POLL_S)
|
|
SPIFI_CONFIG_MCMD_DOUT_S = 15
|
|
SPIFI_CONFIG_MCMD_DOUT_M = (0x1 << SPIFI_CONFIG_MCMD_DOUT_S)
|
|
SPIFI_CONFIG_MCMD_INTLEN_S = 16
|
|
SPIFI_CONFIG_MCMD_INTLEN_M = (0x7 << SPIFI_CONFIG_MCMD_INTLEN_S)
|
|
SPIFI_CONFIG_MCMD_FIELDFORM_S = 19
|
|
SPIFI_CONFIG_MCMD_FIELDFORM_M = (0x3 << SPIFI_CONFIG_MCMD_FIELDFORM_S)
|
|
SPIFI_CONFIG_MCMD_FRAMEFORM_S = 21
|
|
SPIFI_CONFIG_MCMD_FRAMEFORM_M = (0x7 << SPIFI_CONFIG_MCMD_FRAMEFORM_S)
|
|
SPIFI_CONFIG_MCMD_OPCODE_S = 24
|
|
SPIFI_CONFIG_MCMD_OPCODE_M = (0xFF << SPIFI_CONFIG_MCMD_OPCODE_S)
|
|
|
|
# STATUS
|
|
SPIFI_CONFIG_STAT_MCINIT_S = 0
|
|
SPIFI_CONFIG_STAT_MCINIT_M = (0x1 << SPIFI_CONFIG_STAT_MCINIT_S)
|
|
SPIFI_CONFIG_STAT_CMD_S = 1
|
|
SPIFI_CONFIG_STAT_CMD_M = (0x1 << SPIFI_CONFIG_STAT_CMD_S)
|
|
SPIFI_CONFIG_STAT_RESET_S = 4
|
|
SPIFI_CONFIG_STAT_RESET_M = (0x1 << SPIFI_CONFIG_STAT_RESET_S)
|
|
SPIFI_CONFIG_STAT_INTRQ_S = 5
|
|
SPIFI_CONFIG_STAT_INTRQ_M = (0x1 << SPIFI_CONFIG_STAT_INTRQ_S)
|
|
SPIFI_CONFIG_STAT_VERSION_S = 24
|
|
SPIFI_CONFIG_STAT_VERSION_M = (0xFF << SPIFI_CONFIG_STAT_VERSION_S)
|
|
|
|
# --------------------------
|
|
# Commands
|
|
# --------------------------
|
|
SREG1_BUSY = 1
|
|
|
|
READ_SREG_LEN = 1
|
|
READ_LEN = 256
|
|
TIMEOUT = 1000
|
|
|
|
CHIP_ERASE_COMMAND = 0xC7
|
|
SECTOR_ERASE_COMMAND = 0x20
|
|
|
|
WRITE_ENABLE_COMMAND = 0x06
|
|
WRITE_DISABLE_COMMAND = 0x04
|
|
|
|
MEM_CONFIG_COMMAND = 0x61
|
|
MEM_CONFIG_VALUE = 0x7F
|
|
|
|
READ_DATA_COMMAND = 0x03
|
|
|
|
FAST_READ_QUAD_OUTPUT_COMMAND = 0x6B
|
|
|
|
READ_SREG1_COMMAND = 0x05
|
|
WRITE_SREG1_COMMAND = 0x01
|
|
READ_SREG2_COMMAND = 0x35
|
|
WRITE_SREG2_COMMAND = 0x31
|
|
READ_SREG3_COMMAND = 0x15
|
|
WRITE_SREG3_COMMAND = 0x11
|
|
|
|
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
|
|
|
|
QUAD_PAGE_PROGRAM_COMMAND = 0x32
|
|
|
|
|
|
class SREG_Num(Enum):
|
|
SREG1 = 0x00
|
|
SREG2 = 0x30
|
|
SREG3 = 0x10
|
|
|
|
|
|
def spifi_intrq_clear(openocd: OpenOcdTclRpc):
|
|
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(SPIFI_CONFIG_STAT) |
|
|
SPIFI_CONFIG_STAT_INTRQ_M)
|
|
|
|
|
|
INIT_DELAY = 0.001
|
|
|
|
|
|
def spifi_init_periphery(openocd: OpenOcdTclRpc):
|
|
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(SPIFI_CONFIG_STAT) |
|
|
# SPIFI_CONFIG_STAT_INTRQ_M |
|
|
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(SPIFI_CONFIG_ADDR, 0x00)
|
|
openocd.write_word(SPIFI_CONFIG_IDATA, 0x00)
|
|
openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00)
|
|
|
|
time.sleep(INIT_DELAY)
|
|
|
|
|
|
def spifi_init(openocd: OpenOcdTclRpc):
|
|
print("MCU clock init", flush=True)
|
|
|
|
spifi_init_periphery(openocd)
|
|
|
|
control = openocd.read_word(SPIFI_CONFIG_CTRL)
|
|
control |= SPIFI_CONFIG_CTRL_DMAEN_M
|
|
openocd.write_word(SPIFI_CONFIG_CTRL, control)
|
|
|
|
time.sleep(INIT_DELAY)
|
|
|
|
|
|
def spifi_init_memory(openocd: OpenOcdTclRpc):
|
|
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(SPIFI_CONFIG_STAT) |
|
|
SPIFI_CONFIG_STAT_INTRQ_M |
|
|
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(SPIFI_CONFIG_ADDR, 0x00)
|
|
openocd.write_word(SPIFI_CONFIG_IDATA, 0x00)
|
|
openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00)
|
|
openocd.write_word(SPIFI_CONFIG_MCMD, (0 << SPIFI_CONFIG_MCMD_INTLEN_S) |
|
|
(SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_MCMD_FIELDFORM_S) |
|
|
(SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << SPIFI_CONFIG_MCMD_FRAMEFORM_S) |
|
|
(0x03 << SPIFI_CONFIG_MCMD_OPCODE_S))
|
|
|
|
time.sleep(INIT_DELAY)
|
|
|
|
|
|
def SPIFI_WaitIntrqTimeout(openocd: OpenOcdTclRpc, timeout: int) -> int:
|
|
timeout_inner = timeout
|
|
while timeout_inner:
|
|
timeout_inner -= 1
|
|
if (openocd.read_word(SPIFI_CONFIG_STAT) & SPIFI_CONFIG_STAT_INTRQ_M) != 0:
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def spifi_wait_intrq_timeout(openocd: OpenOcdTclRpc, error_message: str):
|
|
if SPIFI_WaitIntrqTimeout(openocd, TIMEOUT) == 0:
|
|
raise Exception(error_message)
|
|
return
|
|
|
|
|
|
class SPIFI_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
|
|
|
|
|
|
class SPIFI_Fieldform(Enum):
|
|
ALL_SERIAL = 0
|
|
DATA_PARALLEL = 1
|
|
OPCODE_SERIAL = 2
|
|
ALL_PARALLEL = 3
|
|
|
|
|
|
class SPIFI_Direction(Enum):
|
|
READ = 0
|
|
WRITE = 1
|
|
|
|
|
|
def spifi_send_command(
|
|
openocd: OpenOcdTclRpc,
|
|
cmd: int,
|
|
frameform: SPIFI_Frameform,
|
|
fieldform: SPIFI_Fieldform,
|
|
byte_count=0,
|
|
address=0,
|
|
idata=0,
|
|
cache_limit=0,
|
|
idata_length=0,
|
|
direction=SPIFI_Direction.READ,
|
|
data: List[int] = [],
|
|
dma: Union[DMA, None] = None
|
|
) -> List[int]:
|
|
if (dma is not None) and (direction == SPIFI_Direction.WRITE):
|
|
openocd.write_memory(0x02003F00, 8, data)
|
|
|
|
dma.channels[0].start(
|
|
0x02003F00,
|
|
SPIFI_CONFIG_DATA32,
|
|
255
|
|
)
|
|
elif (dma is not None) and (direction == SPIFI_Direction.READ):
|
|
dma.channels[1].start(
|
|
SPIFI_CONFIG_DATA32,
|
|
0x02003F00,
|
|
255
|
|
)
|
|
|
|
openocd.write_memory(SPIFI_CONFIG_ADDR, 32, [address, idata])
|
|
|
|
# # spifi_intrq_clear(openocd)
|
|
# openocd.write_word(SPIFI_CONFIG_CMD, (cmd << SPIFI_CONFIG_CMD_OPCODE_S) |
|
|
# (frameform.value << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
|
# (fieldform.value << SPIFI_CONFIG_CMD_FIELDFORM_S) |
|
|
# (byte_count << SPIFI_CONFIG_CMD_DATALEN_S) |
|
|
# (idata_length << SPIFI_CONFIG_CMD_INTLEN_S) |
|
|
# (direction.value << SPIFI_CONFIG_CMD_DOUT_S))
|
|
# # spifi_wait_intrq_timeout(openocd, "Timeout executing write enable command")
|
|
|
|
cmd_write_value = ((cmd << SPIFI_CONFIG_CMD_OPCODE_S) |
|
|
(frameform.value << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
|
(fieldform.value << SPIFI_CONFIG_CMD_FIELDFORM_S) |
|
|
(byte_count << SPIFI_CONFIG_CMD_DATALEN_S) |
|
|
(idata_length << SPIFI_CONFIG_CMD_INTLEN_S) |
|
|
(direction.value << SPIFI_CONFIG_CMD_DOUT_S))
|
|
|
|
openocd.write_memory(SPIFI_CONFIG_CMD, 32, [cmd_write_value])
|
|
|
|
if direction == SPIFI_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(SPIFI_CONFIG_DATA32, 8, 1)[0])
|
|
return out_list
|
|
|
|
if direction == SPIFI_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(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):
|
|
openocd.write_memory(SPIFI_CONFIG_DATA32, 8, [data[i]])
|
|
|
|
return []
|
|
|
|
|
|
def spifi_write_enable(openocd: OpenOcdTclRpc):
|
|
spifi_send_command(openocd, WRITE_ENABLE_COMMAND,
|
|
SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_SERIAL)
|
|
|
|
|
|
def spifi_read_sreg(openocd: OpenOcdTclRpc, sreg: SREG_Num) -> int:
|
|
read_sreg: int = 0
|
|
|
|
return spifi_send_command(
|
|
openocd, READ_SREG1_COMMAND | sreg.value, SPIFI_Frameform.OPCODE_NOADDR,
|
|
SPIFI_Fieldform.ALL_SERIAL, byte_count=READ_SREG_LEN
|
|
)[0]
|
|
|
|
|
|
def spifi_wait_busy(openocd: OpenOcdTclRpc):
|
|
while 1:
|
|
sreg1 = spifi_read_sreg(openocd, SREG_Num.SREG1)
|
|
if not (sreg1 & SREG1_BUSY):
|
|
break
|
|
|
|
|
|
def spifi_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 spifi_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)
|
|
|
|
|
|
def spifi_read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: List[int], dma: Union[DMA, None] = None) -> int:
|
|
read_data: List[int] = []
|
|
|
|
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)
|
|
|
|
# spifi_init_periphery(openocd)
|
|
# read_periph = spifi_send_command(openocd, READ_DATA_COMMAND, SPIFI_Frameform.OPCODE_3ADDR,
|
|
# SPIFI_Fieldform.ALL_SERIAL, byte_count=1, address=(i+address))
|
|
# print(
|
|
# f"DATA[{i+address}] = {read_periph[0]:#0x} expect {bin_data[i]:#0x}", flush=True)
|
|
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
def spifi_page_program(
|
|
openocd: OpenOcdTclRpc,
|
|
ByteAddress: int,
|
|
data: List[int],
|
|
byte_count: int,
|
|
progress: str = "",
|
|
dma: Union[DMA, None] = None
|
|
):
|
|
print(f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True)
|
|
if byte_count > 256:
|
|
raise Exception("Byte count more than 256")
|
|
|
|
spifi_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)
|
|
spifi_wait_busy(openocd)
|
|
|
|
|
|
class EraseType(Enum):
|
|
CHIP_ERASE = CHIP_ERASE_COMMAND
|
|
SECTOR_ERASE = SECTOR_ERASE_COMMAND
|
|
|
|
|
|
def spifi_erase(openocd, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []):
|
|
if erase_type == EraseType.CHIP_ERASE:
|
|
spifi_write_enable(openocd)
|
|
spifi_chip_erase(openocd)
|
|
spifi_wait_busy(openocd)
|
|
elif erase_type == EraseType.SECTOR_ERASE:
|
|
for sector in sectors:
|
|
spifi_write_enable(openocd)
|
|
spifi_sector_erase(openocd, sector)
|
|
spifi_wait_busy(openocd)
|
|
|
|
|
|
def spifi_write(openocd: OpenOcdTclRpc, address: int, data: List[int], data_len: int):
|
|
if data_len > 256:
|
|
raise Exception("Byte count more than 256")
|
|
|
|
spifi_page_program(openocd, address, data, data_len)
|
|
|
|
print("written")
|
|
|
|
|
|
def spifi_write_file(bytes: List[int], openocd: OpenOcdTclRpc):
|
|
# print(bytes)
|
|
print(f"Write {len(bytes)} bytes")
|
|
|
|
openocd.halt()
|
|
spifi_init(openocd)
|
|
spifi_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)
|
|
spifi_write(openocd, address, bytes, 256)
|
|
if spifi_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}]")
|
|
spifi_write(openocd, address, bytes, len(bytes) - address)
|
|
if spifi_read_data(openocd, address, len(bytes) - address, bytes) == 1:
|
|
return 1
|
|
print("end")
|
|
|
|
return 0
|
|
|
|
|
|
def spifi_quad_page_program(
|
|
openocd: OpenOcdTclRpc,
|
|
ByteAddress: int,
|
|
data: List[int],
|
|
byte_count: int,
|
|
progress: str = "",
|
|
dma: Union[DMA, None] = None
|
|
):
|
|
print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
|
|
if byte_count > 256:
|
|
raise Exception("Byte count more than 256")
|
|
|
|
spifi_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)
|
|
spifi_wait_busy(openocd)
|
|
|
|
|
|
def spifi_quad_enable(openocd):
|
|
sreg2 = spifi_read_sreg(openocd, SREG_Num.SREG2)
|
|
|
|
spifi_write_enable(openocd)
|
|
spifi_send_command(openocd, WRITE_SREG2_COMMAND, SPIFI_Frameform.OPCODE_3ADDR,
|
|
SPIFI_Fieldform.ALL_SERIAL, byte_count=1,
|
|
idata=0, cache_limit=0, direction=SPIFI_Direction.WRITE, data=[sreg2 | SREG2_QUAD_ENABLE_M])
|
|
spifi_wait_busy(openocd)
|
|
|
|
|
|
def spifi_quad_disable(openocd):
|
|
sreg2 = spifi_read_sreg(openocd, SREG_Num.SREG2)
|
|
|
|
spifi_write_enable(openocd)
|
|
spifi_send_command(openocd, WRITE_SREG2_COMMAND, SPIFI_Frameform.OPCODE_3ADDR,
|
|
SPIFI_Fieldform.ALL_SERIAL, byte_count=1,
|
|
idata=0, cache_limit=0, direction=SPIFI_Direction.WRITE, data=[
|
|
sreg2 & (~SREG2_QUAD_ENABLE_M)])
|
|
spifi_wait_busy(openocd)
|
|
|
|
|
|
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 list(segments)
|
|
|
|
|
|
def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
|
|
result = 0
|
|
|
|
openocd.halt()
|
|
spifi_init(openocd)
|
|
|
|
JEDEC_ID = spifi_send_command(openocd, 0x9F, SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_SERIAL, 3)
|
|
|
|
print(f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
|
|
|
dma = DMA(openocd)
|
|
dma.init()
|
|
|
|
dma.channels[0].write_buffer = 0
|
|
|
|
dma.channels[0].channel = ChannelIndex.CHANNEL_0
|
|
dma.channels[0].priority = ChannelPriority.VERY_HIGH
|
|
|
|
dma.channels[0].read_mode = ChannelMode.MEMORY
|
|
dma.channels[0].read_increment = ChannelIncrement.ENABLE
|
|
dma.channels[0].read_size = ChannelSize.WORD
|
|
dma.channels[0].read_burst_size = 2
|
|
dma.channels[0].read_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[0].read_ack = ChannelAck.DISABLE
|
|
|
|
dma.channels[0].write_mode = ChannelMode.PERIPHERY
|
|
dma.channels[0].write_increment = ChannelIncrement.DISABLE
|
|
dma.channels[0].write_size = ChannelSize.WORD
|
|
dma.channels[0].write_burst_size = 2
|
|
dma.channels[0].write_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[0].write_ack = ChannelAck.DISABLE
|
|
|
|
dma.channels[1].write_buffer = 0
|
|
|
|
dma.channels[1].channel = ChannelIndex.CHANNEL_1
|
|
dma.channels[1].priority = ChannelPriority.VERY_HIGH
|
|
|
|
dma.channels[1].write_mode = ChannelMode.MEMORY
|
|
dma.channels[1].write_increment = ChannelIncrement.ENABLE
|
|
dma.channels[1].write_size = ChannelSize.WORD
|
|
dma.channels[1].write_burst_size = 2
|
|
dma.channels[1].write_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[1].write_ack = ChannelAck.DISABLE
|
|
|
|
dma.channels[1].read_mode = ChannelMode.PERIPHERY
|
|
dma.channels[1].read_increment = ChannelIncrement.DISABLE
|
|
dma.channels[1].read_size = ChannelSize.WORD
|
|
dma.channels[1].read_burst_size = 2
|
|
dma.channels[1].read_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[1].read_ack = ChannelAck.DISABLE
|
|
|
|
if (use_quad_spi):
|
|
print("Quad Enable")
|
|
spifi_quad_enable(openocd)
|
|
else:
|
|
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 = spifi_read_data(openocd, page_offset, 256, page_bytes, dma=dma)
|
|
|
|
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
|
|
|
|
# # PROFILING IMPORTS
|
|
# import cProfile, pstats, io
|
|
# from pstats import SortKey
|
|
|
|
def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
|
|
result = 0
|
|
|
|
# # PROFILING INIT
|
|
# pr = cProfile.Profile()
|
|
# pr.enable()
|
|
# # PROFILING INIT END
|
|
|
|
openocd.halt()
|
|
spifi_init(openocd)
|
|
|
|
JEDEC_ID = spifi_send_command(openocd, 0x9F, SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_SERIAL, 3)
|
|
|
|
print(f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
|
|
|
dma = DMA(openocd)
|
|
dma.init()
|
|
|
|
dma.channels[0].write_buffer = 0
|
|
|
|
dma.channels[0].channel = ChannelIndex.CHANNEL_0
|
|
dma.channels[0].priority = ChannelPriority.VERY_HIGH
|
|
|
|
dma.channels[0].read_mode = ChannelMode.MEMORY
|
|
dma.channels[0].read_increment = ChannelIncrement.ENABLE
|
|
dma.channels[0].read_size = ChannelSize.WORD
|
|
dma.channels[0].read_burst_size = 2
|
|
dma.channels[0].read_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[0].read_ack = ChannelAck.DISABLE
|
|
|
|
dma.channels[0].write_mode = ChannelMode.PERIPHERY
|
|
dma.channels[0].write_increment = ChannelIncrement.DISABLE
|
|
dma.channels[0].write_size = ChannelSize.WORD
|
|
dma.channels[0].write_burst_size = 2
|
|
dma.channels[0].write_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[0].write_ack = ChannelAck.DISABLE
|
|
|
|
dma.channels[1].write_buffer = 0
|
|
|
|
dma.channels[1].channel = ChannelIndex.CHANNEL_1
|
|
dma.channels[1].priority = ChannelPriority.VERY_HIGH
|
|
|
|
dma.channels[1].write_mode = ChannelMode.MEMORY
|
|
dma.channels[1].write_increment = ChannelIncrement.ENABLE
|
|
dma.channels[1].write_size = ChannelSize.WORD
|
|
dma.channels[1].write_burst_size = 2
|
|
dma.channels[1].write_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[1].write_ack = ChannelAck.DISABLE
|
|
|
|
dma.channels[1].read_mode = ChannelMode.PERIPHERY
|
|
dma.channels[1].read_increment = ChannelIncrement.DISABLE
|
|
dma.channels[1].read_size = ChannelSize.WORD
|
|
dma.channels[1].read_burst_size = 2
|
|
dma.channels[1].read_request = ChannelRequest.SPIFI_REQUEST
|
|
dma.channels[1].read_ack = ChannelAck.DISABLE
|
|
|
|
if use_chip_erase:
|
|
spifi_erase(openocd, EraseType.CHIP_ERASE)
|
|
else:
|
|
spifi_erase(openocd, EraseType.SECTOR_ERASE,
|
|
get_segments_list(list(pages), 4*1024))
|
|
|
|
# for addr in range(0, 4096*2, 256):
|
|
# result = spifi_read_data(openocd, addr, 256, [0xFF]*256, dma=dma)
|
|
|
|
# if result == 1:
|
|
# print("Data error")
|
|
# return result
|
|
|
|
if (use_quad_spi):
|
|
print("Quad Enable")
|
|
spifi_quad_enable(openocd)
|
|
else:
|
|
spifi_quad_disable(openocd)
|
|
|
|
pages_offsets = list(pages)
|
|
|
|
for index, page_offset in enumerate(pages_offsets):
|
|
page_bytes = pages[page_offset]
|
|
|
|
if (use_quad_spi):
|
|
spifi_quad_page_program(
|
|
openocd, page_offset, page_bytes, 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma)
|
|
else:
|
|
spifi_page_program(openocd, page_offset, page_bytes,
|
|
256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma)
|
|
|
|
result = spifi_read_data(openocd, page_offset, 256, page_bytes, dma=dma)
|
|
|
|
if result == 1:
|
|
print("Data error")
|
|
return result
|
|
|
|
if (use_quad_spi):
|
|
spifi_quad_disable(openocd)
|
|
|
|
# # PROFILING GET STATS
|
|
# pr.disable()
|
|
# s = io.StringIO()
|
|
# sortby = SortKey.CUMULATIVE
|
|
# ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
|
|
# ps.print_stats()
|
|
# print(s.getvalue())
|
|
# # PROFILING GET STATS END
|
|
|
|
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) -> int:
|
|
start_time = time.perf_counter()
|
|
while ("halted" not in openocd.run("riscv.cpu curstate")):
|
|
if (time.perf_counter() - start_time) > timeout_seconds:
|
|
print("Wait halted TIMEOUT!")
|
|
openocd.halt()
|
|
return 1
|
|
time.sleep(0.01)
|
|
return 0
|
|
|
|
|
|
def write_pages_by_sectors(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
|
|
result = 0
|
|
|
|
openocd.halt()
|
|
spifi_init(openocd)
|
|
|
|
JEDEC_ID = spifi_send_command(openocd, 0x9F, SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_SERIAL, 3)
|
|
print(f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
|
|
|
sectors_list = get_segments_list(list(pages), 4*1024)
|
|
|
|
openocd.halt()
|
|
pathname = os.path.dirname(sys.argv[0])
|
|
|
|
# openocd.run("load_image {%s}" % pathlib.Path(os.path.join(pathname, "firmware.hex")))
|
|
openocd.run("rbp all")
|
|
openocd.run("load_image {%s}" % pathlib.Path("C:\\Users\\user\\Documents\\PlatformIO\\Projects\\SPIFI_JTAG_driver\\.pio\\build\\mik32v2\\firmware.hex"))
|
|
openocd.run("bp 0x02002010 1 hw")
|
|
openocd.resume(0x02000000)
|
|
if wait_halted(openocd) != 0:
|
|
return 1
|
|
|
|
# spifi erase
|
|
for sector in sectors_list:
|
|
print(f"Erase sector {sector}", flush=True)
|
|
openocd.write_word(0x02002000, 0b0010 | (sector << 8))
|
|
openocd.resume()
|
|
if wait_halted(openocd) != 0:
|
|
return 1
|
|
print(f"Erase sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
|
|
|
return 1
|
|
|
|
# spifi erase check
|
|
for sector in sectors_list:
|
|
# print(f"Erase sector {sector}", flush=True)
|
|
# openocd.write_word(0x02002000, 0b0010 | sector)
|
|
# openocd.resume()
|
|
# if wait_halted(openocd) != 0:
|
|
# return 1
|
|
# print(f"Erase sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
|
|
|
page_bytes = [0xff] * 256
|
|
|
|
result = spifi_read_data(openocd, sector, 256, page_bytes)
|
|
|
|
if result == 1:
|
|
print("Data error")
|
|
return result
|
|
|
|
for sector in sectors_list:
|
|
print(f"Program sector {sector}", flush=True)
|
|
bytes_list: List[int] = []
|
|
for page in range(16):
|
|
page = pages.get(page * 256 + sector * 4096)
|
|
if page is not None:
|
|
bytes_list.extend(page)
|
|
else:
|
|
bytes_list.extend([0]*256)
|
|
|
|
extend_value = 1 + sector
|
|
bytes_list.extend([(extend_value >> 0) & 0xFF, (extend_value >> 8) & 0xFF, (extend_value >> 16) & 0xFF, (extend_value >> 24) & 0xFF])
|
|
# print(bytes_list)
|
|
|
|
while (openocd.read_word(0x0200200c) != 1):
|
|
openocd.resume()
|
|
openocd.halt()
|
|
|
|
openocd.write_memory(0x02001000, 8, bytes_list)
|
|
while (openocd.read_word(0x0200200c) != 1):
|
|
openocd.resume()
|
|
openocd.halt()
|
|
time.sleep(0.5)
|
|
openocd.halt()
|
|
print(f"Program sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
|
|
|
spifi_init_memory(openocd)
|
|
|
|
# check write
|
|
pages_offsets = list(pages)
|
|
for index, page_offset in enumerate(pages_offsets):
|
|
page_bytes = pages[page_offset]
|
|
|
|
memory_bytes = openocd.read_memory(page_offset + 0x80000000, 8, 256)
|
|
print(page_offset, memory_bytes)
|
|
|
|
for i, byte in enumerate(memory_bytes):
|
|
if byte != page_bytes[i]:
|
|
print("Data error!")
|
|
openocd.run("rbp 0x02002010")
|
|
return result
|
|
|
|
|
|
openocd.run("rbp 0x02002010")
|
|
if result == 0:
|
|
# Прошивка страниц флеш памяти по SPIFI была завершена
|
|
print("Flashing of flash memory pages via SPIFI has been completed", flush=True)
|
|
return 0
|