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__ __pycache__
.vscode .vscode
openocd openocd
venv
*.code-workspace *.code-workspace
dist dist
mik32_upload.spec 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 ## [v0.3.1] - 2024-11-14
### Добавлено ### Добавлено
@ -65,17 +83,17 @@
### Добавлено ### Добавлено
- [Update mik32_spifi.py](https://github.com/MikronMIK32/mik32-uploader/commit/1201ab7228b5b0f5a0b58b71933204b6e2bae0f6) - [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) - [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) - [Update mikron-link.cfg](https://github.com/MikronMIK32/mik32-uploader/commit/094a94276878d72564566a1481b6cddccf1e4b81)
Заменена устаревшая команда и добавлена отсутствующая скорость по-умолчанию для конфигурации отладчика Программатор MIK32 Заменена устаревшая команда и добавлена отсутствующая скорость по-умолчанию для конфигурации отладчика Программатор MIK32 (@cryptozoy)
## [v0.1.0] - 2024-07-17 ## [v0.1.0] - 2024-07-17

View File

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

View File

@ -1,204 +1,452 @@
from enum import Enum from enum import Enum
import os
import pathlib
import sys
import time import time
from typing import List, Union from typing import Dict, List, Union
from tclrpc import OpenOcdTclRpc 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 import mik32_debug_hal.dma as dma
# -------------------------- class GenericFlash():
# Commands # --------------------------
# -------------------------- # Commands
SREG1_BUSY = 1 # --------------------------
SREG1_BUSY = 1
READ_LEN = 256 READ_LEN = 256
ENABLE_RESET_COMMAND = 0x66 ENABLE_RESET_COMMAND = 0x66
RESET_COMMAND = 0x99 RESET_COMMAND = 0x99
CHIP_ERASE_COMMAND = 0xC7 CHIP_ERASE_COMMAND = 0xC7
SECTOR_ERASE_COMMAND = 0x20 SECTOR_ERASE_COMMAND = 0x20
WRITE_ENABLE_COMMAND = 0x06 WRITE_ENABLE_COMMAND = 0x06
WRITE_DISABLE_COMMAND = 0x04 WRITE_DISABLE_COMMAND = 0x04
MEM_CONFIG_COMMAND = 0x61 MEM_CONFIG_COMMAND = 0x61
MEM_CONFIG_VALUE = 0x7F 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_SREG1_COMMAND = 0x05
READ_SREG2_COMMAND = 0x35 READ_SREG2_COMMAND = 0x35
WRITE_SREG_COMMAND = 0x01 WRITE_SREG_COMMAND = 0x01
SREG2_QUAD_ENABLE = 9 SREG2_QUAD_ENABLE = 9
SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8) SREG2_QUAD_ENABLE_S = (SREG2_QUAD_ENABLE-8)
SREG2_QUAD_ENABLE_M = 1 << SREG2_QUAD_ENABLE_S 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):
SREG1 = 0x00 return ("ERROR: " + repr(self.value))
SREG2 = 0x30
class SREG_Num(Enum):
SREG1 = 0x00
SREG2 = 0x30
def write_enable(openocd: OpenOcdTclRpc): openocd: OpenOcdTclRpc
spifi.send_command(openocd, WRITE_ENABLE_COMMAND, spifi: SPIFI
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
def __init__(self, spifi: SPIFI):
self.spifi = spifi
self.openocd = self.spifi.openocd
def read_sreg(openocd: OpenOcdTclRpc, sreg: SREG_Num) -> int: # self.init()
return spifi.send_command(
openocd,
READ_SREG1_COMMAND | sreg.value,
spifi.Frameform.OPCODE_NOADDR,
spifi.Fieldform.ALL_SERIAL,
byte_count=1
)[0]
def write_enable(self):
self.spifi.send_command(self.WRITE_ENABLE_COMMAND,
self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
def write_sreg(openocd: OpenOcdTclRpc, sreg1: int, sreg2: int): def read_sreg(self, sreg: SREG_Num) -> int:
write_enable(openocd) return self.spifi.send_command(
spifi.send_command( self.READ_SREG1_COMMAND | sreg.value,
openocd, self.spifi.Frameform.OPCODE_NOADDR,
WRITE_SREG_COMMAND, self.spifi.Fieldform.ALL_SERIAL,
spifi.Frameform.OPCODE_NOADDR, byte_count=1
spifi.Fieldform.ALL_SERIAL, )[0]
byte_count=2,
direction=spifi.Direction.WRITE,
data=[sreg1, sreg2]
)
wait_busy(openocd)
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=self.spifi.Direction.WRITE,
data=[sreg1, sreg2]
)
self.wait_busy()
def wait_busy(openocd: OpenOcdTclRpc): def wait_busy(self):
while 1: while 1:
sreg1 = read_sreg(openocd, SREG_Num.SREG1) sreg1 = self.read_sreg(self.SREG_Num.SREG1)
if not (sreg1 & SREG1_BUSY): if not (sreg1 & self.SREG1_BUSY):
break 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): def chip_erase(self):
spifi.send_command(openocd, ENABLE_RESET_COMMAND, print("Chip erase...", flush=True)
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL) self.spifi.send_command(self.CHIP_ERASE_COMMAND,
spifi.send_command(openocd, RESET_COMMAND, self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL)
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL)
time.sleep(RESET_DELAY)
def sector_erase(self, 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)
def chip_reset_qpi(openocd: OpenOcdTclRpc): def read_data(self, address: int, byte_count: int, bin_data: List[int], dma: Union[dma.DMA, None] = None, use_quad_spi=False) -> int:
spifi.send_command(openocd, ENABLE_RESET_COMMAND, read_data: List[int] = []
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)
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)
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)
def chip_erase(openocd: OpenOcdTclRpc): for i in range(byte_count):
print("Chip erase...", flush=True) if read_data[i] != bin_data[i]:
spifi.send_command(openocd, CHIP_ERASE_COMMAND, print(
spifi.Frameform.OPCODE_NOADDR, spifi.Fieldform.ALL_SERIAL) f"DATA[{i+address}] = {read_data[i]:#0x} expect {bin_data[i]:#0x}", flush=True)
return 1
def sector_erase(openocd: OpenOcdTclRpc, address: int): return 0
print(f"Erase sector {address:#010x}...", flush=True)
spifi.send_command(openocd, SECTOR_ERASE_COMMAND,
spifi.Frameform.OPCODE_3ADDR, spifi.Fieldform.ALL_SERIAL, address=address)
def 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)
if byte_count > 256:
raise self.FlashError("Byte count more than 256")
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: self.write_enable()
read_data: List[int] = [] 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()
if (use_quad_spi): class EraseType(Enum):
read_data = spifi.send_command(openocd, FAST_READ_QUAD_OUTPUT_COMMAND, spifi.Frameform.OPCODE_3ADDR, CHIP_ERASE = 0
spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=address, idata_length=1, dma=dma) SECTOR_ERASE = 1
else:
read_data = spifi.send_command(openocd, READ_DATA_COMMAND, spifi.Frameform.OPCODE_3ADDR,
spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=address, dma=dma)
for i in range(byte_count): def erase(self, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []):
if read_data[i] != bin_data[i]: if erase_type == self.EraseType.CHIP_ERASE:
print( self.write_enable()
f"DATA[{i+address}] = {read_data[i]:#0x} expect {bin_data[i]:#0x}", flush=True) self.chip_erase()
self.wait_busy()
elif erase_type == self.EraseType.SECTOR_ERASE:
for sector in sectors:
self.write_enable()
self.sector_erase(sector)
self.wait_busy()
return 1 def quad_page_program(
self,
return 0
def page_program(
openocd: OpenOcdTclRpc,
ByteAddress: int, ByteAddress: int,
data: List[int], data: List[int],
byte_count: int, byte_count: int,
progress: str = "", progress: str = "",
dma: Union[dma.DMA, None] = None dma: Union[dma.DMA, None] = None
): ):
print(f"Writing Flash page {ByteAddress:#010x}... {progress}", flush=True) print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
if byte_count > 256: if byte_count > 256:
raise Exception("Byte count more than 256") raise self.FlashError("Byte count more than 256")
write_enable(openocd) self.write_enable()
spifi.send_command(openocd, PAGE_PROGRAM_COMMAND, spifi.Frameform.OPCODE_3ADDR, self.spifi.send_command(self.QUAD_PAGE_PROGRAM_COMMAND, self.spifi.Frameform.OPCODE_3ADDR,
spifi.Fieldform.ALL_SERIAL, byte_count=byte_count, address=ByteAddress, self.spifi.Fieldform.DATA_PARALLEL, byte_count=byte_count, address=ByteAddress,
idata=0, cache_limit=0, direction=spifi.Direction.WRITE, data=data, dma=dma) idata=0, cache_limit=0, direction=self.spifi.Direction.WRITE, data=data, dma=dma)
wait_busy(openocd) self.wait_busy()
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
)
class EraseType(Enum): def check_quad_enable(self):
CHIP_ERASE = CHIP_ERASE_COMMAND return (self.read_sreg(self.SREG_Num.SREG2) & self.SREG2_QUAD_ENABLE_M) != 0
SECTOR_ERASE = SECTOR_ERASE_COMMAND
def check_pages(self, pages: Dict[int, List[int]], use_quad_spi=False, use_chip_erase=False):
result = 0
def erase(openocd, erase_type: EraseType = EraseType.CHIP_ERASE, sectors: List[int] = []): self.openocd.halt()
if erase_type == EraseType.CHIP_ERASE: # self.init()
write_enable(openocd)
chip_erase(openocd)
wait_busy(openocd)
elif erase_type == EraseType.SECTOR_ERASE:
for sector in sectors:
write_enable(openocd)
sector_erase(openocd, sector)
wait_busy(openocd)
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
self.chip_reset_qpi()
def quad_page_program( # Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
openocd: OpenOcdTclRpc, self.chip_reset()
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")
write_enable(openocd) JEDEC_ID = self.spifi.send_command(self.JEDEC_ID_COMMAND,
spifi.send_command(openocd, QUAD_PAGE_PROGRAM_COMMAND, spifi.Frameform.OPCODE_3ADDR, self.spifi.Frameform.OPCODE_NOADDR, self.spifi.Fieldform.ALL_SERIAL, 3)
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)
print(
f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
def quad_enable(openocd): dma_instance = self.spifi.dma_config()
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
)
if (use_quad_spi):
print("Using Quad SPI")
self.quad_enable(self.openocd)
else:
print("Using Single SPI")
# spifi_quad_disable(openocd)
def check_quad_enable(openocd): pages_offsets = list(pages)
return (read_sreg(openocd, SREG_Num.SREG2) & SREG2_QUAD_ENABLE_M) != 0
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 import os
from typing import List, NamedTuple, Union from typing import List, NamedTuple, Union
from parsers import Record, RecordType, parse_line from parsers import ParserError, Record, RecordType, parse_line
class MemoryType(Enum): class MemoryType(Enum):
@ -36,11 +36,11 @@ class Segment:
self.memory = section self.memory = section
if self.memory is None: if self.memory is None:
raise Exception( raise ParserError(
f"ERROR: segment with offset {self.offset:#0x} doesn't belong to any section") 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): 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"ERROR: segment with offset {self.offset:#0x} "
f"and length {self.data.__len__()} " f"and length {self.data.__len__()} "
f"overflows section {self.memory.type.name}" f"overflows section {self.memory.type.name}"
@ -75,7 +75,7 @@ class FirmwareFile:
bin_content = list(f.read()) bin_content = list(f.read())
self.segments.append(Segment(offset=0, data=bin_content, sections=sections)) self.segments.append(Segment(offset=0, data=bin_content, sections=sections))
else: 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]): def _parse_hex(self, lines: List[str], sections: List[MemorySection]):
segments: List[Segment] = [] segments: List[Segment] = []

