EEVblog Electronics Community Forum

Electronics => Beginners => Topic started by: IamSynthetiC on September 20, 2020, 03:36:26 pm

Title: IC interface to arduino through SPI
Post by: IamSynthetiC on September 20, 2020, 03:36:26 pm
Greetings,

In my projects i often use arduinos, and i feel extremely limited when i have to use already existing libraries for very specific sensors or ICs. When i browse through ICs i see they "talk" to the arduino through SPI, and that they offer instructions on what kind of signals to send, but i have no idea how to progam those insctructions and i had very little luck finding any instructions on how to do it.

So, are there any tutorials,links or books i can read or study ? is it hard ? and are there any traps i should be weary of ?

Thanks in advance
Title: Re: IC interface to arduino through SPI
Post by: JustMeHere on September 20, 2020, 03:58:27 pm
You basically write to and read from the registers on the slave chip.  Go grab a library like the Adafruit thermocouple lib.  Read through the code.  The compare that with the information in the datasheet.

I'm fairly sure Dave did a video on how to read the timing diagrams.  Also watching the signals through a scope will help learning how thia all works.
Title: Re: IC interface to arduino through SPI
Post by: Benta on September 20, 2020, 04:03:16 pm
SPI is really easy, it's basically just serial-in, serial-out shift registers with synchronous clocking.
You need to select the correct operating mode, there are four depending on clock polarity and clock phase.

The "M68HC11 Reference Manual" has a very good chapter on SPI.

https://www.nxp.com/docs/en/reference-manual/M68HC11RM.pdf (https://www.nxp.com/docs/en/reference-manual/M68HC11RM.pdf)

Title: Re: IC interface to arduino through SPI
Post by: DrG on September 20, 2020, 04:11:54 pm
Greetings,

In my projects i often use arduinos, and i feel extremely limited when i have to use already existing libraries for very specific sensors or ICs. When i browse through ICs i see they "talk" to the arduino through SPI, and that they offer instructions on what kind of signals to send, but i have no idea how to progam those insctructions and i had very little luck finding any instructions on how to do it.

So, are there any tutorials,links or books i can read or study ? is it hard ? and are there any traps i should be weary of ?

Thanks in advance

Arduino libraries offer a huge convenience because the work has been done for you. The price you pay, of course, is that you don't know much about what work has been done. In that regard, I also emphasize that you look at the code in the library.

Sometimes, libraries" can get pretty "integrated" and you should not be afraid to look at some non-Arduino, non-"library" C code as well.

Is it hard? Well, everything is hard when you don't yet understand it :)

Again, a +1 on studying the datasheet. Some are notoriously crap but I never met one that I had to only read once.
Title: Re: IC interface to arduino through SPI
Post by: JustMeHere on September 20, 2020, 04:34:46 pm
Oh and remember the SPI bus is shared.  If you're going to flash your Arduino via it's SPI header, you will need to take measures so the other chips do not interfere.   Since the Arduino (and others) float their pins (high-z, tristate).  The peripheral Chip Select (CS) pins will be floating too.  They might think they are being addressed.  For this reason, I put pull up (most of the time; most do it active low on CS) and pull down (for the few chips that CS when the pin is high) resistors on those lines.   The idea is to make sure they are defaulted to their inactive CS pin status.

It's not a bad idea to even bias the CS pin even if you aren't programming via the SPI header.  You don't want your SPI chip to pick up noise and think it's being commanded.  For example, a SPI motor driver should not drive any motors unless it's commanded.  Since micros will high-z during programming and boot, always consider putting a bias chip on every CS pin. 
Title: Re: IC interface to arduino through SPI
Post by: rstofer on September 20, 2020, 04:51:36 pm
Here is a video on bit-banging SPI:

https://www.youtube.com/watch?v=9hMsNOwY5AQ (https://www.youtube.com/watch?v=9hMsNOwY5AQ)

As an educational experiment, you can try bit-banging the protocol.  You won't want to do this forever but it is a good way to learn.
Title: Re: IC interface to arduino through SPI
Post by: Ian.M on September 20, 2020, 05:10:47 pm
Start from https://www.arduino.cc/en/Reference/SPI (https://www.arduino.cc/en/Reference/SPI) and use something really dumb and simple as a target to experiment with. e.g a 74HC595 (https://www.ti.com/lit/gpn/SN74HC595) eight-bit SIPO shift register.  It's not fully SPI compatible, because it doesn't tri-state its data out or ignore input data when not selected, but its enough to get started with writing code that can send a byte to a chip and get a byte back.

N.B. '595 pin names vary by manufacturer's datasheet, but their function remains unchanged. I'm using the names from the T.I. datasheet I linked.

Hook up its Vcc and Gnd to Arduino +5V and Gnd respectively, tie its /OE pin low, and its /SRCLR pin high, then connect Arduino MOSI to '595 SER, MISO to QH'  (*NOT*  QH), SCK to  SRCLK and SS to RCLK.

