BX35, BX24 Interface with a MCP42010 Dual 10K Potentiometer

copyright, Peter H. Anderson, Dec, '02, Baltimore, MD


Introduction.

This discussion deals with interfacing with the Microchip MCP41XXX/42XXX digital potentiometers. These are available as single (MCP41XXX) or as dual units (MCP42XXX) in a number of values; 10K, 50K and 100K. These are readily available from Digikey for nominally $2.50. In this discussion, I used an MCP42010 Dual 10K potentiometer. This was interfaced with a BX35 using both a bit bang implementation of the SPI protocol and the BX series SPI command capability. Porting these programs to the BX24 may be performed by redefining the terminals.

Note that when the SPI capability of the BX35 (BX24) is used, only a single general purpose IO is required to select this device. One might also use the SPI capability to control SPI series EEPROMs, the MCP3208 A/D and the MAX3100 UART and realize a very powerful design which minimizes the use of the general purpose IO terminals.

Discussion.

The MCP42XX potentiometer is controlled by selecting the device, bringing the associated CS lead low, and performing a two byte transfer and then bringing CS back to high. The nature of the two byte transfer is a command byte followed by a data byte. The command byte is of the form;


	X X C1 C0 X X P1 P0
where C1 and C0 are the command bits and P1 and P0 identify the potentiometer.

Valid vales of CC are 01 (write data) and 10 (shut down).

Valid values of PP are 01 (pot 0), 10 (pot 1) and 11 (both pots)

The second byte is the data to be written. Note that in the case of a shutdown, the data byte really doesn't make sense, but a byte must be sent. The data (or command) is latched when CS goes high.

The data byte, in the range of 0 - 255 is the distance of the wiper from the B side of the potentiometer. Thus, when the data byte is 0, the wiper is connected to the B terminal and when 128, the wiper is mid way between the B and A terminal.

When in the shutdown mode, the wiper is connected to the B side. The pot remains in the shut down mode until a new command is sent or until power is removed and reapplied.

Note that the potentiometer has no EEPROM. On power up, the default setting of the wipers are mid scale (128). However, the EEPROM associated with the BX35 (BX24) may be used to quickly write a default setting. This is not shown in the following routines.

Communication with the potentiometer is one way; from the BX master to the pot. There is no MISO lead. (See below).

Rather, the MCP41XXX/42XXX series of potentiometers may be cascaded; the slave out (SO) being connected to the SI of the next. Each potentiometer may be thought of as a 16 bit shift register and thus in cascading devices, one might bring CS low, send the two byte command for the most distant device, followed by the two byte command for the next most distant, etc, and finally the two byte command for the closest device followed by bringing CS high. I did not show this in the following routines.

Note that although the SO output is intended for cascading, it might be connected to the MISO input of the BX35 (BX24). This would permit the current setting of the pot to be read by sending two data bytes. Just why anyone would really want to do this is an open question.

Routines.

The following routines are functionally the same. MCP42XX_1.Bas uses a bit bang implementation of the SPI interface. MCP42XX_2.Bas is implemented using the BX SPI hardware.

Routine sets Pot 0 to half scale and Pot 1 to quarter scale. Voltages are then measured on ADC7 and ADC6 and displayed (Point 1), followed by a ten second delay.

Both pots are then set to 3/4 scale. Voltages are measured and displayed (Point 2) followed by a delay.

Pot 0 is then shut down. Voltages are measured and displayed (Point 3) followed by a delay.



' MCP42XX_1.Bas
'
' Illustrates an interface with a Microchip MCP42010 Dual 10K Digital Potentiometer.
'
' Uses a bit bang implementation of the SPI interface.  Each bit of a byte is output,
' begriming with the most significant bit on the MOSI output, SCK is brought high, MISO
' is read and SCK is brought low.  The byte is then shifted to the left such that the next bit
' is now in the most significant bit position.  This is repeated for each of the eight bits.
'
' Each command requires a two byte transfer.
'
' The first byte output is a command byte of the form;
'
'
'	X X C1 C0 X X P1 P0
'
' where C1 and C0 are the command bits and P1 and P0 identify the potentiometer.
'
' Valid vales of CC are 01 (write data) and 10 (shut down).
' Valid values of PP are 01 (pot 0), 10 (pot 1) and 11 (both pots)
'
' The second byte is the data to be written.
'
' Routine sets Pot 0 to half scale and Pot 1 to quarter scale.  Voltages are then measured on
' ADC7 and ADC6 and displayed (Point 1), followed by a ten second delay.
'
' Both pots are then set to 3/4 scale.  Voltages are measured and displayed (Point 2) followed by
' a delay.
'
' Pot 0 is then shut down.  Voltages are measured and displayed (Point 3) followed by a delay.
'
' This routine was tested on a BX35.  It may also be run on a BX24 by modifying the term assignments.
'
' BX35				MCP3208
'
'
'  				 SO (term 13)  -------> To SI of Next MCP42XXX
'  Term 39 (MOSI) -------------> SI (term 3)
'  Term 38 (SCK) --------------> SCK (term 2) --------> To SCK of next MCP42XXX
'  Term 37 (CS) ---------------> /CS (term 1) --------> TO /CS of next MCP42XXX
'
'                       +5VDC -- Vdd (term 14)
'                       GRD ---- Vss (term 4)
'
'             +5VDC ---- 10K --- /RS (term 11)
'             +5VDC ---- 10K --- /SHDN (term 12)
'
'                                                        For Testing
'                                 PA0 (term 8) --------  +5 VDC
'                                 PW0 (term 9) --------  To Term 33 (ADC7) of BX35
'                                 PB0 (term 10) -------  GRD
'
'                                 PA1 (term 7) --------  +5 VDC
'                                 PW1 (term 6) --------  To Term 34 (ADC6) of BX35
'                                 PB1 (term 5) --------  GRD
'
'
' Note that MCP46XX_2.Bas illustrates an interface using the SPICmd feature of the BX series.
'
' copyright, Peter H Anderson, Baltimore, MD, Dec, '02


