Seeking advice re SPI timing

I will be running two to four peripherals via SPI. For some, a speed of 0.5 microseconds per bit (4 microseconds per byte) is feasible, others will run slower. In each case, a transmission will consist of 1 to 16 bytes.
For the slow ones (16 or 32 microseconds per byte) I plan to use SPI interrupt. However, for the fast ones, I believe I would get better speed by handling the whole transfer in software using code such as:

	for (int i=0; i<count; i++) {
		SPDR = buffer[i];
		while (!(SPSR & (1 << SPIF)));
		buffer[i] = SPDR;
	}

Is this a reasonable assumption?
A RETI instruction takes 4 cycles; does anyone know approximately how long the interrupt takes?

PeteC: Is this a reasonable assumption?

That's essentially how the ArduinoISP sketch works so I say it is reasonable.

A RETI instruction takes 4 cycles; does anyone know approximately how long the interrupt takes?

Huh?

I think we determined that there’s about 3-4uS overhead at both ends of an ISR. Your polling code is exactly what you have to do for high speed SPI.

The slaves also have to have some warning that a transfer is about to start, or you can preload SPDR with the first byte or just have the master ignore it.


Rob

PeteC:
A RETI instruction takes 4 cycles; does anyone know approximately how long the interrupt takes?

I did detailed timings here:

http://gammon.com.au/interrupts

Using the ISR define (not attachInterrupt) I calculated you would have an overhead of around 2.625 uS. The figure Graynomad mentioned was more for the attachInterrupt ones (ie. the interrupts for pins D2/D3).

On top of that 2.625 uS there is, of course, the time taken by your code itself.

According to my timings here:

http://gammon.com.au/spi

… it takes about 3 uS to use SPI.transfer () so I don’t know if you will achieve a heap by just rolling your own.

However, for the fast ones, I believe I would get better speed by handling the whole transfer in software using code such as:

SPDR = buffer[i];

while (!(SPSR & (1 << SPIF)));
buffer[i] = SPDR;

What’s the difference between your proposed solution, and what SPI.transfer currently does?

byte SPIClass::transfer(byte _data) {
  SPDR = _data;
  while (!(SPSR & _BV(SPIF)))
    ;
  return SPDR;
}

Are you doing the master or the slave?

As far as I know --- the Atmel handles bit-shifting to the bus which frees the CPU to fetch the next byte and put it into the SPI register. But I haven't coded that and do wonder how you know when to do that write.

I presume that instead of:

while (!(SPSR & (1 << SPIF)));

… you would configure for an “end of transmission” interrupt. However I can’t see a whole heap of point to that. Since interrupts take around 2.65 uS to be serviced, and you can send that byte in 3 uS, you wouldn’t get much else done. Could be worthwhile for slower clock speeds though.