SPI.h para ATTiny

¿Existe una implementación diferente de la biblioteca SPI de Arduino que se pueda usar para la serie ATTinyX5? Supongo que, en parte, porque creo que ATTiny SPI se proporciona a través de USI... Obtuve la configuración del entorno usando las instrucciones aquí, pero cuando intento compilar cualquier cosa con SPI.h incluido, arroja todo tipo de errores:

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

En la misma línea, ¿hay algo que deba hacerse con el código que usa SPI de hardware para que funcione en ATTiny? Pude hacerlo funcionar con una implementación de golpes de bits, pero el SPI de hardware sería bueno.

Esto está cubierto por la respuesta de @Kurt, pero básicamente el hardware SPI en los microprocesadores ATtiny es muy diferente del hardware SPI en el hardware ATmega. Tendrá que hacer una serie en el software o encontrar una biblioteca específica de ATtiny.

Respuestas (2)

No dijo si está usando el tinyx5 como maestro o esclavo... si es un esclavo, entonces sugiero conectar la línea de selección de esclavos a una interrupción de hardware para activar la operación de lectura y escritura basada en la entrada del reloj. Si el tinyx5 se usará como maestro, es muy fácil usar una solución de software. No uso Arduino en absoluto, pero estoy muy familiarizado con los dispositivos AVR.

Cuando el USI está involucrado, puede complicarse un poco. Siendo realistas, puede ser más efectivo usar una solución bit-bang que usar el USI como SPI para la mayoría de las necesidades. Los errores que ve surgen porque los registros SPI descritos en el archivo de encabezado no tienen el mismo nombre en todos los dispositivos (si es que existen). En el caso del dispositivo ATtiny, no existen ya que utiliza el módulo USI para actuar como SPI. Podría intentar que el USI funcione como SPI, pero recomendaría probar primero esta sencilla solución de software para ver si se adapta a sus necesidades. Todas las variables de capital deben definirse en su proyecto como los pines de reloj y datos SPI apropiados. Por ejemplo:

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

Haga esto para DO (MOSI), DI (MISO) y SCK. Luego use esta función para transferir un 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
}

Se podría crear otra función para llamar repetidamente a esta función para transferir paquetes de datos más grandes. Solo en el caso de una gran transferencia de datos es útil usar el módulo de hardware, ya que podría ser controlado por interrupciones, dejando al programa principal libre para hacer otras cosas mientras se transfieren los datos. Pero si solo se transfieren unos pocos bytes a la vez, este método de software es muy efectivo.

No sé por qué dices que el USI es complicado. Lo he usado un poco para hablar con algunos DAC SPI, y fue bastante fácil hacerlo funcionar.
@ConnorWolf Lea los foros de AVR.net... muchos usuarios se refieren a numerosos problemas relacionados con el uso de la USI para diversos fines. Muchos también notan que, si se escriben correctamente, las soluciones de software pueden funcionar de manera más efectiva y eficiente, especialmente para SPI, ya que es muy simple. Si se van a transferir muchos datos, hacer que el USI funcione puede ser una mejor opción.
Bueno, todo lo que puedo decir es que no tuve muchos problemas para hacer funcionar el USI en una aplicación en la que estaba trabajando que usaba un ATtiny84. Es posible que mi experiencia no sea representativa.

Eche un vistazo a Atmel App Note AVR319 y el software que lo acompaña.

Debería poder utilizar esos materiales para realizar los cambios necesarios en la biblioteca de Arduino.