earlephilhower / arduino-pico

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

SPI not working Raspberry Pico #417

Closed steeley closed 2 years ago

steeley commented 2 years ago

Have used SPI.h with Arduino and similar boards (Mostly Teensy 3.2/4) with various digital pots, swipes EEProms and all my code works fine.

Nothing appears to work using SPI on RPI Pico. :(

The code below controls a digital pot - works perfectly on every board I have tried. On Pico SPI signals appear to do nothing Software defined CS line seems to be a square wave at 50Hz!!!.

I've tried setting the pins before initing the library( SPI.setTX(SPI_MOSI_PIN). etc but that seems to produce some signals but they are just wrong, or not there.

#include <SPI.h>

const int slaveSelectPin = 10;
//other pins as default:  GP18=CLK GP19=TX for Pico. 13=CLK 11=TX for Teensy 4
void setup() {

  pinMode (slaveSelectPin, OUTPUT);
  SPI.begin();
  delay(500);
//SPI_CLOCK_DIV4 = 0
  //setup pot registers
  SPI.beginTransaction(SPISettings(0, MSBFIRST, SPI_MODE1));
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x18);
  SPI.transfer(0x02);
  digitalWrite(slaveSelectPin,HIGH);
  SPI.endTransaction();
}

void loop() {
  unsigned int val;
  for (val = 10; val <= 500; val++) {
    digitalPotWrite(1024-val);
    delay(10);
  }
  for (val = 500; val > 10; val--) {
    digitalPotWrite(1024-val);
    delay(10);
  } 
}

void digitalPotWrite(unsigned int val) {
  SPI.beginTransaction(SPISettings(0, MSBFIRST, SPI_MODE1));
  digitalWrite(slaveSelectPin, LOW);
  byte highbyte = (val >> 8) + 0x04; //high wiper byte + command
  byte lowbyte = val & 0xFF;
  SPI.transfer(highbyte); //send wiper data high byte
  SPI.transfer(lowbyte); //send wiper data low byte
  digitalWrite(slaveSelectPin, HIGH);
  SPI.endTransaction();
}
earlephilhower commented 2 years ago

SPI most assuredly does work, at least well enough for myself and lots of other folks to interface displays and related stuff.

There is a debug SPI mode setting, enable it and set the debug port itself to Serial and re-run your tests to collect some information on what's being done in the core.

Off the bat, I think the 0 Hz max clock is causing your grief. Set it to 100000 or something (whatever the max SPI rate is for your devices) and retry.

earlephilhower commented 2 years ago

In fact, we take the max speed you pass in and send it directly to the SDK which is probably only able to give a 50hz SPI clock as its lowest speed.

https://github.com/earlephilhower/arduino-pico/blob/1fdc0ab7c13cece1403985c7d695816900eb751e/libraries/SPI/SPI.cpp#L191

So, I do think changing 0 to the proper max speed of your devices will get things rolling.

steeley commented 2 years ago

Ok the issue with this library seems to be the CS line. In the code below I'm using software CS and it works.if I use hardware the line does nothing. As you say there are many people using this successfully., perhaps you could point me to. a code example that shows this working.( on a Pico) I've not found any unfortunately.

`#include //#include

const uint8_t SPI_MISO = 16; const uint8_t SPI_CS = 22; //17 Pico hardware default const uint8_t SPI_SCK = 18; const uint8_t SPI_MOSI = 19; //

SPISettings parSPI(10000, MSBFIRST, SPI_MODE1);

void setup() { Serial.begin(115200); pinMode(22,OUTPUT); //---- Define the SPI pins ------- SPI.setRX(SPI_MISO); SPI.setTX(SPI_MOSI); SPI.setSCK(SPI_SCK); //SPI.setCS(SPI_CS); SPI.begin();

//setup pot registers SPI.beginTransaction(parSPI); digitalWrite(SPI_CS,LOW); SPI.transfer(0x18); SPI.transfer(0x02); digitalWrite(SPI_CS,HIGH); SPI.endTransaction(); }

void loop() { unsigned int val; for (val = 10; val <= 500; val++) { digitalPotWrite(1024-val); delay(10); } for (val = 500; val > 10; val--) { digitalPotWrite(1024-val); delay(10); } }

void digitalPotWrite(unsigned int val) { SPI.beginTransaction(parSPI); digitalWrite(SPI_CS, LOW); byte highbyte = (val >> 8) + 0x04; //high wiper byte + command byte lowbyte = val & 0xFF; SPI.transfer(highbyte); //send wiper data high byte SPI.transfer(lowbyte); //send wiper data low byte digitalWrite(SPI_CS, HIGH); SPI.endTransaction(); }`

earlephilhower commented 2 years ago

The Adafruit graphics libraries and even the included SD card libraries use SPI, so you can look there. The WizNet W5100S-Pico also uses SPI to connect to the onboard TCP chip.

steeley commented 2 years ago

Got a colleague to try running SPI on a Pico and they got the same result. Switched to a different SPI library and the Pico works perfectly again. Not going to waste anymore of your/my time on this. Going with Mbed or back to our usual stm32 stuff.