mik32-uploader/mik32_debug_hal/spifi.py
sh-sergey 9bec497601 переработка eeprom и spifi
функции сгруппированы в классы, для spifi улучшено разделение функционала между контроллерами интерфейса и флеш памяти
2025-01-16 16:21:35 +03:00

215 lines
8.5 KiB
Python

from enum import Enum
from typing import List, Union
import time
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
class SPIFI():
DEFAULT_READ_DATA_COMMAND = 0x03
class SpifiError(Exception):
def __init__(self, value):
self.value = value
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
class Fieldform(Enum):
ALL_SERIAL = 0
DATA_PARALLEL = 1
OPCODE_SERIAL = 2
ALL_PARALLEL = 3
class Direction(Enum):
READ = 0
WRITE = 1
INIT_DELAY = 0.001
TIMEOUT = 1.0
openocd: OpenOcdTclRpc
def __init__(self, openocd: OpenOcdTclRpc):
self.openocd = openocd
self.init()
def intrq_clear(self):
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M)
def init_periphery(self):
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
# SPIFI_CONFIG_STAT_INTRQ_M |
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
time.sleep(self.INIT_DELAY)
def init(self):
self.init_periphery()
control = self.openocd.read_word(mem_map.SPIFI_CONFIG_CTRL)
control |= spifi_fields.SPIFI_CONFIG_CTRL_DMAEN_M
self.openocd.write_word(mem_map.SPIFI_CONFIG_CTRL, control)
time.sleep(self.INIT_DELAY)
def init_memory(self):
self.openocd.write_word(mem_map.SPIFI_CONFIG_STAT, self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) |
spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M |
spifi_fields.SPIFI_CONFIG_STAT_RESET_M)
# openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
# SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
self.openocd.write_word(mem_map.SPIFI_CONFIG_ADDR, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_IDATA, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_CLIMIT, 0x00)
self.openocd.write_word(mem_map.SPIFI_CONFIG_MCMD, (0 << spifi_fields.SPIFI_CONFIG_MCMD_INTLEN_S) |
(spifi_fields.SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL << spifi_fields.SPIFI_CONFIG_MCMD_FIELDFORM_S) |
(spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR << spifi_fields.SPIFI_CONFIG_MCMD_FRAMEFORM_S) |
(self.DEFAULT_READ_DATA_COMMAND << spifi_fields.SPIFI_CONFIG_MCMD_OPCODE_S))
time.sleep(self.INIT_DELAY)
def spifi_wait_intrq_timeout(self, error_message: str):
time_end = time.perf_counter() + self.TIMEOUT
while time.perf_counter() < time_end:
if (self.openocd.read_word(mem_map.SPIFI_CONFIG_STAT) & spifi_fields.SPIFI_CONFIG_STAT_INTRQ_M) != 0:
return
raise self.SpifiError(error_message)
def send_command(
self,
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
)
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_ADDR, 32, [address, idata])
cmd_write_value = ((cmd << spifi_fields.SPIFI_CONFIG_CMD_OPCODE_S) |
(frameform.value << spifi_fields.SPIFI_CONFIG_CMD_FRAMEFORM_S) |
(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))
self.openocd.write_memory(
mem_map.SPIFI_CONFIG_CMD, 32, [cmd_write_value])
if direction == self.Direction.READ:
out_list = []
if dma is not None:
dma.dma_wait(dma.channels[1], 0.1)
out_list.extend(self.openocd.read_memory(
0x02003F00, 8, byte_count))
return out_list
else:
for i in range(byte_count):
out_list.append(self.openocd.read_memory(
mem_map.SPIFI_CONFIG_DATA32, 8, 1)[0])
return out_list
if direction == self.Direction.WRITE:
if dma is not None:
dma.dma_wait(dma.channels[0], 0.1)
else:
if (byte_count % 4) == 0:
for i in range(0, byte_count, 4):
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]])
return []
def dma_config(self) -> dma.DMA:
dma_instance = dma.DMA(self.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