pybd_sf2w: Code fails when located in external flash
Background: micro-gui test scripts displayed nothing when located in external flash. The code was evidently running, but the screen was blank. The scripts displayed when the display driver was located in the filesystem with all the rest of the code in spi flash. With all code except the driver in the filesystem, the script worked correctly if the driver was frozen normally, but failed to display if the driver was located in external flash.
The workround is simply to put the (small) driver in the filesystem but the fault appears to be symptomatic of a firmware issue.
When failing, the SPI transfer which occurs on initialisation was garbled, occurring as short incorrect bursts in place of one long sequence. The following test script demos the problem. Note that occasionally it runs correctly, but it usually fails.
import framebuf
import time
import gc
from machine import Pin, SPI
pp = Pin('EN_3V3')
pp(1)
time.sleep(1)
pdc = Pin('X1', Pin.OUT_PP, value=0)
pcs = Pin('X2', Pin.OUT_PP, value=1)
prst = Pin('X6', Pin.OUT_PP, value=1)
spi = SPI(2, baudrate=2_000_000)
gc.collect() # Precaution before instantiating framebuf
class SSD1351(framebuf.FrameBuffer):
def __init__(self, spi, pincs, pindc, pinrs, height=128, width=128):
self.spi = spi
self.pincs = pincs
self.pindc = pindc # 1 = data 0 = cmd
self.height = height # Required by Writer class
self.width = width
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
gc.collect()
self.buffer = bytearray(self.height * self.width)
super().__init__(self.buffer, self.width, self.height, mode)
self.linebuf = bytearray(self.width * 2)
pinrs(0) # Pulse the reset line
time.sleep_ms(1)
pinrs(1)
time.sleep_ms(1)
self._write(b'\xfd\x12\xfd\xb1\xae\xb3\xf1\xca\x7f\xa0\x74'\
b'\x15\x00\x7f\x75\x00\x7f\xa1\x00\xa2\x00\xb5\x00\xab\x01'\
b'\xb1\x32\xbe\x05\xa6\xc1\xc8\x80\xc8\xc7\x0f'\
b'\xb4\xa0\xb5\x55\xb6\x01\xaf', 0)
pinrs(0) # For stand-alone test: pins are unconnected.
pinrs(1)
gc.collect()
time.sleep(1)
def _write(self, buf, dc):
self.pincs(1)
self.pindc(dc)
self.pincs(0)
self.spi.write(buf)
self.pincs(1)
ssd = SSD1351(spi, pcs, pdc, prst)
I am writing to external flash with the following change to f722_qspi.ld and doing a clean build. The Pyboard is attached to no external hardware.
/* Define output sections */
SECTIONS
{
.text_ext :
{
. = ALIGN(4);
*frozen_content.o(.text* .rodata*)
*lib/btstack/*(.text* .rodata*)
The following images show the behaviour where the transfer starts then prematurely terminates. No further data is transferred. Behaviour in the actual application is more complex, with further brief transfers with unexpected data occurring later.

For comparison this is the start of a successful run:

Zooming out of the failing run:

Firmware:
MicroPython v1.18-355-g9ab66b50c-dirty on 2022-04-29; PYBD-SF2W with STM32F722IEK
STM32: SPI.read(n) fails if n > 1 (regression)
This arose driving an EEPROM using hard SPI on Pyboard D hardware (soft SPI works OK). Baudrate was 5MHz, other args default. Hardware is a Pyboard D on a DIP28 adaptor on a small PCB with a pair of EEPROM chips on the bus. Traces are very short. This setup has worked in the past when developing this driver, and in fact still works with a Pyboard D SF2W running
MicroPython v1.18-355-g9ab66b50c-dirty on 2022-04-29; PYBD-SF2W with STM32F722IEK
With a Pyboard D SF6W running
MicroPython v1.22.1 on 2024-01-05; PYBD-SF6W with STM32F767IIK
it behaves as follows. A single byte read from an arbitrary address returns the correct contents, but a multi-byte read returns a bytes object of the correct length but containing zeros. To investigate the fault reading was done with a simple spi.read(n). The hardware was examined with an LA: the single byte and multi-byte reads were identical aside from the extra byte and conformed with the device spec. The MISO result for a 2-byte read was as follows:

The LA shows correct data being transmitted by the EEPROM but spi.read(2) returned b'\x00\x00'.