PICAXE Interface with SPI Devices

Interfacing with a Microchip MCP3208 8-channel 12-bit A/D

Measuring Barometric Pressure

copyright, Peter H Anderson, Baltimore, MD, Jan, '04
Introduction

This application note discusses an implementation of the Motorola SPI protocol and illustrates an SPI interface with a Microchip MCP3208 eight channel 12-bit A/D. It also illustrates how the 12-bit A/D may be used with a Motorola MPX4115AP or MPX4115AS to measure atmospheric pressure and convert this to barometric pressure..

Many versions of the PICAXE have ten bit A/D converters which provide 1024 levels over the range of 0.0 to 5.0 VDC, which is more than adequate for measuring temperature or relative humidity. However, in measuring atmospheric pressure which is typically 1013 millibars and even a change of one millibar is significant, one might opt to use a 12-bit A/D so as to resolve pressure to within nominally 0.25 millibars.

SPI

The Philips I2C and the Motorola SPI protocol are probably the most widely used standard interfaces in use today. Typical SPI devices include the 25LC640 and many high density EEPROMs, the TI TLC2543 A/D, various speech synthesizers, real time clocks and the MAX7219 7-seg LED Controller.

The SPI interface consists of four signal leads; a chip select (CS) which is used by the processor to select the specific device on the bus, a clock (SCK) which is controlled by the processor, a data out signal, commonly referred to as "master out - slave in" (MOSI), and a data in, "master in - slave out" (MISO). In some cases, there may be no need for one of the data signals. For example, with the MAX6674 K-thermocouple to digital converter, data is simply read and thus there is no MOSI signal lead. For a MAX7219 LED latch, only the MOSI lead may be used as there is no provision to read data for the MAX7219.

Note that the SCK, MOSI and MISO leads may be shared with several devices on a bus. A separate CS is required for each device and only one peripheral device may be active at a time.

A transmission sequence begins by bringing the chip select lead to the active state. In most cases, CS is brought low to select the specific device. However, I recall working with a Dallas RTC with an SPI interface where the active state was high.

Data is then clocked to the slave, beginning with the most significant bit on the MOSI output and at the same time, receiving data bits on the MISO signal lead. This may be thought of as a shift register, which is very simple to implement in hardware and in firmware.

Consider the following;

SPI_IO:

   For N = 1 to 8
      If X > 127 Then SPI_IO_1	' if most sig bit is a one
      Low MOSI 					' otherwise set MOSI to a zero
      Goto SPI_IO_2

SPI_IO_1:
      High MOSI
SPI_IO_2:
      High SCK 					' clk high
      X = X * 2 + MISO			' read MISO
      Low SCK 					' clk low
   Next

   Return

Note that the most significant bit of X is tested and the MOSI output is set to the appropriate state. SCK is then brought high and the slave device then reads the MOSI lead. At the same time, the slave places data on the MISO processor input which is read by the processor, while shifting the data to the left;
     X = X * 2 + MISO
Thus, with the shift, the next to the most significant bit is now in the most significant bit position.

This is repeated for each of the eight bits and thus, X is now the byte which was received from the slave device.

Note that unlike the I2C protocol, the SPI protocol has the capability for full duplex operation. However, just as with a telephone, the full duplex operation may or may not be used. For example, when reading from an SPI EEPROM, a read command is sent and the data which is read is of no consequence, the high and low bytes of the address are sent and again, the data which is read is of no consequence. Any byte is then sent to the EEPROM on the MOSI lead and the meaningful data is read from the EEPROM.

Interfacing with the MCP3208

In performing an A/D conversion using the MCP3208, CS is first brought low to select the device. Three bits are sent using the SPI routine;

	%00000XYZ
where X is always a 1 indicating the "start" of data, Y is 1 for single ended measurements and Z is the most significant bit of the channel;


ADMeas:
   Low SCK
   Low CS
   X = Channel / 8	' most significant bit of three bit channel address
   X = X | $06
   GoSub SPI_IO

Note that in this case, the SPI routine sends the first byte out on the MOSI lead and although a byte is received on MISO, it is not used.

The processor sends a byte consisting of the low two bits of the channel address in the upper two bits and at the same time, receives the high four bits of the A/D result.

   X = Channel * 64		' get low two channel bits in bit positions 7 and 6
   GoSub SPI_IO
   ADVal = X * 256
