I'm working with the SPI library found at Arduino Playground - Spi and have found a problem (or, perhaps a misinterpretation on my part) with the way it works, especially when trying to interface it with a MCP3202 A/D converter.
I wrote a small sketch based on Microchip's instructions for interfacing with micros (from the datasheet). My original code simply called spi_transfer() in the right order and expected a single converted value back. This seemed to be sound based on the datasheet.. but didn't seem to work.
Being suspicious of the slave-select (SS) line, I decided to try explicitly calling digitalWrite(10,LOW) and digitalWrite(10,HIGH) before and after my calls to spi_transfer(). This worked beautifully.
However, the SPI library seems to implicitly suggest (by the #defines in the header file) that it defaults to pin 10 as SS. This made me assume that the library functions were somehow taking the SS line low automatically and I shouldn't have to call them low explicitly. Admittedly, I don't understand some of the finer points of what's being done in the transfer function code.. but it's a little confusing.
The primary annoyance for me is that the two digitalWrite() calls cost me about 10us of execution apiece, limiting the rate at which I can poll the ADC (right now, around 20kHz and I'd like it to be closer to 50kHz).
If anyone with experience or know-how on this subject could help to clarify the subject, please let me know.
The SS pin should either be an output or an input kept high during an SPI transfer else the SPI peripheral switches from master mode to slave mode. The SPI library does initialize the SS pin to be an output, but it may well be that you have to manually set it low. This is what I do and it works without trouble.
If you need stuff to happen as fast as 10us you probably want to get away from using libraries and just do things down at the port level, as there is less overhead.
The SS pin should either be an output or an input kept high during an SPI transfer else the SPI peripheral switches from master mode to slave mode.
This is incorrect; this behavior is exhibited only when the SPI hardware is in slave mode.
When in master (i.e. normal) mode, "SS" is like any other digital output, and is convenient for driving the peripheral's SS line because of its proximity.
You do not want to let the SS pin float, whichever pin you use. Drive it to the deselect level required by the peripheral.
I'm pretty sure the ethernet shield uses that pin for SS, and I know I've done so with other SPI peripherals.
Switching from digitalWrite() and digitalRead() to direct port manipulation will improve performance.
I plan to test the speed of the publicly available MCP3208 (close but not identical to the 3202) code for performance, as I have a requirement to sample 10 inputs at 200kHz. The MCP3208 library bit-bangs SPI, probably because of Microchip's habit of using odd (e.g. not 8 bit) transfers.
I have several SPI devices hooked up to the SPI interface. I'm using several different ports to control each of them, but the ADC SS is on pin 10. I wasn't sure if there was something 'special' about pin 10 that worked faster with the SPI controls versus other ports and if it would automatically go low as a result.
In terms of lower-level manipulation of the ports, are you suggesting that instead code something to the effect of:
This is the sort of thing that looks like it could save me the tens of microseconds I need. The SPI library I originally referred to is already very compact and I'm guessing very little savings is to be had (it uses the SPI control and data registers directly) from discarding it. The bitbang playground example shown for the 3208 is very slow (I used a similar approach before) and clocked in at about 350us per sample.
In terms of lower-level manipulation of the ports, are you suggesting that instead code something to the effect of:
PORTB |= B00000100;
Yup, that's the stuff. A little faster than calling digitalWrite(). As you noted, the transfer() function of the SPI library is about as fast as it's going to get.