earlephilhower / arduino-pico

Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
GNU Lesser General Public License v2.1
1.99k stars 413 forks source link

SPI pin reconfiguration does not allow any combination #1331

Closed therman89 closed 1 year ago

therman89 commented 1 year ago

I'm trying to use SPI on pins other than the default settings. I found that I cannot use any combination of the available pins, and reception of data over SPI does not work all the time. I want to use GP2-GP5 pins to connect to a sensor, but it reception does not work. Using an oscilloscope, I can see that the data is present on both MISO and MOSI pins (so the sensor receives the command and even replies correctly), but the pico reports that there is no reply.

If I change the wires and use GP4-GP7 pins for SPI, the communication works, as well as on GP16-GP19.

I also tried GP0-GP3 and it does not work, either. Is there a restriction regarding the collection of pins that I can use for SPI? GP0-GP7 are all SPI0 pins, so in my understanding any valid combination of these should work. I did not find any information on this, so that's why I'm looking for help here.

Meanwhile, I'll rewire my PCB to use GP4-GP7.

earlephilhower commented 1 year ago

If you have a complete, small app showing it failing, that would help us help you.

SPI pin changing most definitely does work, but there are some rules you need to follow. SPI.setRX/etc. can only be called before SPI.begin() Also, only the HW supported pins (see any RP2040 datasheet) can be assigned, or the Pico will crash.

therman89 commented 1 year ago

I did some testing with different pin collections using the code below. I tested for SPI and SPI1 as well and I my finding was that two collections do not work, although my experiment did not consider every possible combinations only those that have pins close to each other on the Pico.

So here are my findings(checked box means it's working properly):

SPI

SPI1

#include <SPI.h>
#include <SparkFun_MMC5983MA_Arduino_Library.h>

SFE_MMC5983MA myMag;
int sckPin = 2;
int mosiPin = 3;
int misoPin = 0;
int csPin = 1;
void setup() {
  // put your setup code here, to run once:
    Serial.begin(115200);
    delay(2000);
    Serial.println("SPI test start");

    SPI.setCS(csPin);
    SPI.setRX(misoPin);
    SPI.setTX(mosiPin);
    SPI.setSCK(sckPin);
    SPI.begin();
    SPISettings magSPI = {100000, MSBFIRST, SPI_MODE0};
    while (myMag.begin(csPin,magSPI, SPI) == false)
    {
        Serial.println("MMC5983MA did not respond. Retrying...");
        delay(500);
        myMag.softReset();
        delay(500);
    }
    delay(1000);
    Serial.println("MMC5983MA connected");
}

void loop() {
  // put your main code here, to run repeatedly:

}
lyusupov commented 1 year ago

@therman89 https://github.com/earlephilhower/arduino-pico/blob/master/libraries/SPI/src/SPI.cpp#L200 https://github.com/earlephilhower/arduino-pico/blob/master/libraries/SPI/src/SPI.cpp#L217 https://github.com/earlephilhower/arduino-pico/blob/master/libraries/SPI/src/SPI.cpp#L234 https://github.com/earlephilhower/arduino-pico/blob/master/libraries/SPI/src/SPI.cpp#L251

earlephilhower commented 1 year ago

As @lyusupov listed, there are only specific pinouts supported for each bit of the SPI interface. ( You can see the official Raspberry Pi graphic here: https://www.raspberrypi.com/documentation/microcontrollers/images/pico-pinout.svg )

By inspection in the code, you can see the following 0..3 config is allowed (and no other ordering...can't swap TX and RX for example):

SPI.setRX(0);
SPI.setCS(1);
SPI.setSCK(2);
SPI.setTX(3);
treyus30 commented 1 year ago

Hi, noob here. Been pulling my hair out the last couple days on why I couldn't get basic SPI to work going through limited documentation. This thread finally made me realize you MUST declare SPI1 for pins 10-13, so thought I'd document it explicitly. https://arduino-pico.readthedocs.io/en/latest/spi.html << The first couple sentences never made sense to me, or how to invoke, so a better example would be nice! Anyway, thanks for the hard work. I'm out of my depth here.

The code that stopped my USB crashes was this

#include "SPI.h"
int sckPin = 10;
int mosiPin = 11;
int misoPin = 12;
int csPin = 13;

void setup() {
  // put your setup code here, to run once:
    SPI1.setCS(csPin);
    SPI1.setRX(misoPin);
    SPI1.setTX(mosiPin);
    SPI1.setSCK(sckPin);
    SPI1.begin();

    pinMode(25, OUTPUT);
}
earlephilhower commented 1 year ago

...realize you MUST declare SPI1 for pins 10-13...

No, that is not correct. You must follow one of the legal pinouts given by the RP2040 datasheet. For example, https://microcontrollerslab.com/wp-content/uploads/2021/01/Raspberry-Pi-Pico-pinout-diagram.svg . There are multiple options you can choose from, but you can't just randomly pick pins or the Pico will crash as it can't physically do what you're asking it to do.

treyus30 commented 1 year ago

...realize you MUST declare SPI1 for pins 10-13...

No, that is not correct. You must follow one of the legal pinouts given by the RP2040 datasheet. For example, https://microcontrollerslab.com/wp-content/uploads/2021/01/Raspberry-Pi-Pico-pinout-diagram.svg . There are multiple options you can choose from, but you can't just randomly pick pins or the Pico will crash as it can't physically do what you're asking it to do.

I was referring to the need for the "1" in SPI1 to be used for the channels 1, whereas "SPI" (sans-1) is for 0 channels. Am I mistaken? The text turned red when I did so, signifying it was linked to a class/library, and suddenly the Pico was able to boot.

earlephilhower commented 1 year ago

Yup, looks like a misunderstanding. SPI is normally spi0 and SPI1 is normally so look for SPI0.XXX for SPI and SPI1.XXX for SPI1 in the diagrams