View File

@ -7,13 +7,14 @@ import time
from typing import List, Union from typing import List, Union
from mik32_debug_hal.power_manager import pm_init 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 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 import mik32_debug_hal.ram as ram
from hex_parser import FirmwareFile, MemoryType, Segment from hex_parser import FirmwareFile, MemoryType, Segment
from tclrpc import OpenOcdTclRpc, TclException 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( def upload_file(
@ -63,7 +64,7 @@ def upload_file(
logging.debug("OpenOCD started!") logging.debug("OpenOCD started!")
except OSError as e: except OSError as e:
raise OpenOCDStartupException(e) raise OpenOCDError(e)
try: try:
with OpenOcdTclRpc(host, port) as openocd: with OpenOcdTclRpc(host, port) as openocd:
if (all(openocd_interface.find(i) == -1 for i in adapter_speed_not_supported)): 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!") logging.debug("PM configured!")
if (pages.pages_eeprom.__len__() > 0): if (pages.pages_eeprom.__len__() > 0):
eeprom = EEPROM(openocd)
start_time = time.perf_counter() start_time = time.perf_counter()
result |= eeprom.check_pages( 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)") 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): if (pages.pages_spifi.__len__() > 0):
gpio_init(openocd, mik_version) gpio_init(openocd, mik_version)
spifi = SPIFI(openocd)
flash = GenericFlash(spifi)
start_time = time.perf_counter() start_time = time.perf_counter()
result |= spifi.check_pages( result |= flash.check_pages(
pages.pages_spifi, openocd, use_quad_spi=use_quad_spi) pages.pages_spifi, use_quad_spi=use_quad_spi)
write_time = time.perf_counter() - start_time write_time = time.perf_counter() - start_time
write_size = pages.pages_spifi.__len__( 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.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.dma as dma_fields 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. Разрешить читать текущий статус канала # ReadStatus. Разрешить читать текущий статус канала
class CurrentValue(Enum): class CurrentValue(Enum):
ENABLE = 0 # Текущие значения ENABLE = 0 # Текущие значения
@ -201,4 +210,4 @@ class DMA:
if self.get_control() & mask != 0: if self.get_control() & mask != 0:
return return
raise Exception raise DmaError

View File

@ -1,273 +1,16 @@
import datetime
from enum import Enum from enum import Enum
import os import os
import pathlib import pathlib
import sys import sys
from typing import Dict, List, Tuple from typing import Dict, List
import time import time
from tclrpc import OpenOcdTclRpc from tclrpc import OpenOcdTclRpc, TclException
from utils import bytes2words from utils import bytes2words
import mik32_debug_hal.registers.memory_map as mem_map import mik32_debug_hal.registers.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.eeprom as eeprom_fields 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]: def combine_pages(pages: Dict[int, List[int]]) -> List[int]:
""" """
Объединить страницы в последовательность байт с заполнением промежутков Объединить страницы в последовательность байт с заполнением промежутков
@ -287,57 +30,270 @@ def combine_pages(pages: Dict[int, List[int]]) -> List[int]:
return bytes_list return bytes_list
def write_memory(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, driver_path: str) -> int: class EEPROM():
""" openocd: OpenOcdTclRpc
Записать всю память с использованием драйвера.
pages: Dict[int, List[int]] -- страница - список байт, ключ - адрес в EEPROM def __init__(self, openocd: OpenOcdTclRpc):
""" self.openocd = openocd
# TODO: добавить проверку на версию mik32 - текущий драйвер поддерживает self.eeprom_sysinit()
# только версию mik32v2
bytes_list = combine_pages(pages) def eeprom_sysinit(self):
openocd.halt() print("MCU clock init...", flush=True)
openocd.run("riscv.cpu set_reg {mstatus 0 mie 0}") # Отключение прерываний
STATUS_CODE_M = 0xFF class EEPROM_Operation(Enum):
READ = eeprom_fields.OP_RD
ERASE = eeprom_fields.OP_ER
PROGRAM = eeprom_fields.OP_PR
max_address = len(bytes_list) // 128 class EEPROM_AffectedPages(Enum):
openocd.write_memory(0x02003800, 32, [1 | (max_address << 8)]) SINGLE = 0
EVEN = eeprom_fields.BEH_EVEN
ODD = eeprom_fields.BEH_ODD
GLOBAL = eeprom_fields.BEH_GLOB
pathname = os.path.dirname(sys.argv[0]) def eeprom_execute_operation(self, op: EEPROM_Operation, affected_pages: EEPROM_AffectedPages, offset: int, buffer: List[int]):
openocd.run("wp 0x2003800 4 w") # готовимся поймать результат записи # 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)])
print("Uploading driver... ", end="", flush=True) if buffer.__len__() > 32:
openocd.run(f"load_image {{{pathlib.Path(driver_path)}}}") return
print("OK!", flush=True) 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)
))
print("Uploading data... ", end="", flush=True) def eeprom_configure_cycles(self, LD=1, R_1=2, R_2=1, CYCEP1=66667, CYCEP2=500):
openocd.write_memory(0x02001800, 8, bytes_list) self.openocd.write_word(mem_map.EEPROM_REGS_NCYCRL, LD << eeprom_fields.NCYCRL_N_LD_S |
print("OK!", flush=True) 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)
print("Run driver...", flush=True) def eeprom_global_erase(self):
openocd.resume(0x2000000) print("EEPROM global erase...", flush=True)
# configure cycles duration
self.eeprom_execute_operation(
self.EEPROM_Operation.ERASE, self.EEPROM_AffectedPages.GLOBAL, 0x0, [0] * 32)
wait_halted(openocd, 10) # ждем, когда watchpoint сработает def eeprom_global_erase_check(self):
openocd.run("rwp 0x02003800") # watchpoint ловит до изменения слова print("EEPROM global erase check through APB...", flush=True)
openocd.run("step") # делаем шаг, чтобы прочитать новое слово 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)
result = openocd.read_memory(0x2003800, 32, 1)[0] 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)
if (result & 0xFF) == 0: def eeprom_write_page(self, address: int, data: List[int]):
print(f"EEPROM writing successfully completed!", flush=True) self.eeprom_execute_operation(
else: self.EEPROM_Operation.PROGRAM, self.EEPROM_AffectedPages.SINGLE, address, data)
miss_page = (result >> 8) & (64 - 1) time.sleep(0.001)
miss_byte = (result >> 16) & (128 - 1)
expected_byte = pages[miss_page*128][miss_byte]
miss_byte = (result >> 24) & 0xFF
print(f"EEPROM writing failed!", flush=True) def eeprom_check_data_apb(self, words: List[int], offset: int, print_progress=True) -> int:
print(f"First mismatched byte in page {miss_page},") if print_progress:
print(f"byte {miss_byte}, expected {expected_byte}, read {miss_byte}") 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
return 1 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
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:
"""
Записать всю память с использованием драйвера.
pages: Dict[int, List[int]] -- страница - список байт, ключ - адрес в 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}")
STATUS_CODE_M = 0xFF
max_address = len(bytes_list) // 128
self.openocd.write_memory(RAM_DRIVER_STATUS, 32, [
1 | (max_address << 8)])
pathname = os.path.dirname(sys.argv[0])
print("Uploading driver... ", end="", flush=True)
self.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:
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)
try:
# ждем, когда watchpoint сработает
self.wait_halted(10)
except TclException:
print("Timeout!", flush=True)
# return 1
# watchpoint ловит до изменения слова
self.openocd.run(f"rwp 0x{RAM_DRIVER_STATUS:08x}")
# делаем шаг, чтобы прочитать новое слово
self.openocd.run("step")
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)
miss_byte = (result >> 16) & (128 - 1)
expected_byte = pages[miss_page*128][miss_byte]
miss_byte = (result >> 24) & 0xFF
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}")
return 1
return 0

View File

@ -4,30 +4,82 @@ import mik32_debug_hal.registers.bitfields.power_manager as pm_fields
import mik32_debug_hal.registers.bitfields.wakeup as wake_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
AHB_default = ( Возвращаемое значение:
pm_fields.CLOCK_AHB_CPU_M | 0 - успех
pm_fields.CLOCK_AHB_EEPROM_M | 1 - ошибка
pm_fields.CLOCK_AHB_RAM_M | """
pm_fields.CLOCK_AHB_SPIFI_M |
pm_fields.CLOCK_AHB_TCB_M |
pm_fields.CLOCK_AHB_DMA_M
)
# 0x1F
APB_M_default = (
pm_fields.CLOCK_APB_M_PM_M |
pm_fields.CLOCK_APB_M_PAD_CONFIG_M |
pm_fields.CLOCK_APB_M_WU_M
)
# 0x89
APB_P_default = pm_fields.CLOCK_APB_P_GPIO_2_M
# 0x00
openocd.halt() iter = 1
openocd.write_word(mem_map.WU_CLOCKS_BU_OFFSET, WU_CLOCKS_default) max_iter = 2 # число попыток записи регистров
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) while True:
openocd.write_word(mem_map.PM_Clk_AHB_Set_OFFSET, AHB_default) print('Clock init... ', end='')
# определение начальных значений регистров
APB_P_default = 0
AHB_default = (
pm_fields.CLOCK_AHB_CPU_M |
pm_fields.CLOCK_AHB_EEPROM_M |
pm_fields.CLOCK_AHB_RAM_M |
pm_fields.CLOCK_AHB_SPIFI_M |
pm_fields.CLOCK_AHB_TCB_M |
pm_fields.CLOCK_AHB_DMA_M
)
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
)
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)

