Xiao nRF52840 project works when powered with 5V, not with battery or 3.3V

I found the problem! It didn’t seem like a power problem (i.e., wrong voltage or not enough current) to me, since it fails even when providing both the Xiao and the display with 3.3V from a power supply that has plenty of current.

I checked the SPI lines as I said I was going to in my OP, and found that it wasn’t sending anything over SPI. The problem is that the SPIM3 (SPI master 3) peripheral doesn’t work if Vbus (5V) wasn’t supplied during power on or reset: nRF52840 - SPIM3 not working if VBUS not powered when reset · Issue #5233 · adafruit/circuitpython · GitHub

The nRF52840 has 4 SPIM peripherals, with SPIM0 through SPIM2 supporting a max clock frequency of 8MHz and SPIM3 supporting 32MHz. And the Seeed nRF52 board library for the Arduino IDE uses SPIM3 for SPI (search for SPI_32MHZ_INTERFACE at Adafruit_nRF52_Arduino/libraries/SPI/SPI.cpp at master · Seeed-Studio/Adafruit_nRF52_Arduino · GitHub). I read that since SPIM3 supports higher speeds, it requires that the high frequency clock be enabled, and that some other code (I think in the bootloader?) enables it if Vbus is present on reset, but if not, the HFCLK is off and SPIM3 doesn’t work. I haven’t tried it myself, but it should be possible to enable HFCLK in my code.

What I have tried myself is editing SPI.cpp to #define SPI_32MHZ_INTERFACE 1, so it uses SPIM2 instead. The display panel’s SPI interface can only do 10MHz, so it wouldn’t benefit from SPIM3’s higher speed anyway (SPIM3 can’t do 10MHz; the next supported speed after 8MHz would be 16). And with that change, everything works on battery or USB.

Since there’s no benefit for me to use SPIM3 over SPIM2, and that enabling HFCLK uses (a little) more power, I’d rather just use SPIM2 rather than enable HFCLK in my code. So now I’m looking for some way to #define SPI_32MHZ_INTERFACE 1 without editing the board library file. SPI.cpp checks to see if SPI_32MHZ_INTERFACE is already defined before defaulting it to 0 if not, but I need some way to define it to 1 when SPI.cpp is being compiled. It doesn’t work to put the #define in my sketch before #including SPI.h, since that doesn’t cause it to be #defined when SPI.cpp is compiled. I need a way to pass -DSPI_32MHZ_INTERFACE=1 on the g++ commandline, but I don’t know how to do that. Or I guess I could create my own SPI2 instance of SPIClass and change my code to use SPI2 instead of SPI.

2 Likes