' for BX35
Const MCP42XXCS as Byte = 37
Const SCK as Byte = 38
Const MOSI as Byte = 39
Const MISO as Byte = 40	' Not used in the program

' for BX24
'const MCP42XXCS as Byte = 13
'const SCK as Byte = 14
'const MOSI as Byte = 15
'const MISO as Byte = 16

Const POT0 as Byte = 1
Const POT1 as Byte = 2
Const POTBoth as Byte = 3

Sub Main()

   Dim ADVal as Integer
   Dim V0 as Single, V1 as Single

   Call MCP42XXSetUp()			' be sure CS is high and SCK is low

   Do
      Call MCP42XXSetPot(POT0, &H80)	' set to half scale
      Call MCP42XXSetPot(POT1, &H40)	' quarter scale
      ADVal = GetADC(33)
      V0 = CSng(AdVal) * 5.0 / 1024.0
      ADVal = GetADC(34)
      V1 = CSng(AdVal) * 5.0 / 1024.0
      Debug.Print "Point 1 "; CStr(V0); "  "; CStr(V1)

      Call Sleep(10.0)


      Call MCP42XXSetPot(POTBoth, &HA0)	' set both to 3/4 scale
      ADVal = GetADC(33)
      V0 = CSng(AdVal) * 5.0 / 1024.0
      ADVal = GetADC(34)
      V1 = CSng(AdVal) * 5.0 / 1024.0
      Debug.Print "Point 2 "; CStr(V0); "  "; CStr(V1)

      Call Sleep(10.0)

      Call MCP42XXShutDown(Pot0)	' shut down Pot 0, leave other at 3/4
      ADVal = GetADC(33)
      V0 = CSng(AdVal) * 5.0 / 1024.0
      ADVal = GetADC(34)
      V1 = CSng(AdVal) * 5.0 / 1024.0
      Debug.Print "Point 3 "; CStr(V0); "  "; CStr(V1)

      Call Sleep(10.0)

   Loop

End Sub


Sub MCP42XXSetUp()

   Call PutPin(MCP42XXCS, 1)
   Call PutPin(SCK, 0)

End Sub


Sub MCP42XXSetPot(ByVal Pot as Byte, ByVal Setting as Byte)

   Dim DontCare as Byte, X as Byte

   Call PutPin(MCP42XXCS, 0)
   X = bx0001_0000 + Pot	' C1 C0 = 0 1
   DontCare = SPI_IO(X)
   DontCare = SPI_IO(Setting)

   Call PutPin(MCP42XXCS, 1)		' end of session

End Sub

Sub MCP42XXShutDown(ByVal Pot as Byte)

   Dim DontCare as Byte, X as Byte

   Call PutPin(MCP42XXCS, 0)
   X = bx0010_0000 + Pot		' C1 C0 = 1 0
   DontCare = SPI_IO(X)
   DontCare = SPI_IO(DontCare)

   Call PutPin(MCP42XXCS, 1)		' end of session

End Sub


Function SPI_IO(ByVal X as Byte) as Byte
   Dim N as Byte

   For N = 1 to 8
      If ((X AND bx1000_0000) <> 0) Then	' start with most sig bit
         Call PutPin(MOSI, 1)			' set MOSI output to appropriate state
      Else
         Call PutPin(MOSI, 0)
      End If

      Call PutPin(SCK, 1)			' bring clock high
      X = X * 2 + GetPin(MISO)			' read from slave
      Call PutPin(SCK, 0)			' clock low
   Next

   SPI_IO = X

End Function



