Electrical – USART in SPI mode vs. SPI hardware speed

atmegainterruptsspeedspiuart

On AVR ATmega devices, the USART has the capability to function in SPI mode (i.e. synchronous with no start or stop bits). The chief operational difference is that the TX line (i.e. MOSI) has a buffer, while the SPI hardware MOSI has no buffer. According to this Atmel application note (http://www.atmel.com/Images/doc2577.pdf), this buffer makes it possible to continuously transmit data. This is in contrast to the SPI hardware where SCK must be halted while a new byte is being loaded into SPDR.

With this in mind, which of the following programs to transmit 200 bytes from a buffer buf[200] would complete in the shortest amount of time? (Assume that all are configured at fosc / 2.)

Polled SPI:

for(int B = 0; B < 200; ++B)
{
  SPDR = buf[B]; // Load next byte into SPDR
  while(!(SPSR & (1 << SPIF))); // Wait for SPIF to be set
  (int)SPDR;  // Read SPDR to clear SPIF
}

Interrupt-driven SPI:

ISR(SPI_STC_vect)
{
  if(B < 200)
  {
     SPDR = buf[B]; // Load next byte into SPDR
     ++B;
  }
  else
  {
     SPCR &= ~(1 << SPIE); // Disable SPI interrupts
  }
  return;
}

Polled USART in SPI mode:

for(int B = 0; B < 200; ++B)
{
  UDR0 = buf[B]; // Load next byte into UDR
  while(!(UCSR0A & (1 << UDRE))); // Wait for UDR empty
}

Interrupt-driven USART in SPI mode:

ISR(USART0_UDRE_vect)
{
  if(B < 200)
  {
     UDR0 = buf[B]; // Load next byte into SPDR
     ++B;
  }
  else
  {
     UCSR0B &= ~(1 << UDRIE); // Disable UDRE interrupt
  }
  return;
}

Best Answer

Unless there are a lot of competing interrupts, the polling USART method would be fastest.

For fast SPI transfers (with fosc/2) the interrupt entry and exit would be too long, and the SPI methods have the gaps mentioned in the question.