Compare commits

...

22 Commits

Author SHA1 Message Date
sh-sergey
edd479f953 обновлена версия в package.json 2025-03-17 17:59:17 +03:00
sh-sergey
044abedcc9 Обновлены список изменений, версия в файле для пакетного менеджера 2025-03-17 11:39:21 +03:00
sh-sergey
49532c7df7
Merge pull request #8 from cryptozoy/master
Обновление mik32.cfg:
1. Добавлен id для TCB блока МК, убрано предупреждение о некорректном IDCODE;
2. Добавление нестандартного CSR-регистра MCOUNTEN, используемого для управления активностью счётчиков производительности (тактов и команд).
2025-03-17 11:32:16 +03:00
cryptozoy
7a02683c4d
Обновление mik32.cfg
1) Сокращение вывода бесполезных предупреждений;
2) Добавление нестандартного CSR-регистра MCOUNTEN, используемого для управления активностью счётчиков производительности (тактов и команд).
2025-03-16 14:21:55 +03:00
sh-sergey
9f13695d6b изменен номер версии 2025-03-14 18:40:30 +03:00
sh-sergey
92a2b7be18 Обновлен список изменений 2025-03-14 18:35:31 +03:00
sh-sergey
9a36170cea Исправлен выбор порта аргументом --openocd-port 2025-03-14 18:33:59 +03:00
sh-sergey
0f156e9dad убран лишний аргумент 2025-03-05 17:02:54 +03:00
sh-sergey
c1e7f9bdc9 Исправление ошибки записи eeprom при boot=1 (ram) 2025-02-13 18:48:32 +03:00
sh-sergey
9bec497601 переработка eeprom и spifi
функции сгруппированы в классы, для spifi улучшено разделение функционала между контроллерами интерфейса и флеш памяти
2025-01-16 16:21:35 +03:00
sh-sergey
d55a5242a8 Update CHANGELOG.md 2024-12-28 02:50:42 +03:00
sh-sergey
298d46acd4 Добавлена проверка успешного завершения записи сектора, обновлен лист изменений 2024-12-28 02:46:54 +03:00
sh-sergey
304469890b убран лишний вывод 2024-12-27 18:09:50 +03:00
sh-sergey
2d5a23268f рефактор 2024-12-27 11:44:52 +03:00
sh-sergey
c5950bfa4f Проверка ошибок при загрузке драйвером 2024-12-26 13:05:18 +03:00
sh-sergey
d3ae56eff5 Исправлена настройка тактирования + обработка ошибок 2024-12-26 13:03:38 +03:00
sh-sergey
3f35886f66
Merge pull request #7 from cryptozoy/master
Update spifi.py
2024-12-16 11:20:16 +03:00
cryptozoy
89732a8df1
Update spifi.py
Добавление в функцию загрузки прошивки (секторами с драйвером) команд сброса внешней флеш-памяти из всех режимов в стандартный Single SPI, иначе прошивка не заливается.
2024-12-15 01:48:59 +03:00
sh-sergey
31d3eecaa9 Исправлена ошибка в функции прошивки spifi 2024-12-02 14:03:24 +03:00
sh-sergey
329c230337 Update hex_parser.py 2024-11-18 18:22:59 +03:00
sh-sergey
328112232c Добавлена базовая обработка ошибок связи с OpenOCD 2024-11-18 17:23:22 +03:00
sh-sergey
5135347032 Увеличена версия 2024-11-18 10:18:08 +03:00
22 changed files with 1225 additions and 1114 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
__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.0", "spec": {"owner": "mikron", "id": 122, "name": "tool-mik32-uploader", "requirements": null, "uri": null}}
{"type": "tool", "name": "tool-mik32-uploader", "version": "0.3.3", "spec": {"owner": "mikron", "id": 122, "name": "tool-mik32-uploader", "requirements": null, "uri": null}}

View File

