From d4edece7e6698e7687dd8dec1831f9756c8b0017 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 20 Oct 2014 19:46:08 +0200 Subject: [PATCH] [avr] Improved SPI speed on 16bit transfer. From https://github.com/arduino/Arduino/pull/2376#issuecomment-59671152 Quoting Andrew Kroll: [..this commit..] introduces a small delay that can prevent the wait loop form iterating when running at the maximum speed. This gives you a little more speed, even if it seems counter-intuitive. At lower speeds, it is unnoticed. Watch the output on an oscilloscope when running full SPI speed, and you should see closer back-to-back writes. Quoting Paul Stoffregen: I did quite a bit of experimenting with the NOP addition. The one that's in my copy gives about a 10% speedup on AVR. --- libraries/SPI/SPI.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index b54e2df..24ebc12 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -184,6 +184,12 @@ public: // Write to the SPI bus (MOSI pin) and also receive (MISO pin) inline static uint8_t transfer(uint8_t data) { SPDR = data; + /* + * The following NOP introduces a small delay that can prevent the wait + * loop form iterating when running at the maximum speed. This gives + * about 10% more speed, even if it seems counter-intuitive. At lower + * speeds it is unnoticed. + */ asm volatile("nop"); while (!(SPSR & _BV(SPIF))) ; // wait return SPDR; @@ -193,16 +199,20 @@ public: in.val = data; if (!(SPCR & _BV(DORD))) { SPDR = in.msb; + asm volatile("nop"); // See transfer(uint8_t) function while (!(SPSR & _BV(SPIF))) ; out.msb = SPDR; SPDR = in.lsb; + asm volatile("nop"); while (!(SPSR & _BV(SPIF))) ; out.lsb = SPDR; } else { SPDR = in.lsb; + asm volatile("nop"); while (!(SPSR & _BV(SPIF))) ; out.lsb = SPDR; SPDR = in.msb; + asm volatile("nop"); while (!(SPSR & _BV(SPIF))) ; out.msb = SPDR; }