My Arduino needs to do:

  1. Run ISR as many times as possible/ as fast as possible.
  2. Occasionally receive data over I2C.
  3. Output data over SPI in ISR.

My question is regarding SPI and ISR. The documentation about SPI I found, was quite poor.

SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0));

void isr_function()

Is this the correct use of SPI in my case? Can it be faster?

  • The SPI library function; transfer is blocking. If you really need some additional cpu cycles, you can send the data between ISR calls instead. The SPI hardware can send the data while the CPU is doing something useful, instead of waiting for the SPI transfer to finish. You would then latch the data at the beginning of (the next) ISR.
    – Gerben
    Oct 27, 2021 at 14:30
  • PS You can't run SPI at 16Mhz on a Nano. The maximum speed is F_CPU/2, if I remember correctly, which would be 8MHz
    – Gerben
    Oct 27, 2021 at 14:31
  • If you need to push a lot of data quickly through SPI, it's a lot more convenient to use a micro with a SPI peripheral that supports DMA. Most likely the ARM-based arduinos will fit the bill.
    – bobflux
    Nov 1, 2021 at 17:31

1 Answer 1


It is actually fairly easy just to use the SPI peripheral without using the arduino libraries. The attached functions could be used to send a number of bytes through the SPI with one call: (Assuming ATMEGA328)

#include <avr/io.h>
#include <avr/interrupt.h>

static unsigned char spiCnt, *userBufr;

/* Call this function during setup */
void SpiInit (void)
    PPR &= ~0x04;   // Be sure the SPI has power
    DDRB |= 4;      // Be sure SS signal on PORTB bit 2 is output
    SPCR = 0x50;    // Turn SPI on, maximum CLK rate

/* Call this function to initiate the multi-byte send */
void SpiWrite (void *data, unsigned char bytCnt)
    /* Save the the caller's messsage information */
    userBufr = data;
    spiCnt = bytCnt;

    /* Enable the SPI device, send first byte */
    SPCR |= 0x40;           // Enable SPI
    SPDR = *userBufr++;     // Send the first byte
    SPCR |= 0x80;           // Enable interrupts

/* Call this one to be sure the message is finished */
int SpiIsDone (void)
    /* Non-zero when operation is finished */
    return ( ! (SPCR & 0x80));

/* Stay out of this one */
ISR (SPI_STC_vect)
    /* Check the remaining number of bytes to send */
    if (--spiCnt)
        SPDR = *userBufr++;     // Send the next byte

    /* Operation is finished, shut down SPI */
        SPCR &= ~0x80;  // Disable interrupts for SPI

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.