View File

@ -49,8 +49,11 @@ SPIFI_CONFIG_STAT = SPIFI_REGS + 0x01C
PM_REGS = 0x000050000 PM_REGS = 0x000050000
PM_Clk_AHB_Set_OFFSET = PM_REGS + 0x0C 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_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_Set_OFFSET = PM_REGS + 0x1C
PM_Clk_APB_P_Clear_OFFSET = PM_REGS + 0x20
# -------------------------- # --------------------------
@ -66,28 +69,31 @@ WU_CLOCKS_BU_OFFSET = WU_REGS + 0x10
# -------------------------- # --------------------------
PAD_CONFIG_REGS = 0x00050C00 PAD_CONFIG_REGS = 0x00050C00
class PAD_CONFIG_REGS_V0(Enum): class PAD_CONFIG_REGS_V0(Enum):
PORT_0_CFG = 0x00 PORT_0_CFG = 0x00
PORT_1_CFG = 0x04 PORT_1_CFG = 0x04
PORT_2_CFG = 0x08 PORT_2_CFG = 0x08
PORT_0_DS = 0x0C PORT_0_DS = 0x0C
PORT_1_DS = 0x10 PORT_1_DS = 0x10
PORT_2_DS = 0x14 PORT_2_DS = 0x14
PORT_0_PUD = 0x18 PORT_0_PUD = 0x18
PORT_1_PUD = 0x1C PORT_1_PUD = 0x1C
PORT_2_PUD = 0x20 PORT_2_PUD = 0x20
class PAD_CONFIG_REGS_V2(Enum): class PAD_CONFIG_REGS_V2(Enum):
PORT_0_CFG = 0x00 PORT_0_CFG = 0x00
PORT_0_DS = 0x04 PORT_0_DS = 0x04
PORT_0_PUD = 0x08 PORT_0_PUD = 0x08
PORT_1_CFG = 0x0C PORT_1_CFG = 0x0C
PORT_1_DS = 0x10 PORT_1_DS = 0x10
PORT_1_PUD = 0x14 PORT_1_PUD = 0x14
PORT_2_CFG = 0x18 PORT_2_CFG = 0x18
PORT_2_DS = 0x1C PORT_2_DS = 0x1C
PORT_2_PUD = 0x20 PORT_2_PUD = 0x20
# -------------------------- # --------------------------
# EEPROM register offset # EEPROM register offset
# -------------------------- # --------------------------