Then its just a matter of:
Code: [Select]
SPI.beginTransaction(SPISettings(125000, MSBFIRST, SPI_MODE0));
setting the SS pin low, then swapping bytes with the '595 using:
Code: [Select]
receivedVal = SPI.transfer(val);
Send as many bytes as you want, you'll get each one back one byte-transfer later.
Then take the SS pin back high and the last byte you sent will be latched on the '595's  QA (LSB) thru  QH (MSB) outputs.
At this point you can either take SS low again and transfer another packet of bytes, or release the Arduino SPI peripheral by doing:
Code: [Select]
SPI.endTransaction();
which is strongly recommended so other libraries (or interrupt routines) can use it.  Its generally undesirable to hang about waiting between SPI.beginTransaction() and SPI.endTransaction() in a complex system with several peripheral chips using the SPI interface.

You *can* get the hang of this just on 'blind trust' + eight LEDs (with series resistors) on the '595 Qn outputs, but you'll have a much easier time understanding it if you can monitor the four SPI interface signals and some of the  '595 Qn outputs on a logic analyzer.  The SPI clock speed is set to only 125KHz so anything that can do a minimum sample rate of 250KHz will do.  If you are using a scope or other device that doesn't have enough channels, treat SCK as the master channel you reference everything else to,  put a small delay in your main loop outside the code between SPI.beginTransaction() and SPI.endTransaction() so you get bursts of clock pulses while you are actively using the SPI peripheral, and examine each other signal in turn while sending the same data byte, though if you can separately trigger on SS falling edge, it will be helpful to synchronize the scope to your block of transfers even if you cant view the trigger channel.

Once you've got the hang of the basics, to use a SPI interface peripheral chip its just a matter of stuffing the bytes specified in a chip's datasheet down the SPI 'pipe' to control it, and if it returns data, saving the bytes that matter from what you get back from SPI.transfer(), then doing something useful with them (e.g. displaying them) once you've got all the ones you need.

Beware of chips with SPI-like interfaces that aren't quite SPI.  e.g. anything that requires a number of bits that isn't an integer multiple of eight and wont let you 'pad' the transfer with extra clock cycles to bring it up to 8*N bits.

You'll also encounter chips with only one bidirectional data pin.  Put a 1K resistor in series with Arduino MOSI to limit the drive, and connect the chip's data I/O pin to the resistor and MISO.  You'll get the byte you sent back on each transfer except when the chip is outputting something as the 1K resistor makes the MOSI signal weak enough that the chip will 'win' if it has data for you.

Edit: Corrected typo '575' in first paragraph.  Thanks, Benta!
Title: Re: IC interface to arduino through SPI
Post by: Benta on September 20, 2020, 07:06:16 pm
Apart from Ian.M's typo in the first line, I'm with him 100% :)

Like I said, SPI's not difficult.

My suggestion is to start with simple parallel I/O and get that working.

The devices you need for this are:
74HC595 (8-bit parallel latched output).
74HC589 (8-bit parallel latched input).

When those are operating correctly, there's no limit to what you can connect.

Cheers.
Title: Re: IC interface to arduino through SPI
Post by: IamSynthetiC on September 23, 2020, 11:24:42 am
Thank you all for your replies, they have all been more than informative.

I have already designed several circuits with arduinos and different SPI sensors or ICs, but I always had in mind that a friend of mine (programmer) would help on "building a library" for them.
Therefore I did not pay much attention in the SPI part in the datasheet. I am already going back and reading them, but as I said they are several. Should I be aware if any "traps" or incopatabilities ?

Also, some ICs require pull-up resistors, some pull-down and some do not. I have added both a pull-up and pull-down resistor, and will change/remove them when I have the circuit under an osciloscope.
But how does one decide whether a resistor is needed, while still in the designing proccess ?

Thanks again.
Title: Re: IC interface to arduino through SPI
Post by: Ian.M on September 23, 2020, 11:37:38 am
Unlike I2C, SPI does *NOT* require pullups to function correctly. Generally, SPI ICs drive MISO when selected.  A pulldown or pullup is only required to stop MISO floating (to prevent an increase in the MCU's pin input buffer's supply current due to an invalid input level) when no SPI device is selected.  It may well be possible to enable an internal weak pullup for that pin.

Extra pullups or pulldowns on one or more of MOSI, SCLK and SS are only required if its essential to control their state during powerup and MCU reset, before the firmware takes control of the I/O pins driving them.  If the SPI peripherals have reset pins appropriately driven for the short interval after powerup or MCU reset, or a brief incorrect peripheral state has no damaging or seriously undesirable consequences and is fully recoverable by normal peripheral initialization via SPI, you generally don't need them.
Title: Re: IC interface to arduino through SPI
Post by: Cerebus on September 23, 2020, 11:47:11 am
Also, some ICs require pull-up resistors, some pull-down and some do not. I have added both a pull-up and pull-down resistor, and will change/remove them when I have the circuit under an osciloscope.

But how does one decide whether a resistor is needed, while still in the designing proccess ?

By carefully reading the data sheet for the part you're trying to interface. If the data sheet doesn't explicitly call for a pull-up it may say that a particular line is "open drain" or (very rarely nowadays) "open collector". Lines described as "tristate" normally don't require pull-ups. SPI doesn't normally need pull-ups, but might if you're using SPI to drive a "not strictly SPI" part like a general purpose shift register.

Note that almost all recent MCUs allow you to turn on and off pull-up and pull-down resistors that are built into the MCU IO port itself, saving you the trouble of adding a physical component. For instance, the GPIOs on STM32 MCUs have this built in as standard. In the case of the Arduino environment you can activate a pull-up by setting the pin mode:

Code: [Select]
pinMode(pin, INPUT_PULLUP);