Go Down

Topic: Using an ATtiny85 as SPI Slave (Read 10 times) previous topic - next topic

jabami

Hi together,

Im trying to use an Attiny85 as an SPI Slave to do some low Frequency measurements while the Master (an Arduino Mega) is connected to LabView running the Arduino Toolkit. When I say low Frequency I mean like 1kHz maximum. The Frequency to be measured is from an Flowmeter which delivers a nice Squaretype signal.
The Master cannot be used for the measurement as there are multiple sensors hooked up which are polled by the LabView Software directly.

Now what I did:
I first flashed an SPI Slave Code to an Arduino Nano (for testing the SPI connection and the Frquency measurement) which I had lying around.This worked flawlesly.
Here is the Code:

Code: [Select]
// Written by Nick Gammon
// April 2011

#include "pins_arduino.h"
#include <FreqPeriodCounter.h>

// what to do with incoming data
byte command = 0;

int frq;

const byte counterPin = 3;
const byte counterInterrupt = 1; // = pin 3
FreqPeriodCounter counter(counterPin, micros, 0);

void setup (void)
{
  // Serial.begin(9600);
 
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPCR |= _BV(SPIE);

  attachInterrupt(counterInterrupt, counterISR, CHANGE);

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;

  switch (command)
  {
  // no command? then this is the command
  case 0:
    command = c;
    SPDR = 0;
    break;
   
  // add to incoming byte, return result
  case 'a':
    SPDR = frq;  // spit out Frquency Reading
    break;

  } // end of switch

}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
  if(counter.ready()) frq = (counter.hertz());
  // Serial.println(frq);
  // if SPI not active, clear current command
  if (digitalRead (SS) == HIGH)
    command = 0;
}  // end of loop

void counterISR()
{ counter.poll();
}


Now I´m trying to port this Code to an Attiny85. I installed the ATtiny Core libraries and can flash the ATiny85. But I get the following error when trying to compile the code presented above:

SPI_Slave_v1.cpp: In function 'void setup()':
SPI_Slave_v1:20: error: 'MISO' was not declared in this scope
SPI_Slave_v1:23: error: 'SPCR' was not declared in this scope
SPI_Slave_v1:23: error: 'SPE' was not declared in this scope
SPI_Slave_v1:26: error: 'SPIE' was not declared in this scope
SPI_Slave_v1.cpp: In function 'void SPI_STC_vect()':
SPI_Slave_v1:36: error: 'SPDR' was not declared in this scope
SPI_Slave_v1.cpp: In function 'void loop()':
SPI_Slave_v1:60: error: 'SS' was not declared in this scope

Now I understand that the Attiny uses USI as a basis for the SPI interface. But where and how do I declare the Pins (MISO, SPCR etc.) I need for the SPI to work properly? The "normal" SPI.h libraries for the 328 etc. do not need to be configured.
However I found an example for an SPI Slave with USI on an Attiny85 here:
http://avrhelp.mcselec.com/index.html?using_usi_universal_serial_int.htm
So in general I'm confident that it is going to work. I just don't know how.
Any help is appreciated.

Best regards,
Jan

Coding Badly

Hi apart,

Now I understand that the Attiny uses USI as a basis for the SPI interface.


Correct.  The ATtiny family does not have a dedicated SPI subsystem.

Quote
But where and how do I declare the Pins (MISO, SPCR etc.) I need for the SPI to work properly?


Declaring the pins will not get you to your goal.  USI and SPI are very different critters.  You need SPI slave code written specifically for the USI.

Quote
However I found an example for an SPI Slave with USI on an Attiny85 here:
http://avrhelp.mcselec.com/index.html?using_usi_universal_serial_int.htm


That example may work (after porting it to C).  But a sanity check is necessary: What else will the ATtiny processor be doing?  What SPI bitrate are you hoping to use?

jabami

Hi,

thank you for the reply.It seems like the task is more complex than I initially thought. I personally wont be able to port the above linked Code to C. I wonder why nobody else has written an SPI Slave Code for the Attiny using the Arduino IDE. I found the I²C Code for the ATtiny here:
http://www.arduino.cc/playground/Code/USIi2c .
However, this I²C port does not use interrupts and the main loop of the code is stuffed with I²C Communication code. As Im exploiting frequency measuremnents here (which might be scallable in the near future) I find that rather unelegant. The above given SPI Slave example does use interrupts and the main loop is used heavily for the frequency measurement.

The ATtiny85 I will be using is just supposed to constantly measure the frequency of one flowmeter. When polled for it the ATtiny85 should transfer the measured frequency via SPI to the master. I guess a low bitrate will be sufficient for my case. Thus 9600 baud should do the job.

Best regards,
Jan

dhenry

Writing a software slave is always difficult. Writing a spi slave, however, is easier than writing an i2c slave.

A minimum implementation would involve an interrupt to detect changes on the SCK pin. Once in that isr, process the CS line as well as the MOSI line.

You can code it in a way that it is almost register-name compatible with the hardware spi.

fungus


A minimum implementation would involve an interrupt to detect changes on the SCK pin. Once in that isr, process the CS line as well as the MOSI line.


No need for that. The hardware does most of the work for you. You just select an external pin as clock input and wait for the complete byte to arrive (which you can do via polling or generate an interrupt when it's complete).

The Tiny85 datasheet has example code.

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Go Up