Compare commits

..

No commits in common. "master" and "v0.3.1" have entirely different histories.

22 changed files with 1114 additions and 1225 deletions

1
.gitignore vendored
View File

@ -1,7 +1,6 @@
__pycache__
.vscode
openocd
venv
*.code-workspace
dist
mik32_upload.spec

2
.piopm
View File

@ -1 +1 @@
{"type": "tool", "name": "tool-mik32-uploader", "version": "0.3.3", "spec": {"owner": "mikron", "id": 122, "name": "tool-mik32-uploader", "requirements": null, "uri": null}}
{"type": "tool", "name": "tool-mik32-uploader", "version": "0.3.0", "spec": {"owner": "mikron", "id": 122, "name": "tool-mik32-uploader", "requirements": null, "uri": null}}

View File

@ -22,24 +22,6 @@
### Удалено
## [v0.3.3] - 2025-03-17
### Исправлено
- Добавлен id для TCB блока МК, Добавление нестандартного CSR-регистра MCOUNTEN (@cryptozoy)
- Ошибка записи eeprom при boot=1 (ram)
- Выбор порта аргументом --openocd-port
## [v0.3.2] - 2024-12-28
### Добавлено
- Базовая обработка ошибок
- Сброс внешней флеш-памяти из всех режимов в стандартный Single SPI (@cryptozoy)
- Остановка прошивки, если загрузка данных не удалась
### Исправлено
- Ошибка в функции прошивки SPIFI
- Ошибка при настройке тактирования - не происходило отключение блоков
## [v0.3.1] - 2024-11-14
### Добавлено
@ -83,17 +65,17 @@
### Добавлено
- [Update mik32_spifi.py](https://github.com/MikronMIK32/mik32-uploader/commit/1201ab7228b5b0f5a0b58b71933204b6e2bae0f6)
Добавлен программный сброс микросхемы флеш-памяти из режимов QPI и XIP, чтение и печать JEDEC ID (@cryptozoy)
Добавлен программный сброс микросхемы флеш-памяти из режимов QPI и XIP, чтение и печать JEDEC ID
### Изменено
- [Update mik32_spifi.py](https://github.com/MikronMIK32/mik32-uploader/commit/1201ab7228b5b0f5a0b58b71933204b6e2bae0f6)
Убрано отключение Quad SPI режима после прошивки флеш-памяти (@cryptozoy)
Убрано отключение Quad SPI режима после прошивки флеш-памяти
### Исправлено
- [Update mikron-link.cfg](https://github.com/MikronMIK32/mik32-uploader/commit/094a94276878d72564566a1481b6cddccf1e4b81)
Заменена устаревшая команда и добавлена отсутствующая скорость по-умолчанию для конфигурации отладчика Программатор MIK32 (@cryptozoy)
Заменена устаревшая команда и добавлена отсутствующая скорость по-умолчанию для конфигурации отладчика Программатор MIK32
## [v0.1.0] - 2024-07-17

View File

@ -1 +1 @@
applicaton_version = 'v0.3.3'
applicaton_version = 'v0.3.1'

View File

@ -1,16 +1,11 @@
from enum import Enum
import os
import pathlib
import sys
import time
from typing import Dict, List, Union
from typing import List, Union
from tclrpc import OpenOcdTclRpc
from mik32_debug_hal.spifi import SPIFI
# import mik32_debug_hal.spifi as spifi
import mik32_debug_hal.spifi as spifi
import mik32_debug_hal.dma as dma
class GenericFlash():
# --------------------------
# Commands
# --------------------------
@ -48,91 +43,88 @@ class GenericFlash():
JEDEC_ID_COMMAND = 0x9F
class FlashError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return ("ERROR: " + repr(self.value))
class SREG_Num(Enum):
SREG1 = 0x00
SREG2 = 0x30
openocd: OpenOcdTclRpc
spifi: SPIFI
def __init__(self, spifi: SPIFI):
self.spifi = spifi
self.openocd = self.spifi.openocd
def write_enable(openocd: OpenOcdTclRpc):
spifi.send_command(openocd, WRITE_ENABLE_COMMAND,
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
# self.init()
def write_enable(self):
self.spifi.send_command(self.WRITE_ENABLE_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
def read_sreg(self, sreg: SREG_Num) -> int:
return self.spifi.send_command(
self.READ_SREG1_COMMAND | sreg.value,
self.spifi.Frameform.OPCODE_NOADDR,
self.spifi.Fieldform.ALL_SERIAL,
def 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 write_sreg(self, sreg1: int, sreg2: int):
self.write_enable()
self.spifi.send_command(
self.WRITE_SREG_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR,
self.spifi.Fieldform.ALL_SERIAL,
def write_sreg(openocd: OpenOcdTclRpc, sreg1: int, sreg2: int):
write_enable(openocd)
spifi.send_command(
openocd,
WRITE_SREG_COMMAND,
spifi.Frameform.OPCODE_NOADDR,
spifi.Fieldform.ALL_SERIAL,
byte_count=2,
direction=self.spifi.Direction.WRITE,
direction=spifi.Direction.WRITE,
data=[sreg1, sreg2]
)
self.wait_busy()
wait_busy(openocd)
def wait_busy(self):
def wait_busy(openocd: OpenOcdTclRpc):
while 1:
sreg1 = self.read_sreg(self.SREG_Num.SREG1)
if not (sreg1 & self.SREG1_BUSY):
sreg1 = read_sreg(openocd, SREG_Num.SREG1)
if not (sreg1 & SREG1_BUSY):
break
RESET_DELAY = 0.001
def chip_reset(self):
self.spifi.send_command(self.ENABLE_RESET_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
self.spifi.send_command(self.RESET_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
time.sleep(self.RESET_DELAY)
def chip_reset_qpi(self):
self.spifi.send_command(self.ENABLE_RESET_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_PARALLEL)
self.spifi.send_command(self.RESET_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_PARALLEL)
time.sleep(self.RESET_DELAY)
def chip_reset(openocd: OpenOcdTclRpc):
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 chip_erase(self):
def chip_reset_qpi(openocd: OpenOcdTclRpc):
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 chip_erase(openocd: OpenOcdTclRpc):
print("Chip erase...", flush=True)
self.spifi.send_command(self.CHIP_ERASE_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
spifi.send_command(openocd, CHIP_ERASE_COMMAND,
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
def sector_erase(self, address: int):
def sector_erase(openocd: OpenOcdTclRpc, address: int):
print(f"Erase sector {address:#010x}...", flush=True)
self.spifi.send_command(self.SECTOR_ERASE_COMMAND,
self.spifi.Frameform.OPCODE_3ADDR, self.spifi.Fieldform.ALL_SERIAL, address=address)
spifi.send_command(openocd, SECTOR_ERASE_COMMAND,
spifi.Frameform.OPCODE_3ADDR, spifi.Fieldform.ALL_SERIAL, address=address)
def read_data(self, address: int, byte_count: int, bin_data: List[int], dma: Union[dma.DMA, None] = None, use_quad_spi=False) -> int:
def read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: List[int], dma: Union[dma.DMA, None] = None, use_quad_spi=False) -> int:
read_data: List[int] = []
if (use_quad_spi):
read_data = self.spifi.send_command(self.FAST_READ_QUAD_OUTPUT_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=address, idata_length=1, dma=dma)
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 = self.spifi.send_command(self.READ_DATA_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
self.spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=address, dma=dma)
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]:
@ -143,42 +135,45 @@ class GenericFlash():
return 0
def page_program(
self,
openocd: OpenOcdTclRpc,
ByteAddress: int,
data: List[int],
byte_count: int,
progress: str = "",
dma: Union[dma.DMA, None] = None
):
print(
f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True)
print(f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True)
if byte_count > 256:
raise self.FlashError("Byte count more than 256")
raise Exception("Byte count more than 256")
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)
wait_busy(openocd)
self.write_enable()
self.spifi.send_command(self.PAGE_PROGRAM_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
self.spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=ByteAddress,
idata=0, cache_limit=0, direction=self.spifi.Direction.WRITE, data=data, dma=dma)
self.wait_busy()
class EraseType(Enum):
CHIP_ERASE = 0
SECTOR_ERASE = 1
CHIP_ERASE = CHIP_ERASE_COMMAND
SECTOR_ERASE = SECTOR_ERASE_COMMAND
def erase(self, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []):
if erase_type == self.EraseType.CHIP_ERASE:
self.write_enable()
self.chip_erase()
self.wait_busy()
elif erase_type == self.EraseType.SECTOR_ERASE:
def erase(openocd, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []):
if erase_type == EraseType.CHIP_ERASE:
write_enable(openocd)
chip_erase(openocd)
wait_busy(openocd)
elif erase_type == EraseType.SECTOR_ERASE:
for sector in sectors:
self.write_enable()
self.sector_erase(sector)
self.wait_busy()
write_enable(openocd)
sector_erase(openocd, sector)
wait_busy(openocd)
def quad_page_program(
self,
openocd: OpenOcdTclRpc,
ByteAddress: int,
data: List[int],
byte_count: int,
@ -187,266 +182,23 @@ class GenericFlash():
):
print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
if byte_count > 256:
raise self.FlashError("Byte count more than 256")
raise Exception("Byte count more than 256")
self.write_enable()
self.spifi.send_command(self.QUAD_PAGE_PROGRAM_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=ByteAddress,
idata=0, cache_limit=0, direction=self.spifi.Direction.WRITE, data=data, dma=dma)
self.wait_busy()
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)
wait_busy(openocd)
def quad_enable(self):
if (self.check_quad_enable(self.openocd) != True):
self.write_sreg(
self.read_sreg(self.SREG_Num.SREG1),
self.read_sreg(self.SREG_Num.SREG2) | self.SREG2_QUAD_ENABLE_M
def quad_enable(openocd):
if (check_quad_enable(openocd) != True):
write_sreg(
openocd,
read_sreg(openocd, SREG_Num.SREG1),
read_sreg(openocd, SREG_Num.SREG2) | SREG2_QUAD_ENABLE_M
)
def check_quad_enable(self):
return (self.read_sreg(self.SREG_Num.SREG2) & self.SREG2_QUAD_ENABLE_M) != 0
def check_pages(self, pages: Dict[int, List[int]], use_quad_spi=False, use_chip_erase=False):
result = 0
self.openocd.halt()
# self.init()
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
self.chip_reset_qpi()
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
self.chip_reset()
JEDEC_ID = self.spifi.send_command(self.JEDEC_ID_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3)
print(
f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
dma_instance = self.spifi.dma_config()
if (use_quad_spi):
print("Using Quad SPI")
self.quad_enable(self.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 = self.read_data(
self.openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi)
if result == 1:
print("Data error")
# if (use_quad_spi):
# spifi_quad_disable(openocd)
return result
if result == 0:
print("SPIFI pages checking completed", flush=True)
return 0
def write_pages(self, pages: Dict[int, List[int]], use_quad_spi=False, use_chip_erase=False):
result = 0
self.openocd.halt()
# self.init()
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
self.chip_reset_qpi()
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
self.chip_reset()
JEDEC_ID = self.spifi.send_command(self.JEDEC_ID_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3)
print(
f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
dma_instance = self.spifi.dma_config()
if use_chip_erase:
self.erase(
self.openocd, self.EraseType.CHIP_ERASE)
else:
self.erase(self.openocd, self.EraseType.SECTOR_ERASE,
self.get_segments_list(list(pages), 4*1024))
print("Quad Enable", self.check_quad_enable(self.openocd))
if (use_quad_spi):
print("Using Quad SPI")
self.quad_enable(self.openocd)
else:
print("Using Single SPI")
# spifi_quad_disable(openocd)
# print("SREG1", spifi_read_sreg(openocd, SREG_Num.SREG1))
# print("SREG2", spifi_read_sreg(openocd, SREG_Num.SREG2))
pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
page_bytes = pages[page_offset]
if (use_quad_spi):
self.quad_page_program(
self.openocd, page_offset, page_bytes, 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance)
else:
self.page_program(self.openocd, page_offset, page_bytes,
256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance)
result = self.read_data(
self.openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi)
if result == 1:
print("Data error")
return result
if result == 0:
# Прошивка страниц флеш памяти по SPIFI была завершена
print(
"Flashing of flash memory pages via SPIFI has been completed", flush=True)
return 0
def wait_halted(self, timeout_seconds: float = 2):
self.openocd.run(f'wait_halt {int(timeout_seconds * 1000)}')
def write_pages_by_sectors(self, pages: Dict[int, List[int]],
driver_path: str,
use_quad_spi=False,
use_chip_erase=False,
):
result = 0
self.openocd.halt()
# Отключение прерываний
self.openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}")
# self.init()
# openocd.run("rwp")
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
self.chip_reset_qpi()
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
self.chip_reset()
JEDEC_ID = self.spifi.send_command(
0x9F, self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3)
print(
f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
sectors_list = self.get_segments_list(list(pages), 4*1024)
self.openocd.halt()
pathname = os.path.dirname(sys.argv[0])
self.openocd.run("wp 0x2003000 4 w")
print("Uploading driver... ", end="", flush=True)
self.openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
print("OK!", flush=True)
self.openocd.resume(0x2000000)
self.wait_halted()
print("Writing Flash by sectors...", flush=True)
for i, sector in enumerate(sectors_list):
ByteAddress = sector
progress = f"{(i*100)//len(sectors_list)}%"
print(f" {ByteAddress:#010x} {progress:>4}", end="", flush=True)
bytes_list: List[int] = []
for page in range(16):
page = pages.get(page * 256 + sector)
if page is not None:
bytes_list.extend(page)
else:
bytes_list.extend([0]*256)
result = self.openocd.write_memory(0x02002000, 8, bytes_list)
if result:
print("ERROR!", flush=True)
print("An error occurred while writing data to the buffer area!")
print("Aborting...", flush=True)
return 1
self.openocd.run(f"set_reg {{t6 {sector}}}")
self.openocd.resume()
self.wait_halted(10) # ждем, когда watchpoint сработает
# watchpoint ловит до изменения слова
# делаем шаг, чтобы прочитать новое слово
self.openocd.run("step")
result = self.openocd.read_memory(0x2003000, 32, 1)[0]
if result == 0:
print(" OK!", flush=True)
else:
print(" FAIL!", flush=True)
print("result =", result)
break
if result == 0:
print(f" {sectors_list[-1]:#010x} 100% OK!", flush=True)
self.openocd.run("rwp 0x02003000")
self.spifi.init_memory()
if result == 0:
# Прошивка страниц флеш памяти по SPIFI была завершена
print("SPIFI writing successfully completed!", flush=True)
else:
print(f"SPIFI writing failed!", flush=True)
return 1
return result
def write(self, address: int, data: List[int], data_len: int):
if data_len > 256:
raise self.SpifiError("Byte count more than 256")
self.page_program(self.openocd, address, data, data_len)
print("written")
def write_file(self, bytes: List[int]):
# print(bytes)
print(f"Write {len(bytes)} bytes")
self.openocd.halt()
# self.init()
self.erase()
print("bin_data_len = ", len(bytes))
address = 0
for address in range(0, len(bytes), 256):
if ((address + 256) > len(bytes)):
break
print("address = ", address)
self.write(address, bytes, 256)
if self.read_data(address, 256, bytes) == 1:
return 1
if (len(bytes) % 256) != 0:
print(
f"address = {address}, +{len(bytes) - address-1}[{address + len(bytes) - address-1}]")
self.write(address, bytes, len(bytes) - address)
if self.read_data(address, len(bytes) - address, bytes) == 1:
return 1
print("end")
return 0
def get_segments_list(self, pages_offsets: List[int], segment_size: int) -> List[int]:
segments = set()
for offset in pages_offsets:
segments.add(offset & ~(segment_size - 1))
return sorted(list(segments))
def check_quad_enable(openocd):
return (read_sreg(openocd, SREG_Num.SREG2) & SREG2_QUAD_ENABLE_M) != 0

View File

@ -2,7 +2,7 @@ from enum import Enum
import os
from typing import List, NamedTuple, Union
from parsers import ParserError, Record, RecordType, parse_line
from parsers import Record, RecordType, parse_line
class MemoryType(Enum):
@ -36,11 +36,11 @@ class Segment:
self.memory = section
if self.memory is None:
raise ParserError(
f"segment with offset {self.offset:#0x} doesn't belong to any section")
raise Exception(
f"ERROR: segment with offset {self.offset:#0x} doesn't belong to any section")
if (self.offset + self.data.__len__()) > (self.memory.offset + self.memory.length):
raise ParserError(
raise Exception(
f"ERROR: segment with offset {self.offset:#0x} "
f"and length {self.data.__len__()} "
f"overflows section {self.memory.type.name}"
@ -75,7 +75,7 @@ class FirmwareFile:
bin_content = list(f.read())
self.segments.append(Segment(offset=0, data=bin_content, sections=sections))
else:
raise ParserError(f"Unsupported file format: {self.file_extension}")
raise Exception(f"Unsupported file format: {self.file_extension}")
def _parse_hex(self, lines: List[str], sections: List[MemorySection]):
segments: List[Segment] = []

View File

@ -7,14 +7,13 @@ import time
from typing import List, Union
from mik32_debug_hal.power_manager import pm_init
from mik32_upload import BootMode, Pages, form_pages, openocd_exec_path, openocd_scripts_path, openocd_interface_path, openocd_target_path, adapter_default_speed, run_openocd, default_post_action, default_log_path, default_openocd_host, mik32_sections, OpenOCDError, adapter_speed_not_supported, memory_page_size
from mik32_upload import BootMode, Pages, form_pages, openocd_exec_path, openocd_scripts_path, openocd_interface_path, openocd_target_path, adapter_default_speed, run_openocd, default_post_action, default_log_path, default_openocd_host, mik32_sections, OpenOCDStartupException, adapter_speed_not_supported, memory_page_size
from mik32_debug_hal.gpio import MIK32_Version, gpio_init, gpio_deinit
import mik32_debug_hal.eeprom as eeprom
import mik32_debug_hal.spifi as spifi
import mik32_debug_hal.ram as ram
from hex_parser import FirmwareFile, MemoryType, Segment
from tclrpc import OpenOcdTclRpc, TclException
from mik32_debug_hal.eeprom import EEPROM
from mik32_debug_hal.spifi import SPIFI
from flash_drivers.generic_flash import GenericFlash
def upload_file(
@ -64,7 +63,7 @@ def upload_file(
logging.debug("OpenOCD started!")
except OSError as e:
raise OpenOCDError(e)
raise OpenOCDStartupException(e)
try:
with OpenOcdTclRpc(host, port) as openocd:
if (all(openocd_interface.find(i) == -1 for i in adapter_speed_not_supported)):
@ -79,8 +78,6 @@ def upload_file(
logging.debug("PM configured!")
if (pages.pages_eeprom.__len__() > 0):
eeprom = EEPROM(openocd)
start_time = time.perf_counter()
result |= eeprom.check_pages(
@ -93,12 +90,10 @@ def upload_file(
f"Check {write_size} bytes in {write_time:.2f} seconds (effective {(write_size/(write_time*1024)):.1f} kbyte/s)")
if (pages.pages_spifi.__len__() > 0):
gpio_init(openocd, mik_version)
spifi = SPIFI(openocd)
flash = GenericFlash(spifi)
start_time = time.perf_counter()
result |= flash.check_pages(
pages.pages_spifi, use_quad_spi=use_quad_spi)
result |= spifi.check_pages(
pages.pages_spifi, openocd, use_quad_spi=use_quad_spi)
write_time = time.perf_counter() - start_time
write_size = pages.pages_spifi.__len__(

View File

@ -7,15 +7,6 @@ from dataclasses import dataclass
import mik32_debug_hal.registers.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.dma as dma_fields
class DmaError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return ("ERROR: " + repr(self.value))
# ReadStatus. Разрешить читать текущий статус канала
class CurrentValue(Enum):
ENABLE = 0 # Текущие значения
@ -210,4 +201,4 @@ class DMA:
if self.get_control() & mask != 0:
return
raise DmaError
raise Exception

View File

@ -1,16 +1,273 @@
import datetime
from enum import Enum
import os
import pathlib
import sys
from typing import Dict, List
from typing import Dict, List, Tuple
import time
from tclrpc import OpenOcdTclRpc, TclException
from tclrpc import OpenOcdTclRpc
from utils import bytes2words
import mik32_debug_hal.registers.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.eeprom as eeprom_fields
def eeprom_sysinit(openocd: OpenOcdTclRpc):
print("MCU clock init...", flush=True)
class EEPROM_Operation(Enum):
READ = eeprom_fields.OP_RD
ERASE = eeprom_fields.OP_ER
PROGRAM = eeprom_fields.OP_PR
class EEPROM_AffectedPages(Enum):
SINGLE = 0
EVEN = eeprom_fields.BEH_EVEN
ODD = eeprom_fields.BEH_ODD
GLOBAL = eeprom_fields.BEH_GLOB
def eeprom_execute_operation(openocd: OpenOcdTclRpc, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]):
# buffer write enable and select affected pages
openocd.write_memory(mem_map.EEPROM_REGS_EEA, 32, [offset, (1 << eeprom_fields.EECON_BWE_S)
| (affected_pages.value << eeprom_fields.EECON_WRBEH_S)])
if buffer.__len__() > 32:
return
for word in buffer:
openocd.write_word(mem_map.EEPROM_REGS_EEDAT, word)
# start operation
openocd.write_word(mem_map.EEPROM_REGS_EECON, (
(1 << eeprom_fields.EECON_EX_S) | (1 << eeprom_fields.EECON_BWE_S) |
(op.value << eeprom_fields.EECON_OP_S) | (
affected_pages.value << eeprom_fields.EECON_WRBEH_S)
))
def eeprom_configure_cycles(openocd: OpenOcdTclRpc, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500):
openocd.write_word(mem_map.EEPROM_REGS_NCYCRL, LD << eeprom_fields.NCYCRL_N_LD_S |
R_1 << eeprom_fields.NCYCRL_N_R_1_S | R_2 << eeprom_fields.NCYCRL_N_R_2_S)
openocd.write_word(mem_map.EEPROM_REGS_NCYCEP1, CYCEP1)
openocd.write_word(mem_map.EEPROM_REGS_NCYCEP2, CYCEP2)
def eeprom_global_erase(openocd: OpenOcdTclRpc):
print("EEPROM global erase...", flush=True)
# configure cycles duration
eeprom_execute_operation(
openocd, EEPROM_Operation.ERASE, EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32)
def eeprom_global_erase_check(openocd: OpenOcdTclRpc):
print("EEPROM global erase check through APB...", flush=True)
print(" Read Data at ...", flush=True)
ex_value = 0x00000000
openocd.write_word(mem_map.EEPROM_REGS_EEA, 0x00000000)
for i in range(0, 64):
print(f" Row={i+1}/64")
for j in range(0, 32):
value = openocd.read_memory(mem_map.EEPROM_REGS_EEDAT, 32, 1)[0]
if ex_value != value:
print(
f"Unexpect value at Row {i}, Word {j}, expect {ex_value:#0x}, {value:#0x}", flush=True)
def eeprom_write_word(openocd: OpenOcdTclRpc, address: int, word: int):
eeprom_execute_operation(
openocd, EEPROM_Operation.PROGRAM, EEPROM_AffectedPages.SINGLE, address, [word])
time.sleep(0.001)
def eeprom_write_page(openocd: OpenOcdTclRpc, address: int, data: List[int]):
eeprom_execute_operation(
openocd, EEPROM_Operation.PROGRAM, EEPROM_AffectedPages.SINGLE, address, data)
time.sleep(0.001)
def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int:
if print_progress:
print("EEPROM check through APB...", flush=True)
# address load
openocd.write_word(mem_map.EEPROM_REGS_EEA, offset)
word_num = 0
progress = 0
if print_progress:
print("[", end="", flush=True)
for word in words:
value: int = openocd.read_word(mem_map.EEPROM_REGS_EEDAT)
if words[word_num] != value:
print(
f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}", flush=True)
return 1
word_num += 1
curr_progress = int((word_num * 50) / len(words))
if print_progress and (curr_progress > progress):
print("#"*(curr_progress - progress), end="", flush=True)
progress = curr_progress
if print_progress:
print("]", flush=True)
print("EEPROM check through APB done!", flush=True)
return 0
def eeprom_check_data_ahb_lite(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int:
if print_progress:
print("EEPROM check through AHB-Lite...", flush=True)
mem_array = openocd.read_memory(0x01000000 + offset, 32, len(words))
if len(words) != len(mem_array):
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
def wait_halted(openocd: OpenOcdTclRpc, timeout_seconds: float = 2):
openocd.run(f'wait_halt {int(timeout_seconds * 1000)}')
def combine_pages(pages: Dict[int, List[int]]) -> List[int]:
"""
Объединить страницы в последовательность байт с заполнением промежутков
@ -30,197 +287,7 @@ def combine_pages(pages: Dict[int, List[int]]) -> List[int]:
return bytes_list
class EEPROM():
openocd: OpenOcdTclRpc
def __init__(self, openocd: OpenOcdTclRpc):
self.openocd = openocd
self.eeprom_sysinit()
def eeprom_sysinit(self):
print("MCU clock init...", flush=True)
class EEPROM_Operation(Enum):
READ = eeprom_fields.OP_RD
ERASE = eeprom_fields.OP_ER
PROGRAM = eeprom_fields.OP_PR
class EEPROM_AffectedPages(Enum):
SINGLE = 0
EVEN = eeprom_fields.BEH_EVEN
ODD = eeprom_fields.BEH_ODD
GLOBAL = eeprom_fields.BEH_GLOB
def eeprom_execute_operation(self, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]):
# buffer write enable and select affected pages
self.openocd.write_memory(mem_map.EEPROM_REGS_EEA, 32, [offset, (1 << eeprom_fields.EECON_BWE_S)
| (affected_pages.value << eeprom_fields.EECON_WRBEH_S)])
if buffer.__len__() > 32:
return
for word in buffer:
self.openocd.write_word(mem_map.EEPROM_REGS_EEDAT, word)
# start operation
self.openocd.write_word(mem_map.EEPROM_REGS_EECON, (
(1 << eeprom_fields.EECON_EX_S) | (1 << eeprom_fields.EECON_BWE_S) |
(op.value << eeprom_fields.EECON_OP_S) | (
affected_pages.value << eeprom_fields.EECON_WRBEH_S)
))
def eeprom_configure_cycles(self, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500):
self.openocd.write_word(mem_map.EEPROM_REGS_NCYCRL, LD << eeprom_fields.NCYCRL_N_LD_S |
R_1 << eeprom_fields.NCYCRL_N_R_1_S | R_2 << eeprom_fields.NCYCRL_N_R_2_S)
self.openocd.write_word(mem_map.EEPROM_REGS_NCYCEP1, CYCEP1)
self.openocd.write_word(mem_map.EEPROM_REGS_NCYCEP2, CYCEP2)
def eeprom_global_erase(self):
print("EEPROM global erase...", flush=True)
# configure cycles duration
self.eeprom_execute_operation(
self.EEPROM_Operation.ERASE, self.EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32)
def eeprom_global_erase_check(self):
print("EEPROM global erase check through APB...", flush=True)
print(" Read Data at ...", flush=True)
ex_value = 0x00000000
self.openocd.write_word(mem_map.EEPROM_REGS_EEA, 0x00000000)
for i in range(0, 64):
print(f" Row={i+1}/64")
for j in range(0, 32):
value = self.openocd.read_memory(
mem_map.EEPROM_REGS_EEDAT, 32, 1)[0]
if ex_value != value:
print(
f"Unexpect value at Row {i}, Word {j}, expect {ex_value:#0x}, {value:#0x}", flush=True)
def eeprom_write_word(self, address: int, word: int):
self.eeprom_execute_operation(
self.EEPROM_Operation.PROGRAM, self.EEPROM_AffectedPages.SINGLE, address, [word])
time.sleep(0.001)
def eeprom_write_page(self, address: int, data: List[int]):
self.eeprom_execute_operation(
self.EEPROM_Operation.PROGRAM, self.EEPROM_AffectedPages.SINGLE, address, data)
time.sleep(0.001)
def eeprom_check_data_apb(self, words: List[int], offset: int, print_progress=True) -> int:
if print_progress:
print("EEPROM check through APB...", flush=True)
# address load
self.openocd.write_word(mem_map.EEPROM_REGS_EEA, offset)
word_num = 0
progress = 0
if print_progress:
print("[", end="", flush=True)
for word in words:
value: int = self.openocd.read_word(mem_map.EEPROM_REGS_EEDAT)
if words[word_num] != value:
print(
f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}", flush=True)
return 1
word_num += 1
curr_progress = int((word_num * 50) / len(words))
if print_progress and (curr_progress > progress):
print("#"*(curr_progress - progress), end="", flush=True)
progress = curr_progress
if print_progress:
print("]", flush=True)
print("EEPROM check through APB done!", flush=True)
return 0
def eeprom_check_data_ahb_lite(self, words: List[int], offset: int, print_progress=True) -> int:
if print_progress:
print("EEPROM check through AHB-Lite...", flush=True)
mem_array = self.openocd.read_memory(
0x01000000 + offset, 32, len(words))
if len(words) != len(mem_array):
print("ERROR: Wrong number of words in read_memory output!")
return 1
progress = 0
if print_progress:
print("[", end="", flush=True)
for word_num in range(len(words)):
if words[word_num] != mem_array[word_num]:
print(f"Unexpect value at {word_num} word, expect {words[word_num]:#0x}, "
f"get {mem_array[word_num]:#0x}", flush=True)
return 1
curr_progress = int((word_num * 50) / len(words))
if print_progress and (curr_progress > progress):
print("#"*(curr_progress - progress), end="", flush=True)
progress = curr_progress
if print_progress:
print("]", flush=True)
print("EEPROM check through APB done!", flush=True)
return 0
def eeprom_check_data(self, words: List[int], offset: int, print_progress=True, read_through_apb=False) -> int:
if read_through_apb:
return self.eeprom_check_data_apb(words, offset, print_progress)
else:
return self.eeprom_check_data_ahb_lite(words, offset, print_progress)
def check_pages(self, pages: Dict[int, List[int]]) -> int:
self.openocd.halt()
self.eeprom_sysinit()
# configure cycles duration
self.eeprom_configure_cycles(1, 3, 1, 100000, 1000)
time.sleep(0.1)
print("EEPROM checking...", flush=True)
pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
page_words = bytes2words(pages[page_offset])
print(
f"Check page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True)
if self.eeprom_check_data(page_words, page_offset, False):
print("Page mismatch!", flush=True)
return 1
print("EEPROM page check completed", flush=True)
return 0
def write_pages(self, pages: Dict[int, List[int]]) -> int:
self.openocd.halt()
self.eeprom_sysinit()
self.eeprom_global_erase()
if self.eeprom_check_data_ahb_lite([0]*2048, 0, False):
print("EEPROM global erase failed, try again", flush=True)
self.eeprom_global_erase()
if self.eeprom_check_data_ahb_lite([0]*2048, 0, False):
print("EEPROM global erase failed", flush=True)
return 1
# configure cycles duration
self.eeprom_configure_cycles(1, 3, 1, 100000, 1000)
time.sleep(0.1)
print("EEPROM writing...", flush=True)
pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
page_words = bytes2words(pages[page_offset])
print(
f"Writing page {page_offset:#06x}... {(index*100)//pages_offsets.__len__()}%", flush=True)
self.eeprom_write_page(page_offset, page_words)
if self.eeprom_check_data(page_words, page_offset, False):
print("Page mismatch!", flush=True)
return 1
print("EEPROM page recording completed", flush=True)
return 0
def wait_halted(self, timeout_seconds: float = 2):
self.openocd.run(f'wait_halt {int(timeout_seconds * 1000)}')
def write_memory(self, pages: Dict[int, List[int]], driver_path: str) -> int:
def write_memory(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, driver_path: str) -> int:
"""
Записать всю память с использованием драйвера.
@ -230,58 +297,36 @@ class EEPROM():
# TODO: добавить проверку на версию mik32 - текущий драйвер поддерживает
# только версию mik32v2
RAM_OFFSET = 0x02000000
RAM_BUFFER_OFFSET = 0x02001800
RAM_DRIVER_STATUS = 0x02003800
bytes_list = combine_pages(pages)
self.openocd.halt()
# Отключение прерываний
self.openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}")
openocd.halt()
openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний
STATUS_CODE_M = 0xFF
max_address = len(bytes_list) // 128
self.openocd.write_memory(RAM_DRIVER_STATUS, 32, [
1 | (max_address << 8)])
openocd.write_memory(0x02003800, 32, [1 | (max_address << 8)])
pathname = os.path.dirname(sys.argv[0])
openocd.run("wp 0x2003800 4 w") # готовимся поймать результат записи
print("Uploading driver... ", end="", flush=True)
self.openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
print("OK!", flush=True)
print("Uploading data... ", end="", flush=True)
result = self.openocd.write_memory(RAM_BUFFER_OFFSET, 8, bytes_list)
if result:
print("ERROR!", flush=True)
print("An error occurred while writing data to the buffer area!")
print("Aborting...", flush=True)
return 1
else:
openocd.write_memory(0x02001800, 8, bytes_list)
print("OK!", flush=True)
# готовимся поймать результат записи
self.openocd.run(f"wp 0x{RAM_DRIVER_STATUS:08x} 4 w")
print("Run driver...", flush=True)
self.openocd.resume(RAM_OFFSET)
openocd.resume(0x2000000)
try:
# ждем, когда watchpoint сработает
self.wait_halted(10)
except TclException:
print("Timeout!", flush=True)
# return 1
wait_halted(openocd, 10) # ждем, когда watchpoint сработает
openocd.run("rwp 0x02003800") # watchpoint ловит до изменения слова
openocd.run("step") # делаем шаг, чтобы прочитать новое слово
# watchpoint ловит до изменения слова
self.openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}")
# делаем шаг, чтобы прочитать новое слово
self.openocd.run("step")
result = openocd.read_memory(0x2003800, 32, 1)[0]
result = self.openocd.read_memory(RAM_DRIVER_STATUS, 32, 1)[0]
if (result & STATUS_CODE_M) == 0:
if (result & 0xFF) == 0:
print(f"EEPROM writing successfully completed!", flush=True)
else:
miss_page = (result >> 8) & (64 - 1)
@ -291,8 +336,7 @@ class EEPROM():
print(f"EEPROM writing failed!", flush=True)
print(f"First mismatched byte in page {miss_page},")
print(
f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}")
print(f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}")
return 1

View File

@ -4,25 +4,9 @@ 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) -> int:
""" Настройка тактирования
def pm_init(openocd: OpenOcdTclRpc):
Ключевые аргументы:
openocd - объект для доступа к интерфейсу Tcl OpenOCD
Возвращаемое значение:
0 - успех
1 - ошибка
"""
iter = 1
max_iter = 2 # число попыток записи регистров
while True:
print('Clock init... ', end='')
# определение начальных значений регистров
APB_P_default = 0
WU_CLOCKS_default = 128 << wake_fields.CLOCKS_BU_ADJ_RC32K_S
AHB_default = (
pm_fields.CLOCK_AHB_CPU_M |
@ -32,54 +16,18 @@ def pm_init(openocd: OpenOcdTclRpc) -> int:
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
WU_CLOCKS_default = 128 << wake_fields.CLOCKS_BU_ADJ_RC32K_S
# запись начальных значений в регистры
openocd.halt()
openocd.write_word(mem_map.PM_Clk_APB_P_Clear_OFFSET, ~APB_P_default)
openocd.write_word(mem_map.PM_Clk_APB_P_Set_OFFSET, APB_P_default)
openocd.write_word(mem_map.PM_Clk_AHB_Clear_OFFSET, ~AHB_default)
openocd.write_word(mem_map.PM_Clk_AHB_Set_OFFSET, AHB_default)
openocd.write_word(mem_map.PM_Clk_APB_M_Clear_OFFSET, ~APB_M_default)
openocd.write_word(mem_map.PM_Clk_APB_M_Set_OFFSET, APB_M_default)
openocd.write_word(mem_map.WU_CLOCKS_BU_OFFSET, WU_CLOCKS_default)
# проверка записи на случай неожиданного ресета и перезаписи прошивкой
APB_P_real = openocd.read_word(mem_map.PM_Clk_APB_P_Set_OFFSET)
AHB_real = openocd.read_word(mem_map.PM_Clk_AHB_Set_OFFSET)
APB_M_real = openocd.read_word(mem_map.PM_Clk_APB_M_Set_OFFSET)
WU_CLOCKS_real = openocd.read_word(mem_map.WU_CLOCKS_BU_OFFSET)
if (
(WU_CLOCKS_real == WU_CLOCKS_default) and
(AHB_real == AHB_default) and
(APB_M_real == APB_M_default) and
(APB_P_real == APB_P_default)
):
print('OK!')
return 0
print('\nPM initialization results:')
print(
f'wu def 0x{WU_CLOCKS_default:08x} real 0x{WU_CLOCKS_real:08x}')
print(f'ahb def 0x{AHB_default:08x} real 0x{AHB_real:08x}')
print(f'apb_m def 0x{APB_M_default:08x} real 0x{APB_M_real:08x}')
print(f'apb_p def 0x{APB_P_default:08x} real 0x{APB_P_real:08x}')
iter += 1
if iter > max_iter:
print('ERROR: PM initialization failed, aborting', flush=True)
return 1
print(f'ERROR: PM initialization failed, retry #{iter}...', flush=True)
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)

View File

@ -49,11 +49,8 @@ SPIFI_CONFIG_STAT = SPIFI_REGS + 0x01C
PM_REGS = 0x000050000
PM_Clk_AHB_Set_OFFSET = PM_REGS + 0x0C
PM_Clk_AHB_Clear_OFFSET = PM_REGS + 0x10
PM_Clk_APB_M_Set_OFFSET = PM_REGS + 0x14
PM_Clk_APB_M_Clear_OFFSET = PM_REGS + 0x18
PM_Clk_APB_P_Set_OFFSET = PM_REGS + 0x1C
PM_Clk_APB_P_Clear_OFFSET = PM_REGS + 0x20
# --------------------------
@ -69,7 +66,6 @@ WU_CLOCKS_BU_OFFSET = WU_REGS + 0x10
# --------------------------
PAD_CONFIG_REGS = 0x00050C00
class PAD_CONFIG_REGS_V0(Enum):
PORT_0_CFG = 0x00
PORT_1_CFG = 0x04
@ -81,7 +77,6 @@ class PAD_CONFIG_REGS_V0(Enum):
PORT_1_PUD = 0x1C
PORT_2_PUD = 0x20
class PAD_CONFIG_REGS_V2(Enum):
PORT_0_CFG = 0x00
PORT_0_DS = 0x04
@ -93,7 +88,6 @@ class PAD_CONFIG_REGS_V2(Enum):
PORT_2_DS = 0x1C
PORT_2_PUD = 0x20
# --------------------------
# EEPROM register offset
# --------------------------

View File

@ -1,22 +1,77 @@
import datetime
from enum import Enum
from typing import List, Union
import os
import pathlib
import sys
from typing import Dict, List, Union
import time
from tclrpc import TclException
from tclrpc import OpenOcdTclRpc
import mik32_debug_hal.registers.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.spifi as spifi_fields
import mik32_debug_hal.dma as dma
import flash_drivers.generic_flash as generic_flash
class SPIFI():
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)
DEFAULT_READ_DATA_COMMAND = 0x03
class SpifiError(Exception):
def __init__(self, value):
self.value = value
INIT_DELAY = 0.001
TIMEOUT = 1.0
def 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 init(openocd: OpenOcdTclRpc):
print("MCU clock init", flush=True)
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 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) |
(generic_flash.READ_DATA_COMMAND << spifi_fields.SPIFI_CONFIG_MCMD_OPCODE_S))
time.sleep(INIT_DELAY)
def spifi_wait_intrq_timeout(openocd: OpenOcdTclRpc, error_message: str):
time_end = time.perf_counter() + TIMEOUT
while time.perf_counter() < time_end:
if (openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0:
return
raise Exception(error_message)
def __str__(self):
return ("ERROR: " + repr(self.value))
class Frameform(Enum):
RESERVED = 0
@ -28,78 +83,21 @@ class SPIFI():
NOOPCODE_3ADDR = 6
NOOPCODE_4ADDR = 7
class Fieldform(Enum):
ALL_SERIAL = 0
DATA_PARALLEL = 1
OPCODE_SERIAL = 2
ALL_PARALLEL = 3
class Direction(Enum):
READ = 0
WRITE = 1
INIT_DELAY = 0.001
TIMEOUT = 1.0
openocd: OpenOcdTclRpc
def __init__(self, openocd: OpenOcdTclRpc):
self.openocd = openocd
self.init()
def intrq_clear(self):
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M)
def init_periphery(self):
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.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))
self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
time.sleep(self.INIT_DELAY)
def init(self):
self.init_periphery()
control = self.openocd.read_word(mem_map.SPIFI_CONFIG_CTRL)
control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M
self.openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control)
time.sleep(self.INIT_DELAY)
def init_memory(self):
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M |
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_MCMD, (0 << spifi_fields.SPIFI_CONFIG_MCMD_INTLEN_S) |
(spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << spifi_fields.SPIFI_CONFIG_MCMD_FIELDFORM_S) |
(spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << spifi_fields.SPIFI_CONFIG_MCMD_FRAMEFORM_S) |
(self.DEFAULT_READ_DATA_COMMAND << spifi_fields.SPIFI_CONFIG_MCMD_OPCODE_S))
time.sleep(self.INIT_DELAY)
def spifi_wait_intrq_timeout(self, error_message: str):
time_end = time.perf_counter() + self.TIMEOUT
while time.perf_counter() < time_end:
if (self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0:
return
raise self.SpifiError(error_message)
def send_command(
self,
openocd: OpenOcdTclRpc,
cmd: int,
frameform: Frameform,
fieldform: Fieldform,
@ -112,23 +110,22 @@ class SPIFI():
data: List[int] = [],
dma: Union[dma.DMA, None] = None
) -> List[int]:
if (dma is not None) and (direction == self.Direction.WRITE):
self.openocd.write_memory(0x02003F00, 8, data)
if (dma is not None) and (direction == 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 == self.Direction.READ):
elif (dma is not None) and (direction == Direction.READ):
dma.channels[1].start(
mem_map.SPIFI_CONFIG_DATA32,
0x02003F00,
255
)
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata])
openocd.write_memory(mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata])
cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) |
(frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) |
@ -137,40 +134,84 @@ class SPIFI():
(idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) |
(direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S))
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value])
openocd.write_memory(mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value])
if direction == self.Direction.READ:
if direction == Direction.READ:
out_list = []
if dma is not None:
dma.dma_wait(dma.channels[1], 0.1)
out_list.extend(self.openocd.read_memory(
0x02003F00, 8, byte_count))
out_list.extend(openocd.read_memory(0x02003F00, 8, byte_count))
return out_list
else:
for i in range(byte_count):
out_list.append(self.openocd.read_memory(
out_list.append(openocd.read_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0])
return out_list
if direction == self.Direction.WRITE:
if direction == Direction.WRITE:
if dma is not None:
dma.dma_wait(dma.channels[0], 0.1)
else:
if (byte_count % 4) == 0:
for i in range(0, byte_count, 4):
self.openocd.write_memory(mem_map.SPIFI_CONFIG_DATA32, 32, [
openocd.write_memory(mem_map.SPIFI_CONFIG_DATA32, 32, [
data[i] + data[i+1] * 256 + data[i+2] * 256 * 256 + data[i+3] * 256 * 256 * 256])
else:
for i in range(byte_count):
self.openocd.write_memory(
openocd.write_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]])
return []
def dma_config(self) -> dma.DMA:
dma_instance = dma.DMA(self.openocd)
def write(openocd: OpenOcdTclRpc, address: int, data: List[int], data_len: int):
if data_len > 256:
raise Exception("Byte count more than 256")
generic_flash.page_program(openocd, address, data, data_len)
print("written")
def write_file(bytes: List[int], openocd: OpenOcdTclRpc):
# print(bytes)
print(f"Write {len(bytes)} bytes")
openocd.halt()
init(openocd)
generic_flash.erase(openocd)
print("bin_data_len = ", len(bytes))
address = 0
for address in range(0, len(bytes), 256):
if ((address + 256) > len(bytes)):
break
print("address = ", address)
write(openocd, address, bytes, 256)
if generic_flash.read_data(openocd, address, 256, bytes) == 1:
return 1
if (len(bytes) % 256) != 0:
print(
f"address = {address}, +{len(bytes) - address-1}[{address + len(bytes) - address-1}]")
write(openocd, address, bytes, len(bytes) - address)
if generic_flash.read_data(openocd, address, len(bytes) - address, bytes) == 1:
return 1
print("end")
return 0
def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]:
segments = set()
for offset in pages_offsets:
segments.add(offset & ~(segment_size - 1))
return sorted(list(segments))
def dma_config(openocd: OpenOcdTclRpc) -> dma.DMA:
dma_instance = dma.DMA(openocd)
dma_instance.init()
dma_instance.channels[0].write_buffer = 0
@ -212,3 +253,195 @@ class SPIFI():
dma_instance.channels[1].read_ack = dma.ChannelAck.DISABLE
return dma_instance
def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
result = 0
openocd.halt()
init(openocd)
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
generic_flash.chip_reset_qpi(openocd)
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
generic_flash.chip_reset(openocd)
JEDEC_ID = send_command(openocd, generic_flash.JEDEC_ID_COMMAND,
Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3)
print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
dma_instance = dma_config(openocd)
if (use_quad_spi):
print("Using Quad SPI")
generic_flash.quad_enable(openocd)
else:
print("Using Single SPI")
# spifi_quad_disable(openocd)
pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
print(
f"Check page {page_offset:#010x}... {(index*100)//pages_offsets.__len__()}%", flush=True)
page_bytes = pages[page_offset]
result = generic_flash.read_data(
openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi)
if result == 1:
print("Data error")
# if (use_quad_spi):
# spifi_quad_disable(openocd)
return result
if result == 0:
print("SPIFI pages checking completed", flush=True)
return 0
def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
result = 0
openocd.halt()
init(openocd)
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
generic_flash.chip_reset_qpi(openocd)
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
generic_flash.chip_reset(openocd)
JEDEC_ID = send_command(openocd, generic_flash.JEDEC_ID_COMMAND,
Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3)
print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
dma_instance = dma_config(openocd)
if use_chip_erase:
generic_flash.erase(openocd, generic_flash.EraseType.CHIP_ERASE)
else:
generic_flash.erase(openocd, generic_flash.EraseType.SECTOR_ERASE,
get_segments_list(list(pages), 4*1024))
print("Quad Enable", generic_flash.check_quad_enable(openocd))
if (use_quad_spi):
print("Using Quad SPI")
generic_flash.quad_enable(openocd)
else:
print("Using Single SPI")
# spifi_quad_disable(openocd)
# print("SREG1", spifi_read_sreg(openocd, SREG_Num.SREG1))
# print("SREG2", spifi_read_sreg(openocd, SREG_Num.SREG2))
pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
page_bytes = pages[page_offset]
if (use_quad_spi):
generic_flash.quad_page_program(
openocd, page_offset, page_bytes, 256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance)
else:
generic_flash.page_program(openocd, page_offset, page_bytes,
256, f"{(index*100)//pages_offsets.__len__()}%", dma=dma_instance)
result = generic_flash.read_data(
openocd, page_offset, 256, page_bytes, dma=dma_instance, use_quad_spi=use_quad_spi)
if result == 1:
print("Data error")
return result
if result == 0:
# Прошивка страниц флеш памяти по SPIFI была завершена
print("Flashing of flash memory pages via SPIFI has been completed", flush=True)
return 0
def wait_halted(openocd: OpenOcdTclRpc, timeout_seconds: float = 2):
openocd.run(f'wait_halt {int(timeout_seconds * 1000)}')
def write_pages_by_sectors(pages: Dict[int, List[int]],
openocd: OpenOcdTclRpc,
driver_path: str,
use_quad_spi=False,
use_chip_erase=False,
):
result = 0
openocd.halt()
openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний
init(openocd)
# openocd.run("rwp")
JEDEC_ID = send_command(
openocd, 0x9F, Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3)
print(f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
dma_instance = dma_config(openocd)
sectors_list = get_segments_list(list(pages), 4*1024)
openocd.halt()
pathname = os.path.dirname(sys.argv[0])
openocd.run("wp 0x2003000 4 w")
print("Uploading driver... ", end="", flush=True)
openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
print("OK!", flush=True)
openocd.resume(0x2000000)
wait_halted(openocd)
print("Writing Flash by sectors...", flush=True)
for i, sector in enumerate(sectors_list):
ByteAddress = sector
progress = f"{(i*100)//len(sectors_list)}%"
print(f" {ByteAddress:#010x} {progress:>4}", end="", flush=True)
bytes_list: List[int] = []
for page in range(16):
page = pages.get(page * 256 + sector)
if page is not None:
bytes_list.extend(page)
else:
bytes_list.extend([0]*256)
openocd.write_memory(0x02002000, 8, bytes_list)
openocd.run(f"set_reg {{t6 {sector}}}")
openocd.resume()
wait_halted(openocd, 10) # ждем, когда watchpoint сработает
# watchpoint ловит до изменения слова
openocd.run("step") # делаем шаг, чтобы прочитать новое слово
result = openocd.read_memory(0x2003000, 32, 1)[0]
if result == 0:
print(" OK!", flush=True)
else:
print(" FAIL!", flush=True)
print("result =", result)
break
if result == 0:
print(f" {sectors_list[-1]:#010x} 100% OK!", flush=True)
openocd.run("rwp 0x02003800")
init_memory(openocd)
if result == 0:
# Прошивка страниц флеш памяти по SPIFI была завершена
print("SPIFI writing successfully completed!", flush=True)
else:
print(f"SPIFI writing failed!", flush=True)
return 1
return result

View File

@ -7,11 +7,10 @@ import time
from enum import Enum
from typing import List, Dict, NamedTuple, Union
from hex_parser import FirmwareFile, MemorySection, MemoryType, Segment
from tclrpc import OpenOcdTclRpc, TclException, TclPortError
from tclrpc import OpenOcdTclRpc, TclException
from mik32_debug_hal.gpio import MIK32_Version, gpio_init, gpio_deinit
from mik32_debug_hal.eeprom import EEPROM
from mik32_debug_hal.spifi import SPIFI
from flash_drivers.generic_flash import GenericFlash
import mik32_debug_hal.eeprom as eeprom
import mik32_debug_hal.spifi as spifi
import mik32_debug_hal.ram as ram
import mik32_debug_hal.power_manager as power_manager
from _version import applicaton_version
@ -54,6 +53,19 @@ if os.name == 'nt':
adapter_default_speed = 500
def test_connection():
output = ""
with OpenOcdTclRpc() as openocd:
try:
output = openocd.run("capture \"reg\"")
except OSError:
logging.debug("Test connection timed out, try again")
output = openocd.run("capture \"reg\"")
if output == "":
raise Exception("ERROR: no regs found, check MCU connection")
memory_page_size = {
MemoryType.EEPROM: 128,
MemoryType.SPIFI: 256
@ -114,12 +126,12 @@ def segments_to_pages(segments: List[Segment], page_size: int) -> Dict[int, List
return pages
class OpenOCDError(Exception):
class OpenOCDStartupException(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return f"ERROR: OpenOCD Startup Exception: {self.msg}"
return f"OpenOCD Startup Exception: {self.msg}"
def run_openocd(
@ -203,9 +215,9 @@ def upload_file(
use_driver=True,
) -> int:
"""
Запись прошивки в формате Intel HEX или бинарном в память MIK32.
@filename: полный путь до файла прошивки
@return: возвращает 0 в случае успеха, 1 - если прошивка неудачна
Write ihex or binary file into MIK32 EEPROM or external flash memory
@filename: full path to the file with hex or bin file format
@return: return 0 if successful, 1 if failed
"""
print(f"Using {mik_version.value}")
@ -214,22 +226,13 @@ def upload_file(
if not os.path.exists(filename):
print(f"ERROR: File {filename} does not exist")
return 1
exit(1)
try:
file = FirmwareFile(filename, mik32_sections)
except ParserError as e:
print(e)
return 1
segments: List[Segment] = file.get_segments()
pages: Pages = form_pages(segments, boot_mode)
try:
port = int(port)
except ValueError:
print("An integer argument --openocd-port was expected!")
proc: Union[subprocess.Popen, None] = None
if is_run_openocd:
try:
@ -241,39 +244,28 @@ def upload_file(
logging.debug("OpenOCD started!")
except OSError as e:
raise OpenOCDError(e)
raise OpenOCDStartupException(e)
try:
time.sleep(0.1)
with OpenOcdTclRpc(host, port) as openocd:
try:
openocd.run(f"log_output \"{log_path}\"")
openocd.run(f"debug_level 1")
openocd.run("capture \"riscv.cpu curstate\"")
except OSError as e:
print("ERROR: Tcl port connection failed")
print("Check connectivity and OpenOCD log")
return 1
if (all(openocd_interface.find(i) == -1 for i in adapter_speed_not_supported)):
openocd.run(f"adapter speed {adapter_speed}")
openocd.run(f"log_output \"{log_path}\"")
openocd.run(f"debug_level 1")
logging.debug("OpenOCD configured!")
result = power_manager.pm_init(openocd)
if result != 0:
return 1
power_manager.pm_init(openocd)
logging.debug("PM configured!")
if (pages.pages_eeprom.__len__() > 0):
eeprom = EEPROM(openocd)
start_time = time.perf_counter()
if use_driver:
result |= eeprom.write_memory(
pages.pages_eeprom,
openocd,
os.path.join(
default_drivers_path,
'jtag-eeprom',
@ -283,7 +275,8 @@ def upload_file(
)
else:
result |= eeprom.write_pages(
pages.pages_eeprom
pages.pages_eeprom,
openocd
)
write_time = time.perf_counter() - start_time
@ -296,13 +289,12 @@ def upload_file(
f"[{current_time}] Wrote {write_size} bytes in {write_time:.2f} seconds (effective {(write_size/(write_time*1024)):.1f} kbyte/s)")
if (pages.pages_spifi.__len__() > 0):
gpio_init(openocd, mik_version)
spifi = SPIFI(openocd)
flash = GenericFlash(spifi)
start_time = time.perf_counter()
if use_driver:
result |= flash.write_pages_by_sectors(
result |= spifi.write_pages_by_sectors(
pages.pages_spifi,
openocd,
os.path.join(
default_drivers_path,
'jtag-spifi',
@ -311,7 +303,7 @@ def upload_file(
)
)
else:
result |= flash.write_pages(
result |= spifi.write_pages(
pages.pages_spifi,
openocd,
use_quad_spi=use_quad_spi
@ -336,13 +328,8 @@ def upload_file(
openocd.run(post_action)
except ConnectionRefusedError:
print("ERROR: The connection to OpenOCD is not established. Check the settings and connection of the debugger")
except (OpenOCDError, TclPortError, TclException) as e:
print(e)
exit(1)
except ConnectionResetError as e:
print("ERROR: Tcl connection reset")
print("Check OpenOCD log")
print(e.strerror)
except TclException as e:
print(f"ERROR: TclException {e.code} \n {e.msg}")
finally:
if proc is not None:
proc.kill()

View File

@ -8,18 +8,15 @@ proc init_targets {} {
set _CHIPNAME riscv
set _CPUTAPID 0xdeb11001
set _SYSTAPID 0xfffffffe
jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID
jtag newtap $_CHIPNAME sys -irlen 4 -ircapture 0x05 -irmask 0x0F -enable -expected-id $_SYSTAPID -ignore-bypass
jtag newtap $_CHIPNAME sys -irlen 4 -ircapture 0x05 -irmask 0x0F -enable
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -endian little -chain-position $_TARGETNAME -coreid 0
riscv expose_csrs 2016=mcounten
riscv.cpu configure -event reset-init my_init_proc
}

View File

@ -1,6 +1,6 @@
{
"name": "tool-mik32-uploader",
"version": "0.3.3",
"version": "0.2.0",
"description": "mik32-uploader",
"keywords": [
"tools",

View File

@ -5,14 +5,6 @@ from enum import Enum
from typing import List
class ParserError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return ("ERROR: " + repr(self.value))
class RecordType(Enum):
UNKNOWN = -1
DATA = 0
@ -32,14 +24,14 @@ class Record:
def parse_line(line: str, line_n: int, file_extension: str) -> Record:
if file_extension != ".hex":
raise ParserError("Unsupported file format: %s" % (file_extension))
raise Exception("Unsupported file format: %s" % (file_extension))
return parse_hex_line(line, line_n)
def parse_hex_line(line: str, line_n: int) -> Record:
if line[0] != ':':
raise ParserError("Error: unexpected record mark in line %d: %s, expect \':\', get \'%c\'" % (
raise Exception("Error: unexpected record mark in line %d: %s, expect \':\', get \'%c\'" % (
line_n, line, line[0]))
datalen = int(line[1:3], base=16) # Data field length
@ -53,10 +45,9 @@ def parse_hex_line(line: str, line_n: int) -> Record:
splitted_by_bytes.append(data_bytes_line[i*2:i*2+2])
data_bytes = list(map(lambda x: int(x, base=16), splitted_by_bytes))
checksum = (datalen + int(line[3:5], base=16) +
int(line[5:7], base=16) + rectype + sum(data_bytes)) % 256
checksum = (datalen + int(line[3:5], base=16) + int(line[5:7], base=16) + rectype + sum(data_bytes)) % 256
if (checksum + crc) % 256 != 0:
raise ParserError("Checksum mismatch in line %d %s" % (line_n, line))
raise Exception("Checksum mismatch in line %d %s" % (line_n, line))
record = Record(RecordType.UNKNOWN, 0, [])
@ -76,8 +67,7 @@ def parse_hex_line(line: str, line_n: int) -> Record:
# record.data = list(map(lambda x: int(x, base=16), splitted_by_bytes))
elif rectype == 4: # Extended Linear Address Record
record.type = RecordType.EXTADDR
record.address = data_bytes[1] * \
pow(256, 2) + data_bytes[0] * pow(256, 3)
record.address = data_bytes[1] * pow(256, 2) + data_bytes[0] * pow(256, 3)
elif rectype == 5: # Start Linear Address Record
record.type = RecordType.LINEARSTARTADDR
address = 0

View File

@ -11,14 +11,7 @@ class TclException(Exception):
self.msg = msg
def __repr__(self):
return '\nTclException(%d, %r)' % (self.code, self.msg)
class TclPortError(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return 'TclPortError %r' % (self.msg)
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):
@ -92,7 +85,7 @@ class OpenOcdTclRpc:
index = data.find(self.SEPARATOR_BYTES)
if index >= 0:
if index != len(data) - 1:
raise TclPortError('Unhandled extra bytes after %r'.format(self.SEPARATOR_BYTES))
raise Exception('Unhandled extra bytes after %r'.format(self.SEPARATOR_BYTES))
return data[:-1]
def wait_for_port(self, timeout: float = 5.0):

View File

@ -1,13 +1,13 @@
:020000040200F8
:10000000FD62938202400100FD12E39E02FE374131
:10001000000213010100B70100029381016FB705CF
:1000200000029385056F370600021306066FB706B8
:1000300000029386066F39A083A2050023A0560014
:1000400091059106E3EAC5FEB70500029385056FA9
:10005000370600021306066FB70600029386066F86
:10001000000213010100B70100029381016CB705D2
:1000200000029385056C370600021306066CB706BE
:1000300000029386066C39A083A2050023A0560017
:1000400091059106E3EAC5FEB70500029385056CAC
:10005000370600021306066CB70600029386066C8C
:1000600039A083A2050023A0560091059106E3EA7A
:10007000C5FEB70500029385056F3706000213061B
:10008000066F21A023A005009105E3EDC5FEB70092
:10007000C5FEB70500029385056C3706000213061E
:10008000066C21A023A005009105E3EDC5FEB70095
:100090000002E780C00AB7000002E780C00AB7008C
:1000A0000002E780E02273005010F5BF828000005C
:1000B0000000000000000000000000000000000040
@ -33,82 +33,79 @@
:1001F000C1171D8F3E96E374C3F8A5B75D71130652
:1002000080028145280886C6B137BD47230CF1001E
:100210008947230EF1003ED2E177938707082C0827
:100220000A85231AF102C526B640616182803171C8
:100230004AD94ED706DF22DD26DB52D556D35AD116
:1002400037490002653F9307098083A90700854766
:1002500013F7F90F6317F70A614681452800DD3D62
:10026000B707070093D9890061679387074093F91F
:10027000F9031307076A8D461306000281454800FB
:10028000B7240002616A3EC2130909809E09592001
:10029000938404800144130A0A6A130B0008634420
:1002A00034018147A9A8931A040193DA0A01D2877D
:1002B0000147930600022686D68548006D2813065E
:1002C0000008814508107935528793060002101006
:1002D000D68548000D2201471C10BA9783C6070037
:1002E000B307970083C70700638ED7009357744006
:1002F000A207E206D58F4207D98F93E72700232074
:10030000F90001A00507E31967FD130404089384AD
:10031000040871B71C418E0603A88700B3E60601E6
:1003200093E6060894C7144999CA814663DDC6005E
:10033000CCC323A007003A850DE50D458280CCC3D0
:10034000814663CCC600944793E6360094C775D7C0
:10035000C8477D17058965FD828023A007008506B3
:10036000CDB703A8C7007D1513781800E31608FC65
:100370008506910565BF032805000E0783288800C0
:1003800033671701136707082324E800184905C3DA
:1003900001476353D702131527002322B800329573
:1003A00008412320A8003E850DED0D4582802322C3
:1003B000B8000147634FD700032788001367570031
:1003C0002324E800FDD30325C800FD1705897DF926
:1003D000828093152700B2958C4105072320B80031
:1003E000D1BF8328C8007D1593F81800E39E08FA52
:1003F0000507910579BF1C4989CF814763FFD70065
:1004000003280500BA882322B800639108020D452D
:10041000828008414CC163E4D700014582800C41D1
:100420001397270032970CC38507F5B70323C8003D
:10043000FD1813731300E31A03FC832808001398B4
:1004400027003298232018018507910545BF0547ED
:10045000AA876305E50209476300E506054591EBB8
:10046000B7060600DC4A7D771307F73FF98FDCCA31
:10047000014582807D1719EB0D458280930600406F
:1004800037A7070013070712B7050500905D7D8E9B
:1004900075D2370606005C4A7D771307F73FF98F60
:1004A000D58F41115CCA02C613073006B2476359A3
:1004B000F700014541018280856693860680C9B7B1
:1004C000B24785073EC6DDB791476307F50263EA89
:1004D000A7008547630AF50489476309F5040545C4
:1004E0008280A147E31DF5FE0947094501A8FD17D4
:1004F00081EFC8D20D45828005470D45B7A707009B
:1005000093870712B7060500905E798E6DD28A0533
:10051000C98D4111CCD202C613073006B247635AC7
:10052000F7000145410182801147C9BF21470145BC
:10053000F1B7B24785073EC6D5B70547AA87630519
:10054000E50209476304E506054591EBB706060099
:100550009C4A7D771307F73FF98F9CCA014582803B
:100560007D1719EB0D4582809306004037A70700E1
:1005700013070712B7050500905D7D8E75D237070A
:1005800006001C4B7D761306F63FF18FD58F1CCBF2
:10059000232C070085471CCF411102C613073006E4
:1005A000B2476359F7000145410182808566938611
:1005B00006806DBFB24785073EC6DDB711C98547C6
:1005C000630DF50205458280FD1791EB0D45828094
:1005D0000946B7A7070093870712B7060500985E7C
:1005E000718F7DD34111C8D602C613073006B247BA
:1005F0006357F7000145410182800546D9BFB247E4
:1006000085073EC6EDB7011126CAB7040600DC48CF
:1006100006CE22CC4AC84EC652C456C2F19BDCC894
:100620009C482A89C845F19B9CC8D84883C7C50106
:100630002E84137737C08A07D98FDCC883C7D501CA
:1006400098489A071377F7C393F7073CD98F9CC84C
:10065000FD3B0C44AA8A03454400BD351848B70742
:1006600005002A8A98C358480850D8C3184C98C720
:10067000E935AA8948509937834704002A8793F6B9
:10068000170089E6D44893E62600D4C893F62700DD
:1006900099E637060600544A93E6160054CA93F6C4
:1006A000470099E637060600144A93E6260014CA66
:1006B000A18B99E7B70606009C4A93E717009CCAEE
:1006C000F2406244232059012322490123243901A5
:1006D0002326E900D244B249224A924A4A85424935
:1006E00005618280000000000000000000000000A2
:100220000A85231AF102F926B64061618280317194
:1002300006DF22DD26DB4AD94ED752D55AD156D316
:10024000753F6146814528003137B707070093871E
:100250000740B74900023EC2938709808443616723
:100260001307076AA18093F4F4038D461306000276
:100270008145480037290002616A9E0469201309FC
:100280000980014493890980130A0A6A130B000844
:10029000634494008147A9A8931A040193DA0A01E0
:1002A000D2870147930600024A86D68548006D280A
:1002B0001306000881450810713D5287930600021D
:1002C0001010D68548000D2201471C10BA9783C62E
:1002D0000700B307270183C70700638ED700935732
:1002E0007440A207E206D58F4207D98F93E7270013
:1002F00023A0F90001A00507E31967FD1304040812
:100300001309090871B71C418E0603A88700B3E6DC
:10031000060193E6060894C7144999CA814663DD2D
:10032000C600CCC323A007003A850DE50D458280A9
:10033000CCC3814663CCC600944793E6360094C78D
:1003400075D7C8477D17058965FD828023A0070002
:100350008506CDB703A8C7007D1513781800E316EE
:1003600008FC8506910565BF032805000E07832854
:10037000880033671701136707082324E80018492A
:1003800005C301476353D702131527002322B80082
:10039000329508412320A8003E850DED0D45828051
:1003A0002322B8000147634FD70003278800136753
:1003B00057002324E800FDD30325C800FD17058955
:1003C0007DF9828093152700B2958C410507232083
:1003D000B800D1BF8328C8007D1593F81800E39EAC
:1003E00008FA0507910579BF1C4989CF814763FF4A
:1003F000D70003280500BA882322B80063910802B9
:100400000D45828008414CC163E4D70001458280DC
:100410000C411397270032970CC38507F5B70323C8
:10042000C800FD1813731300E31A03FC83280800A7
:10043000139827003298232018018507910545BF9E
:100440000547AA876305E50209476300E5060545F8
:1004500091EBB7060600DC4A7D771307F73FF98F6B
:10046000DCCA014582807D1719EB0D458280930619
:10047000004037A7070013070712B7050500905D76
:100480007D8E75D2370606005C4A7D771307F73FED
:10049000F98FD58F41115CCA02C613073006B247E7
:1004A0006359F70001454101828085669386068085
:1004B000C9B7B24785073EC6DDB791476307F50266
:1004C00063EAA7008547630AF50489476309F504D1
:1004D00005458280A147E31DF5FE0947094501A8AE
:1004E000FD1781EFC8D20D45828005470D45B7A79E
:1004F000070093870712B7060500905E798E6DD2CC
:100500008A05C98D4111CCD202C613073006B24705
:10051000635AF7000145410182801147C9BF214755
:100520000145F1B7B24785073EC6D5B70547AA874B
:100530006305E50209476302E506054591EBB70649
:1005400006009C4A7D771307F73FF98F9CCA014547
:1005500082807D1719EB0D4582809306004037A7F6
:10056000070013070712B7050500905D7D8E75D251
:10057000370706001C4B7D761306F63FF18FD58FAB
:100580001CCB85471CCF411102C613073006B2476A
:100590006359F70001454101828085669386068094
:1005A0007DBFB24785073EC6DDB711C98547630DDC
:1005B000F50205458280FD1791EB0D4582800946C5
:1005C000B7A7070093870712B7060500985E718FDB
:1005D0007DD34111C8D602C613073006B247635710
:1005E000F7000145410182800546D9BFB247850722
:1005F0003EC6EDB7011126CAB7040600DC4806CE98
:1006000022CC4AC84EC652C456C2F19BDCC89C4894
:100610002A89C845F19B9CC883C7C5012E848A07D7
:10062000DCC883C7D5018A079CC8193D0C44AA8A37
:100630000345440059351848B70705002A8A98C36E
:1006400058480850D8C3184C98C7CD35AA89485087
:10065000A93F834704002A8793F6170089E6D44808
:1006600093E62600D4C893F6270099E637060600DD
:10067000544A93E6160054CA93F6470099E63706A3
:100680000600144A93E6260014CAA18B99E7B70620
:1006900006009C4A93E717009CCAF240624423205C
:1006A000590123224901232439012326E900D24498
:1006B000B249224A924A4A85424905618280000035
:0400000502000000F5
:00000001FF

View File

@ -12,4 +12,4 @@
platform = MIK32
board = mik32v2
framework = framework-mik32v2-sdk
board_build.ldscript = ram
board_debug.ldscript = ram

View File

@ -11,7 +11,6 @@
*/
#define STATUS_CODE_S 0
#define STATUS_CODE_M 0xFF
#define STATUS_CODE(X) ((X) << STATUS_CODE_S)
#define STATUS_CODE_OK 0
@ -52,14 +51,6 @@ int main()
xprintf("START DRIVER\n");
#endif
if ((*BUFFER_STATUS & STATUS_CODE_M) != STATUS_CODE(STATUS_CODE_START))
{
#ifdef UART_DEBUG
xprintf("ERROR: BUFFER_STATUS = 0x%08x\n", *BUFFER_STATUS);
#endif
goto final_loop;
}
HAL_EEPROM_HandleTypeDef heeprom = {
.Instance = EEPROM_REGS,
};
@ -111,8 +102,6 @@ debugger_return:
*BUFFER_STATUS = result;
// asm ("wfi");
final_loop:
while (1)
;
}

View File

@ -1,13 +1,13 @@
:020000040200F8
:10000000FD62938202400100FD12E39E02FE374131
:10001000000213010100B7110002938101D9B71545
:100020000002938505D937160002130606D9B716C4
:100030000002938606D939A083A2050023A05600AA
:1000400091059106E3EAC5FEB7150002938505D92F
:1000500037160002130606E2B7160002938606D989
:10001000000213010100B7110002938101D7B71547
:100020000002938505D737160002130606D7B716C8
:100030000002938606D739A083A2050023A05600AC
:1000400091059106E3EAC5FEB7150002938505D731
:1000500037160002130606E0B7160002938606D78D
:1000600039A083A2050023A0560091059106E3EA7A
:10007000C5FEB7150002938505D937160002130691
:1000800006D921A023A005009105E3EDC5FEB70028
:10007000C5FEB7150002938505D737160002130693
:1000800006D721A023A005009105E3EDC5FEB7002A
:100090000002E780C00AB7000002E780C00AB7008C
:1000A0000002E780002373005010F5BF828000003B
:1000B0000000000000000000000000000000000040
@ -33,24 +33,24 @@
:1001F000C1171D8F3E96E374C3F8A5B75D71130652
:1002000080028145280886C6B137BD47230CF1001E
:100210008947230EF1003ED2E177938707082C0827
:100220000A85231AF102EF00607AB640616182808C
:100220000A85231AF102EF00207AB64061618280CC
:100230000D71232E1114232A911423206115232ECE
:100240007113232C8113232A9113232C8114232827
:100250002115232631152324411523225115232846
:10026000A113693F371508000147814621469305D0
:10027000F011130505403D2A37150002130545D03E
:10027000F011130505403D2A371500021305C5CEC0
:10028000BD211306400281456800E935B707070024
:1002900028003EC4EF00300337150002130545D196
:1002A000B9212800EF00301037150002130585D260
:1002900028003EC4EF00B001371500021305C5CF9A
:1002A000B9212800EF00B00E37150002130505D163
:1002B0003D29B73400028547054523A0F400371BCC
:1002C0000002A92193840400B72B0002B71C00028E
:1002D000056CFE8513050BD47E8A1129D285280072
:1002E000EF00701693890B000149814A33044901DC
:1002F000CE86A285130600102800EF00101013060A
:1002D000056CFE8513058BD27E8A1129D2852800F4
:1002E000EF00F01493890B000149814A330449015E
:1002F000CE86A285130600102800EF00900E13068C
:10030000001081450818B935A2851418130600108D
:100310002800EF0090170144130D00101C18B3853E
:100310002800EF0010160144130D00101C18B385BF
:100320008900A29783C6050003C707006387E6001C
:10033000228613858CD5652E894A0504E310A4FF17
:10033000228613850CD4652E894A0504E310A4FF98
:100340001309091093890910E31289FB054523A0BD
:1003500054016D2EBDBF0111B717080006CE02C4AF
:1003600002C6938707406312F502B70705000947E5
@ -88,7 +88,7 @@
:10056000130404FD930705FD93F7F70FE374F7FEFB
:1005700095BF01442547FDB7130750056384E7087D
:10058000130780056382E70813073005E393E7FA52
:10059000832D0D0093094D0013FA24006E85092761
:10059000832D0D0093094D0013FA24006E85ED257F
:1005A0002A8D93041D0063150A00636A8D00268D51
:1005B0006E854535636A8D004E8DCA87D5B51305A6
:1005C0000002BD3D268DF1BF13050002953D050DCE
@ -111,7 +111,7 @@
:1006D000B650265496540659F649664AD64A464BB1
:1006E000B64B264C964C064DF25D656182803971A1
:1006F0002ED24C1006CE32D436D63AD83EDA42DC70
:1007000046DE2EC6AD33F2402161828051A5B74747
:1007000046DE2EC6AD33F2402161828095A5B74703
:100710000800938707402A886303F508B757080045
:10072000938707806303F50A37470800630CE50ADF
:1007300005458280331E1F013376DE0139C2C04178
@ -143,87 +143,85 @@
:1008D000798E6DD28A05C98D4111CCD202C613071B
:1008E0003006B247635AF700014541018280114743
:1008F000C9BF21470145F1B7B24785073EC6D5B705
:100900000547AA876305E50209476304E50605452F
:100900000547AA876305E50209476302E506054531
:1009100091EBB70606009C4A7D771307F73FF98FE6
:100920009CCA014582807D1719EB0D458280930694
:10093000004037A7070013070712B7050500905DB1
:100940007D8E75D2370706001C4B7D761306F63F69
:10095000F18FD58F1CCB232C070085471CCF41116D
:1009600002C613073006B2476359F700014541013B
:1009700082808566938606806DBFB24785073EC636
:10098000DDB711C98547630DF50205458280FD1766
:1009900091EB0D4582800946B7A7070093870712A0
:1009A000B7060500985E718F7DD34111C8D602C687
:1009B00013073006B2476357F700014541018280B3
:1009C0000546D9BFB24785073EC6EDB7011126CA15
:1009D000B7040600DC4806CE22CC4AC84EC652C434
:1009E00056C2F19BDCC89C482A89C845F19B9CC82B
:1009F000D84883C7C5012E84137737C08A07D98F9B
:100A0000DCC883C7D50198489A071377F7C393F7D3
:100A1000073CD98F9CC8FD3B0C44AA8A034544007F
:100A2000BD351848B70705002A8A98C358480850AA
:100A3000D8C3184C98C7E935AA89485099378347D5
:100A400004002A8793F6170089E6D44893E6260027
:100A5000D4C893F6270099E637060600544A93E671
:100A6000160054CA93F6470099E637060600144A62
:100A700093E6260014CAA18B99E7B70606009C4AA4
:100A800093E717009CCAF2406244232059012322B5
:100A90004901232439012326E900D244B249224ADC
:100AA000924A4A85424905618280B7070500DC53B6
:100AB000054721658D8BF9176376F7003755E801F7
:100AC000130505808280011106CE22CC02C402C625
:100AD0002147B707050037550800D8C705448D479B
:100AE0008A85130505803EC022C21531375508009E
:100AF0009307C0038A851305058022C222C43EC025
:100B00003931F240624405618280032305002A8E58
:100B10000325C30113650502232EA3002324C3006C
:100B20001396260149824D8E232603012322C300FA
:100B3000139605016354060299C20545B1CB0147DE
:100B40006346D700639C08020D4582803386E70028
:100B5000034606000507230AC300DDB799C2054511
:100B600005CB8147E3D0D7FE03260E00034546019F
:100B70003306F70085072300A600EDB783270E0094
:100B8000FD18DC4F93F70702D5DF11656D8D11E17C
:100B90008280B707070083C7470113F585001D8DC5
:100BA0003335A00082801C414147D8CF8280E16864
:100BB0009388086A01488147014781460146B70585
:100BC0002006A1B7011106CEA30701008947639350
:100BD000F502B7052035E1681307F1009388086A2C
:100BE00001488147854601460D37F2400345F10033
:100BF00005618280B7052005F9BF011106CE22CC20
:100C000026CA2E844AC8AA84328936C64D37B247CE
:100C1000E16822869388086A01480147CA86B78539
:100C2000800226856164D5351304146A7D1411C4CD
:100C300085452685413F058975F9F2406244D244D5
:100C4000424905618280011106CE22CC26CA2EC6F9
:100C5000AA84B13F3246E1689388086A0148814717
:100C600001478146B705802026856164793D1304DC
:100C7000146A7D1411C485452685A937058975F93F
:100C8000F2406244D24405618280E16836879388ED
:100C9000086AB28601482E868147B7058003B5B53C
:100CA000937735002A879DEFB7867F7F9386F6F787
:100CB000FD5510431107B377D600B697D18FD58F66
:100CC000E389B7FE8346C7FFB307A7408DCA8346B3
:100CD000D7FF9DC20345E7FF3335A0003E95791548
:100CE0008280F9D283470700050793763700F5FB2A
:100CF000098F1305F7FF82801385D7FF8280138544
:100D0000C7FF8280535441525420445249564552A1
:100D10000A0000006D737020696E697420636F6D46
:100D2000706C6574650A000073706966692072658D
:100D300073657420636F6D706C6574650A000000E4
:100D4000455241534520534543544F522030782556
:100D50003038780A00000000616464725B307825E6
:100D60003038783A3078253032785D206275663ACE
:100D70006D656D203D2030782530327820213D2072
:100D80003078253032780A000000000000000000B2
:100D9000411122C406C62A84093BB70705009C43BB
:100DA0001307803E8507B357F502B3D7E7020D67F7
:100DB0001307779CB387E7022167130707D0B3D7E0
:100DC000E70219C4BE82FD12E39F02FE7D147DF886
:100DD000B240224441018280411122C406C62A84C5
:100DE000E931B70705009C431307803E8507B357D9
:100DF000F502B3D7E7022947B387E7022167130754
:100E000007D0B3D7E70219C4BE82FD12E39F02FEEA
:100E10007D147DF8B2402244410182800000000030
:10095000F18FD58F1CCB85471CCF411102C61307E1
:100960003006B2476359F700014541018280856630
:10097000938606807DBFB24785073EC6DDB711C9A5
:100980008547630DF50205458280FD1791EB0D4506
:1009900082800946B7A7070093870712B7060500AC
:1009A000985E718F7DD34111C8D602C613073006F9
:1009B000B2476357F7000145410182800546D9BF20
:1009C000B24785073EC6EDB7011126CAB704060037
:1009D000DC4806CE22CC4AC84EC652C456C2F19B51
:1009E000DCC89C482A89C845F19B9CC883C7C501BF
:1009F0002E848A07DCC883C7D5018A079CC8193DA5
:100A00000C44AA8A0345440059351848B707050025
:100A10002A8A98C358480850D8C3184C98C7CD356F
:100A2000AA894850A93F834704002A8793F61700F4
:100A300089E6D44893E62600D4C893F6270099E6C1
:100A400037060600544A93E6160054CA93F6470048
:100A500099E637060600144A93E6260014CAA18BCD
:100A600099E7B70606009C4A93E717009CCAF24034
:100A700062442320590123224901232439012326DA
:100A8000E900D244B249224A924A4A854249056164
:100A90008280B7070500DC53054721658D8BF91768
:100AA0006376F7003755E801130505808280011150
:100AB00006CE22CC02C402C62147B707050037552F
:100AC0000800D8C705448D478A85130505803EC0B8
:100AD00022C23539375508009307C0038A851305AC
:100AE000058022C222C43EC01D31F240624405612D
:100AF0008280032305002A8E0325C30113650502A6
:100B0000232EA3002324C3001396260149824D8E71
:100B1000232603012322C300139605016354060212
:100B200099C20545B1CB01476346D700639C0802D3
:100B30000D4582803386E700034606000507230A39
:100B4000C300DDB799C2054505CB8147E3D0D7FE89
:100B500003260E00034546013306F70085072300F0
:100B6000A600EDB783270E00FD18DC4F93F70702B0
:100B7000D5DF11656D8D11E18280B707070083C74E
:100B8000470113F585001D8D3335A00082801C417F
:100B90004147D8CF8280E1689388086A014881473D
:100BA000014781460146B7052006A1B7011106CECF
:100BB000A307010089476393F502B7052035E16873
:100BC0001307F1009388086A01488147854601466A
:100BD0000D37F2400345F10005618280B70520051D
:100BE000F9BF011106CE22CC26CA2E844AC8AA8497
:100BF000328936C64D37B247E16822869388086A43
:100C000001480147CA86B785800226856164D535CB
:100C10001304146A7D1411C485452685413F058956
:100C200075F9F2406244D244424905618280011163
:100C300006CE22CC26CA2EC6AA84B13F3246E1682F
:100C40009388086A0148814701478146B70580209B
:100C500026856164793D1304146A7D1411C48545A9
:100C60002685A937058975F9F2406244D2440561A9
:100C70008280E16836879388086AB28601482E86AA
:100C80008147B7058003B5B5937735002A879DEF77
:100C9000B7867F7F9386F6F7FD5510431107B3772C
:100CA000D600B697D18FD58FE389B7FE8346C7FFAD
:100CB000B307A7408DCA8346D7FF9DC20345E7FF10
:100CC0003335A0003E9579158280F9D2834707001D
:100CD000050793763700F5FB098F1305F7FF828030
:100CE0001385D7FF82801385C7FF828053544152FA
:100CF00054204452495645520A0000006D7370203A
:100D0000696E697420636F6D706C6574650A0000AC
:100D1000737069666920726573657420636F6D70A6
:100D20006C6574650A0000004552415345205345E7
:100D300043544F52203078253038780A00000000A4
:100D4000616464725B3078253038783A30782530C9
:100D500032785D206275663A6D656D203D20307891
:100D60002530327820213D203078253032780A0035
:100D7000411122C406C62A84293BB70705009C43BB
:100D80001307803E8507B357F502B3D7E7020D6717
:100D90001307779CB387E7022167130707D0B3D700
:100DA000E70219C4BE82FD12E39F02FE7D147DF8A6
:100DB000B240224441018280411122C406C62A84E5
:100DC000C939B70705009C431307803E8507B35711
:100DD000F502B3D7E7022947B387E7022167130774
:100DE00007D0B3D7E70219C4BE82FD12E39F02FE0B
:100DF0007D147DF8B2402244410182800000000051
:0400000502000000F5
:00000001FF

View File

@ -12,5 +12,5 @@
platform = MIK32
board = mik32v2
framework = framework-mik32v2-sdk
board_build.ldscript = ram
board_debug.ldscript = ram
build_flags = -ffixed-x31 -D MIK32V2