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.