View File

@ -1,447 +1,214 @@
import datetime
from enum import Enum from enum import Enum
import os from typing import List, Union
import pathlib
import sys
from typing import Dict, List, Union
import time import time
from tclrpc import TclException
from tclrpc import OpenOcdTclRpc from tclrpc import OpenOcdTclRpc
import mik32_debug_hal.registers.memory_map as mem_map import mik32_debug_hal.registers.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.spifi as spifi_fields import mik32_debug_hal.registers.bitfields.spifi as spifi_fields
import mik32_debug_hal.dma as dma import mik32_debug_hal.dma as dma
import flash_drivers.generic_flash as generic_flash
def spifi_intrq_clear(openocd: OpenOcdTclRpc): class SPIFI():
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
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))
class Frameform(Enum):
RESERVED = 0
OPCODE_NOADDR = 1
OPCODE_1ADDR = 2
OPCODE_2ADDR = 3
OPCODE_3ADDR = 4
OPCODE_4ADDR = 5
NOOPCODE_3ADDR = 6
NOOPCODE_4ADDR = 7
def init_periphery(openocd: OpenOcdTclRpc): class Fieldform(Enum):
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | ALL_SERIAL = 0
# SPIFI_CONFIG_STAT_INTRQ_M | DATA_PARALLEL = 1
spifi_fields.SPIFI_CONFIG_STAT_RESET_M) OPCODE_SERIAL = 2
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word( ALL_PARALLEL = 3
# 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) class Direction(Enum):
READ = 0
WRITE = 1
INIT_DELAY = 0.001
def init(openocd: OpenOcdTclRpc): TIMEOUT = 1.0
print("MCU clock init", flush=True)
init_periphery(openocd) openocd: OpenOcdTclRpc
control = openocd.read_word(mem_map.SPIFI_CONFIG_CTRL) def __init__(self, openocd: OpenOcdTclRpc):
control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M self.openocd = openocd
openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control)
time.sleep(INIT_DELAY) 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_memory(openocd: OpenOcdTclRpc): def init_periphery(self):
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) | 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_CONFIG_STAT_INTRQ_M |
spifi_fields.SPIFI_CONFIG_STAT_RESET_M) spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word( # openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)) # SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00) self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00) self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00) self.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) time.sleep(self.INIT_DELAY)
def init(self):
def spifi_wait_intrq_timeout(openocd: OpenOcdTclRpc, error_message: str): self.init_periphery()
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)
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)
class Frameform(Enum): time.sleep(self.INIT_DELAY)
RESERVED = 0
OPCODE_NOADDR = 1
OPCODE_1ADDR = 2
OPCODE_2ADDR = 3
OPCODE_3ADDR = 4
OPCODE_4ADDR = 5
NOOPCODE_3ADDR = 6
NOOPCODE_4ADDR = 7
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))
class Fieldform(Enum): time.sleep(self.INIT_DELAY)
ALL_SERIAL = 0
DATA_PARALLEL = 1
OPCODE_SERIAL = 2
ALL_PARALLEL = 3
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)
class Direction(Enum): def send_command(
READ = 0 self,
WRITE = 1 cmd: int,
frameform: Frameform,
fieldform: Fieldform,
byte_count=0,
address=0,
idata=0,
cache_limit=0,
idata_length=0,
direction=Direction.READ,
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)
dma.channels[0].start(
0x02003F00,
mem_map.SPIFI_CONFIG_DATA32,
255
)
elif (dma is not None) and (direction == self.Direction.READ):
dma.channels[1].start(
mem_map.SPIFI_CONFIG_DATA32,
0x02003F00,
255
)
def send_command( self.openocd.write_memory(
openocd: OpenOcdTclRpc, mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata])
cmd: int,
frameform: Frameform,
fieldform: Fieldform,
byte_count=0,
address=0,
idata=0,
cache_limit=0,
idata_length=0,
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)
dma.channels[0].start( cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) |
0x02003F00, (frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) |
mem_map.SPIFI_CONFIG_DATA32, (fieldform.value << spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_S) |
255 (byte_count << spifi_fields.SPIFI_CONFIG_CMD_DATALEN_S) |
) (idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) |
elif (dma is not None) and (direction == Direction.READ): (direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S))
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_CMD, 32, [cmd_write_value])
cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) | if direction == self.Direction.READ:
(frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) | out_list = []
(fieldform.value << spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_S) | if dma is not None:
(byte_count << spifi_fields.SPIFI_CONFIG_CMD_DATALEN_S) | dma.dma_wait(dma.channels[1], 0.1)
(idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) | out_list.extend(self.openocd.read_memory(
(direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S)) 0x02003F00, 8, byte_count))
openocd.write_memory(mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value]) return out_list
if direction == Direction.READ:
out_list = []
if dma is not None:
dma.dma_wait(dma.channels[1], 0.1)
out_list.extend(openocd.read_memory(0x02003F00, 8, byte_count))
return out_list
else:
for i in range(byte_count):
out_list.append(openocd.read_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0])
return out_list
if direction == Direction.WRITE:
if dma is not None:
dma.dma_wait(dma.channels[0], 0.1)
else:
if (byte_count % 4) == 0:
for i in range(0, byte_count, 4):
openocd.write_memory(mem_map.SPIFI_CONFIG_DATA32, 32, [
data[i] + data[i+1] * 256 + data[i+2] * 256 * 256 + data[i+3] * 256 * 256 * 256])
else: else:
for i in range(byte_count): for i in range(byte_count):
openocd.write_memory( out_list.append(self.openocd.read_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]]) mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0])
return out_list
return [] if direction == self.Direction.WRITE:
if dma is not None:
dma.dma_wait(dma.channels[0], 0.1)
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
dma_instance.channels[0].channel = dma.ChannelIndex.CHANNEL_0
dma_instance.channels[0].priority = dma.ChannelPriority.VERY_HIGH
dma_instance.channels[0].read_mode = dma.ChannelMode.MEMORY
dma_instance.channels[0].read_increment = dma.ChannelIncrement.ENABLE
dma_instance.channels[0].read_size = dma.ChannelSize.WORD
dma_instance.channels[0].read_burst_size = 2
dma_instance.channels[0].read_request = dma.ChannelRequest.SPIFI_REQUEST
dma_instance.channels[0].read_ack = dma.ChannelAck.DISABLE
dma_instance.channels[0].write_mode = dma.ChannelMode.PERIPHERY
dma_instance.channels[0].write_increment = dma.ChannelIncrement.DISABLE
dma_instance.channels[0].write_size = dma.ChannelSize.WORD
dma_instance.channels[0].write_burst_size = 2
dma_instance.channels[0].write_request = dma.ChannelRequest.SPIFI_REQUEST
dma_instance.channels[0].write_ack = dma.ChannelAck.DISABLE
dma_instance.channels[1].write_buffer = 0
dma_instance.channels[1].channel = dma.ChannelIndex.CHANNEL_1
dma_instance.channels[1].priority = dma.ChannelPriority.VERY_HIGH
dma_instance.channels[1].write_mode = dma.ChannelMode.MEMORY
dma_instance.channels[1].write_increment = dma.ChannelIncrement.ENABLE
dma_instance.channels[1].write_size = dma.ChannelSize.WORD
dma_instance.channels[1].write_burst_size = 2
dma_instance.channels[1].write_request = dma.ChannelRequest.SPIFI_REQUEST
dma_instance.channels[1].write_ack = dma.ChannelAck.DISABLE
dma_instance.channels[1].read_mode = dma.ChannelMode.PERIPHERY
dma_instance.channels[1].read_increment = dma.ChannelIncrement.DISABLE
dma_instance.channels[1].read_size = dma.ChannelSize.WORD
dma_instance.channels[1].read_burst_size = 2
dma_instance.channels[1].read_request = dma.ChannelRequest.SPIFI_REQUEST
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: else:
bytes_list.extend([0]*256) if (byte_count % 4) == 0:
for i in range(0, byte_count, 4):
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):
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]])
openocd.write_memory(0x02002000, 8, bytes_list) return []
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] def dma_config(self) -> dma.DMA:
dma_instance = dma.DMA(self.openocd)
dma_instance.init()
if result == 0: dma_instance.channels[0].write_buffer = 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") dma_instance.channels[0].channel = dma.ChannelIndex.CHANNEL_0
init_memory(openocd) dma_instance.channels[0].priority = dma.ChannelPriority.VERY_HIGH
if result == 0: dma_instance.channels[0].read_mode = dma.ChannelMode.MEMORY
# Прошивка страниц флеш памяти по SPIFI была завершена dma_instance.channels[0].read_increment = dma.ChannelIncrement.ENABLE
print("SPIFI writing successfully completed!", flush=True) dma_instance.channels[0].read_size = dma.ChannelSize.WORD
else: dma_instance.channels[0].read_burst_size = 2
print(f"SPIFI writing failed!", flush=True) dma_instance.channels[0].read_request = dma.ChannelRequest.SPIFI_REQUEST
return 1 dma_instance.channels[0].read_ack = dma.ChannelAck.DISABLE
return result dma_instance.channels[0].write_mode = dma.ChannelMode.PERIPHERY
dma_instance.channels[0].write_increment = dma.ChannelIncrement.DISABLE
dma_instance.channels[0].write_size = dma.ChannelSize.WORD
dma_instance.channels[0].write_burst_size = 2
dma_instance.channels[0].write_request = dma.ChannelRequest.SPIFI_REQUEST
dma_instance.channels[0].write_ack = dma.ChannelAck.DISABLE
dma_instance.channels[1].write_buffer = 0
dma_instance.channels[1].channel = dma.ChannelIndex.CHANNEL_1
dma_instance.channels[1].priority = dma.ChannelPriority.VERY_HIGH
dma_instance.channels[1].write_mode = dma.ChannelMode.MEMORY
dma_instance.channels[1].write_increment = dma.ChannelIncrement.ENABLE
dma_instance.channels[1].write_size = dma.ChannelSize.WORD
dma_instance.channels[1].write_burst_size = 2
dma_instance.channels[1].write_request = dma.ChannelRequest.SPIFI_REQUEST
dma_instance.channels[1].write_ack = dma.ChannelAck.DISABLE
dma_instance.channels[1].read_mode = dma.ChannelMode.PERIPHERY
dma_instance.channels[1].read_increment = dma.ChannelIncrement.DISABLE
dma_instance.channels[1].read_size = dma.ChannelSize.WORD
dma_instance.channels[1].read_burst_size = 2
dma_instance.channels[1].read_request = dma.ChannelRequest.SPIFI_REQUEST
dma_instance.channels[1].read_ack = dma.ChannelAck.DISABLE
return dma_instance