@ -22,6 +22,24 @@
### Удалено
## [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
### Добавлено
@ -65,17 +83,17 @@
### Добавлено
- [Update mik32_spifi.py](https://github.com/MikronMIK32/mik32-uploader/commit/1201ab7228b5b0f5a0b58b71933204b6e2bae0f6)
Добавлен программный сброс микросхемы флеш-памяти из режимов QPI и XIP, чтение и печать JEDEC ID
Добавлен программный сброс микросхемы флеш-памяти из режимов QPI и XIP, чтение и печать JEDEC ID (@cryptozoy)
### Изменено
- [Update mik32_spifi.py](https://github.com/MikronMIK32/mik32-uploader/commit/1201ab7228b5b0f5a0b58b71933204b6e2bae0f6)
Убрано отключение Quad SPI режима после прошивки флеш-памяти
Убрано отключение Quad SPI режима после прошивки флеш-памяти (@cryptozoy)
### Исправлено
- [Update mikron-link.cfg](https://github.com/MikronMIK32/mik32-uploader/commit/094a94276878d72564566a1481b6cddccf1e4b81)
Заменена устаревшая команда и добавлена отсутствующая скорость по-умолчанию для конфигурации отладчика Программатор MIK32
Заменена устаревшая команда и добавлена отсутствующая скорость по-умолчанию для конфигурации отладчика Программатор MIK32 (@cryptozoy)
## [v0.1.0] - 2024-07-17

View File

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

View File

@ -1,130 +1,138 @@
from enum import Enum
import os
import pathlib
import sys
import time
from typing import List, Union
from typing import Dict, List, Union
from tclrpc import OpenOcdTclRpc
import mik32_debug_hal.spifi as spifi
from mik32_debug_hal.spifi import SPIFI
# import mik32_debug_hal.spifi as spifi
import mik32_debug_hal.dma as dma
# --------------------------
# Commands
# --------------------------
SREG1_BUSY = 1
class GenericFlash():
# --------------------------
# Commands
# --------------------------
SREG1_BUSY = 1
READ_LEN = 256
READ_LEN = 256
ENABLE_RESET_COMMAND = 0x66
RESET_COMMAND = 0x99
ENABLE_RESET_COMMAND = 0x66
RESET_COMMAND = 0x99
CHIP_ERASE_COMMAND = 0xC7
SECTOR_ERASE_COMMAND = 0x20
CHIP_ERASE_COMMAND = 0xC7
SECTOR_ERASE_COMMAND = 0x20
WRITE_ENABLE_COMMAND = 0x06
WRITE_DISABLE_COMMAND = 0x04
WRITE_ENABLE_COMMAND = 0x06
WRITE_DISABLE_COMMAND = 0x04
MEM_CONFIG_COMMAND = 0x61
MEM_CONFIG_VALUE = 0x7F
MEM_CONFIG_COMMAND = 0x61
MEM_CONFIG_VALUE = 0x7F
READ_DATA_COMMAND = 0x03
READ_DATA_COMMAND = 0x03
FAST_READ_QUAD_OUTPUT_COMMAND = 0x6B
FAST_READ_QUAD_OUTPUT_COMMAND = 0x6B
READ_SREG1_COMMAND = 0x05
READ_SREG2_COMMAND = 0x35
WRITE_SREG_COMMAND = 0x01
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
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
PAGE_PROGRAM_COMMAND = 0x02
QUAD_PAGE_PROGRAM_COMMAND = 0x32
QUAD_PAGE_PROGRAM_COMMAND = 0x32
JEDEC_ID_COMMAND = 0x9F
JEDEC_ID_COMMAND = 0x9F
class FlashError(Exception):
def __init__(self, value):
self.value = value
class SREG_Num(Enum):
def __str__(self):
return ("ERROR: " + repr(self.value))
class SREG_Num(Enum):
SREG1 = 0x00
SREG2 = 0x30
openocd: OpenOcdTclRpc
spifi: SPIFI
def write_enable(openocd: OpenOcdTclRpc):
spifi.send_command(openocd, WRITE_ENABLE_COMMAND,
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
def __init__(self, spifi: SPIFI):
self.spifi = spifi
self.openocd = self.spifi.openocd
# self.init()
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,
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,
byte_count=1
)[0]
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,
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,
byte_count=2,
direction=spifi.Direction.WRITE,
direction=self.spifi.Direction.WRITE,
data=[sreg1, sreg2]
)
wait_busy(openocd)
self.wait_busy()
def wait_busy(openocd: OpenOcdTclRpc):
def wait_busy(self):
while 1:
sreg1 = read_sreg(openocd, SREG_Num.SREG1)
if not (sreg1 & SREG1_BUSY):
sreg1 = self.read_sreg(self.SREG_Num.SREG1)
if not (sreg1 & self.SREG1_BUSY):
break
RESET_DELAY = 0.001
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_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):
def chip_erase(self):
print("Chip erase...", flush=True)
spifi.send_command(openocd, CHIP_ERASE_COMMAND,
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
self.spifi.send_command(self.CHIP_ERASE_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
def sector_erase(openocd: OpenOcdTclRpc, address: int):
def sector_erase(self, 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)
self.spifi.send_command(self.SECTOR_ERASE_COMMAND,
self.spifi.Frameform.OPCODE_3ADDR, self.spifi.Fieldform.ALL_SERIAL, address=address)
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:
def read_data(self, 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 = 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)
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)
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)
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)
for i in range(byte_count):
if read_data[i] != bin_data[i]:
@ -135,70 +143,310 @@ def read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_data: L
return 0
def page_program(
openocd: OpenOcdTclRpc,
def page_program(
self,
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 Exception("Byte count more than 256")
raise self.FlashError("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
class EraseType(Enum):
CHIP_ERASE = CHIP_ERASE_COMMAND
SECTOR_ERASE = SECTOR_ERASE_COMMAND
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:
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:
for sector in sectors:
write_enable(openocd)
sector_erase(openocd, sector)
wait_busy(openocd)
self.write_enable()
self.sector_erase(sector)
self.wait_busy()
def quad_page_program(
openocd: OpenOcdTclRpc,
def quad_page_program(
self,
ByteAddress: int,
data: List[int],
byte_count: int,
progress: str = "",
dma: Union[dma.DMA, None] = None
):
):
print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
if byte_count > 256:
raise Exception("Byte count more than 256")
raise self.FlashError("Byte count more than 256")
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)
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()
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 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 check_quad_enable(self):
return (self.read_sreg(self.SREG_Num.SREG2) & self.SREG2_QUAD_ENABLE_M) != 0
def check_quad_enable(openocd):
return (read_sreg(openocd, SREG_Num.SREG2) & 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))

View File

@ -2,7 +2,7 @@ from enum import Enum
import os
from typing import List, NamedTuple, Union
from parsers import Record, RecordType, parse_line
from parsers import ParserError, Record, RecordType, parse_line
class MemoryType(Enum):
@ -36,11 +36,11 @@ class Segment:
self.memory = section
if self.memory is None:
raise Exception(
f"ERROR: segment with offset {self.offset:#0x} doesn't belong to any section")
raise ParserError(
f"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 Exception(
raise ParserError(
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 Exception(f"Unsupported file format: {self.file_extension}")
raise ParserError(f"Unsupported file format: {self.file_extension}")
def _parse_hex(self, lines: List[str], sections: List[MemorySection]):
segments: List[Segment] = []

View File

@ -7,13 +7,14 @@ 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, OpenOCDStartupException, 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, OpenOCDError, 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(
@ -63,7 +64,7 @@ def upload_file(
logging.debug("OpenOCD started!")
except OSError as e:
raise OpenOCDStartupException(e)
raise OpenOCDError(e)
try:
with OpenOcdTclRpc(host, port) as openocd:
if (all(openocd_interface.find(i) == -1 for i in adapter_speed_not_supported)):
@ -78,6 +79,8 @@ 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(
@ -90,10 +93,12 @@ 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 |= spifi.check_pages(
pages.pages_spifi, openocd, use_quad_spi=use_quad_spi)
result |= flash.check_pages(
pages.pages_spifi, use_quad_spi=use_quad_spi)
write_time = time.perf_counter() - start_time
write_size = pages.pages_spifi.__len__(

View File

@ -7,6 +7,15 @@ 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 # Текущие значения
@ -201,4 +210,4 @@ class DMA:
if self.get_control() & mask != 0:
return
raise Exception
raise DmaError

View File

@ -1,273 +1,16 @@
import datetime
from enum import Enum
import os
import pathlib
import sys
from typing import Dict, List, Tuple
from typing import Dict, List
import time
from tclrpc import OpenOcdTclRpc
from tclrpc import OpenOcdTclRpc, TclException
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]:
"""
Объединить страницы в последовательность байт с заполнением промежутков
@ -287,7 +30,197 @@ def combine_pages(pages: Dict[int, List[int]]) -> List[int]:
return bytes_list
def write_memory(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, driver_path: str) -> int:
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:
"""
Записать всю память с использованием драйвера.
@ -297,36 +230,58 @@ def write_memory(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, driver_pat
# TODO: добавить проверку на версию mik32 - текущий драйвер поддерживает
# только версию mik32v2
RAM_OFFSET = 0x02000000
RAM_BUFFER_OFFSET = 0x02001800
RAM_DRIVER_STATUS = 0x02003800
bytes_list = combine_pages(pages)
openocd.halt()
openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний
self.openocd.halt()
# Отключение прерываний
self.openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}")
STATUS_CODE_M = 0xFF
max_address = len(bytes_list) // 128
openocd.write_memory(0x02003800, 32, [1 | (max_address << 8)])
self.openocd.write_memory(RAM_DRIVER_STATUS, 32, [
1 | (max_address << 8)])
pathname = os.path.dirname(sys.argv[0])
openocd.run("wp 0x2003800 4 w") # готовимся поймать результат записи
print("Uploading driver... ", end="", flush=True)
openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
self.openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}")
print("OK!", flush=True)
print("Uploading data... ", end="", flush=True)
openocd.write_memory(0x02001800, 8, bytes_list)
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:
print("OK!", flush=True)
# готовимся поймать результат записи
self.openocd.run(f"wp 0x{RAM_DRIVER_STATUS:08x} 4 w")
print("Run driver...", flush=True)
openocd.resume(0x2000000)
self.openocd.resume(RAM_OFFSET)
wait_halted(openocd, 10) # ждем, когда watchpoint сработает
openocd.run("rwp 0x02003800") # watchpoint ловит до изменения слова
openocd.run("step") # делаем шаг, чтобы прочитать новое слово
try:
# ждем, когда watchpoint сработает
self.wait_halted(10)
except TclException:
print("Timeout!", flush=True)
# return 1
result = openocd.read_memory(0x2003800, 32, 1)[0]
# watchpoint ловит до изменения слова
self.openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}")
# делаем шаг, чтобы прочитать новое слово
self.openocd.run("step")
if (result & 0xFF) == 0:
result = self.openocd.read_memory(RAM_DRIVER_STATUS, 32, 1)[0]
if (result & STATUS_CODE_M) == 0:
print(f"EEPROM writing successfully completed!", flush=True)
else:
miss_page = (result >> 8) & (64 - 1)
@ -336,7 +291,8 @@ def write_memory(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, driver_pat
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,9 +4,25 @@ 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):
def pm_init(openocd: OpenOcdTclRpc) -> int:
""" Настройка тактирования
WU_CLOCKS_default = 128 << wake_fields.CLOCKS_BU_ADJ_RC32K_S
Ключевые аргументы:
openocd - объект для доступа к интерфейсу Tcl OpenOCD
Возвращаемое значение:
0 - успех
1 - ошибка
"""
iter = 1
max_iter = 2 # число попыток записи регистров
while True:
print('Clock init... ', end='')
# определение начальных значений регистров
APB_P_default = 0
AHB_default = (
pm_fields.CLOCK_AHB_CPU_M |
@ -16,18 +32,54 @@ def pm_init(openocd: OpenOcdTclRpc):
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.WU_CLOCKS_BU_OFFSET, WU_CLOCKS_default)
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_APB_M_Set_OFFSET, APB_M_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)

View File

@ -49,8 +49,11 @@ 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
# --------------------------
@ -66,6 +69,7 @@ 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
@ -77,6 +81,7 @@ 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
@ -88,6 +93,7 @@ class PAD_CONFIG_REGS_V2(Enum):
PORT_2_DS = 0x1C
PORT_2_PUD = 0x20
# --------------------------
# EEPROM register offset
# --------------------------

View File

@ -1,79 +1,24 @@
import datetime
from enum import Enum
import os
import pathlib
import sys
from typing import Dict, List, Union
from typing import 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
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)
class SPIFI():
DEFAULT_READ_DATA_COMMAND = 0x03
INIT_DELAY = 0.001
class SpifiError(Exception):
def __init__(self, value):
self.value = value
TIMEOUT = 1.0
def __str__(self):
return ("ERROR: " + repr(self.value))
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)
class Frameform(Enum):
class Frameform(Enum):
RESERVED = 0
OPCODE_NOADDR = 1
OPCODE_1ADDR = 2
@ -83,21 +28,78 @@ class Frameform(Enum):
NOOPCODE_3ADDR = 6
NOOPCODE_4ADDR = 7
class Fieldform(Enum):
class Fieldform(Enum):
ALL_SERIAL = 0
DATA_PARALLEL = 1
OPCODE_SERIAL = 2
ALL_PARALLEL = 3
class Direction(Enum):
class Direction(Enum):
READ = 0
WRITE = 1
INIT_DELAY = 0.001
def send_command(
openocd: OpenOcdTclRpc,
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,
cmd: int,
frameform: Frameform,
fieldform: Fieldform,
@ -109,23 +111,24 @@ def send_command(
direction=Direction.READ,
data: List[int] = [],
dma: Union[dma.DMA, None] = None
) -> List[int]:
if (dma is not None) and (direction == Direction.WRITE):
openocd.write_memory(0x02003F00, 8, data)
) -> List[int]:
if (dma is not None) and (direction == self.Direction.WRITE):
self.openocd.write_memory(0x02003F00, 8, data)
dma.channels[0].start(
0x02003F00,
mem_map.SPIFI_CONFIG_DATA32,
255
)
elif (dma is not None) and (direction == Direction.READ):
elif (dma is not None) and (direction == self.Direction.READ):
dma.channels[1].start(
mem_map.SPIFI_CONFIG_DATA32,
0x02003F00,
255
)
openocd.write_memory(mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata])
self.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) |
@ -134,84 +137,40 @@ def send_command(
(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])
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value])
if direction == Direction.READ:
if direction == self.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))
out_list.extend(self.openocd.read_memory(
0x02003F00, 8, byte_count))
return out_list
else:
for i in range(byte_count):
out_list.append(openocd.read_memory(
out_list.append(self.openocd.read_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0])
return out_list
if direction == Direction.WRITE:
if direction == self.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, [
self.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(
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]])
return []
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)
def dma_config(self) -> dma.DMA:
dma_instance = dma.DMA(self.openocd)
dma_instance.init()
dma_instance.channels[0].write_buffer = 0
@ -253,195 +212,3 @@ def dma_config(openocd: OpenOcdTclRpc) -> dma.DMA:
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,10 +7,11 @@ 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
from tclrpc import OpenOcdTclRpc, TclException, TclPortError
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
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.ram as ram
import mik32_debug_hal.power_manager as power_manager
from _version import applicaton_version
@ -53,19 +54,6 @@ 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
@ -126,12 +114,12 @@ def segments_to_pages(segments: List[Segment], page_size: int) -> Dict[int, List
return pages
class OpenOCDStartupException(Exception):
class OpenOCDError(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return f"OpenOCD Startup Exception: {self.msg}"
return f"ERROR: OpenOCD Startup Exception: {self.msg}"
def run_openocd(
@ -215,9 +203,9 @@ def upload_file(
use_driver=True,
) -> int:
"""
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
Запись прошивки в формате Intel HEX или бинарном в память MIK32.
@filename: полный путь до файла прошивки
@return: возвращает 0 в случае успеха, 1 - если прошивка неудачна
"""
print(f"Using {mik_version.value}")
@ -226,13 +214,22 @@ def upload_file(
if not os.path.exists(filename):
print(f"ERROR: File {filename} does not exist")
exit(1)
return 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:
@ -244,28 +241,39 @@ def upload_file(
logging.debug("OpenOCD started!")
except OSError as e:
raise OpenOCDStartupException(e)
raise OpenOCDError(e)
try:
time.sleep(0.1)
with OpenOcdTclRpc(host, port) as openocd:
if (all(openocd_interface.find(i) == -1 for i in adapter_speed_not_supported)):
openocd.run(f"adapter speed {adapter_speed}")
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}")
logging.debug("OpenOCD configured!")
power_manager.pm_init(openocd)
result = power_manager.pm_init(openocd)
if result != 0:
return 1
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',
@ -275,8 +283,7 @@ def upload_file(
)
else:
result |= eeprom.write_pages(
pages.pages_eeprom,
openocd
pages.pages_eeprom
)
write_time = time.perf_counter() - start_time
@ -289,12 +296,13 @@ 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 |= spifi.write_pages_by_sectors(
result |= flash.write_pages_by_sectors(
pages.pages_spifi,
openocd,
os.path.join(
default_drivers_path,
'jtag-spifi',
@ -303,7 +311,7 @@ def upload_file(
)
)
else:
result |= spifi.write_pages(
result |= flash.write_pages(
pages.pages_spifi,
openocd,
use_quad_spi=use_quad_spi
@ -328,8 +336,13 @@ 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 TclException as e:
print(f"ERROR: TclException {e.code} \n {e.msg}")
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)
finally:
if proc is not None:
proc.kill()

View File

@ -8,15 +8,18 @@ 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
jtag newtap $_CHIPNAME sys -irlen 4 -ircapture 0x05 -irmask 0x0F -enable -expected-id $_SYSTAPID -ignore-bypass
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.2.0",
"version": "0.3.3",
"description": "mik32-uploader",
"keywords": [
"tools",

View File

@ -5,6 +5,14 @@ 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
@ -24,14 +32,14 @@ class Record:
def parse_line(line: str, line_n: int, file_extension: str) -> Record:
if file_extension != ".hex":
raise Exception("Unsupported file format: %s" % (file_extension))
raise ParserError("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 Exception("Error: unexpected record mark in line %d: %s, expect \':\', get \'%c\'" % (
raise ParserError("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
@ -45,9 +53,10 @@ 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 Exception("Checksum mismatch in line %d %s" % (line_n, line))
raise ParserError("Checksum mismatch in line %d %s" % (line_n, line))
record = Record(RecordType.UNKNOWN, 0, [])
@ -67,7 +76,8 @@ 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,7 +11,14 @@ class TclException(Exception):
self.msg = msg
def __repr__(self):
return 'TclException(%d, %r)' % (self.code, self.msg)
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)
_RE_SIMPLE_TCL_WORD = re.compile(r"^[a-zA-Z_0-9:+./@=,'-]+$")
def tcl_quote_word(word):
@ -85,7 +92,7 @@ class OpenOcdTclRpc:
index = data.find(self.SEPARATOR_BYTES)
if index >= 0:
if index != len(data) - 1:
raise Exception('Unhandled extra bytes after %r'.format(self.SEPARATOR_BYTES))
raise TclPortError('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
:10001000000213010100B70100029381016CB705D2
:1000200000029385056C370600021306066CB706BE
:1000300000029386066C39A083A2050023A0560017
:1000400091059106E3EAC5FEB70500029385056CAC
:10005000370600021306066CB70600029386066C8C
:10001000000213010100B70100029381016FB705CF
:1000200000029385056F370600021306066FB706B8
:1000300000029386066F39A083A2050023A0560014
:1000400091059106E3EAC5FEB70500029385056FA9
:10005000370600021306066FB70600029386066F86
:1000600039A083A2050023A0560091059106E3EA7A
:10007000C5FEB70500029385056C3706000213061E
:10008000066C21A023A005009105E3EDC5FEB70095
:10007000C5FEB70500029385056F3706000213061B
:10008000066F21A023A005009105E3EDC5FEB70092
:100090000002E780C00AB7000002E780C00AB7008C
:1000A0000002E780E02273005010F5BF828000005C
:1000B0000000000000000000000000000000000040
@ -33,79 +33,82 @@
:1001F000C1171D8F3E96E374C3F8A5B75D71130652
:1002000080028145280886C6B137BD47230CF1001E
:100210008947230EF1003ED2E177938707082C0827
: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
: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
:0400000502000000F5
:00000001FF

View File

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

View File

@ -11,6 +11,7 @@
*/
#define STATUS_CODE_S 0
#define STATUS_CODE_M 0xFF
#define STATUS_CODE(X) ((X) << STATUS_CODE_S)
#define STATUS_CODE_OK 0
@ -51,6 +52,14 @@ 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,
};
@ -102,6 +111,8 @@ debugger_return:
*BUFFER_STATUS = result;
// asm ("wfi");
final_loop:
while (1)
;
}

View File

@ -1,13 +1,13 @@
:020000040200F8
:10000000FD62938202400100FD12E39E02FE374131
:10001000000213010100B7110002938101D7B71547
:100020000002938505D737160002130606D7B716C8
:100030000002938606D739A083A2050023A05600AC
:1000400091059106E3EAC5FEB7150002938505D731
:1000500037160002130606E0B7160002938606D78D
:10001000000213010100B7110002938101D9B71545
:100020000002938505D937160002130606D9B716C4
:100030000002938606D939A083A2050023A05600AA
:1000400091059106E3EAC5FEB7150002938505D92F
:1000500037160002130606E2B7160002938606D989
:1000600039A083A2050023A0560091059106E3EA7A
:10007000C5FEB7150002938505D737160002130693
:1000800006D721A023A005009105E3EDC5FEB7002A
:10007000C5FEB7150002938505D937160002130691
:1000800006D921A023A005009105E3EDC5FEB70028
:100090000002E780C00AB7000002E780C00AB7008C
:1000A0000002E780002373005010F5BF828000003B
:1000B0000000000000000000000000000000000040
@ -33,24 +33,24 @@
:1001F000C1171D8F3E96E374C3F8A5B75D71130652
:1002000080028145280886C6B137BD47230CF1001E
:100210008947230EF1003ED2E177938707082C0827
:100220000A85231AF102EF00207AB64061618280CC
:100220000A85231AF102EF00607AB640616182808C
:100230000D71232E1114232A911423206115232ECE
:100240007113232C8113232A9113232C8114232827
:100250002115232631152324411523225115232846
:10026000A113693F371508000147814621469305D0
:10027000F011130505403D2A371500021305C5CEC0
:10027000F011130505403D2A37150002130545D03E
:10028000BD211306400281456800E935B707070024
:1002900028003EC4EF00B001371500021305C5CF9A
:1002A000B9212800EF00B00E37150002130505D163
:1002900028003EC4EF00300337150002130545D196
:1002A000B9212800EF00301037150002130585D260
:1002B0003D29B73400028547054523A0F400371BCC
:1002C0000002A92193840400B72B0002B71C00028E
:1002D000056CFE8513058BD27E8A1129D2852800F4
:1002E000EF00F01493890B000149814A330449015E
:1002F000CE86A285130600102800EF00900E13068C
:1002D000056CFE8513050BD47E8A1129D285280072
:1002E000EF00701693890B000149814A33044901DC
:1002F000CE86A285130600102800EF00101013060A
:10030000001081450818B935A2851418130600108D
:100310002800EF0010160144130D00101C18B385BF
:100310002800EF0090170144130D00101C18B3853E
:100320008900A29783C6050003C707006387E6001C
:10033000228613850CD4652E894A0504E310A4FF98
:10033000228613858CD5652E894A0504E310A4FF17
:100340001309091093890910E31289FB054523A0BD
:1003500054016D2EBDBF0111B717080006CE02C4AF
:1003600002C6938707406312F502B70705000947E5
@ -88,7 +88,7 @@
:10056000130404FD930705FD93F7F70FE374F7FEFB
:1005700095BF01442547FDB7130750056384E7087D
:10058000130780056382E70813073005E393E7FA52
:10059000832D0D0093094D0013FA24006E85ED257F
:10059000832D0D0093094D0013FA24006E85092761
:1005A0002A8D93041D0063150A00636A8D00268D51
:1005B0006E854535636A8D004E8DCA87D5B51305A6
:1005C0000002BD3D268DF1BF13050002953D050DCE
@ -111,7 +111,7 @@
:1006D000B650265496540659F649664AD64A464BB1
:1006E000B64B264C964C064DF25D656182803971A1
:1006F0002ED24C1006CE32D436D63AD83EDA42DC70
:1007000046DE2EC6AD33F2402161828095A5B74703
:1007000046DE2EC6AD33F2402161828051A5B74747
:100710000800938707402A886303F508B757080045
:10072000938707806303F50A37470800630CE50ADF
:1007300005458280331E1F013376DE0139C2C04178
@ -143,85 +143,87 @@
:1008D000798E6DD28A05C98D4111CCD202C613071B
:1008E0003006B247635AF700014541018280114743
:1008F000C9BF21470145F1B7B24785073EC6D5B705
:100900000547AA876305E50209476302E506054531
:100900000547AA876305E50209476304E50605452F
:1009100091EBB70606009C4A7D771307F73FF98FE6
:100920009CCA014582807D1719EB0D458280930694
:10093000004037A7070013070712B7050500905DB1
:100940007D8E75D2370706001C4B7D761306F63F69
: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
: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
:0400000502000000F5
:00000001FF

View File

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