mirror of
https://github.com/MikronMIK32/mik32-uploader.git
synced 2026-01-01 13:37:03 +03:00
initial commit
This commit is contained in:
commit
61678651da
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
.vscode
|
||||
249
mik32_eeprom.py
Normal file
249
mik32_eeprom.py
Normal file
@ -0,0 +1,249 @@
|
||||
|
||||
import time
|
||||
from tclrpc import TclException
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
|
||||
# --------------------------
|
||||
# PM register offset
|
||||
# --------------------------
|
||||
PM_BASE_ADDRESS = 0x000050000
|
||||
|
||||
PM_Clk_AHB_Set_OFFSET = 0x0C
|
||||
PM_Clk_APB_M_Set_OFFSET = 0x14
|
||||
PM_Clk_APB_P_Set_OFFSET = 0x1C
|
||||
|
||||
# --------------------------
|
||||
# PM register fields
|
||||
# --------------------------
|
||||
# AHB BUS
|
||||
PM_CLOCK_CPU_S = 0
|
||||
PM_CLOCK_CPU_M = (1 << PM_CLOCK_CPU_S)
|
||||
PM_CLOCK_EEPROM_S = 1
|
||||
PM_CLOCK_EEPROM_M = (1 << PM_CLOCK_EEPROM_S)
|
||||
PM_CLOCK_RAM_S = 2
|
||||
PM_CLOCK_RAM_M = (1 << PM_CLOCK_RAM_S)
|
||||
PM_CLOCK_SPIFI_S = 3
|
||||
PM_CLOCK_SPIFI_M = (1 << PM_CLOCK_SPIFI_S)
|
||||
PM_CLOCK_TCB_S = 4
|
||||
PM_CLOCK_TCB_M = (1 << PM_CLOCK_TCB_S)
|
||||
PM_CLOCK_DMA_S = 5
|
||||
PM_CLOCK_DMA_M = (1 << PM_CLOCK_DMA_S)
|
||||
PM_CLOCK_CRYPTO_S = 6
|
||||
PM_CLOCK_CRYPTO_M = (1 << PM_CLOCK_CRYPTO_S)
|
||||
PM_CLOCK_CRC32_S = 7
|
||||
PM_CLOCK_CRC32_M = (1 << PM_CLOCK_CRC32_S)
|
||||
|
||||
# APB M
|
||||
PM_CLOCK_PM_S = 0
|
||||
PM_CLOCK_PM_M = (1 << PM_CLOCK_PM_S)
|
||||
|
||||
# --------------------------
|
||||
# WU register offset
|
||||
# --------------------------
|
||||
WU_BASE_ADDRESS = 0x00060000
|
||||
|
||||
WU_Clocks_OFFSET = 0x10
|
||||
|
||||
# --------------------------
|
||||
# EEPROM register offset
|
||||
# --------------------------
|
||||
EEPROM_REGS_BASE_ADDRESS = 0x00070400
|
||||
|
||||
EEPROM_REGS_EEDAT = EEPROM_REGS_BASE_ADDRESS + 0x00
|
||||
EEPROM_REGS_EEA = EEPROM_REGS_BASE_ADDRESS + 0x04
|
||||
EEPROM_REGS_EECON = EEPROM_REGS_BASE_ADDRESS + 0x08
|
||||
EEPROM_REGS_EESTA = EEPROM_REGS_BASE_ADDRESS + 0x0C
|
||||
EEPROM_REGS_EERB = EEPROM_REGS_BASE_ADDRESS + 0x10
|
||||
EEPROM_REGS_EEADJ = EEPROM_REGS_BASE_ADDRESS + 0x14
|
||||
EEPROM_REGS_NCYCRL = EEPROM_REGS_BASE_ADDRESS + 0x18
|
||||
EEPROM_REGS_NCYCEP1 = EEPROM_REGS_BASE_ADDRESS + 0x1C
|
||||
EEPROM_REGS_NCYCEP2 = EEPROM_REGS_BASE_ADDRESS + 0x20
|
||||
|
||||
# --------------------------
|
||||
# EEPROM register fields
|
||||
# --------------------------
|
||||
# EECON
|
||||
EEPROM_EX_S = 0
|
||||
EEPROM_OP_S = 1
|
||||
EEPROM_WRBEH_S = 3
|
||||
EEPROM_APBNWS_S = 5
|
||||
EEPROM_DISECC_S = 6
|
||||
EEPROM_BWE_S = 7
|
||||
EEPROM_IESERR_S = 8
|
||||
# EESTA
|
||||
EEPROM_BSY_S = 0
|
||||
EEPROM_SERR_S = 1
|
||||
# NCYCRL
|
||||
EEPROM_N_LD_S = 0
|
||||
EEPROM_N_R_1_S = 8
|
||||
EEPROM_N_R_2_S = 16
|
||||
# --------------------------
|
||||
# EEPROM codes
|
||||
# --------------------------
|
||||
EEPROM_OP_RD = 0
|
||||
EEPROM_OP_ER = 1
|
||||
EEPROM_OP_PR = 2
|
||||
EEPROM_BEH_EVEN = 1
|
||||
EEPROM_BEH_ODD = 2
|
||||
EEPROM_BEH_GLOB = 3
|
||||
|
||||
EEPROM_PAGE_MASK = 0x1F80
|
||||
|
||||
def eeprom_sysinit(openocd: OpenOcdTclRpc):
|
||||
print("MCU clock init...")
|
||||
|
||||
openocd.write_word(WU_BASE_ADDRESS + WU_Clocks_OFFSET, 0x202)
|
||||
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_P_Set_OFFSET, 0xffffffff)
|
||||
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_M_Set_OFFSET, 0xffffffff)
|
||||
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_AHB_Set_OFFSET, 0xffffffff)
|
||||
|
||||
|
||||
def eeprom_global_erase(openocd: OpenOcdTclRpc):
|
||||
print("EEPROM global erase...")
|
||||
with OpenOcdTclRpc() as openocd:
|
||||
openocd.write_word(EEPROM_REGS_NCYCRL, 1 << EEPROM_N_LD_S |
|
||||
3 << EEPROM_N_R_1_S | 1 << EEPROM_N_R_2_S)
|
||||
openocd.write_word(EEPROM_REGS_NCYCEP1, 100000)
|
||||
openocd.write_word(EEPROM_REGS_NCYCEP2, 1000)
|
||||
time.sleep(0.1)
|
||||
openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_BWE_S)
|
||||
| (EEPROM_BEH_GLOB << EEPROM_WRBEH_S))
|
||||
openocd.write_word(EEPROM_REGS_EEA, 0x00000000)
|
||||
# buffer load
|
||||
for i in range(0, 32):
|
||||
openocd.write_word(EEPROM_REGS_EEDAT, 0x00000000)
|
||||
# start operation
|
||||
openocd.write_word(EEPROM_REGS_EECON, (
|
||||
(1 << EEPROM_EX_S) | (1 << EEPROM_BWE_S) |
|
||||
(EEPROM_OP_ER << EEPROM_OP_S) | (EEPROM_BEH_GLOB << EEPROM_WRBEH_S)
|
||||
))
|
||||
|
||||
def eeprom_global_erase_check(openocd: OpenOcdTclRpc):
|
||||
print("EEPROM global erase check through APB...")
|
||||
print(" Read Data at ...")
|
||||
ex_value = 0x00000000
|
||||
openocd.write_word(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(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}")
|
||||
|
||||
|
||||
def eeprom_write_word(openocd: OpenOcdTclRpc, address:int, word:int):
|
||||
openocd.write_word(EEPROM_REGS_EECON, 1 << EEPROM_BWE_S)
|
||||
openocd.write_word(EEPROM_REGS_EEA, address)
|
||||
# buffer load
|
||||
openocd.write_word(EEPROM_REGS_EEDAT, word)
|
||||
openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_EX_S) | (1 << EEPROM_BWE_S) | (EEPROM_OP_PR << EEPROM_OP_S))
|
||||
time.sleep(0.001)
|
||||
|
||||
def eeprom_write_page(openocd: OpenOcdTclRpc, address:int, data:list[int]):
|
||||
openocd.write_word(EEPROM_REGS_EECON, 1 << EEPROM_BWE_S)
|
||||
openocd.write_word(EEPROM_REGS_EEA, address)
|
||||
page_address = address & EEPROM_PAGE_MASK
|
||||
n = 0
|
||||
# buffer load
|
||||
for word in data:
|
||||
if ((address + n) & EEPROM_PAGE_MASK) != page_address:
|
||||
raise Exception("ERROR: word outside page!")
|
||||
openocd.write_word(EEPROM_REGS_EEDAT, word)
|
||||
openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_EX_S) | (1 << EEPROM_BWE_S) | (EEPROM_OP_PR << EEPROM_OP_S))
|
||||
time.sleep(0.001)
|
||||
|
||||
def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: list[int]):
|
||||
print("EEPROM check through APB...")
|
||||
openocd.write_word(EEPROM_REGS_EEA, 0x00000000)
|
||||
word_num = 0
|
||||
progress = 0
|
||||
print("[", end="", flush=True)
|
||||
for word in words:
|
||||
value:int = openocd.read_word(EEPROM_REGS_EEDAT)
|
||||
if words[word_num] != value:
|
||||
print(f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}")
|
||||
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
|
||||
print("]")
|
||||
print("EEPROM check through APB done!")
|
||||
|
||||
def eeprom_check_data_ahb_lite(openocd: OpenOcdTclRpc, words: list[int]):
|
||||
print("EEPROM check through AHB-Lite...")
|
||||
mem_array = openocd.read_memory(0x01000000, 32, len(words))
|
||||
if len(words) != len(mem_array):
|
||||
raise Exception("Wrong number of words in read_memory output!")
|
||||
progress = 0
|
||||
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}, \
|
||||
get {mem_array[word_num]:#0x}")
|
||||
curr_progress = int((word_num * 50) / len(words))
|
||||
if curr_progress > progress:
|
||||
print("#"*(curr_progress - progress), end="", flush=True)
|
||||
progress = curr_progress
|
||||
print("]")
|
||||
print("EEPROM check through APB done!")
|
||||
|
||||
|
||||
def write_words(words: list[int], write_by_word = False, read_through_apb = False):
|
||||
"""
|
||||
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 visualisation, add option check page immidiately after writing
|
||||
"""
|
||||
print(f"Write {len(words*4)} bytes")
|
||||
with OpenOcdTclRpc() as openocd:
|
||||
openocd.halt()
|
||||
eeprom_sysinit(openocd)
|
||||
eeprom_global_erase(openocd)
|
||||
# eeprom_global_erase_check(openocd)
|
||||
openocd.write_word(EEPROM_REGS_NCYCRL, 1<<EEPROM_N_LD_S | 3<<EEPROM_N_R_1_S | 1<<EEPROM_N_R_2_S)
|
||||
openocd.write_word(EEPROM_REGS_NCYCEP1, 100000)
|
||||
openocd.write_word(EEPROM_REGS_NCYCEP2, 1000)
|
||||
time.sleep(0.1)
|
||||
word_num:int = 0
|
||||
progress:int = 0
|
||||
print("EEPROM writing...")
|
||||
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("]")
|
||||
if read_through_apb:
|
||||
eeprom_check_data_apb(openocd, words)
|
||||
else:
|
||||
eeprom_check_data_ahb_lite(openocd, words)
|
||||
openocd.resume(0)
|
||||
print("EEPROM write file done!")
|
||||
452
mik32_spifi.py
Normal file
452
mik32_spifi.py
Normal file
@ -0,0 +1,452 @@
|
||||
import time
|
||||
from tclrpc import TclException
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
|
||||
# --------------------------
|
||||
# PM register offset
|
||||
# --------------------------
|
||||
PM_BASE_ADDRESS = 0x000050000
|
||||
|
||||
PM_Clk_AHB_Set_OFFSET = 0x0C
|
||||
PM_Clk_APB_M_Set_OFFSET = 0x14
|
||||
PM_Clk_APB_P_Set_OFFSET = 0x1C
|
||||
|
||||
# --------------------------
|
||||
# PM register fields
|
||||
# --------------------------
|
||||
# AHB BUS
|
||||
PM_CLOCK_CPU_S = 0
|
||||
PM_CLOCK_CPU_M = (1 << PM_CLOCK_CPU_S)
|
||||
PM_CLOCK_EEPROM_S = 1
|
||||
PM_CLOCK_EEPROM_M = (1 << PM_CLOCK_EEPROM_S)
|
||||
PM_CLOCK_RAM_S = 2
|
||||
PM_CLOCK_RAM_M = (1 << PM_CLOCK_RAM_S)
|
||||
PM_CLOCK_SPIFI_S = 3
|
||||
PM_CLOCK_SPIFI_M = (1 << PM_CLOCK_SPIFI_S)
|
||||
PM_CLOCK_TCB_S = 4
|
||||
PM_CLOCK_TCB_M = (1 << PM_CLOCK_TCB_S)
|
||||
PM_CLOCK_DMA_S = 5
|
||||
PM_CLOCK_DMA_M = (1 << PM_CLOCK_DMA_S)
|
||||
PM_CLOCK_CRYPTO_S = 6
|
||||
PM_CLOCK_CRYPTO_M = (1 << PM_CLOCK_CRYPTO_S)
|
||||
PM_CLOCK_CRC32_S = 7
|
||||
PM_CLOCK_CRC32_M = (1 << PM_CLOCK_CRC32_S)
|
||||
|
||||
# APB M
|
||||
PM_CLOCK_PM_S = 0
|
||||
PM_CLOCK_PM_M = (1 << PM_CLOCK_PM_S)
|
||||
|
||||
# --------------------------
|
||||
# WU register offset
|
||||
# --------------------------
|
||||
WU_BASE_ADDRESS = 0x00060000
|
||||
|
||||
WU_Clocks_OFFSET = 0x10
|
||||
|
||||
# --------------------------
|
||||
# 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 = 1
|
||||
READ_LEN = 256
|
||||
TIMEOUT = 100000
|
||||
|
||||
CHIP_ERASE_COMMAND = 0xC7
|
||||
|
||||
WRITE_ENABLE_COMMAND = 0x06
|
||||
WRITE_DISABLE_COMMAND = 0x04
|
||||
|
||||
MEM_CONFIG_COMMAND = 0x61
|
||||
MEM_CONFIG_VALUE = 0x7F
|
||||
|
||||
READ_DATA_COMMAND = 0x03
|
||||
READ_SREG_COMMAND = 0x05
|
||||
|
||||
PAGE_PROGRAM_COMMAND = 0x02
|
||||
|
||||
|
||||
def spifi_intrq_clear(openocd: OpenOcdTclRpc):
|
||||
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(SPIFI_CONFIG_STAT) |
|
||||
SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
|
||||
|
||||
def spifi_init(openocd: OpenOcdTclRpc):
|
||||
print("MCU clock init...")
|
||||
|
||||
openocd.write_word(WU_BASE_ADDRESS + WU_Clocks_OFFSET, 0x202)
|
||||
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_P_Set_OFFSET, 0xffffffff)
|
||||
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_M_Set_OFFSET, 0xffffffff)
|
||||
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_AHB_Set_OFFSET, 0xffffffff)
|
||||
|
||||
"""
|
||||
*
|
||||
* STAT - регистр статуса
|
||||
* INTRQ - Запись «1» в бит сбрасывает запрос на прерывание от контроллера SPIFI
|
||||
* RESET - Бит предназначен для того, чтобы прервать текущую команду периферийного режима или режима памяти
|
||||
*
|
||||
* ADDR - Исполнительный адрес команды
|
||||
*
|
||||
* IDATA - регистр промежуточных данных
|
||||
*
|
||||
* CLIMIT - Верхний предел кэшируемой памяти
|
||||
*
|
||||
* CTRL - регистр управления
|
||||
* INTEN - Бит разрешения прерывания при завершении выполнения команды (если этот бит равен «1», то прерывание разрешено)
|
||||
*
|
||||
"""
|
||||
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_ADDR, 0x00)
|
||||
openocd.write_word(SPIFI_CONFIG_IDATA, 0x00)
|
||||
openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00)
|
||||
|
||||
time.sleep(1)
|
||||
print("Finish init SPIFI")
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
def spifi_write_enable(openocd: OpenOcdTclRpc):
|
||||
"""
|
||||
*
|
||||
* CMD код операции
|
||||
* OPCODE - код операции
|
||||
* FRAMEFORM - Бит управления полями кода операции и адреса команды:
|
||||
* «0» – резерв;
|
||||
* «1» – выдается только код операции, адреса нет; (SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR)
|
||||
* «2» – код операции и младший байт адреса;
|
||||
* «3» – код операции и два младших байта адреса;
|
||||
* «4» – код операции и три младших байта адреса;
|
||||
* «5» – код операции и 4 байта адреса;
|
||||
* «6» – нет кода операции, три младших байта адре-са;
|
||||
* «7» – нет кода операции, 4 байта адреса
|
||||
*
|
||||
* FIELDFORM - Формат вывода полей команды:
|
||||
* «0» – все поля выводятся в последовательном режиме; (SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL)
|
||||
* «1» – данные выводятся в четырех или двух битовом режиме, а остальные поля в последовательном режиме;
|
||||
* «2» – код операции выводится в последовательном режиме, а остальные в четырех или двух битовом;
|
||||
* «3» – все поля в четырех или двух битовом режиме
|
||||
*
|
||||
"""
|
||||
print("Start write en")
|
||||
# spifi_intrq_clear(openocd)
|
||||
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(
|
||||
SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
openocd.write_word(SPIFI_CONFIG_CMD, (WRITE_ENABLE_COMMAND << SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||
(SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||
(SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_CMD_FIELDFORM_S))
|
||||
spifi_wait_intrq_timeout(openocd, "Timeout executing write enable command")
|
||||
|
||||
|
||||
def spifi_read_sreg_1(openocd: OpenOcdTclRpc) -> int:
|
||||
read_sreg: int = 0
|
||||
|
||||
"""
|
||||
*
|
||||
* CMD код операции
|
||||
* OPCODE - код операции
|
||||
* FRAMEFORM - Бит управления полями кода операции и адреса команды:
|
||||
* «0» – резерв;
|
||||
* «1» – выдается только код операции, адреса нет; (SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR)
|
||||
* «2» – код операции и младший байт адреса;
|
||||
* «3» – код операции и два младших байта адреса;
|
||||
* «4» – код операции и три младших байта адреса;
|
||||
* «5» – код операции и 4 байта адреса;
|
||||
* «6» – нет кода операции, три младших байта адре-са;
|
||||
* «7» – нет кода операции, 4 байта адреса
|
||||
*
|
||||
* FIELDFORM - Формат вывода полей команды:
|
||||
* «0» – все поля выводятся в последовательном режиме; (SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL)
|
||||
* «1» – данные выводятся в четырех или двух битовом режиме, а остальные поля в последовательном режиме;
|
||||
* «2» – код операции выводится в последовательном режиме, а остальные в четырех или двух битовом;
|
||||
* «3» – все поля в четырех или двух битовом режиме
|
||||
*
|
||||
"""
|
||||
# spifi_intrq_clear(openocd)
|
||||
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(
|
||||
SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
openocd.write_word(SPIFI_CONFIG_CMD, (READ_SREG_COMMAND << SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||
(SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||
(SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_CMD_FIELDFORM_S) |
|
||||
(READ_SREG << SPIFI_CONFIG_CMD_DATALEN_S))
|
||||
spifi_wait_intrq_timeout(openocd, "Timeout executing read sreg1 command")
|
||||
return openocd.read_memory(SPIFI_CONFIG_DATA32, 8, 1)[0]
|
||||
|
||||
|
||||
def spifi_wait_busy(openocd: OpenOcdTclRpc):
|
||||
print("Wait busy")
|
||||
while 1:
|
||||
sreg = spifi_read_sreg_1(openocd)
|
||||
if not (sreg & SREG1_BUSY):
|
||||
break
|
||||
|
||||
|
||||
def spifi_chip_erase(openocd: OpenOcdTclRpc):
|
||||
print("Start erase")
|
||||
# spifi_intrq_clear(openocd)
|
||||
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(
|
||||
SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
openocd.write_word(SPIFI_CONFIG_CMD, (CHIP_ERASE_COMMAND << SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||
(SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||
(SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_CMD_FIELDFORM_S))
|
||||
spifi_wait_intrq_timeout(openocd, "Timeout executing chip erase command")
|
||||
|
||||
|
||||
def spifi_read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: list[int]):
|
||||
print("read data")
|
||||
read_data: list[int] = []
|
||||
openocd.write_word(SPIFI_CONFIG_ADDR, address)
|
||||
|
||||
"""
|
||||
*
|
||||
* CMD код операции
|
||||
* OPCODE - код операции
|
||||
* FRAMEFORM - Бит управления полями кода операции и адреса команды:
|
||||
* «0» – резерв;
|
||||
* «1» – выдается только код операции, адреса нет; (SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_NOADDR)
|
||||
* «2» – код операции и младший байт адреса;
|
||||
* «3» – код операции и два младших байта адреса;
|
||||
* «4» – код операции и три младших байта адреса;
|
||||
* «5» – код операции и 4 байта адреса;
|
||||
* «6» – нет кода операции, три младших байта адре-са;
|
||||
* «7» – нет кода операции, 4 байта адреса
|
||||
*
|
||||
* FIELDFORM - Формат вывода полей команды:
|
||||
* «0» – все поля выводятся в последовательном режиме; (SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL)
|
||||
* «1» – данные выводятся в четырех или двух битовом режиме, а остальные поля в последовательном режиме;
|
||||
* «2» – код операции выводится в последовательном режиме, а остальные в четырех или двух битовом;
|
||||
* «3» – все поля в четырех или двух битовом режиме
|
||||
*
|
||||
"""
|
||||
spifi_intrq_clear(openocd)
|
||||
openocd.write_word(SPIFI_CONFIG_CMD, (READ_DATA_COMMAND << SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||
(SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||
(SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_CMD_FIELDFORM_S) |
|
||||
(byte_count << SPIFI_CONFIG_CMD_DATALEN_S))
|
||||
# spifi_wait_intrq_timeout(openocd, "Timeout executing read data command")
|
||||
for i in range(byte_count):
|
||||
data8 = openocd.read_memory(SPIFI_CONFIG_DATA32, 8, 1)[0]
|
||||
read_data.append(data8)
|
||||
print(f"DATA[{i+address}] = {read_data[i]:#0x}")
|
||||
|
||||
for i in range(byte_count):
|
||||
if read_data[i] != bin_data[address + i]:
|
||||
print(f"DATA[{i+address}] = {read_data[i]:#0x} - ошибка")
|
||||
|
||||
|
||||
def spifi_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: list[int], byte_count: int):
|
||||
if byte_count > 256:
|
||||
raise Exception("Byte count more than 256")
|
||||
|
||||
print("Start page program")
|
||||
|
||||
# spifi_intrq_clear(openocd)
|
||||
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(
|
||||
SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
openocd.write_word(SPIFI_CONFIG_ADDR, ByteAddress)
|
||||
openocd.write_word(SPIFI_CONFIG_IDATA, 0x00)
|
||||
openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00000000)
|
||||
openocd.write_word(SPIFI_CONFIG_CMD, (PAGE_PROGRAM_COMMAND << SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||
(SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||
(SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << SPIFI_CONFIG_CMD_FIELDFORM_S) |
|
||||
(0 << SPIFI_CONFIG_CMD_INTLEN_S) |
|
||||
(1 << SPIFI_CONFIG_CMD_DOUT_S) |
|
||||
(0 << SPIFI_CONFIG_CMD_POLL_S) |
|
||||
(byte_count << SPIFI_CONFIG_CMD_DATALEN_S))
|
||||
for i in range(ByteAddress, ByteAddress + byte_count, 1):
|
||||
# openocd.write_word(SPIFI_CONFIG_DATA32, data[i+ByteAddress])
|
||||
openocd.write_memory(SPIFI_CONFIG_DATA32, 8, [data[i]])
|
||||
# spifi_intrq_clear(openocd)
|
||||
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(
|
||||
SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
|
||||
|
||||
def spifi_erase(openocd):
|
||||
spifi_write_enable(openocd)
|
||||
spifi_chip_erase(openocd)
|
||||
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_write_enable(openocd)
|
||||
spifi_page_program(openocd, address, data, data_len)
|
||||
spifi_wait_busy(openocd)
|
||||
|
||||
print("written")
|
||||
|
||||
|
||||
def spifi_write_file(bytes: list[int]):
|
||||
"""
|
||||
Write bytes in MIK32 External SPIFI Flash memory
|
||||
|
||||
@bytes: list of bytes to write at offset 0x0
|
||||
|
||||
TODO: implement setting byte array offset, add error handling,
|
||||
improve progress visualisation
|
||||
"""
|
||||
print(f"Write {len(bytes)} bytes")
|
||||
with OpenOcdTclRpc() as openocd:
|
||||
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)
|
||||
spifi_read_data(openocd, address, 256, bytes)
|
||||
|
||||
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)
|
||||
spifi_read_data(openocd, address, len(bytes) - address, bytes)
|
||||
print("end")
|
||||
openocd.resume(0)
|
||||
159
mik32_upload.py
Normal file
159
mik32_upload.py
Normal file
@ -0,0 +1,159 @@
|
||||
import mik32_eeprom
|
||||
import mik32_spifi
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
# class bcolors:
|
||||
# OK = '\033[92m'
|
||||
# WARNING = '\033[93m'
|
||||
# FAIL = '\033[91m'
|
||||
# ENDC = '\033[0m'
|
||||
# BOLD = '\033[1m'
|
||||
# UNDERLINE = '\033[4m'
|
||||
|
||||
|
||||
def parse_hex(file: str) -> dict:
|
||||
"""
|
||||
TODO: Implement support for more record types
|
||||
"""
|
||||
with open(file,
|
||||
"r", encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
memory_blocks = {}
|
||||
bytes = []
|
||||
block_offset = -1
|
||||
|
||||
def add_memory_block():
|
||||
memory_blocks[block_offset] = bytes[:]
|
||||
|
||||
is_error = False
|
||||
byte_len = 0
|
||||
|
||||
next_line_offset = -1
|
||||
|
||||
for i in range(lines.__len__()):
|
||||
line = lines[i]
|
||||
if line[0] != ':':
|
||||
print("Error: unexpected record mark on line %i, expect \':\', get \'%c\'" % (
|
||||
i+1, line[0]))
|
||||
is_error = True
|
||||
break
|
||||
|
||||
reclen = int(line[1:3], base=16) # Record length
|
||||
load_offset = int(line[3:7], base=16) # Initial address of data byte
|
||||
rectype = int(line[7:9], base=16) # Record type
|
||||
data_bytes: list[str] = []
|
||||
|
||||
data_bytes_line = line[9:reclen*2 + 9]
|
||||
for i in range(reclen):
|
||||
data_bytes.append(data_bytes_line[i*2:i*2+2])
|
||||
byte_len += 1
|
||||
|
||||
match rectype:
|
||||
case 0: # Data Record
|
||||
if next_line_offset == -1:
|
||||
next_line_offset = load_offset
|
||||
block_offset = load_offset
|
||||
|
||||
if next_line_offset != load_offset:
|
||||
add_memory_block()
|
||||
bytes.clear()
|
||||
block_offset = load_offset
|
||||
next_line_offset = load_offset
|
||||
|
||||
for i in range(reclen):
|
||||
byte = data_bytes[i]
|
||||
byte = int(f"0x{byte}", base=16)
|
||||
bytes.append(byte)
|
||||
|
||||
next_line_offset += reclen
|
||||
|
||||
# for i in range(data_len//4):
|
||||
# data_bytes = word_bytes.reverse()
|
||||
# print("data words: ", data_words)
|
||||
case 1: # End of File Record
|
||||
print("End of File")
|
||||
add_memory_block()
|
||||
case 2: # Extended Segment Address Record
|
||||
print("Record 2: Extended Segment Address Record")
|
||||
print("ERROR: unimplemented record type 2 on line %i" % (i+1))
|
||||
is_error = True
|
||||
break
|
||||
case 3: # Start Segment Address Record
|
||||
print("Start Segment Address Record")
|
||||
print("ERROR: unimplemented record type 3 on line %i" % (i+1))
|
||||
is_error = True
|
||||
case 4: # Extended Linear Address Record
|
||||
print("Extended Linear Address Record")
|
||||
print("ERROR: unimplemented record type 4 on line %i" % (i+1))
|
||||
is_error = True
|
||||
case 5: # Start Linear Address Record
|
||||
print("Start Linear Address Record")
|
||||
print("ERROR: unimplemented record type 5 on line %i" % (i+1))
|
||||
is_error = True
|
||||
case _:
|
||||
print("ERROR: unexpected record type %i on line %i" %
|
||||
(rectype, i+1))
|
||||
is_error = True
|
||||
break
|
||||
# print("line %i data_bytes=%i line_addr=%i" % (i+1, data_bytes, line_addr))
|
||||
|
||||
# for word in memory_blocks[0]:
|
||||
# print(f"{word:#0x}")
|
||||
|
||||
if is_error:
|
||||
print("ERROR: error while parsing")
|
||||
exit()
|
||||
|
||||
return memory_blocks
|
||||
|
||||
|
||||
def parse_bin(filename: str) -> list[int]:
|
||||
arr: list[int] = []
|
||||
with open(filename, "rb") as f:
|
||||
while byte := f.read(1):
|
||||
arr.append(byte[0])
|
||||
return arr
|
||||
|
||||
|
||||
def bytes2words(arr: list[int]) -> list[int]:
|
||||
word = []
|
||||
words = []
|
||||
for byte in arr:
|
||||
word.append(byte)
|
||||
if word.__len__() == 4:
|
||||
words.append(word[0]+2**8*word[1]+2**16*word[2]+2**24*word[3])
|
||||
word = []
|
||||
return words
|
||||
|
||||
|
||||
def upload_file(filename: str, boot_source: str = "eeprom"):
|
||||
"""
|
||||
Write ihex or binary file into MIK32 EEPROM or external flash memory
|
||||
|
||||
@filename: full path to the file with hex or bin file format
|
||||
@boot_source: boot source, eeprom or spifi, define memory block mapped to boot memory area (0x0 offset)
|
||||
|
||||
TODO: Implement error handling
|
||||
"""
|
||||
if filename.endswith(".bin"):
|
||||
content = parse_bin(filename)
|
||||
elif filename.endswith(".hex"):
|
||||
content = parse_hex(filename)
|
||||
else:
|
||||
raise Exception("Unsupported file format")
|
||||
|
||||
if boot_source == "eeprom":
|
||||
if type(content) is list:
|
||||
mik32_eeprom.write_words(bytes2words(content))
|
||||
elif type(content) is dict:
|
||||
mik32_eeprom.write_words(bytes2words(content[0]))
|
||||
elif boot_source == "spifi":
|
||||
if type(content) is list:
|
||||
mik32_spifi.spifi_write_file(content)
|
||||
elif type(content) is dict:
|
||||
mik32_spifi.spifi_write_file(content[0])
|
||||
else:
|
||||
raise Exception("Unsupported boot source, use eeprom or spifi")
|
||||
|
||||
153
tclrpc.py
Normal file
153
tclrpc.py
Normal file
@ -0,0 +1,153 @@
|
||||
import re
|
||||
import socket
|
||||
from logging import getLogger
|
||||
logger = getLogger(__name__)
|
||||
|
||||
class TclException(Exception):
|
||||
def __init__(self, code, msg):
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
|
||||
def __repr__(self):
|
||||
return 'TclException(%d, %r)' % (self.code, self.msg)
|
||||
|
||||
_RE_SIMPLE_TCL_WORD = re.compile(r"^[a-zA-Z_0-9:+./@=,'-]+$")
|
||||
def tcl_quote_word(word):
|
||||
"""Quotes one word for TCL"""
|
||||
global _RE_SIMPLE_TCL_WORD
|
||||
if _RE_SIMPLE_TCL_WORD.match(word):
|
||||
return word
|
||||
else:
|
||||
return '{' + word + '}'
|
||||
|
||||
def tcl_quote_cmd(arg):
|
||||
"""Quote a TCL command
|
||||
|
||||
Argument must be a string (assumed to be already quoted) or list
|
||||
"""
|
||||
if type(arg) is str:
|
||||
return arg
|
||||
elif type(arg) is list or type(arg) is tuple:
|
||||
return ' '.join([tcl_quote_word(word) for word in arg])
|
||||
else:
|
||||
raise TypeError("Expected str or list or tuple, got %s: %r" % (type(arg), arg))
|
||||
|
||||
class OpenOcdTclRpc:
|
||||
DEFAULT_PORT = 6666
|
||||
SEPARATOR_VALUE = 0x1a
|
||||
SEPARATOR_BYTES = b'\x1a'
|
||||
BUFFER_SIZE = 10240
|
||||
|
||||
__slots__ = (
|
||||
'host',
|
||||
'port',
|
||||
'sock',
|
||||
)
|
||||
|
||||
def __init__(self, host='127.0.0.1', port=DEFAULT_PORT):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.sock = None
|
||||
|
||||
def __enter__(self):
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.connect((self.host, self.port))
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
|
||||
def sendrecv(self, cmd):
|
||||
"""Send a command string and return reply"""
|
||||
logger.debug('send: %s', cmd)
|
||||
data = cmd.encode('utf-8') + self.SEPARATOR_BYTES
|
||||
self.sock.sendall(data)
|
||||
reply = self._recv().decode('utf-8')
|
||||
logger.debug('recv: %s', reply)
|
||||
return reply
|
||||
|
||||
def _recv(self):
|
||||
"""Read bytes until self.SEPARATOR"""
|
||||
data = bytes()
|
||||
while True:
|
||||
chunk = self.sock.recv(self.BUFFER_SIZE)
|
||||
data += chunk
|
||||
index = data.find(self.SEPARATOR_BYTES)
|
||||
if index >= 0:
|
||||
if index != len(data) - 1:
|
||||
raise Exception('Unhandled extra bytes after %r'.format(self.SEPARATOR_BYTES))
|
||||
return data[:-1]
|
||||
|
||||
def run(self, cmd):
|
||||
"""Run a command and raise an error if it returns an error"""
|
||||
wrap = 'set _code [catch {%s} _msg];expr {"$_code $_msg"}' % tcl_quote_cmd(cmd)
|
||||
reply = self.sendrecv(wrap)
|
||||
code, msg = reply.split(' ', 1)
|
||||
code = int(code)
|
||||
|
||||
if code:
|
||||
raise TclException(code, msg)
|
||||
else:
|
||||
return msg
|
||||
|
||||
def halt(self):
|
||||
"""Halt MCU and raise an error if it returns an error"""
|
||||
return self.run("capture \"halt\"")
|
||||
|
||||
def resume(self, address:int|None=None):
|
||||
"""Resume the target at its current code position, or the optional address
|
||||
if it is provided.
|
||||
OpenOCD will wait 5 seconds for the target to resume."""
|
||||
if address is None:
|
||||
return self.run(f"capture \"resume\"")
|
||||
else:
|
||||
return self.run(f"capture \"resume {address:#0x}\"")
|
||||
|
||||
def mww(self, addr:int, word:int):
|
||||
"""Write the word on addr and raise an error if it returns an error"""
|
||||
return self.run(f"capture \"mww {addr:#0x} {word:#0x}\"")
|
||||
|
||||
def write_memory(self, address:int, width:int, data:list[int]):
|
||||
"""This function provides an efficient way to write to the target memory
|
||||
from a Tcl script
|
||||
|
||||
address ... target memory address
|
||||
|
||||
width ... memory access bit size, can be 8, 16, 32 or 64
|
||||
|
||||
data ... Tcl list with the elements to write """
|
||||
data_words: list[str] = []
|
||||
for word in data:
|
||||
data_words.append(str(f"{word:#0x}"))
|
||||
data_string = " ".join(data_words)
|
||||
return self.run(f"capture \"write_memory {address:#0x} {width} {{{data_string}}}\"")
|
||||
|
||||
def write_word(self, address:int, word:int):
|
||||
return self.write_memory(address, 32, [word])
|
||||
|
||||
def read_memory(self, address:int, width:int, count:int):
|
||||
"""This function provides an efficient way to read the target memory from a Tcl script.
|
||||
A Tcl list containing the requested memory elements is returned by this function.
|
||||
|
||||
address ... target memory address
|
||||
|
||||
width ... memory access bit size, can be 8, 16, 32 or 64
|
||||
|
||||
count ... number of elements to read """
|
||||
data = self.run(f"capture \"read_memory {address:#0x} {width} {count}\"").split(" ")
|
||||
return list(map(lambda word: int(word, base=16), data))
|
||||
|
||||
def read_word(self, address:int):
|
||||
"""This function provides an efficient way to read the target memory from a Tcl script.
|
||||
A Tcl list containing the requested memory elements is returned by this function.
|
||||
|
||||
address ... target memory address
|
||||
|
||||
width ... memory access bit size, can be 8, 16, 32 or 64
|
||||
|
||||
count ... number of elements to read """
|
||||
data = self.run(f"capture \"read_memory {address:#0x} 32 1\"").split(" ")
|
||||
return int(data[0], base=16)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user