0
Offline
Jr. Member
Karma: 0
Posts: 52
Arduino rocks
|
 |
« on: March 02, 2011, 08:17:30 am » |
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.htmlI have an Arduino Uno. Thanks John
|
|
|
|
|
Logged
|
|
|
|
|
Massachusetts, USA
Offline
Tesla Member
Karma: 96
Posts: 6339
|
 |
« Reply #1 on: March 02, 2011, 10:24:20 am » |
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
|
|
|
|
|
Manchester, New Hampshire
Online
Edison Member
Karma: 0
Posts: 1119
Propmaker
|
 |
« Reply #2 on: March 02, 2011, 10:42:28 am » |
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
Tesla Member
Karma: 96
Posts: 6339
|
 |
« Reply #3 on: March 02, 2011, 12:56:23 pm » |
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
|
|
|
|
|
Global Moderator
Boston area, metrowest
Offline
Brattain Member
Karma: 240
Posts: 16433
Available for Design & Build services
|
 |
« Reply #4 on: March 02, 2011, 01:00:47 pm » |
Well, not really disconnect, more to indicate "this message is not for you!"
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 52
Arduino rocks
|
 |
« Reply #5 on: March 02, 2011, 08:01:28 pm » |
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
Brattain Member
Karma: 240
Posts: 16433
Available for Design & Build services
|
 |
« Reply #6 on: March 02, 2011, 08:47:10 pm » |
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
|
|
|
|
|
Left Coast, CA (USA)
Offline
Brattain Member
Karma: 279
Posts: 15310
Measurement changes behavior
|
 |
« Reply #7 on: March 02, 2011, 09:08:02 pm » |
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. 
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6808
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #8 on: March 02, 2011, 09:29:20 pm » |
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
|
|
|
|
|
Manchester, New Hampshire
Online
Edison Member
Karma: 0
Posts: 1119
Propmaker
|
 |
« Reply #9 on: March 03, 2011, 07:34:04 am » |
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
Brattain Member
Karma: 279
Posts: 15310
Measurement changes behavior
|
 |
« Reply #10 on: March 03, 2011, 11:39:33 am » |
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.   Quite serious, here is the ISR routine that performs the 32 bit serial shifting out to the shift registers: 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
Online
Edison Member
Karma: 0
Posts: 1119
Propmaker
|
 |
« Reply #11 on: March 03, 2011, 01:33:12 pm » |
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: 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: 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: 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
Tesla Member
Karma: 96
Posts: 6339
|
 |
« Reply #12 on: March 03, 2011, 01:53:35 pm » |
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: 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
|
|
|
|
|
Manchester, New Hampshire
Online
Edison Member
Karma: 0
Posts: 1119
Propmaker
|
 |
« Reply #13 on: March 03, 2011, 02:03:42 pm » |
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: // 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
Online
Edison Member
Karma: 0
Posts: 1119
Propmaker
|
 |
« Reply #14 on: March 03, 2011, 02:06:50 pm » |
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: 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
|
|
|
|
|
|