# SPI.h for ATTiny

Is there a different implementation of the Arduino SPI library that can be used for the ATTinyX5 series? I assume, partly because I believe the ATTiny SPI is provided via USI... I got the environment setup using the instructions here but when I try to compile anything with SPI.h included it just throws all sorts of errors:

C:\Program Files (x86)\arduino\libraries\SPI/SPI.h: In static member function 'static byte SPIClass::transfer(byte)':
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:56: error: 'SPDR' was not declared in this scope
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:57: error: 'SPSR' was not declared in this scope
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:57: error: 'SPIF' was not declared in this scope
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h: In static member function 'static void SPIClass::attachInterrupt()':
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:63: error: 'SPCR' was not declared in this scope
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:63: error: 'SPIE' was not declared in this scope
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h: In static member function 'static void SPIClass::detachInterrupt()':
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:67: error: 'SPCR' was not declared in this scope
C:\Program Files (x86)\arduino\libraries\SPI/SPI.h:67: error: 'SPIE' was not declared in this scope


Along the same lines, is there anything that needs to be done to code that uses hardware SPI to get it to work on the ATTiny? I was able to get it working with a bit-banging implementation but hardware SPI would be nice.

• This is kind of covered by @Kurt's answer, but basically the SPI hardware in the ATtiny microprocessors is very different from the SPI hardware in the ATmega hardware. You will need to either do serial in software, or find an ATtiny specific library. May 20, 2013 at 9:46

You didn't say if you are using the tinyx5 as a master or slave... if it is a slave, then I suggest connecting the slave select line to a hardware interrupt to trigger the read and write operation based on the clock input. If the tinyx5 will be used as a master, than it is very easy to just use a software solution. I do not use Arduino at all, but I am very familiar with AVR devices.

When the USI is involved, it can get a little complicated. Realistically, it can be more effective to use a bit-bang solution than to use the USI as SPI for most needs. The errors you see arise because the SPI registers described in the header file are not named the same thing in every device (if they even exist). In the case of the ATtiny device, they do not exist since it uses the USI module to act as the SPI. You could try to get the USI to work as SPI, but I would recommend trying this simple software solution first to see if it will suit your needs. The all capital variables need to be defined in your project as the appropriate SPI data and clock pins. For example:

#define _USI_SPI_PORT PORTB
#define _U_DO         (1<<PB0)  // Or _BV(PB0)


Do this for DO (MOSI), DI (MISO), and SCK. Then use this function to transfer a byte:

unsigned char SPI_transferByte(unsigned char data)
{
unsigned char bit = 0;

_U_SPI_PORT &= ~_U_SS                 // Need to manually Lower the SS line first

for(bit = 0; bit < 8; bit++)          // Loop through 8 bits
{
if(data & 0x80) _U_SPI_PORT |= _U_DO;   // If bit(7) of "data" is high
else _U_SPI_PORT &= ~_U_DO;          // if bit(7) of "data" is low
_U_SPI_PORT |= _U_SCK;                  // Serial Clock Rising Edge
data <<= 1;                             // Shift "data" to the left by one bit
if(_U_SPI_PIN & _U_DI) data |= 0x01;    // If bit of slave data is high
else data &= ~0x01;                  // if bit of slave data is low
_U_SPI_PORT &= ~_U_SCK;              // Serial Clock Falling Edge
}
_U_SPI_PORT |= _U_SS                 // Need to manually Raise the SS line Last

return data;                      // Returns shifted data in value
}


Another function could be created to repeatedly call this function to transfer larger packets of data. Only in the case of large data transfer is it useful to use the hardware module since it could be interrupt driven, leaving the main program free to do other things while the data transfers. But if only a few bytes are transferred at a time, this software method is very effective.

• I don't know why you say the USI is complicated. I've used it a bit to talk to some SPI DACs, and it was quite easy to get working. May 20, 2013 at 9:47
• @ConnorWolf Read the AVR.net forums... a lot of users refer to numerous issues regarding use of the USI for various purposes. Many also note that if written correctly, software solutions can work more effectively and efficiently, especially for SPI since it is so simple. If a lot of data will be transferred, then getting the USI to work may be a better option. May 20, 2013 at 19:19
• Well, all I can say is I didn't have much trouble getting the USI working in an application I was working on that used an ATtiny84. It's possible my experience may not be representative. May 21, 2013 at 0:22

Please take a look at Atmel App Note AVR319 and the accompanying software.

You should be able to use those materials to make the necessary changes to the Arduino library.