# How do you use SPI.Tranfer(Buffer, size)?

Right now I’m transferring 192 bits of data via 24 bytes using SPI.Transfer(myByte here).

I would like to see is I can achieve better transfer speed using SPI.Tranfer(Buffer, size).

Looked all over the net for example with no success.
Can anyone point me in the right direction?

I have found that writing the code as per below is much faster than using a for - loop.
I have four case statement totaling 768 bits to be transfer; I would like to do this faster and neater if possible.

I have included a part of my code, first how i get the bits in to my bytes then a part of the SPI transfer.

``````  void Cube::LED(byte CY, byte CX, byte CZ, byte CR, byte CG, byte CB) { //****LED Routine****LED Routine****LED Routine****LED Routine

// First, check and make sure nothing went beyond the limits, Limits are either 0 or 11/8 for location, and 0 or 15 for brightness/colour - BAM_RESOLUTION = 4

CY = constrain(CY, 0, Size_Y - 1);//Cube Y axis
CX = constrain(CX, 0, Size_X - 1);//Cube X axis
CZ = constrain(CZ, 0, Size_Z - 1);//Cube Y axis
CR = constrain(CR, 0, (1<<BAM_RESOLUTION)-1); //Cube Red
CG = constrain(CG, 0, (1<<BAM_RESOLUTION)-1); //Cube Green
CB = constrain(CB, 0, (1<<BAM_RESOLUTION)-1); //Cube Blue

//There are 768 LEDs in the cube, so when we write to level (Y) 2, column (X) 5, row 4 (Z), that needs to be translated into a number from 0 to 767
int whichbyte = ((CY * Size_Layer ) + (CX * Size_X) + CZ) / 8;

// This next variable is the same thing as before, but here we don't divide by 8, so we get the LED number 0-767
int wholebyte = (CY * Size_Layer) + (CX * Size_X) + CZ;

//This is 4 bit color resolution, so each color contains 4 x 96 byte arrays.

for(byte I = 0;I < BAM_RESOLUTION; I++){
//*** RED ***
bitWrite(red[I][whichbyte], wholebyte - (8 * whichbyte), bitRead(CR, I));

//*** GREEN ***
bitWrite(green[I][whichbyte], wholebyte - (8 * whichbyte), bitRead(CG, I));

//*** BLUE ***
bitWrite(blue[I][whichbyte], wholebyte - (8 * whichbyte), bitRead(CB, I));
}

}//****LED ROUTINE END****

case 0:
//Green
SPI.transfer(green[0][dataLevel]);
SPI.transfer(green[0][dataLevel + 1]);
SPI.transfer(green[0][dataLevel + 2]);
SPI.transfer(green[0][dataLevel + 3]);
SPI.transfer(green[0][dataLevel + 4]);
SPI.transfer(green[0][dataLevel + 5]);
SPI.transfer(green[0][dataLevel + 6]);
SPI.transfer(green[0][dataLevel + 7]);

//Red
SPI.transfer(red[0][dataLevel]);
SPI.transfer(red[0][dataLevel + 1]);
SPI.transfer(red[0][dataLevel + 2]);
SPI.transfer(red[0][dataLevel + 3]);
SPI.transfer(red[0][dataLevel + 4]);
SPI.transfer(red[0][dataLevel + 5]);
SPI.transfer(red[0][dataLevel + 6]);
SPI.transfer(red[0][dataLevel + 7]);

//Blue
SPI.transfer(blue[0][dataLevel]);
SPI.transfer(blue[0][dataLevel + 1]);
SPI.transfer(blue[0][dataLevel + 2]);
SPI.transfer(blue[0][dataLevel + 3]);
SPI.transfer(blue[0][dataLevel + 4]);
SPI.transfer(blue[0][dataLevel + 5]);
SPI.transfer(blue[0][dataLevel + 6]);
SPI.transfer(blue[0][dataLevel + 7]);

break;
``````

Looked all over the net for example with no success.

For an example of what? How to define an array? How to populate an array? How to call a function that takes an array?

Have you tried it? What happened?

First thing to try is create a 24 byte buffer (byte buf[24]) and just call the function: SPI.Transfer(buf, 24);

KeithRB:
Have you tried it?
What happened?

First thing to try is create a 24 byte buffer (byte buf[24]) and just call the function:
SPI.Transfer(buf, 24);

I’m not familiar with buffers. I’m not sure how to populate the buffer, how to use them in general.

As you can see from my code, I’m filling a byte array. Do I need to then transfer my array data to the buffer, if so how, or am I better to just fill the buffer instead of the array?

The "buffer" is just another name for your byte array.

Fastest way to send is to use discrete statements and not wait for the SPI.transfer interrupt. Use the SPI command to set the SPI clock divisor to 2 for 8 MHz transfers. Then:

``````digitalWrite (ssPin, LOW);
SPDR = buffer[0];nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
SPDR = buffer[1];nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
:
:
SPDR = buffer[22];nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
SPDR = buffer[23];nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
digitalWrite(ssPin,HIGH);
``````

