mirror of
https://github.com/MikronMIK32/mik32-uploader.git
synced 2026-10-29 18:11:13 +03:00
Перенос драйверов и регистров в модуль
This commit is contained in:
1 parent
537deb8860
commit
e0408a03aa
16 files changed
+686
-681
No files matched your search
@@ -0,0 +1,204 @@
|
||||
from enum import Enum
|
||||
from typing import Dict, List
|
||||
import time
|
||||
from tclrpc import TclException
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
from dataclasses import dataclass
|
||||
import mik32_debug_hal.registers.memory_map as mem_map
|
||||
import mik32_debug_hal.registers.bitfields.dma as dma_fields
|
||||
|
||||
# ReadStatus. Разрешить читать текущий статус канала
|
||||
class CurrentValue(Enum):
|
||||
ENABLE = 0 # Текущие значения
|
||||
DISABLE = 1 # Значения при настройке
|
||||
|
||||
|
||||
class ChannelIndex(Enum):
|
||||
CHANNEL_0 = 0
|
||||
CHANNEL_1 = 1
|
||||
CHANNEL_2 = 2
|
||||
CHANNEL_3 = 3
|
||||
|
||||
|
||||
class ChannelPriority(Enum):
|
||||
LOW = 0
|
||||
MEDIUM = 1
|
||||
HIGH = 2
|
||||
VERY_HIGH = 3
|
||||
|
||||
|
||||
class ChannelMode(Enum):
|
||||
PERIPHERY = 0
|
||||
MEMORY = 1
|
||||
|
||||
|
||||
class ChannelIncrement(Enum):
|
||||
DISABLE = 0
|
||||
ENABLE = 1
|
||||
|
||||
|
||||
class ChannelSize(Enum):
|
||||
BYTE = 0
|
||||
HALFWORD = 1
|
||||
WORD = 1
|
||||
|
||||
|
||||
class ChannelAck(Enum):
|
||||
DISABLE = 0
|
||||
ENABLE = 1
|
||||
|
||||
|
||||
class ChannelRequest(Enum):
|
||||
USART_0_REQUEST = 0
|
||||
USART_1_REQUEST = 1
|
||||
CRYPTO_REQUEST = 2
|
||||
SPI_0_REQUEST = 3
|
||||
SPI_1_REQUEST = 4
|
||||
I2C_0_REQUEST = 5
|
||||
I2C_1_REQUEST = 6
|
||||
SPIFI_REQUEST = 7
|
||||
TIMER32_1_REQUEST = 8
|
||||
TIMER32_2_REQUEST = 9
|
||||
TIMER32_0_REQUEST = 10
|
||||
|
||||
|
||||
class DMA_Channel:
|
||||
openocd: OpenOcdTclRpc
|
||||
|
||||
write_buffer: int = 0
|
||||
|
||||
channel: ChannelIndex
|
||||
priority: ChannelPriority
|
||||
|
||||
read_mode: ChannelMode
|
||||
read_increment: ChannelIncrement
|
||||
read_size: ChannelSize
|
||||
read_ack: ChannelAck
|
||||
read_burst_size: int
|
||||
read_request: ChannelRequest
|
||||
|
||||
write_mode: ChannelMode
|
||||
write_increment: ChannelIncrement
|
||||
write_size: ChannelSize
|
||||
write_ack: ChannelAck
|
||||
write_burst_size: int
|
||||
write_request: ChannelRequest
|
||||
|
||||
def __init__(self, openocd: OpenOcdTclRpc):
|
||||
self.openocd = openocd
|
||||
|
||||
def set_source(self, source: int):
|
||||
self.openocd.write_word(mem_map.DMA_CHANNEL_SOURCE(1), source)
|
||||
|
||||
def set_destination(self, source: int):
|
||||
self.openocd.write_word(mem_map.DMA_CHANNEL_DESTINATION(1), source)
|
||||
|
||||
def set_length(self, source: int):
|
||||
self.openocd.write_word(mem_map.DMA_CHANNEL_LEN(1), source)
|
||||
|
||||
def set_config(self, source: int):
|
||||
self.openocd.write_word(mem_map.DMA_CHANNEL_CONFIG(1), source)
|
||||
|
||||
def start(
|
||||
self,
|
||||
source_address: int,
|
||||
destination_address: int,
|
||||
length: int,
|
||||
):
|
||||
self.write_buffer |= (dma_fields.CFG_CH_ENABLE_M
|
||||
| (self.priority.value << dma_fields.CFG_CH_PRIOR_S)
|
||||
| (self.read_mode.value << dma_fields.CFG_CH_READ_MODE_S)
|
||||
| (self.read_increment.value << dma_fields.CFG_CH_READ_INCREMENT_S)
|
||||
| (self.read_size.value << dma_fields.CFG_CH_READ_SIZE_S)
|
||||
| (self.read_burst_size << dma_fields.CFG_CH_READ_BURST_SIZE_S)
|
||||
| (self.read_request.value << dma_fields.CFG_CH_READ_REQ_S)
|
||||
| (self.read_ack.value << dma_fields.CFG_CH_ACK_READ_S)
|
||||
| (self.write_mode.value << dma_fields.CFG_CH_WRITE_MODE_S)
|
||||
| (self.write_increment.value << dma_fields.CFG_CH_WRITE_INCREMENT_S)
|
||||
| (self.write_size.value << dma_fields.CFG_CH_WRITE_SIZE_S)
|
||||
| (self.write_burst_size << dma_fields.CFG_CH_WRITE_BURST_SIZE_S)
|
||||
| (self.write_request.value << dma_fields.CFG_CH_WRITE_REQ_S)
|
||||
| (self.write_ack.value << dma_fields.CFG_CH_ACK_WRITE_S))
|
||||
|
||||
self.openocd.write_memory(mem_map.DMA_CHANNEL_DESTINATION(
|
||||
1), 32, [destination_address, source_address, length, self.write_buffer])
|
||||
|
||||
|
||||
class DMA:
|
||||
openocd: OpenOcdTclRpc
|
||||
|
||||
current_value: CurrentValue = CurrentValue.ENABLE
|
||||
write_buffer: int = 0
|
||||
|
||||
channels: List[DMA_Channel] = []
|
||||
|
||||
def __init__(self, openocd: OpenOcdTclRpc):
|
||||
self.openocd = openocd
|
||||
self.channels.append(DMA_Channel(self.openocd))
|
||||
self.channels.append(DMA_Channel(self.openocd))
|
||||
self.channels.append(DMA_Channel(self.openocd))
|
||||
self.channels.append(DMA_Channel(self.openocd))
|
||||
|
||||
def init(self):
|
||||
self.current_value = CurrentValue.ENABLE
|
||||
|
||||
self.write_buffer = 0
|
||||
self.openocd.write_memory(0x40000, 32, [0] * 16)
|
||||
self.clear_irq()
|
||||
self.set_current_value(self.current_value)
|
||||
|
||||
def set_control(self, control: int):
|
||||
if (control > 2**32 or control < 0):
|
||||
raise ValueError
|
||||
|
||||
self.openocd.write_word(mem_map.DMA_CONTROL, control)
|
||||
|
||||
def get_control(self) -> int:
|
||||
return self.openocd.read_word(mem_map.DMA_CONTROL)
|
||||
|
||||
def clear_irq(self):
|
||||
self.clear_local_irq()
|
||||
self.clear_global_irq()
|
||||
self.clear_error_irq()
|
||||
|
||||
def clear_local_irq(self):
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M |
|
||||
dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M | dma_fields.CONTROL_CLEAR_ERROR_IRQ_M)
|
||||
self.write_buffer |= dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M
|
||||
self.set_control(self.write_buffer)
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M |
|
||||
dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M | dma_fields.CONTROL_CLEAR_ERROR_IRQ_M)
|
||||
|
||||
def clear_global_irq(self):
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M |
|
||||
dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M | dma_fields.CONTROL_CLEAR_ERROR_IRQ_M)
|
||||
self.write_buffer |= dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M
|
||||
self.set_control(self.write_buffer)
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M |
|
||||
dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M | dma_fields.CONTROL_CLEAR_ERROR_IRQ_M)
|
||||
|
||||
def clear_error_irq(self):
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M |
|
||||
dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M | dma_fields.CONTROL_CLEAR_ERROR_IRQ_M)
|
||||
self.write_buffer |= dma_fields.CONTROL_CLEAR_ERROR_IRQ_M
|
||||
self.set_control(self.write_buffer)
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CLEAR_LOCAL_IRQ_M |
|
||||
dma_fields.CONTROL_CLEAR_GLOBAL_IRQ_M | dma_fields.CONTROL_CLEAR_ERROR_IRQ_M)
|
||||
|
||||
def set_current_value(self, current_value: CurrentValue):
|
||||
self.current_value = current_value
|
||||
self.write_buffer &= ~(dma_fields.CONTROL_CURRENT_VALUE_M)
|
||||
self.write_buffer |= current_value.value << dma_fields.CONTROL_CURRENT_VALUE_S
|
||||
self.set_control(self.write_buffer)
|
||||
|
||||
def dma_wait(self, channel: DMA_Channel, timeout: float):
|
||||
channel_index = channel.channel.value
|
||||
mask = (1 << channel_index) << dma_fields.STATUS_READY_S
|
||||
|
||||
begin = time.perf_counter()
|
||||
|
||||
while (begin - time.perf_counter()) < timeout:
|
||||
if self.get_control() & mask != 0:
|
||||
return
|
||||
|
||||
raise Exception
|
||||
@@ -0,0 +1,302 @@
|
||||
from enum import Enum
|
||||
from typing import Dict, List
|
||||
import time
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
from utils import bytes2words
|
||||
|
||||
|
||||
# --------------------------
|
||||
# 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...", flush=True)
|
||||
|
||||
|
||||
class EEPROM_Operation(Enum):
|
||||
READ = EEPROM_OP_RD
|
||||
ERASE = EEPROM_OP_ER
|
||||
PROGRAM = EEPROM_OP_PR
|
||||
|
||||
|
||||
class EEPROM_AffectedPages(Enum):
|
||||
SINGLE = 0
|
||||
EVEN = EEPROM_BEH_EVEN
|
||||
ODD = EEPROM_BEH_ODD
|
||||
GLOBAL = EEPROM_BEH_GLOB
|
||||
|
||||
|
||||
def eeprom_execute_operation(openocd: OpenOcdTclRpc, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]):
|
||||
# buffer write enable and select affected pages
|
||||
openocd.write_memory(EEPROM_REGS_EEA, 32, [offset, (1 << EEPROM_BWE_S)
|
||||
| (affected_pages.value << EEPROM_WRBEH_S)])
|
||||
|
||||
if buffer.__len__() > 32:
|
||||
return
|
||||
for word in buffer:
|
||||
openocd.write_word(EEPROM_REGS_EEDAT, word)
|
||||
# start operation
|
||||
openocd.write_word(EEPROM_REGS_EECON, (
|
||||
(1 << EEPROM_EX_S) | (1 << EEPROM_BWE_S) |
|
||||
(op.value << EEPROM_OP_S) | (affected_pages.value << EEPROM_WRBEH_S)
|
||||
))
|
||||
|
||||
|
||||
def eeprom_configure_cycles(openocd: OpenOcdTclRpc, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500):
|
||||
openocd.write_word(EEPROM_REGS_NCYCRL, LD << EEPROM_N_LD_S |
|
||||
R_1 << EEPROM_N_R_1_S | R_2 << EEPROM_N_R_2_S)
|
||||
openocd.write_word(EEPROM_REGS_NCYCEP1, CYCEP1)
|
||||
openocd.write_word(EEPROM_REGS_NCYCEP2, CYCEP2)
|
||||
|
||||
|
||||
def eeprom_global_erase(openocd: OpenOcdTclRpc):
|
||||
print("EEPROM global erase...", flush=True)
|
||||
# configure cycles duration
|
||||
eeprom_execute_operation(
|
||||
openocd, EEPROM_Operation.ERASE, EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32)
|
||||
|
||||
|
||||
def eeprom_global_erase_check(openocd: OpenOcdTclRpc):
|
||||
print("EEPROM global erase check through APB...", flush=True)
|
||||
print(" Read Data at ...", flush=True)
|
||||
ex_value = 0x00000000
|
||||
openocd.write_word(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}", flush=True)
|
||||
|
||||
|
||||
def eeprom_write_word(openocd: OpenOcdTclRpc, address: int, word: int):
|
||||
eeprom_execute_operation(
|
||||
openocd, EEPROM_Operation.PROGRAM, EEPROM_AffectedPages.SINGLE, address, [word])
|
||||
time.sleep(0.001)
|
||||
|
||||
|
||||
def eeprom_write_page(openocd: OpenOcdTclRpc, address: int, data: List[int]):
|
||||
eeprom_execute_operation(
|
||||
openocd, EEPROM_Operation.PROGRAM, EEPROM_AffectedPages.SINGLE, address, data)
|
||||
time.sleep(0.001)
|
||||
|
||||
|
||||
def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int:
|
||||
if print_progress:
|
||||
print("EEPROM check through APB...", flush=True)
|
||||
# address load
|
||||
openocd.write_word(EEPROM_REGS_EEA, offset)
|
||||
word_num = 0
|
||||
progress = 0
|
||||
if print_progress:
|
||||
print("[", end="", flush=True)
|
||||
for word in words:
|
||||
value: int = openocd.read_word(EEPROM_REGS_EEDAT)
|
||||
if words[word_num] != value:
|
||||
print(
|
||||
f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}", flush=True)
|
||||
return 1
|
||||
word_num += 1
|
||||
curr_progress = int((word_num * 50) / len(words))
|
||||
if print_progress and (curr_progress > progress):
|
||||
print("#"*(curr_progress - progress), end="", flush=True)
|
||||
progress = curr_progress
|
||||
if print_progress:
|
||||
print("]", flush=True)
|
||||
print("EEPROM check through APB done!", flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
def eeprom_check_data_ahb_lite(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int:
|
||||
if print_progress:
|
||||
print("EEPROM check through AHB-Lite...", flush=True)
|
||||
mem_array = openocd.read_memory(0x01000000 + offset, 32, len(words))
|
||||
if len(words) != len(mem_array):
|
||||
raise Exception(
|
||||
"Wrong number of words in read_memory output!")
|
||||
progress = 0
|
||||
if print_progress:
|
||||
print("[", end="", flush=True)
|
||||
for word_num in range(len(words)):
|
||||
if words[word_num] != mem_array[word_num]:
|
||||
print(f"Unexpect value at {word_num} word, expect {words[word_num]:#0x}, "
|
||||
f"get {mem_array[word_num]:#0x}", flush=True)
|
||||
return 1
|
||||
curr_progress = int((word_num * 50) / len(words))
|
||||
if print_progress and (curr_progress > progress):
|
||||
print("#"*(curr_progress - progress), end="", flush=True)
|
||||
progress = curr_progress
|
||||
if print_progress:
|
||||
print("]", flush=True)
|
||||
print("EEPROM check through APB done!", flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
def eeprom_check_data(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True, read_through_apb=False) -> int:
|
||||
if read_through_apb:
|
||||
return eeprom_check_data_apb(openocd, words, offset, print_progress)
|
||||
else:
|
||||
return eeprom_check_data_ahb_lite(openocd, words, offset, print_progress)
|
||||
|
||||
|
||||
def write_words(words: List[int], openocd: OpenOcdTclRpc, write_by_word=False, read_through_apb=False) -> int:
|
||||
"""
|
||||
Write words in MIK32 EEPROM through APB bus
|
||||
|
||||
@words: list of words to write at offset 0x0
|
||||
@write_by_word: if True, write every word in separete page flash operation
|
||||
@read_through_apb: if True, check written words through APB instead of AHB-Lite
|
||||
|
||||
TODO: implement setting byte array offset, add error handling,
|
||||
improve progress visualization, add option check page immidiately after writing
|
||||
|
||||
@return: return 0 if successful, 1 if failed
|
||||
"""
|
||||
print(f"Write {len(words*4)} bytes", flush=True)
|
||||
|
||||
openocd.halt()
|
||||
eeprom_sysinit(openocd)
|
||||
eeprom_global_erase(openocd)
|
||||
# eeprom_global_erase_check(openocd)
|
||||
# configure cycles duration
|
||||
eeprom_configure_cycles(openocd, 1, 3, 1, 100000, 1000)
|
||||
time.sleep(0.1)
|
||||
word_num: int = 0
|
||||
progress: int = 0
|
||||
print("EEPROM writing...", flush=True)
|
||||
print("[", end="", flush=True)
|
||||
if write_by_word:
|
||||
for word in words:
|
||||
eeprom_write_word(openocd, word_num*4, word)
|
||||
word_num += 1
|
||||
curr_progress = int((word_num * 50) / len(words))
|
||||
if curr_progress > progress:
|
||||
print("#"*(curr_progress - progress), end="", flush=True)
|
||||
progress = curr_progress
|
||||
else:
|
||||
page = []
|
||||
page_num = 0
|
||||
page_size = 32
|
||||
while word_num < len(words):
|
||||
if word_num < page_size*(page_num+1):
|
||||
page.append(words[word_num])
|
||||
word_num += 1
|
||||
else:
|
||||
# print(list(map(lambda word: f"{word:#0x}", page)))
|
||||
eeprom_write_page(openocd, page_num*page_size*4, page)
|
||||
page_num += 1
|
||||
page.clear()
|
||||
curr_progress = int((word_num * 50) / len(words))
|
||||
if curr_progress > progress:
|
||||
print("#"*(curr_progress - progress), end="", flush=True)
|
||||
progress = curr_progress
|
||||
eeprom_write_page(openocd, page_num*page_size*4, page)
|
||||
print("]", flush=True)
|
||||
if read_through_apb:
|
||||
result = eeprom_check_data_apb(openocd, words, 0)
|
||||
else:
|
||||
result = eeprom_check_data_ahb_lite(openocd, words, 0)
|
||||
|
||||
if result == 0:
|
||||
print("EEPROM write file done!", flush=True)
|
||||
return result
|
||||
|
||||
|
||||
def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc) -> int:
|
||||
openocd.halt()
|
||||
eeprom_sysinit(openocd)
|
||||
# configure cycles duration
|
||||
eeprom_configure_cycles(openocd, 1, 3, 1, 100000, 1000)
|
||||
time.sleep(0.1)
|
||||
print("EEPROM checking...", flush=True)
|
||||
|
||||
pages_offsets = list(pages)
|
||||
|
||||
for index, page_offset in enumerate(pages_offsets):
|
||||
page_words = bytes2words(pages[page_offset])
|
||||
|
||||
print(
|
||||
f"Check page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True)
|
||||
|
||||
if eeprom_check_data(openocd, page_words, page_offset, False):
|
||||
print("Page mismatch!", flush=True)
|
||||
return 1
|
||||
|
||||
print("EEPROM page check completed", flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc) -> int:
|
||||
openocd.halt()
|
||||
eeprom_sysinit(openocd)
|
||||
eeprom_global_erase(openocd)
|
||||
if eeprom_check_data_ahb_lite(openocd, [0]*2048, 0, False):
|
||||
print("EEPROM global erase failed, try again", flush=True)
|
||||
eeprom_global_erase(openocd)
|
||||
|
||||
if eeprom_check_data_ahb_lite(openocd, [0]*2048, 0, False):
|
||||
print("EEPROM global erase failed", flush=True)
|
||||
return 1
|
||||
# configure cycles duration
|
||||
eeprom_configure_cycles(openocd, 1, 3, 1, 100000, 1000)
|
||||
time.sleep(0.1)
|
||||
print("EEPROM writing...", flush=True)
|
||||
|
||||
pages_offsets = list(pages)
|
||||
|
||||
for index, page_offset in enumerate(pages_offsets):
|
||||
page_words = bytes2words(pages[page_offset])
|
||||
|
||||
print(
|
||||
f"Writing page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True)
|
||||
eeprom_write_page(openocd, page_offset, page_words)
|
||||
|
||||
if eeprom_check_data(openocd, page_words, page_offset, False):
|
||||
print("Page mismatch!", flush=True)
|
||||
return 1
|
||||
|
||||
print("EEPROM page recording completed", flush=True)
|
||||
return 0
|
||||
@@ -0,0 +1,56 @@
|
||||
from enum import Enum
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
import mik32_debug_hal.registers.memory_map as mem_map
|
||||
|
||||
|
||||
class MIK32_Version(Enum):
|
||||
MIK32V0 = "MIK32V0"
|
||||
MIK32V2 = "MIK32V2"
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
port2_value = 0
|
||||
|
||||
|
||||
def gpio_init(openocd: OpenOcdTclRpc, version: MIK32_Version):
|
||||
|
||||
port2_addr = 0
|
||||
if version == MIK32_Version.MIK32V0:
|
||||
port2_addr = mem_map.PAD_CONFIG_REGS + mem_map.PAD_CONFIG_REGS_V0.PORT_2_CFG.value
|
||||
elif version == MIK32_Version.MIK32V2:
|
||||
port2_addr = mem_map.PAD_CONFIG_REGS + mem_map.PAD_CONFIG_REGS_V2.PORT_2_CFG.value
|
||||
else:
|
||||
return
|
||||
|
||||
openocd.halt()
|
||||
port2_value = openocd.read_memory(port2_addr, 32, 1)[0]
|
||||
|
||||
port2_value_updated = port2_value
|
||||
|
||||
port2_value_updated &= 0xF000
|
||||
|
||||
if version == MIK32_Version.MIK32V0:
|
||||
port2_value_updated |= 0x000
|
||||
elif version == MIK32_Version.MIK32V2:
|
||||
port2_value_updated |= 0x555
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
openocd.write_word(port2_addr, port2_value_updated)
|
||||
|
||||
openocd.write_word(port2_addr + 8, 0x0500)
|
||||
|
||||
|
||||
def gpio_deinit(openocd: OpenOcdTclRpc, version: MIK32_Version):
|
||||
|
||||
if version == MIK32_Version.MIK32V0:
|
||||
port2_addr = mem_map.PAD_CONFIG_REGS + mem_map.PAD_CONFIG_REGS_V0.PORT_2_CFG.value
|
||||
elif version == MIK32_Version.MIK32V2:
|
||||
port2_addr = mem_map.PAD_CONFIG_REGS + mem_map.PAD_CONFIG_REGS_V2.PORT_2_CFG.value
|
||||
else:
|
||||
return
|
||||
|
||||
openocd.write_word(port2_addr, port2_value)
|
||||
@@ -0,0 +1,33 @@
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
import mik32_debug_hal.registers.memory_map as mem_map
|
||||
import mik32_debug_hal.registers.bitfields.power_manager as pm_fields
|
||||
import mik32_debug_hal.registers.bitfields.wakeup as wake_fields
|
||||
|
||||
|
||||
def pm_init(openocd: OpenOcdTclRpc):
|
||||
|
||||
WU_CLOCKS_default = 128 << wake_fields.CLOCKS_BU_ADJ_RC32K_S
|
||||
|
||||
AHB_default = (
|
||||
pm_fields.CLOCK_AHB_CPU_M |
|
||||
pm_fields.CLOCK_AHB_EEPROM_M |
|
||||
pm_fields.CLOCK_AHB_RAM_M |
|
||||
pm_fields.CLOCK_AHB_SPIFI_M |
|
||||
pm_fields.CLOCK_AHB_TCB_M |
|
||||
pm_fields.CLOCK_AHB_DMA_M
|
||||
)
|
||||
# 0x1F
|
||||
APB_M_default = (
|
||||
pm_fields.CLOCK_APB_M_PM_M |
|
||||
pm_fields.CLOCK_APB_M_PAD_CONFIG_M |
|
||||
pm_fields.CLOCK_APB_M_WU_M
|
||||
)
|
||||
# 0x89
|
||||
APB_P_default = pm_fields.CLOCK_APB_P_GPIO_2_M
|
||||
# 0x00
|
||||
|
||||
openocd.halt()
|
||||
openocd.write_word(mem_map.WU_CLOCKS_BU_OFFSET, WU_CLOCKS_default)
|
||||
openocd.write_word(mem_map.PM_Clk_APB_P_Set_OFFSET, APB_P_default)
|
||||
openocd.write_word(mem_map.PM_Clk_APB_M_Set_OFFSET, APB_M_default)
|
||||
openocd.write_word(mem_map.PM_Clk_AHB_Set_OFFSET, AHB_default)
|
||||
@@ -0,0 +1,40 @@
|
||||
from typing import List
|
||||
from mik32_upload import Segment
|
||||
from tclrpc import TclException
|
||||
from tclrpc import OpenOcdTclRpc
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
from utils import bytes2words
|
||||
|
||||
def write_file(filename):
|
||||
|
||||
with OpenOcdTclRpc() as openocd:
|
||||
openocd.halt()
|
||||
print(openocd.run("load_image {%s} 0x0" % Path(filename)))
|
||||
print("RAM write file maybe done")
|
||||
|
||||
|
||||
def write_segments(segments: List[Segment], openocd: OpenOcdTclRpc):
|
||||
openocd.halt()
|
||||
for segment in segments:
|
||||
t = time.localtime()
|
||||
current_time = time.strftime("%H:%M:%S", t)
|
||||
print(f"[{current_time}] Writing segment %s with size %d..." % (hex(segment.offset), segment.data.__len__()))
|
||||
segment_words = bytes2words(segment.data)
|
||||
openocd.write_memory(segment.offset, 32, segment_words)
|
||||
|
||||
|
||||
def check_segments(segments: List[Segment], openocd: OpenOcdTclRpc) -> int:
|
||||
openocd.halt()
|
||||
for segment in segments:
|
||||
print("Checking segment %s with size %d..." % (hex(segment.offset), segment.data.__len__()))
|
||||
segment_words = bytes2words(segment.data)
|
||||
segment_memory_words = openocd.read_memory(segment.offset, 32, len(segment_words))
|
||||
|
||||
for i in range(len(segment_words)):
|
||||
if segment_words[i] != segment_memory_words[i]:
|
||||
print(f"Word [{i}] expect {segment_words[i]} != read {segment_memory_words[i]} in segment {segment.offset}")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
@@ -0,0 +1,96 @@
|
||||
# --------------------------
|
||||
# DMA register fields
|
||||
# --------------------------
|
||||
|
||||
CHANNEL_COUNT = 4
|
||||
|
||||
CHANNEL_M = ((1 << CHANNEL_COUNT) - 1)
|
||||
|
||||
# CONTROL
|
||||
|
||||
CONTROL_CLEAR_LOCAL_IRQ_S = 0
|
||||
CONTROL_CLEAR_LOCAL_IRQ_M = (
|
||||
CHANNEL_M << CONTROL_CLEAR_LOCAL_IRQ_S)
|
||||
|
||||
|
||||
def CONTROL_CLEAR_LOCAL_IRQ(i):
|
||||
return ((1 << (CONTROL_CLEAR_LOCAL_IRQ_S + (i))) & CONTROL_CLEAR_LOCAL_IRQ_M)
|
||||
|
||||
|
||||
CONTROL_CLEAR_GLOBAL_IRQ_S = (CHANNEL_COUNT + 0)
|
||||
CONTROL_CLEAR_GLOBAL_IRQ_M = (1 << CONTROL_CLEAR_GLOBAL_IRQ_S)
|
||||
CONTROL_CLEAR_ERROR_IRQ_S = (CHANNEL_COUNT + 1)
|
||||
CONTROL_CLEAR_ERROR_IRQ_M = (1 << CONTROL_CLEAR_ERROR_IRQ_S)
|
||||
CONTROL_GLOBAL_IRQ_ENA_S = (CHANNEL_COUNT + 2)
|
||||
CONTROL_GLOBAL_IRQ_ENA_M = (1 << CONTROL_GLOBAL_IRQ_ENA_S)
|
||||
CONTROL_ERROR_IRQ_ENA_S = (CHANNEL_COUNT + 3)
|
||||
CONTROL_ERROR_IRQ_ENA_M = (1 << CONTROL_ERROR_IRQ_ENA_S)
|
||||
CONTROL_CURRENT_VALUE_S = (CHANNEL_COUNT + 4)
|
||||
CONTROL_CURRENT_VALUE_M = (1 << CONTROL_CURRENT_VALUE_S)
|
||||
|
||||
CFG_CH_ENABLE_S = 0
|
||||
CFG_CH_ENABLE_M = (1 << CFG_CH_ENABLE_S)
|
||||
CFG_CH_DISABLE_M = (0 << CFG_CH_ENABLE_S)
|
||||
|
||||
CFG_CH_PRIOR_S = 1
|
||||
CFG_CH_PRIOR_M = (0x3 << CFG_CH_PRIOR_S)
|
||||
|
||||
CFG_CH_READ_MODE_S = 3
|
||||
CFG_CH_READ_MODE_memory_M = (1 << CFG_CH_READ_MODE_S)
|
||||
CFG_CH_READ_MODE_periphery_M = (0 << CFG_CH_READ_MODE_S)
|
||||
|
||||
CFG_CH_WRITE_MODE_S = 4
|
||||
CFG_CH_WRITE_MODE_memory_M = (1 << CFG_CH_WRITE_MODE_S)
|
||||
CFG_CH_WRITE_MODE_periphery_M = (0 << CFG_CH_WRITE_MODE_S)
|
||||
|
||||
CFG_CH_READ_INCREMENT_S = 5
|
||||
CFG_CH_READ_INCREMENT_M = (1 << CFG_CH_READ_INCREMENT_S)
|
||||
CFG_CH_READ_no_INCREMENT_M = (0 << CFG_CH_READ_INCREMENT_S)
|
||||
|
||||
CFG_CH_READ_INCREMENT_S = 5
|
||||
CFG_CH_READ_INCREMENT_M = (1 << CFG_CH_READ_INCREMENT_S)
|
||||
CFG_CH_READ_no_INCREMENT_M = (0 << CFG_CH_READ_INCREMENT_S)
|
||||
|
||||
CFG_CH_WRITE_INCREMENT_S = 6
|
||||
CFG_CH_WRITE_INCREMENT_M = (1 << CFG_CH_WRITE_INCREMENT_S)
|
||||
CFG_CH_WRITE_no_INCREMENT_M = (0 << CFG_CH_WRITE_INCREMENT_S)
|
||||
|
||||
CFG_CH_READ_SIZE_S = 7
|
||||
CFG_CH_READ_SIZE_byte_M = (0B00 << CFG_CH_READ_SIZE_S) # байт
|
||||
CFG_CH_READ_SIZE_2byte_M = (0B01 << CFG_CH_READ_SIZE_S) # полуслово
|
||||
CFG_CH_READ_SIZE_4byte_M = (0B10 << CFG_CH_READ_SIZE_S) # слово
|
||||
CFG_CH_READ_SIZE_rez_M = (0B11 << CFG_CH_READ_SIZE_S) # резерв
|
||||
|
||||
CFG_CH_WRITE_SIZE_S = 9
|
||||
CFG_CH_WRITE_SIZE_byte_M = (0B00 << CFG_CH_WRITE_SIZE_S) # байт
|
||||
CFG_CH_WRITE_SIZE_2byte_M = (0B01 << CFG_CH_WRITE_SIZE_S) # полуслово
|
||||
CFG_CH_WRITE_SIZE_4byte_M = (0B10 << CFG_CH_WRITE_SIZE_S) # слово
|
||||
CFG_CH_WRITE_SIZE_rez_M = (0B11 << CFG_CH_WRITE_SIZE_S) # резерв
|
||||
|
||||
# Кол-во байт пакетной передачи: 2^Read_burst_size
|
||||
CFG_CH_READ_BURST_SIZE_S = 11
|
||||
# Кол-во байт пакетной передачи: 2^Write_burst_size
|
||||
CFG_CH_WRITE_BURST_SIZE_S = 14
|
||||
|
||||
CFG_CH_READ_REQ_S = 17 # выбор канала чтения
|
||||
CFG_CH_READ_REQ_M = (0xF << CFG_CH_READ_REQ_S)
|
||||
|
||||
|
||||
def CFG_CH_READ_REQ(v):
|
||||
return (((v) << CFG_CH_READ_REQ_S) & CFG_CH_READ_REQ_M)
|
||||
|
||||
|
||||
CFG_CH_WRITE_REQ_S = 21 # выбор канала записи
|
||||
CFG_CH_WRITE_REQ_M = (0xF << CFG_CH_WRITE_REQ_S)
|
||||
|
||||
|
||||
def CFG_CH_WRITE_REQ(v):
|
||||
return (((v) << CFG_CH_WRITE_REQ_S) & CFG_CH_WRITE_REQ_M)
|
||||
|
||||
|
||||
CFG_CH_ACK_READ_S = 25
|
||||
CFG_CH_ACK_READ_M = (1 << CFG_CH_ACK_READ_S)
|
||||
CFG_CH_ACK_WRITE_S = 26
|
||||
CFG_CH_ACK_WRITE_M = (1 << CFG_CH_ACK_WRITE_S)
|
||||
|
||||
STATUS_READY_S = 0
|
||||
@@ -0,0 +1,77 @@
|
||||
# --------------------------
|
||||
# PM register fields
|
||||
# --------------------------
|
||||
|
||||
# AHB BUS
|
||||
CLOCK_AHB_CPU_S = 0
|
||||
CLOCK_AHB_CPU_M = (1 << CLOCK_AHB_CPU_S)
|
||||
CLOCK_AHB_EEPROM_S = 1
|
||||
CLOCK_AHB_EEPROM_M = (1 << CLOCK_AHB_EEPROM_S)
|
||||
CLOCK_AHB_RAM_S = 2
|
||||
CLOCK_AHB_RAM_M = (1 << CLOCK_AHB_RAM_S)
|
||||
CLOCK_AHB_SPIFI_S = 3
|
||||
CLOCK_AHB_SPIFI_M = (1 << CLOCK_AHB_SPIFI_S)
|
||||
CLOCK_AHB_TCB_S = 4
|
||||
CLOCK_AHB_TCB_M = (1 << CLOCK_AHB_TCB_S)
|
||||
CLOCK_AHB_DMA_S = 5
|
||||
CLOCK_AHB_DMA_M = (1 << CLOCK_AHB_DMA_S)
|
||||
CLOCK_AHB_CRYPTO_S = 6
|
||||
CLOCK_AHB_CRYPTO_M = (1 << CLOCK_AHB_CRYPTO_S)
|
||||
CLOCK_AHB_CRC32_S = 7
|
||||
CLOCK_AHB_CRC32_M = (1 << CLOCK_AHB_CRC32_S)
|
||||
|
||||
# APB M
|
||||
CLOCK_APB_M_PM_S = 0
|
||||
CLOCK_APB_M_PM_M = (1 << CLOCK_APB_M_PM_S)
|
||||
CLOCK_APB_M_EPIC_S = 1
|
||||
CLOCK_APB_M_EPIC_M = (1 << CLOCK_APB_M_EPIC_S)
|
||||
CLOCK_APB_M_TIMER32_0_S = 2
|
||||
CLOCK_APB_M_TIMER32_0_M = (1 << CLOCK_APB_M_TIMER32_0_S)
|
||||
CLOCK_APB_M_PAD_CONFIG_S = 3
|
||||
CLOCK_APB_M_PAD_CONFIG_M = (1 << CLOCK_APB_M_PAD_CONFIG_S)
|
||||
CLOCK_APB_M_WDT_BUS_S = 4
|
||||
CLOCK_APB_M_WDT_BUS_M = (1 << CLOCK_APB_M_WDT_BUS_S)
|
||||
CLOCK_APB_M_OTP_S = 5
|
||||
CLOCK_APB_M_OTP_M = (1 << CLOCK_APB_M_OTP_S)
|
||||
CLOCK_APB_M_PMON_S = 6
|
||||
CLOCK_APB_M_PMON_M = (1 << CLOCK_APB_M_PMON_S)
|
||||
CLOCK_APB_M_WU_S = 7
|
||||
CLOCK_APB_M_WU_M = (1 << CLOCK_APB_M_WU_S)
|
||||
CLOCK_APB_M_RTC_S = 8
|
||||
CLOCK_APB_M_RTC_M = (1 << CLOCK_APB_M_RTC_S)
|
||||
|
||||
# APB_P
|
||||
CLOCK_APB_P_WDT_S = 0
|
||||
CLOCK_APB_P_WDT_M = (1 << CLOCK_APB_P_WDT_S)
|
||||
CLOCK_APB_P_UART_0_S = 1
|
||||
CLOCK_APB_P_UART_0_M = (1 << CLOCK_APB_P_UART_0_S)
|
||||
CLOCK_APB_P_UART_1_S = 2
|
||||
CLOCK_APB_P_UART_1_M = (1 << CLOCK_APB_P_UART_1_S)
|
||||
CLOCK_APB_P_TIMER16_0_S = 3
|
||||
CLOCK_APB_P_TIMER16_0_M = (1 << CLOCK_APB_P_TIMER16_0_S)
|
||||
CLOCK_APB_P_TIMER16_1_S = 4
|
||||
CLOCK_APB_P_TIMER16_1_M = (1 << CLOCK_APB_P_TIMER16_1_S)
|
||||
CLOCK_APB_P_TIMER16_2_S = 5
|
||||
CLOCK_APB_P_TIMER16_2_M = (1 << CLOCK_APB_P_TIMER16_2_S)
|
||||
CLOCK_APB_P_TIMER32_1_S = 6
|
||||
CLOCK_APB_P_TIMER32_1_M = (1 << CLOCK_APB_P_TIMER32_1_S)
|
||||
CLOCK_APB_P_TIMER32_2_S = 7
|
||||
CLOCK_APB_P_TIMER32_2_M = (1 << CLOCK_APB_P_TIMER32_2_S)
|
||||
CLOCK_APB_P_SPI_0_S = 8
|
||||
CLOCK_APB_P_SPI_0_M = (1 << CLOCK_APB_P_SPI_0_S)
|
||||
CLOCK_APB_P_SPI_1_S = 9
|
||||
CLOCK_APB_P_SPI_1_M = (1 << CLOCK_APB_P_SPI_1_S)
|
||||
CLOCK_APB_P_I2C_0_S = 10
|
||||
CLOCK_APB_P_I2C_0_M = (1 << CLOCK_APB_P_I2C_0_S)
|
||||
CLOCK_APB_P_I2C_1_S = 11
|
||||
CLOCK_APB_P_I2C_1_M = (1 << CLOCK_APB_P_I2C_1_S)
|
||||
CLOCK_APB_P_GPIO_0_S = 12
|
||||
CLOCK_APB_P_GPIO_0_M = (1 << CLOCK_APB_P_GPIO_0_S)
|
||||
CLOCK_APB_P_GPIO_1_S = 13
|
||||
CLOCK_APB_P_GPIO_1_M = (1 << CLOCK_APB_P_GPIO_1_S)
|
||||
CLOCK_APB_P_GPIO_2_S = 14
|
||||
CLOCK_APB_P_GPIO_2_M = (1 << CLOCK_APB_P_GPIO_2_S)
|
||||
CLOCK_APB_P_ANALOG_S = 15
|
||||
CLOCK_APB_P_ANALOG_M = (1 << CLOCK_APB_P_ANALOG_S)
|
||||
CLOCK_APB_P_GPIO_IRQ_S = 16
|
||||
CLOCK_APB_P_GPIO_IRQ_M = (1 << CLOCK_APB_P_GPIO_IRQ_S)
|
||||
@@ -0,0 +1,111 @@
|
||||
# --------------------------
|
||||
# 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)
|
||||
@@ -0,0 +1,15 @@
|
||||
# --------------------------
|
||||
# WU register fields
|
||||
# --------------------------
|
||||
|
||||
# CLOCKS_BU
|
||||
CLOCKS_BU_OCS32K_EN_S = 0
|
||||
CLOCKS_BU_OCS32K_EN_M = (1 << CLOCKS_BU_OCS32K_EN_S)
|
||||
CLOCKS_BU_RC32K_EN_S = 1
|
||||
CLOCKS_BU_RC32K_EN_M = (1 << CLOCKS_BU_RC32K_EN_S)
|
||||
CLOCKS_BU_ADJ_RC32K_S = 2
|
||||
CLOCKS_BU_ADJ_RC32K_M = (0b11111111 << CLOCKS_BU_ADJ_RC32K_S)
|
||||
CLOCKS_BU_RTC_CLK_MUX_S = 10
|
||||
CLOCKS_BU_RTC_CLK_MUX_M = (1 << CLOCKS_BU_RTC_CLK_MUX_S)
|
||||
CLOCKS_BU_OSC32K_SM_S = 14
|
||||
CLOCKS_BU_OSC32K_SM_M = (1 << CLOCKS_BU_OSC32K_SM_S)
|
||||
@@ -0,0 +1,89 @@
|
||||
# --------------------------
|
||||
# DMA register offset
|
||||
# --------------------------
|
||||
from enum import Enum
|
||||
|
||||
|
||||
DMA_REGS = 0x00040000
|
||||
DMA_CONTROL = DMA_REGS + 0x40
|
||||
|
||||
DMA_CHANNEL_SIZEOF = 0x4 * 4
|
||||
|
||||
|
||||
def DMA_CHANNEL_DESTINATION(i):
|
||||
return DMA_REGS + i*DMA_CHANNEL_SIZEOF + 0x4*0
|
||||
|
||||
|
||||
def DMA_CHANNEL_SOURCE(i):
|
||||
return DMA_REGS + i*DMA_CHANNEL_SIZEOF + 0x4*1
|
||||
|
||||
|
||||
def DMA_CHANNEL_LEN(i):
|
||||
return DMA_REGS + i*DMA_CHANNEL_SIZEOF + 0x4*2
|
||||
|
||||
|
||||
def DMA_CHANNEL_CONFIG(i):
|
||||
return DMA_REGS + i*DMA_CHANNEL_SIZEOF + 0x4*3
|
||||
|
||||
|
||||
# --------------------------
|
||||
# SPIFI register offset
|
||||
# --------------------------
|
||||
SPIFI_REGS = 0x00070000
|
||||
|
||||
SPIFI_CONFIG_CTRL = SPIFI_REGS + 0x000
|
||||
SPIFI_CONFIG_CMD = SPIFI_REGS + 0x004
|
||||
SPIFI_CONFIG_ADDR = SPIFI_REGS + 0x008
|
||||
SPIFI_CONFIG_IDATA = SPIFI_REGS + 0x00C
|
||||
SPIFI_CONFIG_CLIMIT = SPIFI_REGS + 0x010
|
||||
SPIFI_CONFIG_DATA32 = SPIFI_REGS + 0x014
|
||||
SPIFI_CONFIG_MCMD = SPIFI_REGS + 0x018
|
||||
SPIFI_CONFIG_STAT = SPIFI_REGS + 0x01C
|
||||
|
||||
|
||||
# --------------------------
|
||||
# PM register offset
|
||||
# --------------------------
|
||||
|
||||
|
||||
PM_REGS = 0x000050000
|
||||
|
||||
PM_Clk_AHB_Set_OFFSET = PM_REGS + 0x0C
|
||||
PM_Clk_APB_M_Set_OFFSET = PM_REGS + 0x14
|
||||
PM_Clk_APB_P_Set_OFFSET = PM_REGS + 0x1C
|
||||
|
||||
|
||||
# --------------------------
|
||||
# WU register offset
|
||||
# --------------------------
|
||||
WU_REGS = 0x00060000
|
||||
|
||||
WU_CLOCKS_BU_OFFSET = WU_REGS + 0x10
|
||||
|
||||
|
||||
# --------------------------
|
||||
# GPIO register offset
|
||||
# --------------------------
|
||||
PAD_CONFIG_REGS = 0x00050C00
|
||||
|
||||
class PAD_CONFIG_REGS_V0(Enum):
|
||||
PORT_0_CFG = 0x00
|
||||
PORT_1_CFG = 0x04
|
||||
PORT_2_CFG = 0x08
|
||||
PORT_0_DS = 0x0C
|
||||
PORT_1_DS = 0x10
|
||||
PORT_2_DS = 0x14
|
||||
PORT_0_PUD = 0x18
|
||||
PORT_1_PUD = 0x1C
|
||||
PORT_2_PUD = 0x20
|
||||
|
||||
class PAD_CONFIG_REGS_V2(Enum):
|
||||
PORT_0_CFG = 0x00
|
||||
PORT_0_DS = 0x04
|
||||
PORT_0_PUD = 0x08
|
||||
PORT_1_CFG = 0x0C
|
||||
PORT_1_DS = 0x10
|
||||
PORT_1_PUD = 0x14
|
||||
PORT_2_CFG = 0x18
|
||||
PORT_2_DS = 0x1C
|
||||
PORT_2_PUD = 0x20
|
||||
@@ -0,0 +1,761 @@
|
||||
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_debug_hal.dma import DMA, ChannelMode, ChannelIndex, ChannelAck, ChannelIncrement, ChannelPriority, ChannelRequest, ChannelSize
|
||||
import mik32_debug_hal.registers.memory_map as mem_map
|
||||
import mik32_debug_hal.registers.bitfields.spifi as spifi_fields
|
||||
|
||||
# --------------------------
|
||||
# Commands
|
||||
# --------------------------
|
||||
SREG1_BUSY = 1
|
||||
|
||||
READ_LEN = 256
|
||||
TIMEOUT = 1000
|
||||
|
||||
ENABLE_RESET_COMMAND = 0x66
|
||||
RESET_COMMAND = 0x99
|
||||
|
||||
CHIP_ERASE_COMMAND = 0xC7
|
||||
SECTOR_ERASE_COMMAND = 0x20
|
||||
|
||||
WRITE_ENABLE_COMMAND = 0x06
|
||||
WRITE_DISABLE_COMMAND = 0x04
|
||||
|
||||
#DISABLE_QPI_COMMAND = 0xFF
|
||||
|
||||
MEM_CONFIG_COMMAND = 0x61
|
||||
MEM_CONFIG_VALUE = 0x7F
|
||||
|
||||
READ_DATA_COMMAND = 0x03
|
||||
|
||||
FAST_READ_QUAD_OUTPUT_COMMAND = 0x6B
|
||||
|
||||
READ_SREG1_COMMAND = 0x05
|
||||
READ_SREG2_COMMAND = 0x35
|
||||
WRITE_SREG_COMMAND = 0x01
|
||||
|
||||
SREG2_QUAD_ENABLE = 9
|
||||
SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8)
|
||||
SREG2_QUAD_ENABLE_M = 1 << SREG2_QUAD_ENABLE_S
|
||||
|
||||
PAGE_PROGRAM_COMMAND = 0x02
|
||||
|
||||
QUAD_PAGE_PROGRAM_COMMAND = 0x32
|
||||
|
||||
JEDEC_ID_COMMAND = 0x9F
|
||||
|
||||
|
||||
class SREG_Num(Enum):
|
||||
SREG1 = 0x00
|
||||
SREG2 = 0x30
|
||||
|
||||
|
||||
def spifi_intrq_clear(openocd: OpenOcdTclRpc):
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
|
||||
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M)
|
||||
|
||||
|
||||
INIT_DELAY = 0.001
|
||||
|
||||
|
||||
def spifi_init_periphery(openocd: OpenOcdTclRpc):
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
|
||||
# SPIFI_CONFIG_STAT_INTRQ_M |
|
||||
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
|
||||
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
|
||||
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
|
||||
|
||||
time.sleep(INIT_DELAY)
|
||||
|
||||
|
||||
def spifi_init(openocd: OpenOcdTclRpc):
|
||||
print("MCU clock init", flush=True)
|
||||
|
||||
spifi_init_periphery(openocd)
|
||||
|
||||
control = openocd.read_word(mem_map.SPIFI_CONFIG_CTRL)
|
||||
control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control)
|
||||
|
||||
time.sleep(INIT_DELAY)
|
||||
|
||||
|
||||
def spifi_init_memory(openocd: OpenOcdTclRpc):
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
|
||||
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M |
|
||||
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
|
||||
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
|
||||
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
|
||||
openocd.write_word(mem_map.SPIFI_CONFIG_MCMD, (0 << spifi_fields.SPIFI_CONFIG_MCMD_INTLEN_S) |
|
||||
(spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << spifi_fields.SPIFI_CONFIG_MCMD_FIELDFORM_S) |
|
||||
(spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << spifi_fields.SPIFI_CONFIG_MCMD_FRAMEFORM_S) |
|
||||
(READ_DATA_COMMAND << spifi_fields.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(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.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,
|
||||
mem_map.SPIFI_CONFIG_DATA32,
|
||||
255
|
||||
)
|
||||
elif (dma is not None) and (direction == SPIFI_Direction.READ):
|
||||
dma.channels[1].start(
|
||||
mem_map.SPIFI_CONFIG_DATA32,
|
||||
0x02003F00,
|
||||
255
|
||||
)
|
||||
|
||||
openocd.write_memory(mem_map.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_fields.SPIFI_CONFIG_CMD_OPCODE_S) |
|
||||
(frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) |
|
||||
(fieldform.value << spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_S) |
|
||||
(byte_count << spifi_fields.SPIFI_CONFIG_CMD_DATALEN_S) |
|
||||
(idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) |
|
||||
(direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S))
|
||||
|
||||
openocd.write_memory(mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value])
|
||||
|
||||
if direction == 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(mem_map.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(mem_map.SPIFI_CONFIG_DATA32, 32, [
|
||||
data[i] + data[i+1] * 256 + data[i+2] * 256 * 256 + data[i+3] * 256 * 256 * 256])
|
||||
else:
|
||||
for i in range(byte_count):
|
||||
openocd.write_memory(mem_map.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:
|
||||
return spifi_send_command(
|
||||
openocd,
|
||||
READ_SREG1_COMMAND | sreg.value,
|
||||
SPIFI_Frameform.OPCODE_NOADDR,
|
||||
SPIFI_Fieldform.ALL_SERIAL,
|
||||
byte_count=1
|
||||
)[0]
|
||||
|
||||
|
||||
def spifi_write_sreg(openocd: OpenOcdTclRpc, sreg1: int, sreg2: int):
|
||||
# spifi_send_command(openocd, DISABLE_QPI_COMMAND,
|
||||
# SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_PARALLEL)
|
||||
spifi_write_enable(openocd)
|
||||
spifi_send_command(
|
||||
openocd,
|
||||
WRITE_SREG_COMMAND,
|
||||
SPIFI_Frameform.OPCODE_NOADDR,
|
||||
SPIFI_Fieldform.ALL_SERIAL,
|
||||
byte_count=2,
|
||||
direction=SPIFI_Direction.WRITE,
|
||||
data=[sreg1, sreg2]
|
||||
)
|
||||
spifi_wait_busy(openocd)
|
||||
|
||||
|
||||
def spifi_wait_busy(openocd: OpenOcdTclRpc):
|
||||
while 1:
|
||||
sreg1 = spifi_read_sreg(openocd, SREG_Num.SREG1)
|
||||
if not (sreg1 & SREG1_BUSY):
|
||||
break
|
||||
|
||||
RESET_DELAY = 0.001
|
||||
|
||||
def spifi_chip_reset(openocd: OpenOcdTclRpc):
|
||||
#print("Sending 'Reset' to external chip in SPI mode", flush=True)
|
||||
spifi_send_command(openocd, ENABLE_RESET_COMMAND,
|
||||
SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_SERIAL)
|
||||
spifi_send_command(openocd, RESET_COMMAND,
|
||||
SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_SERIAL)
|
||||
time.sleep(RESET_DELAY)
|
||||
|
||||
|
||||
def spifi_chip_reset_qpi(openocd: OpenOcdTclRpc):
|
||||
#print("Sending 'Reset' to external chip in QPI mode", flush=True)
|
||||
spifi_send_command(openocd, ENABLE_RESET_COMMAND,
|
||||
SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_PARALLEL)
|
||||
spifi_send_command(openocd, RESET_COMMAND,
|
||||
SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_PARALLEL)
|
||||
time.sleep(RESET_DELAY)
|
||||
|
||||
#def spifi_chip_disable_qpi(openocd: OpenOcdTclRpc):
|
||||
#print("Sending 'Disable QPI' command to external flash chip in QPI mode.", flush=True)
|
||||
# spifi_send_command(openocd, DISABLE_QPI_COMMAND,
|
||||
# SPIFI_Frameform.OPCODE_NOADDR, SPIFI_Fieldform.ALL_PARALLEL)
|
||||
|
||||
|
||||
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, use_quad_spi=False) -> int:
|
||||
read_data: List[int] = []
|
||||
|
||||
if (use_quad_spi):
|
||||
read_data = spifi_send_command(openocd, FAST_READ_QUAD_OUTPUT_COMMAND, SPIFI_Frameform.OPCODE_3ADDR, SPIFI_Fieldform.DATA_PARALLEL, byte_count=byte_count, address=address, idata_length=1, dma=dma)
|
||||
else:
|
||||
read_data = spifi_send_command(openocd, READ_DATA_COMMAND, SPIFI_Frameform.OPCODE_3ADDR, SPIFI_Fieldform.ALL_SERIAL, byte_count=byte_count, address=address, dma=dma)
|
||||
|
||||
for i in range(byte_count):
|
||||
if read_data[i] != bin_data[i]:
|
||||
print(
|
||||
f"DATA[{i+address}] = {read_data[i]:#0x} expect {bin_data[i]:#0x}", flush=True)
|
||||
|
||||
# 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):
|
||||
if (spifi_check_quad_enable(openocd) != True):
|
||||
spifi_write_sreg(
|
||||
openocd,
|
||||
spifi_read_sreg(openocd, SREG_Num.SREG1),
|
||||
spifi_read_sreg(openocd, SREG_Num.SREG2) | SREG2_QUAD_ENABLE_M
|
||||
)
|
||||
|
||||
|
||||
#def spifi_quad_disable(openocd):
|
||||
# if (spifi_check_quad_enable(openocd) == True):
|
||||
# spifi_write_sreg(
|
||||
# openocd,
|
||||
# spifi_read_sreg(openocd, SREG_Num.SREG1),
|
||||
# spifi_read_sreg(openocd, SREG_Num.SREG2) & (0xFF ^ SREG2_QUAD_ENABLE_M)
|
||||
# )
|
||||
|
||||
|
||||
def spifi_check_quad_enable(openocd):
|
||||
return (spifi_read_sreg(openocd, SREG_Num.SREG2) & SREG2_QUAD_ENABLE_M) != 0
|
||||
|
||||
|
||||
def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]:
|
||||
segments = set()
|
||||
for offset in pages_offsets:
|
||||
segments.add(offset & ~(segment_size - 1))
|
||||
return 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)
|
||||
|
||||
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
|
||||
spifi_chip_reset_qpi(openocd)
|
||||
|
||||
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
|
||||
spifi_chip_reset(openocd)
|
||||
|
||||
JEDEC_ID = spifi_send_command(openocd, JEDEC_ID_COMMAND, 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("Using Quad SPI")
|
||||
spifi_quad_enable(openocd)
|
||||
else:
|
||||
print("Using Single SPI")
|
||||
# spifi_quad_disable(openocd)
|
||||
|
||||
pages_offsets = list(pages)
|
||||
|
||||
for index, page_offset in enumerate(pages_offsets):
|
||||
print(f"Check page {page_offset:#010x}... {(index*100)//pages_offsets.__len__()}%", flush=True)
|
||||
page_bytes = pages[page_offset]
|
||||
|
||||
result = spifi_read_data(openocd, page_offset, 256, page_bytes, dma=dma, use_quad_spi=use_quad_spi)
|
||||
|
||||
if result == 1:
|
||||
print("Data error")
|
||||
#if (use_quad_spi):
|
||||
# spifi_quad_disable(openocd)
|
||||
return result
|
||||
|
||||
if result == 0:
|
||||
print("SPIFI pages checking completed", flush=True)
|
||||
return 0
|
||||
|
||||
# # 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)
|
||||
|
||||
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
|
||||
spifi_chip_reset_qpi(openocd)
|
||||
|
||||
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
|
||||
spifi_chip_reset(openocd)
|
||||
|
||||
JEDEC_ID = spifi_send_command(openocd, JEDEC_ID_COMMAND, 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
|
||||
|
||||
print("Quad Enable", spifi_check_quad_enable(openocd))
|
||||
|
||||
if (use_quad_spi):
|
||||
print("Using Quad SPI")
|
||||
spifi_quad_enable(openocd)
|
||||
else:
|
||||
print("Using Single SPI")
|
||||
#spifi_quad_disable(openocd)
|
||||
|
||||
# print("SREG1", spifi_read_sreg(openocd, SREG_Num.SREG1))
|
||||
# print("SREG2", spifi_read_sreg(openocd, SREG_Num.SREG2))
|
||||
|
||||
pages_offsets = list(pages)
|
||||
|
||||
for index, page_offset in enumerate(pages_offsets):
|
||||
page_bytes = pages[page_offset]
|
||||
|
||||
if (use_quad_spi):
|
||||
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, use_quad_spi=use_quad_spi)
|
||||
|
||||
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
|
||||
Reference in new issue
Block a user