The processor sends "garbage", that is anything, using the SPI routine and receives the low byte of the A/D result and terminates the transmission sequence by bringing CS high.
   GoSub SPI_IO
   ADVAL = ADVAL + X
   ADVAL = ADVAL & $0fff	' only the lower 12 bits
   High CS
The full program for the MCP3208 appears below.


' MCP320x.Bas - PICAXE 18X
'
' Illustrates an interface with a Microchip MCP3208 8-channel 12-bit
' A/D.
'
' Perfroms a single ended A/D measure on each of the eigh channel and
' displays to the terminal.
'
' PICAXE-18X			MCP3208
'
' CS, Pin0 (term 6) ------------ /CS (term 10)
' SCK, Pin1 (term 7) ----------- CLK (term 13)
' MOSI, Pin 2 (term 8) --------- Din (term 11)
' MISO, Input0 (term 17) <------ Dout (term 12)
'
'
' copyright, Peter H. Anderson, Baltimore, MD, Jan, '04

   Symbol ADVal = W0

   Symbol Channel = B2
   Symbol Dig = B3
   Symbol X = B6
   Symbol N = B7

   Symbol CS = Output0
   Symbol SCK = Output1
   Symbol MOSI = Output2
   Symbol MISO = Input0

Top:
   For Channel = 0 to 7
      GoSub ADMeas
      GoSub DisplayADVal
   Next
   Wait 1
   GoTo Top