Each byte will take 17 clocks to go out, just over 1uS each (17 * 1/16000000 = 1.0625uS) You can also turn off interrupts before you start the datablast so there are no breaks in the datastream from the micros()/millis() interrupts. I did the same to send out 45 bytes at a 20KHz rate. Just enough time left to do a couple instructions between transfers. (not sure if it's 'SPDR' or 'spdr', and 'nop' needs to be defined as an assembly instruction)

Thanks for the responses. I’m +8 UTC, so my response is delayed due to sleeping time, LOL.

Delta_G:
The “buffer” is just another name for your byte array.

I got the impression from reading other “Help” that buffers are different somehow. Thanks for clarification here.

(not sure if it’s ‘SPDR’ or ‘spdr’, and ‘nop’ needs to be defined as an assembly instruction)

I’m not sure what or how to accomplish this “and ‘nop’ needs to be defined as an assembly instruction”.

I’m looking forward to trying this method. I’m using SPI at 8 MHz “(SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));”

My theoretical BEST transfer speed is 24µs + some incidentals µs for a small bit of code before and during the transfer. Right now, using my scope, my transfer rate is 69 µs, i would like to get this down…

Below is ALL of the code that is in the 69 µs, If you can see ways to improving speed, I’m all ears.
I’m monitoring the “blank_pin” from High to low with my scope = 69µs.

