mik32-uploader/mik32_debug_hal/spifi.py

444 lines
15 KiB
Python

import datetime
from enum import Enum
import os
import pathlib
import sys
from typing import Dict, List, Union
import time
from tclrpc import TclException
from tclrpc import OpenOcdTclRpc
import mik32_debug_hal.registers.memory_map as mem_map
import mik32_debug_hal.registers.bitfields.spifi as spifi_fields
import mik32_debug_hal.dma as dma
import flash_drivers.generic_flash as generic_flash
def spifi_intrq_clear(openocd: OpenOcdTclRpc):
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M)
INIT_DELAY = 0.001
TIMEOUT = 1.0
def init_periphery(openocd: OpenOcdTclRpc):
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
# SPIFI_CONFIG_STAT_INTRQ_M |
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
time.sleep(INIT_DELAY)
def init(openocd: OpenOcdTclRpc):
print("MCU clock init", flush=True)
init_periphery(openocd)
control = openocd.read_word(mem_map.SPIFI_CONFIG_CTRL)
control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M
openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control)
time.sleep(INIT_DELAY)
def init_memory(openocd: OpenOcdTclRpc):
openocd.write_word(mem_map.SPIFI_CONFIG_STAT, openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M |
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
openocd.write_word(mem_map.SPIFI_CONFIG_MCMD, (0 << spifi_fields.SPIFI_CONFIG_MCMD_INTLEN_S) |
(spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << spifi_fields.SPIFI_CONFIG_MCMD_FIELDFORM_S) |
(spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << spifi_fields.SPIFI_CONFIG_MCMD_FRAMEFORM_S) |
(generic_flash.READ_DATA_COMMAND << spifi_fields.SPIFI_CONFIG_MCMD_OPCODE_S))
time.sleep(INIT_DELAY)
def spifi_wait_intrq_timeout(openocd: OpenOcdTclRpc, error_message: str):
time_end = time.perf_counter() + TIMEOUT
while time.perf_counter() < time_end:
if (openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0:
return
raise Exception(error_message)
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
class Fieldform(Enum):
ALL_SERIAL = 0
DATA_PARALLEL = 1
OPCODE_SERIAL = 2
ALL_PARALLEL = 3
class Direction(Enum):
READ = 0
WRITE = 1
def send_command(
openocd: OpenOcdTclRpc,
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(
0x02003F00,
mem_map.SPIFI_CONFIG_DATA32,
255
)
elif (dma is not None) and (direction == Direction.READ):
dma.channels[1].start(
mem_map.SPIFI_CONFIG_DATA32,
0x02003F00,
255
)
openocd.write_memory(mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata])
cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) |
(frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) |
(fieldform.value << spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_S) |
(byte_count << spifi_fields.SPIFI_CONFIG_CMD_DATALEN_S) |
(idata_length << spifi_fields.SPIFI_CONFIG_CMD_INTLEN_S) |
(direction.value << spifi_fields.SPIFI_CONFIG_CMD_DOUT_S))
openocd.write_memory(mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value])
if direction == 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:
for i in range(byte_count):
openocd.write_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, [data[i]])
return []
def write(openocd: OpenOcdTclRpc, address: int, data: List[int], data_len: int):
if data_len > 256:
raise Exception("Byte count more than 256")
generic_flash.page_program(openocd, address, data, data_len)
print("written")
def write_file(bytes: List[int], openocd: OpenOcdTclRpc):
# print(bytes)
print(f"Write {len(bytes)} bytes")
openocd.halt()
init(openocd)
generic_flash.erase(openocd)
print("bin_data_len = ", len(bytes))
address = 0
for address in range(0, len(bytes), 256):
if ((address + 256) > len(bytes)):
break
print("address = ", address)
write(openocd, address, bytes, 256)
if generic_flash.read_data(openocd, address, 256, bytes) == 1:
return 1
if (len(bytes) % 256) != 0:
print(
f"address = {address}, +{len(bytes) - address-1}[{address + len(bytes) - address-1}]")
write(openocd, address, bytes, len(bytes) - address)
if generic_flash.read_data(openocd, address, len(bytes) - address, bytes) == 1:
return 1
print("end")
return 0
def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]:
segments = set()
for offset in pages_offsets:
segments.add(offset & ~(segment_size - 1))
return sorted(list(segments))
def dma_config(openocd: OpenOcdTclRpc) -> dma.DMA:
dma_instance = dma.DMA(openocd)
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()
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...", flush=True)
openocd.run("load_image {%s}" % pathlib.Path(driver_path))
openocd.resume(0x2000000)
wait_halted(openocd)
for i, sector in enumerate(sectors_list):
# print(f"Program sector {sector}", flush=True)
ByteAddress = sector
progress = f"{(i*100)//len(sectors_list)}%"
print(f"Writing Flash sector {ByteAddress:#010x}... {progress:>4}", end="", flush=True)
bytes_list: List[int] = []
for page in range(16):
page = pages.get(page * 256 + sector)
if page is not None:
bytes_list.extend(page)
else:
bytes_list.extend([0]*256)
openocd.write_memory(0x02002000, 8, bytes_list)
openocd.run(f"set_reg {{t6 {sector}}}")
openocd.resume()
wait_halted(openocd, 10) # ждем, когда watchpoint сработает
# watchpoint ловит до изменения слова
openocd.run("step") # делаем шаг, чтобы прочитать новое слово
result = openocd.read_memory(0x2003000, 32, 1)[0]
if result == 0:
print(" OK!", flush=True)
else:
print(" FAIL!", flush=True)
print("result =", result)
break
if result == 0:
print(f"Writing Flash sector {sectors_list[-1]:#010x}... 100% OK!", flush=True)
openocd.run("rwp 0x02003800")
init_memory(openocd)
if result == 0:
# Прошивка страниц флеш памяти по SPIFI была завершена
print("SPIFI writing successfully completed", flush=True)
else:
print(f"SPIFI writing failed!", flush=True)
return 1
return result