Pages: 1 ... 3 4 [5] 6 7   Go Down
Author Topic: Arduino as SPI slave?  (Read 9431 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Yes I'm here. Looks promising. Thanks for your effort. I did tight loop polling but without success, but without disabling interrupt. I'll try this and report back to you!


Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick,
Can you try a test where the slave sends out at the same time as the master sends out, see if the both receive the data okay?
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not clear about what you mean. Are we talking about 3 devices?

If not, the slave does a
Code:
y = SPI.transfer (x);
where it sends x and receives y at the same time.

After all this is what SPI.transfer does:

Code:
byte SPIClass::transfer(byte _data) {
  SPDR = _data;
  while (!(SPSR & _BV(SPIF)))
    ;
  return SPDR;
}

So one more line of code (to assign to SPDR) and you are sending as well as receiving. I think that would be done at the hardware level as the clock pulses come in, so I don't see why that wouldn't work.
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, I am talking Master sending and receiving from slave at same time, while slave receives & sends at same time.
Then can do something like send a burst of data over for the slave to process, when send the 2nd burst it returns the results from the first burst.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, you would typically use one-byte lookahead here. Since you can't "reply" to the first byte (as it each bit is being sent as each bit is being received) you would get byte 1, and "reply" to it by sending something on byte 2, which is the response to byte 1.

Running at high speed, I am not sure if the extra overhead of fetching the responses (or indeed computing them) would slow down the slave too much.

I suppose if you had a buffer already set up, yes you could do what you suggest and just copy a 256 byte buffer back to the master at the same time you receive another 256 byte buffer. Is that what you want me to test?
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes please. My coding at that level is not good, no experience at the very low level since 1 assembler class back in college. That's one of the things I like about the IDE, it seems to me to be not much harder than writing in BASIC.
But once down in the register level stuff, I just kind of glaze over looking at stuff like while (!(SPSR & _BV(SPIF))) after working all day.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm, well I got it to work but it was tight. That is, this works ...

Master:

Code:
// Written by Nick Gammon
// September 2011

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

byte rbuf [256];

void setup (void)
{
  SPI.begin ();
  Serial.begin (115200);  
}  // end of setup

void loop (void)
{
  delay (2000);

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  for (byte i = 0; i < 255; i++)
    rbuf [i] = SPI.transfer (i);   // send and receive one byte

  // disable Slave Select
  digitalWrite(SS, HIGH);

  // check valid
  Serial.println ("Checking ...");
  for (byte i = 0; i < 255; i++)
    if (rbuf [i] != i)
      {
      Serial.print ("Error at position ");
      Serial.print (i, DEC);
      Serial.print (" got ");
      Serial.println (rbuf [i], DEC);
      return;  
      }
      
  Serial.println ("Passed.");    
    
}  // end of loop

Slave:

Code:
// Written by Nick Gammon
// September 2011

#include "pins_arduino.h"

byte rbuf [256];

void setup (void)
{
  Serial.begin (115200);   // debugging

  // have to send on master in, *slave out*
  pinMode (MISO, OUTPUT);
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
}  // end of setup

// main loop - wait for flag set in interrupt routine
void loop (void)
{
byte rpos;

    Serial.println ("Starting ...");
    rpos = 0;
    
    noInterrupts ();    
    while (rpos < 255)
      {
      // send a byte
      SPDR = rpos;
      
      // receive a byte
      while(!(SPSR & (1<<SPIF)))
        {}
      rbuf [rpos++] = SPDR;
      }
    
    interrupts ();
        
    // check valid
    Serial.println ("Checking ...");
    for (byte i = 0; i < 255; i++)
      if (rbuf [i] != i)
        {
        Serial.print ("Error at position ");
        Serial.print (i, DEC);
        Serial.print (" got ");
        Serial.println (rbuf [i], DEC);
        return;  
        }
        
    Serial.println ("Passed.");        
}  // end of loop

But I was getting errors until I moved:

Code:
byte rpos;

from being a global variable to a local one (maybe that got put into a register). And I couldn't send a buffer. So CPU cycles must be really tight. I doubt if you could do anything useful at that speed.

Quote
I just kind of glaze over looking at stuff like while (!(SPSR & _BV(SPIF))) after working all day.

Yeah that stuff can be mind-boggling, but really it is just reading a byte from the processor (the SPI status byte) and seeing if a particular bit is set. In this case the SPIF bit is the high-order bit, so you could write this, but perhaps not be as portable:

Code:
while (SPSR & 0x80 == 0)
    ;

Or even:

Code:
while (SPSR & 0b10000000 == 0)
    ;
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

"I doubt if you could do anything useful at that speed."  Rats.
Okay, I'm gonna keep working on a FIFO interface then.
Guess I should make it FIFO both direction for ultimate flexibility.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8473
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

But you can save and display at 4MHz, that does make a somewhat useful sniffer but only for one channel, ie MISO or MOSI but not both and to be really useful though I think you need to be able to sample both, so your FIFO setup would be the go for that I reckon but you'll need two FIFOs.

Another way to do this is with high-speed SRAMs, you can get 1 or 4 bit versions with fast access times that would make good sampling chips, although they would need more support hardware.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The FIFOs are really fast, just need the serial/parallel shift registers, and a counter to keep in sync with the bytes.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8473
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Crossroads, did you do any more work on that FIFO design?

I just had a brilliant (I think) idea to do a cheap analyser, I might start another thread to write it up.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ordered some 50 MHz FIFO parts and the Saleae analyzer, busy with fencing this weekend.  Competed this morning, marked out strips at our club this afternoon, back at it tomorrow, classes on Tuesdays. Entering stuff for some upcoming tournaments now.
What'd you have in mind?
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8473
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I started a thread here

http://arduino.cc/forum/index.php/topic,71396.new.html#new

Just a thought. Mind you the FIFOs would do a similar thing.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Done some more test on the heater controller today and finally I got it working. My conclusions:

- Yes, the AVR can be a SPI slave running at 4 MHz. Since there is also a few us delay between incoming bytes on the controller that I'll monitor you can also do some processing on the incoming bytes before storing them in an array for printing.

- A logic level converter is necessary - otherwise clock line is lost, I used a 78HC08 running av 5V. I also inverted the CS line from the controller and used that signal as the other AND input. In that way the clock line is low

- The clock is, of course, running also when data is transfered from slave to master. When a slave is eavesdropping only one line (MOSI) on the SPI traffic this results in lots of $FF. A large buffer wouldn't even get me half the way to the data I'm after.

- After analyzing output from the SPI line, dropping the $FF's and being careful on what to print out on serial I found that the data I was after was found on position 549 and onwards. This does not include the $FF's. The controller was reading two blocks and writing one block of data before writing one block to the textfile.

Here is the code for printing out the useful data:

Code:
#include "pins_arduino.h"

byte rbuf [512];

void setup (void)
{
  Serial.begin (115200);   // debugging

  // have to send on master in, *slave out*
  pinMode (MISO, OUTPUT);
  pinMode (SS, INPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
}  // end of setup

// main loop - wait for flag set in interrupt routine
void loop (void)
{
    int rpos;
    int wd;
   
    Serial.println ("Starting ...");
   
    rpos = 0;
    // wait for SS pin to go low
    while(digitalRead(SS) == HIGH)
    {}
   
    // data is found at position 549 -1060
    noInterrupts ();   
    while (rpos < 1060)
      {
      // wait for a byte
      while(!(SPSR & (1<<SPIF)))
        { }
     
      // read SPDR
      byte c = SPDR;
     
      // filter out 0xFF and store pos 549 - 1060
      if(c != 0xFF )
      {
         if(rpos >=549)
            rbuf [rpos-549] = c;
        // increment counter
        rpos++;
      } 
      }
    interrupts ();
   
    Serial.println ("Printing ...");
    for (int i = 0; i < 512; i++)
    {
      Serial.print(i);
      Serial.print(";");
      Serial.print(rbuf[i],DEC);
      Serial.print(";");
      Serial.println(rbuf[i]);
      rbuf[i] = 0;
    }
    Serial.println ("Done ...");       
} // end of loop

Thanks for the help!

Remaining issues:

1. Find out if an Arduino Ethernet can be a SPI slave or if the ethernet IC messes up the spi lines. Check if another pin can be CS line

2. Find the last line of text from the rbuf, probably will have to check for $FF since this is 0xFFFF is FAT eof marker.

3. Find out how to implement some kind of watchdog working when interrupts are disabled. Could a ++ counter be enough?

Regards,
Torgil


Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 525
Posts: 26521
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

For #1, each SPI slave needs its own CS line from the master. Any pin can be used as the SS line.

#2, sounds like a function of your code.

#3, not sure what you're after.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Pages: 1 ... 3 4 [5] 6 7   Go Up
Jump to: