Hardware SPI questions

Hey guys,

I'm studying how to do hardware SPI because I don't think doing it in software is going to be fast enough to write to a DAC at the sampling rates I need.

I've already discovered that to do hardware SPI I need to connect my DAC to specific pins. SPI may use any or all of the following:

D10 - CS aka Chip Select aka SS aka Slave Select
D11 - SDI aka ??? aka MOSI aka Master Out Slave In aka Output
D12 - ??? aka ??? aka MISO aka Master In Slave Out aka Input
D13 - CLK aka SLK aka Serial Clock

What I need to know is this:

  1. Do I need to connect pin 10 to the DAC, if it is the only thing I am communicating with? Could I stick a pullup/pulldown resistor on the DAC's CS pin instead to keep it eneabled?

  2. If I can get away without connecting pin 10 to the DAC, can I put it to other use without issue, or will the hardware SPI mess with the pin?

  3. Question 2 applies to pin 12 as well. The DAC has no way to send data back to the atmega, so that pin will be connected to nothing. Can I use it for something else without screwing up my communications, and without the communications messing with whatever's on the pin?

I found the page for the SPI library:

It says the following:

On the Arduino Duemilanove and other ATmega168 / 328-based boards, the SPI bus uses pins 10 (SS), 11 (MOSI), 12 (MISO), and 13 (SCK). On the Arduino Mega, this is 50 (MISO), 51 (MOSI), 52 (SCK), and 53 (SS). Note that even if you're not using the SS pin, it must remain set as an output; otherwise, the SPI interface can be put into slave mode, rendering the library inoperative.

When they say "even if you're not using the SS pin, it must remain set as an output" do they mean you can't do anything with the pin, or is it just a warning that if you do do anything with the pin, like blink an LED, it's gotta be used as an ouput pin?

Also:

This transfer function sends and recieves a byte at the same time. What happens if after I set up my SPI communications I set pin 12 to output and use it for other things and then call this function? Will I just get garbage back? Will it toggle pin 12 back to an input?

The DAC has no way to send data back to the atmega, so that pin will be connected to nothing. Can I use it for something else without screwing up my communications,

Yes

So how about pin 10? As long as I leave that set to output, can I do other things with that? Or will the SPI lib pull it low every time I try to send a byte to the DAC?

So how about pin 10?

It's absolutely essential to "real" SPI (occasionally, you'll see a manufacturer call some other shift-register-based interface "SPI" when it's not the same as the original Motorola design. You need to watch out for that when picking parts): it tells the slave "This data is for you" and "This is where the byte starts and ends". So you can't just tie it low if you have only one slave.

Thanks. That confirms what I read earlier this morning when trying to figure out how to communicate with my dac:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1286797300

My main problem now is that I think I can't use hardware SPI to communicate with this DAC because I think it expects 16 bits before the CS pin goes high again.

Got another question about hardware SPI.

The DAC I want to talk to requores 16 bits before the CS pin goes high.

Yet from what I've read, it seems the Arduino's hardware SPI library sets the CS pin high after each bit you tell it to send.

Posts by Grumpymike and others have indicated that you may need to bit bang if you want to send a 16 bit word to an SPI device because the Arduino's hardware can't handle that.

But I was reading the ATMega328's datasheet, and it had this to say on page 168:

When configured as a Master, the SPI interface has no automatic control of the SS line. This
must be handled by user software before communication can start. When this is done, writing a
byte to the SPI Data Register starts the SPI clock generator, and the hardware shifts the eight
bits into the Slave. After shifting one byte, the SPI clock generator stops, setting the end of
Transmission Flag (SPIF). If the SPI Interrupt Enable bit (SPIE) in the SPCR Register is set, an
interrupt is requested. The Master may continue to shift the next byte by writing it into SPDR, or
signal the end of packet by pulling high the Slave Select, SS line.

Now that sure sounds to me like the library is at fault here, and that the library must be the one setting the CS/SS pin high and low and that the hardware transfer that takes place has nothing to do with that pin's state being changed. Is that correct?

If so, it sure would be nice if the hardware SPI lib had a function to send 16bits at once, or a function that sent a byte but didn't toggle the SS/CS pin at the start and end of the transmission.

I know this thread is a bit old now, but it came up in a search about SPI.

I am using just the clock and data ( SCK and MOSI ) outputs with a SPI.transfer(a); type instruction.

I am not driving a real SPI device, just some shift registers.

I completely forgot about the SS and MISO pins 10 and 12 being used by the SPI library, and I used them for completely different functions, and luckily it all works fine.

It was also luck that I had pin 12 as an input and 10 as an output, as the SPI spec requires.

From the SPI wiki page:

Note that even if you're not using the SS pin, it must remain set as an output; otherwise, the SPI interface can be put into slave mode, rendering the library inoperative.

I was initially confused about this too until I read the ATmega328 documentation. The important thing is that pin 10 be configured as an output, the value of it is then ignore by the SPI hardware.

The Atmega documentation says:

If SS is configured as an output, the pin is a general output pin which does not affect the SPI system.

This means you can usefully set it high and low yourself to tell your peripheral that you are about to send data to it (with SPI.transfer). The library doesn't do this for you because it doesn't know for sure which pin you are going to use for the SS pin (you might have multiple peripherals).

As for the 16 or more bits, I don't see what is stopping you sending more than 8 bits before raising SS back to high. For example, this test code appears to "work", at least, connected to a logic analyzer:

const char * test = "Hello world";

 SPI.begin ();
 char c;
 const char * p = test;

// commence "transaction"
 digitalWrite(SS_PIN, LOW);  // this is pin 10 in SPI.h
 
// send test string
for ( ; c = *p; p++)
  SPI.transfer (c);

// end of transaction
 digitalWrite(SS_PIN, HIGH);
 SPI.end ();

Analysing the Ethernet shield in operation appears to confirm that holding the SS pin low for extended transfers is perfectly normal.

The constructor for the inbuilt SPI library appears to configure all 4 pins in the correct directions, so you shouldn't need to change them yourself, unless you are planning to use a different SS pin (in which case you also need to set that to output).

But as I said above, it appears that the library does not manage the SS pin for you apart from setting pin 10 as an output.

Thanks Nick, that explains the SS function a lot better, I wont worry about changing pin 10 now.

I am feeding a row of shift registers to run a display,and the latching is done externally from the micro, so I just bang all the pixel pattern bits ( at the right time ) without using the SS function at all .

SPI.transfer(h);
SPI.transfer(hx); and so on.

I suppose I could make my 2 bytes into a sixteen bit word , but it works fine like this, and makes the lookup table smaller.

I have just noticed that I don't even take the SS low at the beginning and it works fine ..... ( a little knowledge is a dangerous thing :slight_smile: I am a newbie )

On another project I take SS low and then send 50 bytes before bringing it high again to latch the registers.

Glad I could help. :slight_smile:

According to some documentation I read, you could leave SS low (eg. tie it to ground at the peripheral end) and that would work with some devices but not others.

However some other devices (apparently) do not respond until they see the high-to-low transition. This makes a certain amount of sense, because otherwise a single glitch on the clock line could throw everything out by one bit, forever.

The act of pulling SS low effectively synchronizes sending and receiving, at least for those devices that look for such a transition.

Yes, I pull the shift registers latch low and high from the external circuit to latch it all in.
I should really do a notSCLR between data I suppose to make sure it doesn't get out of sync?