initial commit

This commit is contained in:
Sergey Shchelkanov 2022-12-13 15:02:44 +03:00
commit 61678651da
5 changed files with 1015 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__
.vscode

249
mik32_eeprom.py Normal file
View 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
View 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
View 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
View 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)