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

Since this seems to be a dead end without solution I'm thinking on another aproach. I'll start a new topic "SD Card SPI with two masters".
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hard to believe we can send data out faster than we can receive it. Makes you wonder how all the slave we talk to keep up, like the MAX7219/7221.

They probably have dedicated shift registers and buffers designed to handle the (probably small) amount of data they need to receive.
Logged

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

Quote
Makes you wonder how all the slave we talk to keep up, like the MAX7219/7221.
Most SPI slave chips are 100% hardware, when you use an AVR half the job is done in software.

AVRs are crap at being an SPI slave because they are not double buffered. As such the ISP (if you use one) has to service the SPI data reg within 1 SPI clock cycle, ie after the 8 bit is clocked in but before the 9th. At high speed this is not an option.

You will never do high speed using interrupts.

You should be able to do it with some tight polling, otherwise AFAIK you have to add a small delay when transmitting bytes.

Although the code in the early post did poll the SPI it then spent half an hour printing and dicking around, meanwhile probably 29 bytes had been received.

______
Rob
« Last Edit: August 30, 2011, 09:11:50 am by Graynomad » Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 435
Posts: 23611
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 found some large FIFOs at Newark, I have a schematic mostly done to use 74AC299 Universal Shift Register (I bought 20 of them a while back) to clock in the bit stream, transfer to the FIFO, then parallel read or serially shift out using 2nd 74AC299.
Need to work in clock edge counter next to capture bytes when SS is held low for burts of 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.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

AVRs are crap at being an SPI slave because they are not double buffered.

From the Atmega328 datasheet, page 167:

Quote
The system is single buffered in the transmit direction and double buffered in the receive direction. This means that bytes to be transmitted cannot be written to the SPI Data Register before the entire shift cycle is completed. When receiving data, however, a received character must be read from the SPI Data Register before the next character has been completely shifted in. Otherwise, the first byte is lost.

So it's double buffered. But the rate (for this application) is still too high according to the specs.
Logged

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

Yep it is, for some reason I thought it didn't even have that buffer.

So in most apps it should be easy enough to respond in time if you're careful about reading the data and then dealing with it later. But in this case you may have a continuous data stream and never get a chance to display it. Even if it's not continuous you need to know when you have a break in the data to go off and do something else.

Bottom line is I think that this can't be done with a slow(ish) processor and fast data unless you can determine when there's a break in the data.

I'd spend $150 and get a Saleae logic analyzer, you'll be decoding the data in a few minutes with the right tool.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You will never do high speed using interrupts.

You should be able to do it with some tight polling, otherwise AFAIK you have to add a small delay when transmitting bytes.

I was curious if that was true, so I did some careful measuring.



Test 1, using interrupts:

Code:
void isr () {
  PORTB = 0x20;      // LED on   
}

void setup() {
  pinMode(13, OUTPUT);     
  attachInterrupt(0, isr, FALLING);     
}

void loop() {
  PORTB = 0;     // LED off   
}

To reduce overhead, I used direct port manipulation to turn the LED on pin 13. I then pumped through gradually increasing square waves into D2 to see what would happen. The bottom line was that it took around 3.5 uS for the LED to turn on after the trailing edge on D2. Also, you couldn't handle a frequency much higher than 150 kHz before some edges were missed (ie. around 6.7 uS all-round response).

This was somewhat poorer response than I expected, as the datasheet says the processor responds to interrupts "in 4 clock cycles". However a bit of research shows that the internal interrupt routine is actually this:

Code:
SIGNAL(INT0_vect) {
 166: 1f 92        push r1
 168: 0f 92        push r0
 16a: 0f b6        in r0, 0x3f ; 63
 16c: 0f 92        push r0
 16e: 11 24        eor r1, r1
 170: 2f 93        push r18
 172: 3f 93        push r19
 174: 4f 93        push r20
 176: 5f 93        push r21
 178: 6f 93        push r22
 17a: 7f 93        push r23
 17c: 8f 93        push r24
 17e: 9f 93        push r25
 180: af 93        push r26
 182: bf 93        push r27
 184: ef 93        push r30
 186: ff 93        push r31
  if(intFunc[EXTERNAL_INT_0])
 188: 80 91 00 01 lds r24, 0x0100
 18c: 90 91 01 01 lds r25, 0x0101
 190: 89 2b        or r24, r25
 192: 29 f0        breq .+10      ; 0x19e <__vector_1+0x38>
    intFunc[EXTERNAL_INT_0]();
 194: e0 91 00 01 lds r30, 0x0100
 198: f0 91 01 01 lds r31, 0x0101
 19c: 09 95        icall
}
 19e: ff 91        pop r31
 1a0: ef 91        pop r30
 1a2: bf 91        pop r27
 1a4: af 91        pop r26
 1a6: 9f 91        pop r25
 1a8: 8f 91        pop r24
 1aa: 7f 91        pop r23
 1ac: 6f 91        pop r22
 1ae: 5f 91        pop r21
 1b0: 4f 91        pop r20
 1b2: 3f 91        pop r19
 1b4: 2f 91        pop r18
 1b6: 0f 90        pop r0
 1b8: 0f be        out 0x3f, r0 ; 63
 1ba: 0f 90        pop r0
 1bc: 1f 90        pop r1
 1be: 18 95        reti

