earlephilhower / arduino-pico

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

SPI Slave mode not available ? #1680

Closed willwaush closed 1 year ago

willwaush commented 1 year ago

Hello.

I am trying to interact with a master device (which sends up the CS and SCK signals) to my RP2040 Nano board. The RP2040 board should reply with a stream of bits synced to the Master clock pulses when CS triggers an interrupt.

There are solutions for other Arduino boards, but I need this to work with the RP2040.

Some of the solutions I found online mention the ISR function, which in this case doesn't even get compiled at all.

I looked at the SPI.h and .cpp files, and there seems to be no function or real implementation of an ISR and a Slave mode. Is this possible to implement? Or are there any workarounds for me to make this still work?

This is one example I found online about SPI slave mode on an Arduino Nano board.

void setup (void){
  pinMode(MISO, OUTPUT); // arduino is a slave device
  SPCR |= _BV(SPE);      // Enables the SPI when 1
  SPCR |= _BV(SPIE);     // Enables the SPI interrupt when 1

  // interrupt for SS rising edge. Arduino Uno Pin10 must be connected to Pin2!!!
  attachInterrupt (0, ss_rising, RISING);
}

ISR (SPI_STC_vect) {
  SPDR = byte[i++]; // load the next byte to SPI output register and return.
}
earlephilhower commented 1 year ago

Your code example is only applicable to the AVR 8-bit hardware, not the Pico RP2040 HW. So if you see code twiddlilng SPDR bits and using ISR() please ignore it when using this core.

SPI slave here is not implemented. The Pico-Examples SPI slave example completely blocks one core waiting for SPI slave connections which is pretty awful in the general purpose and not IRQ related at all.

PRs always welcome. 😆

willwaush commented 1 year ago

Understood, thanks for the explanation.

In my case of application (and I guess for many it can still be useful), I can potentially assign one full core at doing only the Slave SPI task. Would it be possible for you to show here an example of how to actually do this with your arduino-pico core? I would just need to set up the SPI pins, slave mode and reply with bytes on the MISO line at each CS trigger.

Hopefully in the meantime someone can help find a solution to make it possible using interrupts (unfortunately I wouldn't know where to start, otherwise I would be happy to help!)

Thank you in advance!

earlephilhower commented 1 year ago

If you look at the example linked, it's a starting point. You'll need to configure the SPI to be a slave clock (check the Pico SDK docs), too, and ignore any of the stdio_init_xxx stuff since Arduino just uses Serial.

gesucristino commented 1 year ago

Hello! Following your tips I managed to make SPI work between two RP2040 boards. Although when attempting to communicate though SPI with an external (Master) peripheral, it simply isn't capable of producing any sort of SPI MISO "reply".

I know maybe this is not related a lot with the arduino-pico repo, but can anyone help me with this? Is there anything I can modify in the inner pico-core libraries to make this work?

I guess knowing how to "bend" the RP2040 SPI protocol could be useful to many.

Attached you can find the arduino files as well as some screenshots of my digital signal analyzer.

SPI example folder.zip

earlephilhower commented 1 year ago

@willwaush and @gesucristino check out PR #1717. It implements a simple SPI slave mode with a working 1-board example (core 0 SPI master, core 1 SPI slave).