Adafruit-GFX-Library
Adafruit-GFX-Library copied to clipboard
SPI peripheral mapping not working on some RP2040 based boards
This forum poster was trying to get a Feather RP2040 CAN working with a TFT FeatherWing: https://forums.adafruit.com/viewtopic.php?t=217465
Dealing with ensuring the various CS pins were being handled properly worked to a certain point, however, it was not possible to get a full working example using both CAN and TFT at the same time. I tried to work up an example and ran into a similar issue. Drilling into things, it seems like an issue with some conditional mapping being done to set up the SPI peripheral being used. There are numerous instances of this code: https://github.com/adafruit/Adafruit-GFX-Library/blob/87e15509a9e16892e60947bc4231027882edbd34/Adafruit_SPITFT.cpp#L1034-L1035
However, it seems the philhower core maps spi0 and spi1 to the RP2040's SPI0 and SPI1 peripherals. The Feather RP2040 CAN's default SPI pins use the SPI1 peripheral:
also: https://github.com/earlephilhower/arduino-pico/blob/e05dd50d626d2871ab988d8e72aa7c12e18e603c/variants/adafruit_feather_can/pins_arduino.h#L32-L37
So it seems like that tertiary logic ends up mapping to spi0 instead of spi1 as needed.
Doing a quick hack and changing all instances of:
spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1;
to:
spi_inst_t *pi_spi = spi1;
resolves the issue.
So the problem is known, but at this point unclear what a good code fix would be.
Example test sketch:
/*
* TFTFeatherWing + Feather RP2040 CAN Example
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_MCP2515.h>
#define MCP_CS PIN_CAN_CS // CAN
#define STMPE_CS 6 // touch
#define TFT_CS 9 // TFT
#define TFT_DC 10
#define SD_CS 5 // SD
#define CAN_BAUDRATE (250000)
// CAN
Adafruit_MCP2515 mcp(MCP_CS);
// TFT
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
void setup() {
Serial.begin(115200);
while(!Serial) delay(10);
Serial.println("TX Feather RP2040 CAN + TFT FeatherWing test!");
// force disable all SPI things
pinMode(MCP_CS, OUTPUT); digitalWrite(MCP_CS, HIGH);
pinMode(STMPE_CS, OUTPUT); digitalWrite(STMPE_CS, HIGH);
pinMode(SD_CS, OUTPUT); digitalWrite(SD_CS, HIGH);
pinMode(TFT_CS, OUTPUT); digitalWrite(9, HIGH);
Serial.println("CAN init");
if (!mcp.begin(CAN_BAUDRATE)) {
Serial.println("Error initializing MCP2515.");
while(1) delay(10);
}
Serial.println("MCP2515 chip found");
Serial.println("TFT init");
tft.begin();
uint8_t x = tft.readcommand8(ILI9341_RDMODE);
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDMADCTL);
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDPIXFMT);
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDIMGFMT);
Serial.print("Image Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDSELFDIAG);
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
// fill color pattern
tft.fillScreen(ILI9341_RED);
delay(5000);
tft.fillScreen(ILI9341_GREEN);
delay(5000);
tft.fillScreen(ILI9341_BLUE);
delay(5000);
Serial.println("START DONE");
}
void loop() {
// send packet: id is 11 bits, packet can contain up to 8 bytes of data
Serial.print("Sending packet ... ");
mcp.beginPacket(0x12);
mcp.write('h');
mcp.write('e');
mcp.write('l');
mcp.write('l');
mcp.write('o');
mcp.endPacket();
Serial.println("done");
delay(1000);
// send extended packet: id is 29 bits, packet can contain up to 8 bytes of data
Serial.print("Sending extended packet ... ");
mcp.beginExtendedPacket(0xabcdef);
mcp.write('w');
mcp.write('o');
mcp.write('r');
mcp.write('l');
mcp.write('d');
mcp.endPacket();
Serial.println("done");
delay(1000);
}
CURRENT BEHAVIOR:
BEHAVIOR WITH HACK FIX:
Here's the related PR that brought in these changes: https://github.com/adafruit/Adafruit-GFX-Library/pull/360
grepping in the variants subfolder of the RP2040 BSP for boards that map spi1 to __SPI0_DEVICE:
$ grep -r __SPI0_DEVICE | grep spi1
adafruit_feather_thinkink/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_prop_maker/pins_arduino.h:#define __SPI0_DEVICE spi1
amken_revelop_es/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_dvi/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_metro_rp2350/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_scorpio/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_rfm/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_can/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_usb_host/pins_arduino.h:#define __SPI0_DEVICE spi1
silicognition_rp2040_shim/pins_arduino.h:#define __SPI0_DEVICE spi1
sparkfun_iotnode_lorawanrp2350/pins_arduino.h:#define __SPI0_DEVICE spi1
adafruit_feather_adalogger/pins_arduino.h:#define __SPI0_DEVICE spi1
This issue would affect all of those boards.
This works for the CAN Feather, but not a universal fix since not all boards have these defines:
spi_inst_t *pi_spi = hwspi._spi == &SPI ? __SPI0_DEVICE : __SPI1_DEVICE;
The BSP has defaults, but in .cpp file: https://github.com/earlephilhower/arduino-pico/blob/e05dd50d626d2871ab988d8e72aa7c12e18e603c/libraries/SPI/src/SPI.cpp#L419-L424
did this get resolved with the PR?