Now adding up the clock cycles for those instructions (the push alone takes two cycles and there are 15 of them) it comes to 45, plus 4 to enter the interrupt, plus 3 for the JMP from the interrupt vector table. Then there is this in "my" interrupt routine:

Code:
void isr () {
  PORTB = 0x20;       
 100: 80 e2        ldi r24, 0x20 ; 32
 102: 85 b9        out 0x05, r24 ; 5
}
 104: 08 95        ret

That's another couple of cycles to turn on the LED. Total being 45 + 4 + 3 + 2 = 54 cycles. That accounts for 3.38 uS response time, which is pretty close to the measured one. Then there is all the stuff to exit interrupts (ret = 4 + 35 others) and that would account for another 2.4 uS.



Test 2, using a tight loop:

Code:
void setup() {
  pinMode(13, OUTPUT);     
  noInterrupts();
}

void loop() {
  while (true)
  {
    if (PIND & 0x04)
      PORTB = 0;
    else
      PORTB = 0x20;
  }
}

This time I measured something like 480 nS for the LED to light, which indicates it was noticed within about 7 clock cycles. The relevant code is:

Code:
  while (true)
  {
    if (PIND & 0x04)
 102: 4a 9b        sbis 0x09, 2 ; 9
 104: 02 c0        rjmp .+4      ; 0x10a <loop+0xa>
      PORTB = 0;
 106: 15 b8        out 0x05, r1 ; 5
 108: fc cf        rjmp .-8      ; 0x102 <loop+0x2>
    else
      PORTB = 0x20;
 10a: 85 b9        out 0x05, r24 ; 5
 10c: fa cf        rjmp .-12      ; 0x102 <loop+0x2>

Clearly there are less instructions there than in the interrupt routine, so taking something like 6 cycles to notice the pin change would be about right.



So I'll have to agree, whilst interrupts are pretty useful, they can't respond as fast as a tight loop. But on the other hand, if you are using a tight loop you aren't doing anything else useful, so it would depend on the application somewhat.
Logged

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

Yep, "responding to interrupts" and actually doing some useful work are different things.

I argued this exact scenario the other day on another thread but just guestimated the times, thanks for quantifying it.

Quote
so it would depend on the application somewhat.
Always trade offs to decide about, that's why we get the big bucks smiley

______
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

Thankyou for investigating the difference in overhead between interrupt and polling. Could it be the compiler causing some of the overhead? It seems like part of the ISR is connected to restoring stack variables.

If anyone is still interested in where this thread started I think that I have now got an explanation to all the $FF's recieved by the Arduino when eavesdropping the SPI line. After studying SD card library I've noticed that there is a card initialization sequence run when the card is accessed. This sequence is run on a low clock speed, normally 1/128 or 125 kHz and sends 10 $FF bytes. My guess is that this is done by the controller more than once during the logging sequence that occurs every 5 secs.

I've also been looking into FIFO's and shift registers, but to me it seems like a much more simple solution to add some logics to make it possible for two SPI masters to access the same SD card. Now I need a SD card holder to try this aproach. Regarding shift register + FIFO I guess the idea is to use parallell input to the arduino? It would then also be necessary to add some logic to divide the clock/8 and reset the shift register on cs high-low transition?
Logged

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

Quote
Could it be the compiler causing some of the overhead?
Yes, you can use the _ISR_NAKED directive to stop the compiler inserting the pre and postambles. This works well because you can save just some of the regs, but of course you need to know what needs saving smiley

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 435
Posts: 23611
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

"Regarding shift register + FIFO I guess the idea is to use parallell input to the arduino? It would then also be necessary to add some logic to divide the clock/8 and reset the shift register on cs high-low transition?"
That's what I am drawing up. Shift register to convert serial to parallel, counter to sync SS with Write pulse to the FIFO (important for >1 byte bursts of data), parallel to serial shift register and/or parallel read out of the FIFO for "playback". Was drawing up mixing the counter output with SS and SPI clock last night to create FIFO write pulse in the correct place (valid data on shift register, no funny clock glitches to cause spurious writes). Expect to have it down tonight. Got busy with yardwork last night & was too tired to think.
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.

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


Interesting, looking forward to hear about your progress. I'm waiting for an Arduino SD card shield to try my aproach, will probably arrive tomorrow. I've got the logics wired and it seems to operate ok. Have tried with a 4 MHz squarewave and is getting through quite ok. The FIFO setup might not be suitable for my project since I need most of the pins on the arduino for other puposes.
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 435
Posts: 23611
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

Sounds like you need a Bobuino then! Lots of IO, SD card built in.
Check my link below smiley
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
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 435
Posts: 23611
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

Rob,
How's this look as an SPI Sniffer?
My only concern is the very first rising edge - may have to delay the edge a bit until after the 1st Qa high transition so there's no glitch to start.


* SPI_Data_Sniffer.jpg (339.85 KB, 2532x1478 - viewed 15 times.)
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: 121
Posts: 8431
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oooo, like I said before, you've got way too much time on your hands smiley

It will take me a while to have a good look, first thoughts though

Why not just use Qd as the FIFO clock? I think that will get rid of all the ORd inverters.

EDIT: Ignore for the moment, I don't think I looked close enough.

______
Rob
« Last Edit: August 31, 2011, 08:18:36 pm by Graynomad » Logged

Rob Gray aka the GRAYnomad www.robgray.com

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