[AVR] SPI atomicity fix avr (part 1/2 of #2376)

This pull request broke into 6 simpler commits the big patch in #2376.

/cc @xxxajk @PaulStoffregen 

The numbers don't lie. I'll see what I can come up with in about 3 to 4
hours.
On Oct 22, 2014 5:15 AM, "Cristian Maglie" <notifications@github.com> wrote:

> In hardware/arduino/avr/libraries/SPI/SPI.h:
>
> > @@ -225,23 +258,31 @@ class SPIClass {
> >    // After performing a group of transfers and releasing the chip select
>
> @xxxajk <https://github.com/xxxajk>
>
> I've made some test with the following sketch:
>
> #include <SPI.h>
> char buff[1000];
> void testByteTransfer() {
>   unsigned long start = micros();
>   for (uint16_t i=0; i<10000; i++) {
>     SPI.transfer(0x55);
>     SPI.transfer(0xAA);
>     SPI.transfer(0x55);
>     SPI.transfer(0xAA);
>     SPI.transfer(0x55);
>     SPI.transfer(0xAA);
>     SPI.transfer(0x55);
>     SPI.transfer(0xAA);
>     SPI.transfer(0x55);
>     SPI.transfer(0xAA);
>   }
>   unsigned long stop = micros();
>   Serial.print("Byte transfer (us): ");
>   Serial.println(stop-start);
>   delay(500); // Wait for serial buffer to flush}
> void testWordTransfer() {
>   unsigned long start = micros();
>   for (uint16_t i=0; i<10000; i++) {
>     SPI.transfer16(0xAA55);
>     SPI.transfer16(0x55AA);
>     SPI.transfer16(0xAA55);
>     SPI.transfer16(0x55AA);
>     SPI.transfer16(0xAA55);
>     SPI.transfer16(0x55AA);
>     SPI.transfer16(0xAA55);
>     SPI.transfer16(0x55AA);
>     SPI.transfer16(0xAA55);
>     SPI.transfer16(0x55AA);
>   }
>   unsigned long stop = micros();
>   Serial.print("Word transfer (us): ");
>   Serial.println(stop-start);
>   delay(500); // Wait for serial buffer to flush}
> void testSmallBlockTransfer() {
>   unsigned long start = micros();
>   for (uint16_t i=0; i<10000; i++)
>     SPI.transfer(buff, 4);
>   unsigned long stop = micros();
>   Serial.print("Small block transfer (us): ");
>   Serial.println(stop-start);
>   delay(500); // Wait for serial buffer to flush}
> void testLargeBlockTransfer() {
>   unsigned long start = micros();
>   for (uint16_t i=0; i<100; i++)
>     SPI.transfer(buff, 1000);
>   unsigned long stop = micros();
>   Serial.print("Large block transfer: ");
>   Serial.println(stop-start);
>   delay(500); // Wait for serial buffer to flush}
> void setup() {
>   SPI.begin();
>   // Set SPI to max speed
>   SPI.beginTransaction(SPISettings(100000000, MSBFIRST, SPI_MODE0));
>   Serial.begin(9600);
>
>   testByteTransfer();
>   testWordTransfer();
>   testSmallBlockTransfer();
>   testLargeBlockTransfer();}
> void loop() {}
>
> It basically measure the time to perform a couple of SPI transfers.
> Tested on a Mega1280 I got the following results:
>   Byte transfer uS   with NOP *197304* (best)  without NOP 216260    Word
> transfer uS   with both NOPs *360804* (best)  with first NOP only 379732  with
> second NOP only 379732  without NOPs 398448    Block transfer uS (small) uS
> (large)   with both NOPs 72308 144760  with NOP inside send loop only
> 71676 144744  with NOP on the last byte only 70428 138472  without NOPs
> *69784* (best) *138460* (best)
>
> so my conclusions are that the commit is right as is it now and the block
> transfer cannot be improved by adding NOPs. Do you agree or I'm missing
> something?
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/arduino/Arduino/pull/2381/files#r19201992>.
>