What happens when an interrupt occurs in the middle of an SPI data transfer?

Hello all!

I have a project I'm working on that has two interrupts (one attached to timer0 and one triggered off of a pin) and a display driven by eight different subordinate boards via an SPI interface. I'm using an Arduino Nano.

My question is: What happens if one of my interrupts fires while my Nano is transmitting data via SPI?

I can think of 3 possibilities:

  • The outbound data gets mangled due to an unexpected disruption of the transmission
  • Handling of the interrupt is ignored or delayed while the SPI library is transmitting data
  • The Arduino simply stops clocking out data via SPI, essentially "pausing" it to handle the interrupt, and data transmission successfully resumes after a delay to handle the interrupt

I suspect (and hope!) number 3 is the case, as in this application the interrupts are very time sensitive and I would prefer to not have anything get in their way---however it's been hard to find a concrete answer since most of my searches are polluted by people trying to perform SPI inside an interrupt.

Thanks in advance! This is my first post on this forum but I've found it to be an invaluable resource for quite a while.

I think (but have not checked the Atmega 328 datasheet (hint)) that the single byte SPI transfer is handled by hardware that is not affected by interrupts.

...R

Let us see what happens when an interrupt occurs due to TOV0 (Timer-0 overflow) flag while the MCU is executing the following Arduino SPI Code:

byte x = SPI.transfer(0x25);

The above Arduino SPI code is functionally equivalent to the following register level codes:

SPDR = 0x25;

while(bitRead(SPSR, SPIF) != HIGH)
{
   ;
}

byte x = SPDR;

If interrupt arrives during the execution of SPDR = 0x25; code, the following events occur:
1. The MCU will finish this (current) instruction;

2. It will then save the address of the next instruction (which the MCU would execute in absence of interrupt) onto stack;

3. It will deactivate global interrupt flag to prevent the occurrence of any other interrupt until the current interrupt process is finished;

4. It will then jump to ISRTOV0 (interrupt sub routine due to Timer-0 overflow).

5. The MCU will finish the ISR;

6. It will retrieve return address from stack;

7. It will the resume the mainline program from the point where it was interrupted.

There is no issue of pollution or loss of signal. (While the MCU returns to mainline program, the global interrupt flag is automatically activated.)

GolamMostafa:
If interrupt arrives during the execution of SPDR = 0x25; code, the following events occur:
1. The MCU will finish this (current) instruction;

2. It will then save the address of the next instruction (which the MCU would execute in absence of interrupt) onto stack;

I think the important stuff happens between those two items.

My reading of the datasheet is that when a byte is written to SPDR it gets sent, and the incoming byte is received. Interrupts have nothing to do with it - they are separate, and operate in parallel.

...R

  1. If an interrupt happens while the the SPI hardware is executing a byte transfer, the hardware completes that transfer and awaits another instruction.

Robin2:
I think (but have not checked the Atmega 328 datasheet (hint)) that the single byte SPI transfer is handled by hardware that is not affected by interrupts.

I fully agree with you what you have said, and it is clearly demonstrated by the following SPI hardware structure; where once data is loaded into SPDR register, the SCK is automatically generated by the dedicated hardware to complete simultaneous data exchange between Master and Slave without the intervention of MCU. Therefore, the interrupt process may proceed in parallel.
spi328x.png
Figure-1: SPI transaction between Master and Slave

But, there is still something to say in the light of my working experience with interrupt processes of 8085, 6802, 80x86, 89S52, ATmega32A, and ATmega328P.

The SPDR = 0x25; instruction is further broken down into the following codes:

ldi   r16, 0x25  ; E205
out  SPDR, r16 ; BD0E

From the above break down of codes, we may state that the interrupt may arrive during the execution of this instruction: ldi r16, 0x25;. The instruction: out SPDR, r16; which actually loads the data into SPDR register will be executed after returning from ISR. It is for the note of OP that there is no way for the SPI transaction to get out-of-order due to interrupt. However, care must be taken into consideration that the interrupt interval is long enough (and practically, it is long enough) so that the MCU has time to execute the codes of the MLP (main line program).

It is also for the note of OP that the execution time of SPDR = 0x25; instruction is equal to the execution times of the above two assembly lines, which is : (1/16000000)*2 = 0.125 us (these are 1-cycle instructions). The instruction execution time is the time that the MCU needs to fetch the code (E205) from flash, put it into instruction register for decoding, and then placing to the control matrix (the sequence generator). The data transfer time from Master<---->Slave at 125 kbits/sec rate is: (1/125000)*8 = 64 us.

Robin2:
My reading of the datasheet is that when a byte is written to SPDR it gets sent, and the incoming byte is received. Interrupts have nothing to do with it - they are separate, and operate in parallel.

As the Master has to wait at least for 64 us (assuming @125 kbits/sec) for the data to arrive into SPDR of Master from the SPDR of the Slave (Fig-1), there may (very unlikely) appear interrupt which will be honored in parallel while the data from Slave to Master is still in transition. Again, your proposition is in line with what is happening at the hardware level.

spi328x.png

GolamMostafa:
Figure-1: SPI transaction between Master and Slave

Is that diagram from an authoritative source (if so please post a link to the source so we can study it) or is it one you created yourself?

If the command SPDR = 0x25; is actually implemented as two assembler instructions then I agree that the interrupt could happen between them (unless they are protected against that). However my point was, and remains, that once the SPI transfer begins its completion will not be affected by an interrupt. And I believe that is what was worrying the OP.

...R

The referred diagram (Fig-1) belongs to the pdf of this link. I believe that the diagram has been prepared (a presentation slide) based on the official version (Fig-2).
spi328x.png
Figure-1: SPI structure (compiled version)

spiAtmega328PX.png
Figure-2: SPI structure (official version)

spiAtmega328PX.png

spi328x.png