Pages: [1] 2   Go Down
Author Topic: SPI Pins  (Read 2306 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I see on the Arduino SPI reference page that pins 10, 11, 12, 13 are for the SPI. I see examples and tutorials that use other pins.

Are the examples that use other pins for SPI wrong?

Here is one example.

http://www.ladyada.net/learn/sensors/thermocouple.html

I have an Arduino Uno.

Thanks
John
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can do software SPI on whatever data pins you like.  I expect that is what the thermocouple adapter library is doing.  The hardware SPI is on pins 10-13.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Manchester, New Hampshire
Offline Offline
Edison Member
*
Karma: 4
Posts: 1368
Propmaker
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If I'm not mistaken, the hardware SPI is actually pins 11-13.  Pin 10 seems to be most often reccomended as the chip select pin, but as you have to set it high and low manually before you send data with the SPI lib, you could use any pin you want really, and if you want to have more than one chip using the hardware SPI bus then you'll have to if you want to select each chip in turn.
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If I'm not mistaken, the hardware SPI is actually pins 11-13.  Pin 10 seems to be most often reccomended as the chip select pin, but as you have to set it high and low manually before you send data with the SPI lib, you could use any pin you want really, and if you want to have more than one chip using the hardware SPI bus then you'll have to if you want to select each chip in turn.

You are right for the most common case of the Arduino being the SPI Master.  In that case the SS pin (D10) is left to user control so it, or any other free data pin, can be used for Slave Select.  If the Arduino is acting as an SPI Slave then the SS pin (D10) is used by the hardware to disconnect the Arduino from the SPI buss when it is not being addressed.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

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

Well, not really disconnect, more to indicate "this message is not for you!"
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.

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can do software SPI on whatever data pins you like.  I expect that is what the thermocouple adapter library is doing.  The hardware SPI is on pins 10-13.

What does hardware SPI vs software SPI mean?

Thanks
John
Logged

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

software spi is the shiftout command, basically:
digitalWrite (output_pin, bit0_of_data_byte);
digitalWrite (clock_pin, LOW);
digitalWrite (clock_pin, HIGH);
repeat  7 times for bits 1-7.
Only written more efficiently. Still controlled bit by bit.

Hardware spi is basically a built-in shift-out hardware register that spits the same data out way quicker.
See section 18 of the ATMega328 data sheet.
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.

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 362
Posts: 17306
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

software spi is the shiftout command, basically:
digitalWrite (output_pin, bit0_of_data_byte);
digitalWrite (clock_pin, LOW);
digitalWrite (clock_pin, HIGH);
repeat  7 times for bits 1-7.
Only written more efficiently. Still controlled bit by bit.

Hardware spi is basically a built-in shift-out hardware register that spits the same data out way quicker.
See section 18 of the ATMega328 data sheet.

I did effectivly that for a led cube project, as I was needing to shift out a 32 bit long variable and it was easier on my head to do it that way then to figure out how to breakup the variable into byte size chunks and use SPI four times.  smiley-wink

Logged

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

Most AVRs have hardware to to the SPI shifting, this hardware it conncted to 4 pins and that connection cannot be changed so you have to use those four pins.

However you can replicate the functionality by "bit banging" the bits on any pins you like, this is quite easy (as a master anyway) and just needs a loop that fiddles with the pins or on the Arduino the shiftOut() function.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Manchester, New Hampshire
Offline Offline
Edison Member
*
Karma: 4
Posts: 1368
Propmaker
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I did effectivly that for a led cube project, as I was needing to shift out a 32 bit long variable and it was easier on my head to do it that way then to figure out how to breakup the variable into byte size chunks and use SPI four times.  ;)

« Last Edit: March 03, 2011, 08:13:57 am by scswift » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 362
Posts: 17306
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I did effectivly that for a led cube project, as I was needing to shift out a 32 bit long variable and it was easier on my head to do it that way then to figure out how to breakup the variable into byte size chunks and use SPI four times.  smiley-wink



Quite serious, here is the ISR routine that performs the 32 bit serial shifting out to the shift registers:

Quote
void refresh_display() {
 if (!updateinprogress) {
  unsigned long shiftdata = active_display[active_row]; // get row data for 25 leds
  unsigned long shiftmask = 1;

  for (byte i = 0; i < 32; i++) {                     // shift 32 bits (only 25 bits are wired up to cube) of data out for the 25 display columns

    if (shiftdata & shiftmask) {
      digitalWrite(dataPin, HIGH);
    }
    else {
      digitalWrite(dataPin, LOW);
    }

    digitalWrite(clockPin, HIGH);                     //  clock each bit into shift register
    digitalWrite(clockPin, LOW);

    shiftmask = shiftmask * 2;       //right shift bit mask one bit
  }

  if (active_row == 0) {
    digitalWrite(row4Pin, LOW);            // turn off row 4 driver if row 0 is now active, this is wrap around case
  }
  else {
    digitalWrite((active_row + 1), LOW);  // turn off driver from prior row update interrupt
  }

  digitalWrite(latchPin, HIGH);           // turn on shift register output pins, column drivers
  digitalWrite(latchPin, LOW);
  digitalWrite((active_row + 2), HIGH);   // turn on active row driver transistor

  // Set next active row number for next timer interrrupt 
  if (active_row >= 4) {   
    active_row = 0;  // wraparound case
    }
  else {
    active_row++;  // increament row number for next interrupt cycle
    }
 }
}  // end of ISR code


Lefty
Logged