' MCP42XX_2.Bas
'
' Illustrates an interface with a Microchip MCP42010 Dual 10K Digital Potentiomenter.
'
' This program uses the BX series SPI bus and thus aside from the chip select which specically
' selects the MCP42XX Pot, this approach uses no additional IO terms on the BX-35 (BX-24).
'
' Uses the OpenSPI amd SPICommand commands.  The SPI channel is configured for most sig bit first
' clock mostly low, read in middle of clock, freq/4.  Thus the setup byte is &H00.
'
' Each command requires a two byte transfer.
'
' The first byte output is a command byte of the form;
'
'
'	X X C1 C0 X X P1 P0
'
' where C1 and C2 are the command bits and P1 and P0 identify the potentiometer.
'
' Valid vales of CC are 01 (write data) and 10 (shut down).
' Vaid values of PP are 01 (pot 0), 10 (pot 1) and 11 (both pots)
'
' The second byte is the data to be written.
'
' Routine sets Pot 0 to half scale and Pot 1 to quarter scale.  Voltages are then measured on
' ADC7 and ADC6 and displayed Point 1), followed by a ten second delay.
'
' Both pots are then set to 3/4 scale.  Voltages are measured and displayed (Point 2) followed by
' a delay.
'
' Pot 0 is then shut down.  Voltages are measured and displayed (Point 3) followed by a delay.
'
'
' This routine was tested on a BX35.  It may also be run on a BX24 by modifying the term assignments.
'
' BX35						MCP42XX Pot
'
'
'  				                SO (term 13)  -------> To SI of Next MCP42XXX
'  Term 6 (MOSI) -------------> SI (term 3)
'  Term 8 (SCK) --------------> SCK (term 2) --------> To SCK of next MCP42XXX
'  Term 39 (CS) ---------------> /CS (term 1) --------> TO /CS of next MCP42XXX
'
'                       +5VDC -- Vdd (term 14)
'                       GRD ---- Vss (term 4)
'
'             +5VDC ---- 10K --- /RS (term 11)
'             +5VDC ---- 10K --- /SHDN (term 12)
'
'                                                        For Testing
'                                 PA0 (term 8) --------  +5 VDC
'                                 PW0 (term 9) --------  To Term 33 (ADC7) of BX35
'                                 PB0 (term 10) -------  GRD
'
'                                 PA1 (term 7) --------  +5 VDC
'                                 PW1 (term 6) --------  To Term 34 (ADC6) of BX35
'                                 PB1 (term 5) --------  GRD
'
'
' Note that MCP46XX_2.Bas illustrates an interface using the SPICmd feature of the BX series.
'
' copyright, Peter H Anderson, Baltimore, MD, Nov, '02


' SPI setup byte
Const SPI_LSB as Byte = &H20 'lsb transmitted first
Const SPI_CPOL as Byte = &H08 'sck is mostly high
Const SPI_CPHA as Byte = &H04 'clock phase, see Atmel docs for timing
Const SPI_SCK4 as Byte = &H00 'clock speed f/4
Const SPI_SCK16 as Byte = &H01 'clock speed f/16
Const SPI_SCK64 as Byte = &H02 'clock speed f/64
Const SPI_SCK128 as Byte = &H03 'clock speed f/128

Const POT0 as Byte = 1
Const POT1 as Byte = 2
Const POTBoth as Byte = 3

Sub Main()

   Dim ADVal as Integer
   Dim V0 as Single, V1 as Single

   Call MCP42XXSetUp()			' Set up SPI channel 2

   Do
      Call MCP42XXSetPot(POT0, &H80)	' set to half scale
      Call MCP42XXSetPot(POT1, &H40)	' quarter scale
      ADVal = GetADC(33)
      V0 = CSng(AdVal) * 5.0 / 1024.0
      ADVal = GetADC(34)
      V1 = CSng(AdVal) * 5.0 / 1024.0
      Debug.Print "Point 1 "; CStr(V0); "  "; CStr(V1)

      Call Sleep(10.0)


      Call MCP42XXSetPot(POTBoth, &HA0)	' set both to 3/4 scale
      ADVal = GetADC(33)
      V0 = CSng(AdVal) * 5.0 / 1024.0
      ADVal = GetADC(34)
      V1 = CSng(AdVal) * 5.0 / 1024.0
      Debug.Print "Point 2 "; CStr(V0); "  "; CStr(V1)

      Call Sleep(10.0)

      Call MCP42XXShutDown(Pot0)	' shut down Pot 0, leave other at 3/4
      ADVal = GetADC(33)
      V0 = CSng(AdVal) * 5.0 / 1024.0
      ADVal = GetADC(34)
      V1 = CSng(AdVal) * 5.0 / 1024.0
      Debug.Print "Point 3 "; CStr(V0); "  "; CStr(V1)

      Call Sleep(10.0)

   Loop

End Sub


Sub MCP42XXSetUp()

   Call OpenSPI(2, &H00, 39)	' open SPI channel 1, with setup byte of &H00, CS on terminal 39

End Sub


Sub MCP42XXSetPot(ByVal Pot as Byte, ByVal Setting as Byte)

   Dim A(1 to 2) as Byte

   A(1) = bx0001_0000 + Pot
   A(2) = Setting
   Call SPICmd(2, 2, A(1), 0, A(1))

End Sub

Sub MCP42XXShutDown(ByVal Pot as Byte)

   Dim A(1 to 2) as Byte

   A(1) = bx0010_0000 + Pot
   ' value in A(2) is don't care
   Call SPICmd(2, 2, A(1), 0, A(1))

End Sub