From 97f8db871c537091cd1bceeca638145d0e41a0e2 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 25 Jul 2024 01:41:27 +0000 Subject: [PATCH] applet.memory.25x: use QSPI controller instead of SPI. This makes it possible to use higher transfer rates, at the cost of WP# and HOLD# pins becoming mandatory. --- .../interface/qspi_controller/__init__.py | 9 ++--- .../glasgow/applet/memory/_25x/__init__.py | 33 +++++++------------ software/glasgow/applet/memory/_25x/test.py | 11 +++---- 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/software/glasgow/applet/interface/qspi_controller/__init__.py b/software/glasgow/applet/interface/qspi_controller/__init__.py index f37349329..b5b6b4c56 100644 --- a/software/glasgow/applet/interface/qspi_controller/__init__.py +++ b/software/glasgow/applet/interface/qspi_controller/__init__.py @@ -233,12 +233,13 @@ class QSPIControllerApplet(GlasgowApplet): """ @classmethod - def add_build_arguments(cls, parser, access): + def add_build_arguments(cls, parser, access, *, include_pins=True): super().add_build_arguments(parser, access) - access.add_pin_argument(parser, "sck", default=True) - access.add_pin_set_argument(parser, "io", width=4, default=True) - access.add_pin_set_argument(parser, "cs", width=1, default=True) + if include_pins: + access.add_pin_argument(parser, "sck", default=True) + access.add_pin_set_argument(parser, "io", width=4, default=True) + access.add_pin_set_argument(parser, "cs", width=1, default=True) # Most devices that advertise QSPI support should work at 1 MHz. parser.add_argument( diff --git a/software/glasgow/applet/memory/_25x/__init__.py b/software/glasgow/applet/memory/_25x/__init__.py index 6c0125a4c..db4ebd588 100644 --- a/software/glasgow/applet/memory/_25x/__init__.py +++ b/software/glasgow/applet/memory/_25x/__init__.py @@ -11,7 +11,7 @@ from ....support.logging import dump_hex from ....database.jedec import * from ....protocol.sfdp import * -from ...interface.spi_controller import SPIControllerApplet +from ...interface.qspi_controller import QSPIControllerApplet from ... import * @@ -236,7 +236,7 @@ async def read(self, offset, length): return await self._m25x_iface.read_sfdp(offset, length) -class Memory25xApplet(SPIControllerApplet): +class Memory25xApplet(QSPIControllerApplet): logger = logging.getLogger(__name__) help = "read and write 25-series SPI Flash memories" description = """ @@ -272,22 +272,11 @@ class Memory25xApplet(SPIControllerApplet): @classmethod def add_build_arguments(cls, parser, access): - super().add_build_arguments(parser, access, omit_pins=True) - - access.add_pin_argument(parser, "cs", default=True, required=True) - access.add_pin_argument(parser, "cipo", default=True, required=True) - access.add_pin_argument(parser, "wp", default=True) - access.add_pin_argument(parser, "copi", default=True, required=True) - access.add_pin_argument(parser, "sck", default=True, required=True) - access.add_pin_argument(parser, "hold", default=True) - - def build_subtarget(self, target, args): - subtarget = super().build_subtarget(target, args) - if args.pin_hold is not None: - hold_t = self.mux_interface.get_deprecated_pad(args.pin_hold) - else: - hold_t = None - return Memory25xSubtarget(subtarget, hold_t) + super().add_build_arguments(parser, access, include_pins=False) + + access.add_pin_set_argument(parser, "cs", width=1, required=True, default=[5]) + access.add_pin_set_argument(parser, "io", width=4, required=True, default=[2, 4, 3, 0]) + access.add_pin_argument( parser, "sck", required=True, default=1) async def run(self, device, args): spi_iface = await self.run_lower(Memory25xApplet, device, args) @@ -456,10 +445,10 @@ async def interact(self, device, args, m25x_iface): if args.operation in ("read", "fast-read"): if args.operation == "read": data = await m25x_iface.read(args.address, args.length, - callback=self._show_progress) + callback=self._show_progress) if args.operation == "fast-read": data = await m25x_iface.fast_read(args.address, args.length, - callback=self._show_progress) + callback=self._show_progress) if args.file: args.file.write(data) @@ -478,10 +467,10 @@ async def interact(self, device, args, m25x_iface): await m25x_iface.page_program(args.address, data) if args.operation == "program": await m25x_iface.program(args.address, data, args.page_size, - callback=self._show_progress) + callback=self._show_progress) if args.operation == "erase-program": await m25x_iface.erase_program(args.address, data, args.sector_size, - args.page_size, callback=self._show_progress) + args.page_size, callback=self._show_progress) if args.operation == "verify": if args.data is not None: diff --git a/software/glasgow/applet/memory/_25x/test.py b/software/glasgow/applet/memory/_25x/test.py index 8c572ef1d..7eef9e06b 100644 --- a/software/glasgow/applet/memory/_25x/test.py +++ b/software/glasgow/applet/memory/_25x/test.py @@ -7,15 +7,14 @@ class Memory25xAppletTestCase(GlasgowAppletTestCase, applet=Memory25xApplet): @synthesis_test def test_build(self): - self.assertBuilds(args=["--pin-sck", "0", "--pin-cs", "1", - "--pin-copi", "2", "--pin-cipo", "3"]) + self.assertBuilds() # Flash used for testing: Winbond 25Q32FV hardware_args = [ - "--voltage", "3.3", - "--pin-cs", "0", "--pin-cipo", "1", - "--pin-copi", "2", "--pin-sck", "3", - "--pin-hold", "4" + "--voltage", "3.3", + "--pin-sck", "0", + "--pins-io", "1:4", + "--pins-cs", "5", ] dut_ids = (0xef, 0x15, 0x4016) dut_page_size = 0x100