DisplayADVal:
   If ADVAL >= 100 Then DisplayVal_2

   SerTxD (#ADVal)	' if one or two digits, just go ahead and display it
DisplayADVal_1:
   SerTxD (13, 10)
   Return

DisplayVal_2:
   Dig = ADVal  / 100
   ADVal = ADVal % 100
   SerTxD (#Dig)

   Dig = ADVal / 10
   ADVal = ADVal % 10
   SerTxD (#Dig)

   Dig = ADVal
   SerTxD (#Dig)

   GoTo DisplayADVal_1

ADMeas:
   Low SCK
   Low CS
   X = Channel / 8
   X = X | $06
   GoSub SPI_IO
   X = Channel * 64
   GoSub SPI_IO
   ADVal = X * 256
   GoSub SPI_IO
   ADVAL = ADVAL + X
   ADVAL = ADVAL & $0fff
   High CS
   Return

SPI_IO:

   For N = 1 to 8
      If X > 127 Then SPI_IO_1
      Low MOSI
      Goto SPI_IO_2

SPI_IO_1:
      High MOSI
SPI_IO_2:
      High SCK

      X = X * 2 + MISO
      Low SCK
   Next

   Return


Atmospheric Pressure.

This section illustrates how to interface a Motorola MPX4115 with the MCP3208 A/D converter to measure atmospheric pressure.



  MPX4115 (term 2) ------------------ MCP3208 Ch0 (term 1)


The output of the MPX4115 is proportional to pressure;

	(1)	VChannel0 = VRef * (P * 0.0009 - 0.095)
Where P is the pressure in millibars and VRef is the nominal 5V supply.

The voltage on Channel 0 is calculated as;

	(2)	VChannel0 = ADVal / 4096 * VRef
where ADVal is the 12-bit quantity in the range of 0 through 4095 and V_ref is the nominal +5 VDC supply.

Equating expressions (1) and (2)

	VRef * (P * 0.0009 - 0.095) = ADVal / 4096 * VRef
Eliminating VRef and solving for P;
	P = (ADVal / 4096 + 0.095) / 0.0009
or
	(3)	P = 0.271 * ADVal + 105.5
It is interesting (and pleasing) to observe that VRef does not appear in this calculation.

The pressure is calculated and displayed;

   Pressure = ADVal * 2 / 10
   Pressure = ADVal * 7 / 100 + Pressure
   Pressure = ADVal / 1000 + 105 + Pressure

   GoSub DisplayPressure
Note that this is in millibars.

In the United States, we use inches of mercury. One millibar corresponds to 0.02953 inches of mercury.

Thus expression (3) may be modified to calculate the pressure in inches of mercury times 100.

	(4)	PHg_100 = 0.797 * ADVal + 295
This may be calculated using the PICAXE in a manner quite similar to the above as;
   PHg_100 = ADVal * 7 / 10
   PHg_100 = ADVal * 9 / 100 + PHg_100
   PHg_100 = ADVal * 7 / 1000 + 295 + PHg_100
Note that in the following routine, the display subroutine was written to display the pressure in millibars. It would be necessary to modify this slightly to display the quantity in a form appropriate for inches of mercury (XX.YY).



' Barometer.Bas - PICAXE 18X
'
' Illustrates an interface with a Microchip MCP3208 12-bit A/D converter
' to measure atmospheric pressure using a Motorola MPX4115AP or MPX4115AS.
'
' Pressure = 0.271 * ADVal + 105.5.  Note that this is atmospheric pressure
' and must be adjusted for altitude to determine barometric pressure.
'
' PICAXE-18X			MCP3208
'
' CS, Pin0 (term 6) ------------ /CS (term 10)
' SCK, Pin1 (term 7) ----------- CLK (term 13)
' MOSI, Pin 2 (term 8) --------- Din (term 11)
' MISO, Input0 (term 15) <------ Dout (term 12)
'
'
' copyright, Peter H. Anderson, Baltimore, MD, Jan, '04

   Symbol ADVal = W0
   Symbol Pressure = W4
   Symbol Channel = B2
   Symbol Dig = B3
   Symbol X = B6
   Symbol N = B7

   Symbol CS = Output0
   Symbol SCK = Output1
   Symbol MOSI = Output2
   Symbol MISO = Input0

Top:
   Channel = 0	' MPX4115 is on this channel
   GoSub ADMeas

   Pressure = ADVal * 2 / 10
   Pressure = ADVal * 7 / 100 + Pressure
   Pressure = ADVal / 1000 + 105 + Pressure

   GoSub DisplayPressure
   Wait 1
   GoTo Top

DisplayPressure:
   If Pressure >= 100 Then DisplayPressure_2

   SerTxD (#Pressure)	' if one or two digits, just go ahead and display it
DisplayPressure_1:
   SerTxD (13, 10)
   Return

DisplayPressure_2:
   Dig = Pressure / 100
   Pressure = Pressure % 100
   SerTxD (#Dig)

   Dig = Pressure / 10
   Pressure = Pressure % 10
   SerTxD (#Dig)

   Dig = Pressure
   SerTxD (#Dig)

   GoTo DisplayPressure_1

ADMeas:
   Low SCK
   Low CS
   X = Channel / 8
   X = X | $06
   GoSub SPI_IO
   X = Channel * 64
   GoSub SPI_IO
   ADVal = X * 256
   GoSub SPI_IO
   ADVAL = ADVAL + X
   ADVAL = ADVAL & $0fff
   High CS
   Return

SPI_IO:

   For N = 1 to 8
      If X > 127 Then SPI_IO_1
      Low MOSI
      Goto SPI_IO_2

SPI_IO_1:
      High MOSI
SPI_IO_2:
      High SCK

      X = X * 2 + MISO
      Low SCK
   Next

   Return


Converting Atmospheric Pressure to Barometric Pressure

Normal atmospheric at sea level is nominally 1013 millibars and this is termed barometric pressure. Relatively small changes indicate drastically different weather conditions. For example, in the eye of a recent category 5 hurricane, the pressure was reported as 960 millibars.

However, atmospheric pressure decreases with altitude and thus if one were to interpret the atmospheric pressure in mile high Denver as being the barometric pressure, the number would suggest a daily catastrophe of biblical proportions. Rather, an expression is used to convert from atmospheric to barometric pressure which takes the altitude into account. Thus, the normal barometric pressure in Denver is reported as if Denver were at sea level.

The simplest technique for converting atmospheric pressure to barometric pressure for your installation is simply to scale the result. For example, assume the MPX4115 is reporting the atmospheric pressure as 861 millibars. However, your local weather reports the barometric pressure as 1010 millibars. Thus, the scaling factor is 1010 / 861 or 1.173. Simply multiply the atmospheric pressure by this altitude scaling factor. In this case;

	BaroPress = Pressure
	BaroPress = Pressure * 1 / 10 + BaroPress
	BaroPress = Pressure * 7 / 100 + BaroPress
	BaroPress = Pressure * 3 / 1000 + BaroPress