Design issues with Adafruit ImageReader, SPIFlash & SdFat libraries

I’d like to share a problem to do with the Adafruit ImageReader, SPIFLash & SdFat libraries that others may encounter. I have a solution for it but would rather see a better one from Adafruit or perhaps from someone else who may have come across the same issue.

Recently I’ve got hold of a Adafruit 2.4" TFT FeatherWing (ILI9341) with a builtin microSD and a Resistive Touch Screen. I plan to use the display with a Particle Xenon board for a neat dev kit.

Using PlatformIO with the Arduino Framework (and also with the Arduino IDE), I had no issues with getting the screen to display text, graphics or run the touchpoint_featherwing sample. However, I got a string of compilation errors when attempting to build the Adafruit_ImageReader->FeatherWingILI9341 (see details below).

I was trying to use the microSD to retrieve & display images onto the FeatherWing display and use the sample settings that had the QSPI flash (Adafruit_SPIFlash) off, so compilation should have ignored the QSPI pin definitions. Unfortunately it was not the case.

In digging further into the Adafruit / Arduino ImageReader Library, it turns out that after a major refactoring since v2.0, Adafruit ImageReader is closely coupled to the Adafruit_SPIFlash and SdFat. This was apparently done to provide additional QSPI flash load/store functionality.

However, it means that anyone who wants to just use the SdFat functionality and if their board doesn’t have the QSPI flash with the appropriate clock & data signals (like the FeatherWing compatible Particle Xenon board), they will somehow need to resolve the Adafruit_SPIFlash errors. This is a bad design decision!

I tried a couple of ways to resolve the compilation errors but in the end decided to add dummy QSPI pin definitions to the particle_xenon variant.h file.

.platformio/packages/framework-arduinoadafruitnrf52/variants/particle_xenon/variant.h

All seems to work fine but I shouldn’t have had to modify a board file just to use the microSD card.

Environment:

 OS: macOS 10.14.6
 PlatformIO: 5.1.1
 MCU: Particle Xenon
 Display: Adafruit 2.4" TFT FeatherWing (with microSD & Resistive Touch)

platform.ini:

[env:xenon]
platform = nordicnrf52
board = particle_xenon
framework = arduino
lib_deps = 
    adafruit/Adafruit BusIO@^1.7.2
    adafruit/Adafruit ILI9341@^1.5.6
    adafruit/Adafruit GFX Library@^1.10.6
    adafruit/Adafruit EPD@^4.3.3
    adafruit/SdFat - Adafruit Fork@^1.2.3
    adafruit/Adafruit SPIFlash@^3.4.1
    adafruit/Adafruit ImageReader Library@^2.6.1
upload_protocol= jlink
debug_tool = jlink
debug_init_break = tbreak setup

Errors:

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp: In constructor ‘Adafruit_FlashTransport_QSPI::Adafruit_FlashTransport_QSPI()’:

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp:34:36: error: 'PIN_QSPI_SCK' was not declared in this scope; did you mean 'PIN_SPI_SCK'?
   34 |     : Adafruit_FlashTransport_QSPI(PIN_QSPI_SCK, PIN_QSPI_CS, PIN_QSPI_IO0,
      |                                    ^~~~~~~~~~~~
      |                                    PIN_SPI_SCK

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp:34:50: error: 'PIN_QSPI_CS' was not declared in this scope; did you mean 'PIN_SPI_SS'?
   34 |     : Adafruit_FlashTransport_QSPI(PIN_QSPI_SCK, PIN_QSPI_CS, PIN_QSPI_IO0,
      |                                                  ^~~~~~~~~~~
      |                                                  PIN_SPI_SS

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp:34:63: error: 'PIN_QSPI_IO0' was not declared in this scope; did you mean 'PIN_SPI_SCK'?
   34 |     : Adafruit_FlashTransport_QSPI(PIN_QSPI_SCK, PIN_QSPI_CS, PIN_QSPI_IO0,
      |                                                               ^~~~~~~~~~~~
      |                                                               PIN_SPI_SCK

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp:35:36: error: 'PIN_QSPI_IO1' was not declared in this scope; did you mean 'PIN_SPI_SCK'?
   35 |                                    PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3) {}
      |                                    ^~~~~~~~~~~~
      |                                    PIN_SPI_SCK

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp:35:50: error: 'PIN_QSPI_IO2' was not declared in this scope; did you mean 'PIN_SPI_SCK'?
   35 |                                    PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3) {}
      |                                                  ^~~~~~~~~~~~
      |                                                  PIN_SPI_SCK

/Documents/Arduino/libraries/Adafruit_SPIFlash/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp:35:64: error: 'PIN_QSPI_IO3' was not declared in this scope; did you mean 'PIN_SPI_SCK'?
   35 |                                    PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3) {}
      |                                                                ^~~~~~~~~~~~
      |                                                                PIN_SPI_SCK

Resolution:

In the case of the particle_xenon board, add the QSPI pin definition to variant header.

.platformio/packages/framework-arduinoadafruitnrf52/variants/particle_xenon/variant.h

// QSPI Pins
#define PIN_QSPI_SCK         27
#define PIN_QSPI_CS          28
#define PIN_QSPI_IO0         29
#define PIN_QSPI_IO1         30
#define PIN_QSPI_IO2         31
#define PIN_QSPI_IO3         32