``````//***************************  LEDs off  ***************************
PORTH |= 1 << blank_pin; //NOW we turn all of the LEDs OFF, by writing a 1 to the blank pin (OE)
// *** This routine selects levels ***.
//Switch levels now, otherwise you get a ghosting effect on the previous level
switch (anodeLevel) {
case 0://Level 1
PORTL = B00000000;    //Turn off level 12
PORTA = B00000010;    //Turn on level 1
break;
case 1: //Level 2
PORTA = B00001000;    //Turn on level 2, off Level 1
break;
case 2: //Level 3
PORTA = B00100000;    //Turn on level 3, Off Level 2
break;
case 3: //Level 4
PORTA = B10000000;    //Turn on level 4, off level 3
break;
case 4: //Level 5
PORTA = B00000000;    //Turn off level 4
PORTC = B01000000;    //Turn on level 5
break;
case 5: //Level 6
PORTC = B00010000;    //Turn on level 6, off level 5
break;
case 6: //Level 7
PORTC = B00000100;   //Turn on level 7, off level 6
break;
case 7: //Level 8
PORTC = B00000001;    //Turn on level 8, off level 7
break;
case 8: //Level 9
PORTC = B00000000;  //Turn off level 8
PORTG = B00000100;  //Turn on level 9
break;
case 9: //Level 10
PORTG = B00000001; //Turn on level 10, off level 9
break;
case 10: //Level 11
PORTG = B00000000;  //Turn off level 10
PORTL = B01000000;  //Turn on level 11
break;
case 11: //Level 12
PORTL = B00010000;  ////Turn on level 12, off level 11
break;
}
//**** Send out the Layer data - 4 Integers (64 bits) per colour - Green, Red then Blue. ****
switch (BAM_Bit) { //The BAM bit will be a value from 0-3
case 0:
//Green
SPI.transfer(green[0][dataLevel]);
SPI.transfer(green[0][dataLevel + 1]);
SPI.transfer(green[0][dataLevel + 2]);
SPI.transfer(green[0][dataLevel + 3]);
SPI.transfer(green[0][dataLevel + 4]);
SPI.transfer(green[0][dataLevel + 5]);
SPI.transfer(green[0][dataLevel + 6]);
SPI.transfer(green[0][dataLevel + 7]);
//Red
SPI.transfer(red[0][dataLevel]);
SPI.transfer(red[0][dataLevel + 1]);
SPI.transfer(red[0][dataLevel + 2]);
SPI.transfer(red[0][dataLevel + 3]);
SPI.transfer(red[0][dataLevel + 4]);
SPI.transfer(red[0][dataLevel + 5]);
SPI.transfer(red[0][dataLevel + 6]);
SPI.transfer(red[0][dataLevel + 7]);
//Blue
SPI.transfer(blue[0][dataLevel]);
SPI.transfer(blue[0][dataLevel + 1]);
SPI.transfer(blue[0][dataLevel + 2]);
SPI.transfer(blue[0][dataLevel + 3]);
SPI.transfer(blue[0][dataLevel + 4]);
SPI.transfer(blue[0][dataLevel + 5]);
SPI.transfer(blue[0][dataLevel + 6]);
SPI.transfer(blue[0][dataLevel + 7]);
break;
case 1:
//Green
SPI.transfer(green[1][dataLevel]);
SPI.transfer(green[1][dataLevel + 1]);
SPI.transfer(green[1][dataLevel + 2]);
SPI.transfer(green[1][dataLevel + 3]);
SPI.transfer(green[1][dataLevel + 4]);
SPI.transfer(green[1][dataLevel + 5]);
SPI.transfer(green[1][dataLevel + 6]);
SPI.transfer(green[1][dataLevel + 7]);
//Red
SPI.transfer(red[1][dataLevel]);
SPI.transfer(red[1][dataLevel + 1]);
SPI.transfer(red[1][dataLevel + 2]);
SPI.transfer(red[1][dataLevel + 3]);
SPI.transfer(red[1][dataLevel + 4]);
SPI.transfer(red[1][dataLevel + 5]);
SPI.transfer(red[1][dataLevel + 6]);
SPI.transfer(red[1][dataLevel + 7]);
//Blue
SPI.transfer(blue[1][dataLevel]);
SPI.transfer(blue[1][dataLevel + 1]);
SPI.transfer(blue[1][dataLevel + 2]);
SPI.transfer(blue[1][dataLevel + 3]);
SPI.transfer(blue[1][dataLevel + 4]);
SPI.transfer(blue[1][dataLevel + 5]);
SPI.transfer(blue[1][dataLevel + 6]);
SPI.transfer(blue[1][dataLevel + 7]);
break;
case 2:
//Green
SPI.transfer(green[2][dataLevel]);
SPI.transfer(green[2][dataLevel + 1]);
SPI.transfer(green[2][dataLevel + 2]);
SPI.transfer(green[2][dataLevel + 3]);
SPI.transfer(green[2][dataLevel + 4]);
SPI.transfer(green[2][dataLevel + 5]);
SPI.transfer(green[2][dataLevel + 6]);
SPI.transfer(green[2][dataLevel + 7]);

//Red
SPI.transfer(red[2][dataLevel]);
SPI.transfer(red[2][dataLevel + 1]);
SPI.transfer(red[2][dataLevel + 2]);
SPI.transfer(red[2][dataLevel + 3]);
SPI.transfer(red[2][dataLevel + 4]);
SPI.transfer(red[2][dataLevel + 5]);
SPI.transfer(red[2][dataLevel + 6]);
SPI.transfer(red[2][dataLevel + 7]);
//Blue
SPI.transfer(blue[2][dataLevel]);
SPI.transfer(blue[2][dataLevel + 1]);
SPI.transfer(blue[2][dataLevel + 2]);
SPI.transfer(blue[2][dataLevel + 3]);
SPI.transfer(blue[2][dataLevel + 4]);
SPI.transfer(blue[2][dataLevel + 5]);
SPI.transfer(blue[2][dataLevel + 6]);
SPI.transfer(blue[2][dataLevel + 7]);
break;
case 3:
//Green
SPI.transfer(green[3][dataLevel]);
SPI.transfer(green[3][dataLevel + 1]);
SPI.transfer(green[3][dataLevel + 2]);
SPI.transfer(green[3][dataLevel + 3]);
SPI.transfer(green[3][dataLevel + 4]);
SPI.transfer(green[3][dataLevel + 5]);
SPI.transfer(green[3][dataLevel + 6]);
SPI.transfer(green[3][dataLevel + 7]);
//Red
SPI.transfer(red[3][dataLevel]);
SPI.transfer(red[3][dataLevel + 1]);
SPI.transfer(red[3][dataLevel + 2]);
SPI.transfer(red[3][dataLevel + 3]);
SPI.transfer(red[3][dataLevel + 4]);
SPI.transfer(red[3][dataLevel + 5]);
SPI.transfer(red[3][dataLevel + 6]);
SPI.transfer(red[3][dataLevel + 7]);
//Blue
SPI.transfer(blue[3][dataLevel]);
SPI.transfer(blue[3][dataLevel + 1]);
SPI.transfer(blue[3][dataLevel + 2]);
SPI.transfer(blue[3][dataLevel + 3]);
SPI.transfer(blue[3][dataLevel + 4]);
SPI.transfer(blue[3][dataLevel + 5]);
SPI.transfer(blue[3][dataLevel + 6]);
SPI.transfer(blue[3][dataLevel + 7]);
break;
}//switch_case
PORTH |= 1 << latch_pin; //Latch pin HIGH
PORTH &= ~(1 << latch_pin); //Latch pin LOW
PORTH &= ~(1 << blank_pin); //Blank pin (OE) LOW to turn on the LEDs with the new data
//********************************** LEDs ON *******************
``````

Great news, I have speed up my transfer somewhat. In fact from 69 µs to 40 µs. (actual data is 37 µs)
I did get the data transfer down to 27 µs but found a shift in which LED was on.

EG ( in Y,X,Z format) when I asked 0,0,0 - 0,0,1 – 0,0,2 LEDs to turn on LEDs 0,1,6 – 0,1,7 – 0,0,0 came on, odd. :o

Anyway this is what I have come up with to make thing work.

``````case 0:
//Green
myTransfer(green[0][dataLevel]);
myTransfer(green[0][dataLevel + 1]);
//ECT - See above post for full code.
//Then
inline static uint8_t myTransfer(uint8_t C_data){
SPDR = C_data;
asm volatile("nop");asm volatile("nop");
}
``````

This is the same code used in SPI.h with the listen and return removed.