SPI Interrupts

Hi there,
I have two Arduinos and I want to send numbers inputted from the serial monitor to the master Arduino from the slave Arduino using an interrupt pin. Has anyone got any idea as to how you would do this? Been doing some searching and doesn't seem to be that much on the topic. Hopefully this thread can also help anybody in the future.

A SPI slave can only "send" in response to an incoming SPI request from the master.

When the slave has something to notify the master of...

  • Raise the interrupt pin.

When the master detects that the slave has raised the interrupt...

  • Send an SPI request to the slave to retrieve the data

The slave needs to be able to detect when the master has retrieved the data and de-assert the relevant interrupt. If that's not possible you also need to build in a SPI request to your protocol to explicitly clear the interrupt.

Also, if the slave has more than one reason for raising an interrupt, you'll either need more than one IRQ line, or an interrupt flags register that the master can read to determine the cause.

A very common approach on more complex slave devices is...
An interrupt enable register: Each bit of the register enables/disables the corresponding interrupt.
An interrupt flags register: Each bit of the register signifies if an interrupt is pending. The master can clear pending interrupts by writing a 1 bit. 0 bits leave the current state unchanged.

Look at the design of say the NRF24 SPI protocol if you want an example.

What does "using an interrupt pin" mean and why do you think you need to do it that way?

Thanks for the replies.

@pcbbc-That's what I've gathered from the research I've been doing. I was more looking for some example code as there doesn't seem to be any.

@gfvalvo-What I've researched is that you can set a pin on the slave to send a signal to the master to indicate that the slave has data to send. The master will then send dummy bytes to receive the data the slave has. Thats why I assumed that there has to be another pin.

The @gfvalvo the only other way for a slave to "send" data to the master is for the master to continuously pole a register in the slave checking to see if data is available. I use "send" in quotes because really the only way is for master to request data from a slave - the slave can't unilaterally send.

The interrupt pin is just a way to avoid that overhead. So the slave says "Hey, I need attention" by asserting the IRQ pin, and the master responds by requesting data.

@Callum_Austin11 there's more to it than sending the dummy bytes. Usually you would begin with a read command indicating which data register you wish the slave send. Then follow that by dummy bytes for as many bytes as the slave has to send, or perhaps until it de-asserts IRQ.

There is no-defined method for how to do this, the protocol you decide to use over SPI is entirely of the device designers choosing. So probably why there is no example.

You also don't need to use an interrupt on the master, just have an input pin. Poll the IRQ pin in the loop() of the Arduino to decide if the slave needs attention.

If your sketch is using correct Arduino design principles (i.e. no delay() or long running code in loop()) it will be just as good...

if (digitalRead(slaveIRQPin))
{
  uint8_t status = SPI.transfer(READ_DATA_REG);
  while (digitalRead(slaveIRQPin))
  {
     uint8_t data = SPI.transfer(DUMMY_REG);  
  }
}

That makes sense. I suggest not using "IRQ" to name anything that doesn't actually cause an interrupt. As you describe it, it's only a Service Request. The pin that you assign to it, has no interrupt logic and that could be confusing later on.

aarg:
That makes sense. I suggest not using "IRQ" to name anything that doesn't actually cause an interrupt. As you describe it, it's only a Service Request. The pin that you assign to it, has no interrupt logic and that could be confusing later on.

THAT was the point of my question.

Maybe I'm over complicating it in my head. This is an example I've found on another forum; (scroll down to reply #4)

In this example the SPI Master sends data item 0x1234 to the SPI slave and it is shown in the serial monitor of the Slave. However, can we reverse that. So that the SPI Slave sends data item 0x1234 to the SPI Master and we can see that in the serial monitor of the Master.

Yes, but as already noted, all transfers must be initiated by the master.

That is only because the data flow in SPI can be simultaneously bidirectional. But the slave still can not initiate a transfer.

Also I have seen polling. I have a feeling this won't work as the master has to be doing other stuff and has a rather large loop code using delaymicroseconds(). Maybe it I will, I'm not sure though.

I know the slave CANNOT initiate a data transfer. The master must do that. That's why I'm talking about using an interrupt pin. Where the slave will tell the master that it has data to send. The master will then initiate transmission.

Callum_Austin11:
Also I have seen polling. I have a feeling this won't work as the master has to be doing other stuff and has a rather large loop code using delaymicroseconds(). Maybe it I will, I'm not sure though.

I know the slave CANNOT initiate a data transfer. The master must do that. That's why I'm talking about using an interrupt pin. Where the slave will tell the master that it has data to send. The master will then initiate transmission.

That's more than likely due to bad design. Also, all the ISR should do is set a flag to be picked up in the main loop(). So, it will require polling of the flag anyway. You might as well fix your loop code and poll the GPIO directly.

Could also use a PCINT interrupt so polling is not needed.
The PCINT sets a flag, loop() checks if the flag is sent and starts SPI.transfer()s from there.

CrossRoads:
Could also use a PCINT interrupt so polling is not needed.
The PCINT sets a flag, loop() checks if the flag is sent and starts SPI.transfer()s from there.

If the master can afford to spend the entire time required for the transfer in its ISR with servicing of all other interrupts being deferred.

gfvalvo:
That’s more than likely due to bad design. Also, all the ISR should do is set a flag to be picked up in the main loop(). So, it will require polling of the flag anyway. You might as well fix your loop code and poll the GPIO directly.

It’s allowed to do more than set a flag (although I agree with the mantra that an ISR should do as little as possible). It could initiate the first byte of the SPI transfer, then use an SPI interrupt to do further transfers to retrieve the data and put it in a buffer.

If it only sets a flag it’s the equivalent of polling the pin. And loop() still needs to check the flag, so there’s no benefit over checking the pin directly.

However if you’re going down the route of doing SPI from interrupts, ALL your SPI interface code has to be interrupt driven. Depending onwhat other comms are required between master/slave this could be quite an undertaking.

I'm starting to understand it a little more. I am still learning about it all. In the simplest form I can give you, what I want to do is send a number in the serial monitor of the Slave and display it on the serial monitor of the Master over SPI. Can this be done? If so, I would be grateful if someone could maybe write some example code as to be honest I have no where to start.

Of course it can be done. It's been explained in painful detail here, how to do it. If you want people to write code for you, please post in the "Gigs and Collaborations" forum and explain what renumeration is offered.

I don't think what I've asked has exactly been answered. I've asked this a lot and seem to get the same response everytime "Slave cannot initiate the transfer the master must do that". Which I understand. I was hoping this thread can save a lot of hair for many different people as I believe the question gets asked a lot. I'm not looking to pay someone. Otherwise I would have done that from the start and asked them to write the whole code I actually want. I would rather learn it or have it explained to me in the simplest form possible. I am quite nooby at it and have really only just got into it.

That is not true. This thread contains good explanations of how a slave can be made to transfer data to the master. It's better if those people go and read the original SPI library documentation and maybe watch some tutorials. It's not unconventional enough to justify a hair saving thread. The simple answer to your question is, "continually poll the slave for data". You can do that either by using the data itself for signalling (creating a data protocol), or by assigning a hardware pin as a request line, as has been thoroughly explicated above.

Also there are existing threads on this topic:
https://www.arduino.cc/search?q=poll+SPI+slave&tab=forum&domains=https%3A%2F%2Fforum.arduino.cc&sitesearch=https%3A%2F%2Fforum.arduino.cc