Manchester, New Hampshire
Offline Offline
Edison Member
*
Karma: 4
Posts: 1368
Propmaker
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Code:
unsigned long shiftdata = active_display[active_row]; // get row data for 25 leds
  unsigned long shiftmask = 1;

  for (byte i = 0; i < 32; i++) {                     // shift 32 bits (only 25 bits are wired up to cube) of data out for the 25 display columns

    if (shiftdata & shiftmask) {
      digitalWrite(dataPin, HIGH);
    }
    else {
      digitalWrite(dataPin, LOW);
    }

    digitalWrite(clockPin, HIGH);                     //  clock each bit into shift register
    digitalWrite(clockPin, LOW);

    shiftmask = shiftmask * 2;       //right shift bit mask one bit
  }


Well this is how to do it with hardware SPI:

Code:
unsigned long shiftdata = active_display[active_row]; // get row data for 25 leds

digitalWrite(pinSPI_SS, LOW); // Select chip.

SPI.transfer(shiftdata & 255); // Write first byte.
SPI.transfer((shiftdata>>8) & 255); // Shift second byte into first byte and write out first byte.
SPI.transfer((shiftdata>>16) & 255);
SPI.transfer((shiftdata>>24) & 255);

digitalWrite(pinSPI_SS, HIGH); // Deselect chip.

And here's a simpler method to do it in software:

Code:
unsigned long shiftdata = active_display[active_row]; // get row data for 25 leds

digitalWrite(pinShiftLatch, LOW); // Select chip

shiftOut(pinShiftData, pinShiftClock, MSBFIRST, shiftdata);
shiftOut(pinShiftData, pinShiftClock, MSBFIRST, shiftdata>>8);
shiftOut(pinShiftData, pinShiftClock, MSBFIRST, shiftdata>>16);
shiftOut(pinShiftData, pinShiftClock, MSBFIRST, shiftdata>>24);

digitalWrite(pinShiftLatch, HIGH);  // Deselect chip

I don't know when the shiftout function became available so maybe you didn't have the option to use it though.  And you don't need the & 255 on the shifted bits because the shiftout fucntion only shifts out the lower 8 bits of the int passed to it.

I also assume you're selecting the chip outside the function, but I included the code to do that here so others reading it wouldn't be confused about the need to do that.

And just for kicks, here's another way you could have done it manually:

Code:
unsigned long shiftdata = active_display[active_row]; // get row data for 25 leds

  for (byte i = 0; i < 32; i++) {                     // shift 32 bits (only 25 bits are wired up to cube) of data out for the 25 display columns

    if ((shiftdata>>byte) & 1) {
      digitalWrite(dataPin, HIGH);
    }
    else {
      digitalWrite(dataPin, LOW);
    }

    digitalWrite(clockPin, HIGH);                     //  clock each bit into shift register
    digitalWrite(clockPin, LOW);

  }
« Last Edit: March 03, 2011, 01:36:56 pm by scswift » Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a note that SPI is bi-directional and SPI.transaction(outByte) returns the byte that was sent by the Slave while the Master was sending.

In software SPI this would be something like:

Code:
uint8_t SPITransaction(uint8_t outByte)
    {
    uint8_t inByte = 0;
    for (uint8_t i = 0; i < i; i++)
        {
        digitalWrite(MOSIpin,  ((outData>>i) & 1);

        digitalWrite(SCKpin, HIGH);                     //  clock each bit into shift register
        digitalWrite(SCKpin, LOW);

        if (digitalRead(MISOpin))
            inByte += (1<<i);

        }
    return inByte;
   }

That would be one place where a shiftout() call would not work.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Manchester, New Hampshire
Offline Offline
Edison Member
*
Karma: 4
Posts: 1368
Propmaker
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

And just for the sake of completeness, here's the code to set up the SPI.  You'll need to modify it to suit whatever chip you're using:

Code:
  // Initialize Serial-Parralel Interface:
              
        pinMode(pinSPI_SS, OUTPUT); // Set the slave/chip select pin to output.
        
        SPI.begin();      
        SPI.setBitOrder(MSBFIRST); // Send most significant bit first when transferring a byte.
        SPI.setDataMode(SPI_MODE0); // Base value of clock is 0, data is captured on clock's rising edge.
        //SPI.setClockDivider(SPI_CLOCK_DIV4); // Set SPI data rate to 16mhz/4. IE: 4mhz.
        SPI.setClockDivider(SPI_CLOCK_DIV2); // Set SPI data rate to 16mhz/2. IE: 8mhz.
Logged

Manchester, New Hampshire
Offline Offline
Edison Member
*
Karma: 4
Posts: 1368
Propmaker
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a note that SPI is bi-directional and SPI.transaction(outByte) returns the byte that was sent by the Slave while the Master was sending.

In software SPI this would be something like:

Code:
uint8_t SPITransaction(uint8_t outByte)
    {
    uint8_t inByte = 0;
    for (uint8_t i = 0; i < i; i++)
        {
        digitalWrite(MOSIpin,  ((outData>>i) & 1);

        digitalWrite(SCKpin, HIGH);                     //  clock each bit into shift register
        digitalWrite(SCKpin, LOW);

        if (digitalRead(MISOpin))
            inByte += (1<<i);

        }
    return inByte;
   }

That would be one place where a shiftout() call would not work.


That's in the case where you have a slave that's sending data back to you though, right?  So it wouldn't apply to a shift register.  (Or a dac, as it is being used in my code.)
Logged

Pages: [1] 2   Go Up
Jump to: