PIC32 SPI Project

SPI (Serial Peripheral Interface)

The SPI (Serial Peripheral Interface) is a method of interconnecting electronic devices. This can be two microcontrollers or a microcontroller and a peripheral device. The link features are:

  • 3 Wire + 1 interface
  • 2 data lines one is output and the other is input.
  • A clock is used.
  • Chip select used for device addressing.
  • Master-Slave operation, the master device controls the clock.
  • Normally uses commands.
  • Bi-directional – full duplex communication possible.

It is essentially a 3 wire + 1 interface with a concept of master and slave. The master does the clocking whilst the slave responds to the clock. The interface is unfortunately compromised by the lack of standards which means that the clock can be either positive or negative, the data in and out lines can also have differences and the data can be either MSB (most significant bit) first or LSB first. This all leads to a rather complex register configuration on the PIC32, however so far all the devices I have tested seem to work with a single configuration so that will be used.

The two main communication connections are:

MOSI (master out slave in)
MISO (master in slave out)

In common with RS232, the output of one goes into the input of another (crossed over). One interesting aspect of this interface is that whilst data is being clocked in, it is also being clocked out at the same time. If just read is required then 0xff is normally clocked in order to get the data out.

There does not seem to be as many SPI devices as there are i2c devices. SPI tends to be reserved for devices that require high speed namely, SC Cards, Network interfaces and radio links. There are a couple of exceptions and one of them is presented here.

The Digital Potentiometer

Digital Pot (variable resistor), these are sometimes used as digital to analogue convertors and can be very useful for real world interfacing. The one used here is a MCP41xxx variety that has just the one potentiometer but others are available with two pots on board.

spi schematic

Port E bit 6 is used as the chip select and this must be taken low before any reading or writing of the spi bus. The wiring as shown will output a voltage in 256 steps from near 0V to near 5V. To make things simple, the same interface (spi2) is used that is used for the SC Card and so no initialisation of the interface is required.

// spi interface to MCP41xxx digtal pot
// this device works at 20MHz
// using spi2
// cs is RE6  

function spi_init
    portb "etc" 6
    portb "eos" 6
endf

// value from 0 to 255 will set resistance between
// 0 and 10k
function pot(value)
    portb "eoc" 6 // cs low
    spi2(0x11) // command byte
    spi2(value)
    portb "eos" 6 // cs high
endf

The complete program interface is show here along with comments, spi_init should be run first as this sets up the port used for the chip select. As this is a simple device the keyword ‘spi2’ is used to feed bytes to the device. This particular device requires 16 bits, the first 8 bits is a command (0x11), which means write to pot 0, the second 8 bits is the value sent to the pot.

As this device only has one pot and is not capable of read, this is the only command that is really acceptable. SPI1 can also be used if required but this will require initialising:

function spi_init
    // chip select
    portb "etc" 6
    portb "eos" 6
    // set up spi1 which is also UART1
    spiinit 1 2000000
endf    

Setting up SPI1 is very simple but remember that it uses the same interface as UART1 and so this UART cannot be used if SPI1 is going to be used.

SPI EEPROM

Another useful SPI device, and low cost, is the serial EEPROM. The device chosen for this example is the M95xx or the AT25. Different manufactures have different part numbers. There may also be slight variations in commands required so reference to the part datasheet is essential. The examples given are for the M951.

M95xx connection diagram

This is a small 8 pin DIL as shown. For this application both the HOLD and W lines are tied to the +5V rail.

spi m95xx schematic

Chip select is as before using port F6 which can be obtained on connector J3-2. SPI1 shares the port lines with UART1 and so initialising the SPI will disable this UART. The main communication through the USB uses UART2 so this will not be affected.

// read into a buffer from an EEPROM connected to
// SPI1
function spi_read(address, buf%, length)
dim hi, lo
    spi_cs 0 // cs low
    hi = and(rshift(address,8),0xff)
    lo = and(address,0xff)
    spi1(0x3) // read instruction
    spi1(hi)
    spi1(lo)  // send address
    spiread 1 buf% length
    spi_cs 1 // cs high
endf

// write a string to an EEPROM connected to
// SPI1
function spi_write(address, s$)
dim hi, lo
    hi = and(rshift(address,8),0xff)
    lo = and(address,0xff)
    spi_w 6 // write enable
    spi_cs 0 // cs low
    spi1(2) // write instruction
    spi1(hi)     spi1(lo)  // send address
    spiwrite 1 adr(s$) len(s$)
    while spi_ready = 1 : wend // wait for write to finish
    spi_cs 1
endf

Just the read and write routines are shown here and these are intended for reading and writing strings. A buffer address must be supplied to the read routine, supplying a string and then presenting its address to ‘spiread’ will not work because the parameter variables, the ones in brackets after the function name, are local to that function. For example:

function spi_read(address, s$, length)
.
.
.
spiread 1 adr(s$) length
.
.

The string s$ is local and so although s$ will be filled with the contents, the string passed into the function will not. Remember also that when using page write as above, these devices usually have a limit to the page, this device in particular is 32 bytes.