mirror of
https://github.com/MikronMIK32/mik32-uploader.git
synced 2026-01-01 21:37:05 +03:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edd479f953 | ||
|
|
044abedcc9 | ||
|
|
49532c7df7 | ||
|
|
7a02683c4d | ||
|
|
9f13695d6b | ||
|
|
92a2b7be18 | ||
|
|
9a36170cea | ||
|
|
0f156e9dad | ||
|
|
c1e7f9bdc9 | ||
|
|
9bec497601 | ||
|
|
d55a5242a8 | ||
|
|
298d46acd4 | ||
|
|
304469890b | ||
|
|
2d5a23268f | ||
|
|
c5950bfa4f | ||
|
|
d3ae56eff5 | ||
|
|
3f35886f66 | ||
|
|
89732a8df1 | ||
|
|
31d3eecaa9 | ||
|
|
329c230337 | ||
|
|
328112232c | ||
|
|
5135347032 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
2
.piopm
@ -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}}
|
||||||
24
CHANGELOG.md
24
CHANGELOG.md
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
applicaton_version = 'v0.3.1'
|
applicaton_version = 'v0.3.3'
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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] = []
|
||||||
|
|||||||
@ -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__(
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
# --------------------------
|
# --------------------------
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
20
parsers.py
20
parsers.py
@ -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
|
||||||
|
|||||||
11
tclrpc.py
11
tclrpc.py
@ -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):
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user