View File

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

View File

@ -8,15 +8,18 @@ proc init_targets {} {
set _CHIPNAME riscv set _CHIPNAME riscv
set _CPUTAPID 0xdeb11001 set _CPUTAPID 0xdeb11001
set _SYSTAPID 0xfffffffe
jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID 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 set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -endian little -chain-position $_TARGETNAME -coreid 0 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 riscv.cpu configure -event reset-init my_init_proc
} }

View File

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

View File

@ -5,6 +5,14 @@ from enum import Enum
from typing import List 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): class RecordType(Enum):
UNKNOWN = -1 UNKNOWN = -1
DATA = 0 DATA = 0
@ -24,14 +32,14 @@ class Record:
def parse_line(line: str, line_n: int, file_extension: str) -> Record: def parse_line(line: str, line_n: int, file_extension: str) -> Record:
if file_extension != ".hex": 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) return parse_hex_line(line, line_n)
def parse_hex_line(line: str, line_n: int) -> Record: def parse_hex_line(line: str, line_n: int) -> Record:
if line[0] != ':': 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])) line_n, line, line[0]))
datalen = int(line[1:3], base=16) # Data field length 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]) 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)) 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: 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, []) 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)) # record.data = list(map(lambda x: int(x, base=16), splitted_by_bytes))
elif rectype == 4: # Extended Linear Address Record elif rectype == 4: # Extended Linear Address Record
record.type = RecordType.EXTADDR 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 elif rectype == 5: # Start Linear Address Record
record.type = RecordType.LINEARSTARTADDR record.type = RecordType.LINEARSTARTADDR
address = 0 address = 0

