You are here

SPI Introduction

spi_intro_data_transfer.jpg21.04 KB
Author: Matthew Schinkel | Jallib Group

Introduction to SPI - Serial Peripheral interface

What is SPI?

SPI is a protocol is simply a way to send data from device to device in a serial fashion (bit by bit). This protocol is used for things like SD memory cards, MP3 decoders, memory devices and other high speed applications.

We can compare SPI to other data transfer protocols:

Table 1. Protocol Comparison Chart
  SPI RS-232 I2C
PINS 3 + 1 per device 2 2
Number Of Devices unlimited 2 1024
Bits in one data byte transfer 8 10 (8 bytes + 1 start bit + 1 stop bit) 9 (8 bytes + 1 ack bit)
Must send one device address byte before transmission No No Yes
Clock Type Master clock only Both device clocks must match Master Clock that slave can influence
Data can transfer in two directions at the same time (full-duplex) Yes Yes No

As you can see SPI sends the least bit's per data byte transfer byte and does not need to send a device address before transmission. This makes SPI the fastest out of the three we compared.

Although SPI allows "unlimited" devices, and I2C allows for 1024 devices, the number of devices that can be connected to each of these protocol's are still limited by your hardware setup. This tutorial does not go into detail about connecting a large number of devices on the same bus. When connecting more devices, unrevealed problems may appear.

How does SPI work?

Firstly, SPI works in a master/slave setup. The master is the one that sends the clock pulses. At each pulse, data will be sent and received.

SPI has a chip select pin. Every device will share the "SDI", "SDO" and "Clock" pins, but each device will have it's own chip select pin (also known as slave select). This means we can have a virtually unlimited number of devices on the same SPI bus. You should also note that the chip select pin can be active high or active low depending on the device.

For some devices, the chip select pin must stay enabled throughout the transmission, and others require a change in the chip select line before the next transmission.

SPI is Dual-Duplex. This means data can be sent and received at the same time. If you wish to send data and not receive any, the PIC will receive data anyways. You may ignore the return byte.

Here's a diagram showing the way in which SPI sends & receives data:

SPI Modes

If you are using a device that does not yet have a Jallib library, you will need to get the devices SPI mode. Some device datasheets tell you the SPI mode, and some don't. Your device should tell you the clock idle state and sample edge, with this information, you can find the SPI mode. SPI devices can be set to run in 4 different modes depending on the clock's idle state polarity & data sample rising or falling edge.

The image above is SPI mode 1,1. See if you can understand why.

Clock Polarity (CKP) - Determines if the clock is normally high or normally low during it's idle state.

If CKP = 1 - the clock line will be high during idle.

If CKP = 0 - the clock will be low during idle.

Data Clock Edge (CKE) - The edge that the data is sampled on (rising edge or falling edge)

If CKP = 0, CKE = 0 - Data is read on the clocks rising edge (idle to active clock state)

If CKP = 0, CKE = 1 - Data is read on the clocks falling edge (active to idle clock state)

If CKP =1, CKE = 0 - Data is read on the clocks falling edge (idle to active clock state)

If CKP = 1, CKE = 1 - Data is read on the clocks rising edge (active to idle clock state)

We can put this in a chart to name the modes:

0,0 0 1
0,1 0 0
1,0 1 1
1,1 1 0
Note: I noticed the mode numbers & mode table on Wikipedia is different then the table in the Microchip PDF. I am going by the Microchip PDF, as well as the tested and working PIC Jallib library + samples. Wikipedia also names these registers CPOL/CPHA instead of CKP/CKE.

Using The Jallib Library

At the moment, there is only a SPI master hardware library, therefore any device you wish to control must be connected to the PIC's SDI, SDO, SCK pins. The chip select pin can be any digital output pin.

The library requires you to set the pin directions of the SDI, SDO, SCK lines as follows:

-- setup SPI
include spi_master_hw         -- first include the library

-- define SPI inputs/outputs
pin_sdi_direction = input    -- spi data input
pin_sdo_direction = output   -- spi data output
pin_sck_direction = output   -- spi data clock

You only need to set the pin direction of the chip select pin, the PIC will set the direction of the SDI, SDO & SCK for you. You will Alias this chip select pin as required by the device's jallib library.

If you are using more then one device in your circuit, you will need to declare your chip select pin near the beginning of your program. If you do not do this at the beginning of your program, some of your devices may receive data because their chip select pin could be enabled during init procedures of other devices on the SPI bus.

-- choose your SPI chip select pin
-- pin_SS is the PIC's slave select (or chip select) pin.
ALIAS device_chip_select_direction   is pin_SS_direction
ALIAS device_chip_select             is pin_SS
device_chip_select_direction = output    -- chip select/slave select pin
device_chip_select = low                -- disable the device

Now the last step in setting up the SPI library is to use the init procedure.

Use the SPI mode name chart to get your SPI mode. The modes can be any of the following:





You will also need to set the spi bus speed. Here is a list of the speeds you may choose from:

SPI_RATE_FOSC_4 -- oscillator / 4

SPI_RATE_FOSC_16 -- oscillator / 16

SPI_RATE_FOSC_64 -- oscillator / 64

SPI_RATE_TMR -- PIC's internal timer

You will use the following init procedure with your custom values entered:

spi_init(SPI_MODE_11,SPI_RATE_FOSC_16) -- choose spi mode and speed

Now your ready to use the procedures to send and receive data. First you must enable the device with the chip select line:

device_chip_select = high -- enable the device

You can use the pseudo variable spi_master_hw to send and receive data as follows:

-- send decimal 50 to spi bus
spi_master_hw = 50

Or receive data like this:

-- receive data from the spi port into byte x
var byte x
x = spi_master_hw

You can also send and receive data at the same time with the spi_master_hw_exchange procedure. here's an example:

-- send decimal byte 50 and receive data into byte x
var byte x
x = spi_master_hw_exchange (50)

When your done transmitting & receiving data, don't forget to disable your device

device_chip_select = low -- enable the device

Alright, now you should be able to implement SPI into any of your own devices. If you need assistance, contact us at the Jallist Support Group or at Jallib Group.


The Jallib spi_master_hw library - Written by William Welch

Microchip Technology SPI Overview -

Wikipedia -

Anonymous (not verified)
Small incorrect info on the site


"10 (8 bytes + 1 start bit + 1 stop bit)"

UART basic protocol: 1 start bit  + 8 bits data + 1 stop bit, in total 10 bits per 1 byte data

Similar with I2C

Log in to post comments