View File

@ -11,7 +11,14 @@ class TclException(Exception):
self.msg = msg self.msg = msg
def __repr__(self): 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:+./@=,'-]+$") _RE_SIMPLE_TCL_WORD = re.compile(r"^[a-zA-Z_0-9:+./@=,'-]+$")
def tcl_quote_word(word): def tcl_quote_word(word):
@ -85,7 +92,7 @@ class OpenOcdTclRpc:
index = data.find(self.SEPARATOR_BYTES) index = data.find(self.SEPARATOR_BYTES)
if index >= 0: if index >= 0:
if index != len(data) - 1: 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] return data[:-1]
def wait_for_port(self, timeout: float = 5.0): def wait_for_port(self, timeout: float = 5.0):

View File

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

View File

@ -12,4 +12,4 @@
platform = MIK32 platform = MIK32
board = mik32v2 board = mik32v2
framework = framework-mik32v2-sdk 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_S 0
#define STATUS_CODE_M 0xFF
#define STATUS_CODE(X) ((X) << STATUS_CODE_S) #define STATUS_CODE(X) ((X) << STATUS_CODE_S)
#define STATUS_CODE_OK 0 #define STATUS_CODE_OK 0
@ -51,6 +52,14 @@ int main()
xprintf("START DRIVER\n"); xprintf("START DRIVER\n");
#endif #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 = { HAL_EEPROM_HandleTypeDef heeprom = {
.Instance = EEPROM_REGS, .Instance = EEPROM_REGS,
}; };
@ -102,6 +111,8 @@ debugger_return:
*BUFFER_STATUS = result; *BUFFER_STATUS = result;
// asm ("wfi"); // asm ("wfi");
final_loop:
while (1) while (1)
; ;
} }

View File

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

View File

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