Interfacing the BX24 with a MAX518 Dual D/A Converter

copyright, Peter H. Anderson, Baltimore, MD, Jan, '00


Note that all routines discussed in the following may be downloaded in zipped format.

Introduction.

The MAX518 is a Dual Rail to Rail D/A which uses the Philips I2C 2-Wire protocol. The high five bits of the address are defined by the manufacturer as 01011. The lower two bits are defined by the strapping on terminals AD1 and AD0 on the MAX518. Thus, up to four MAX518s may be accommodated on the same SDA and SCL bus.

A data sheet for the MAX518 is available at the Maxim web site. We sell these for $4.50.

The D/As are 8-bit and use the local 5.0 VDC supply as Vref. Thus, each band corresponds to 5.0 / 256.0. Therefore to ouput a voltage which is half of Vref, the data output to the MAX518 is 128 producing a voltage of 128 * 5.0 / 256.

The D/A outputs are rail to rail. That is, the output will fall to 0.0 and rise to 5.0. Indeed, when outputting 0 and 255 I did measure 0.0 VDC and 4.98 VDC respectively.

The application which gave rise to developing this material was the control of valves where a control voltage in the range of 0.0 to 10.0 corresponds to the valve being fully open to fully closed. Note that the outputs of the MAX518 are limited to the range of 0.0 to 5.0 VDC. However, the outputs might be buffered with an LM324 quad operational amplifier configured as voltage followers with a gain of 2.0. Note that the LM324 will perform down to the negative rail (0.0) but will rise to only V+ - 1.8. However, if powered with +12.0 VDC, the output will rise as high as 10.0.

Note that the following routines use common low level I2C routines which may be used for all manner of devices; 24LC16, 32, 64, 128 and 256 EEPROM, PCF8574 8-bit I/O expander, DS1621 or DS1624 Temperature Sensor, DS1307 or PCF8583 RTC, DS1803 Dual Potentiometer and many others.

Control of the MAX518 consists of addressing the device in the write mode, followed by a command byte, followed by the data. The specific D/A which is addressed is specified in bit 0.

The device may be placed in a power down mode by addressing the device followed by the command byte with the PD bit (bit 3) set to a one. The device may be reset, which I assume sets both D/A outputs to 0.0 by addressing the device followed by the command byte with the RST bit (bit 4) set to a 1. However, I did not test the reset feature.

Progam MAX518_1.Bas

This program outputs a data value of 128 corresponding to a voltage of 2.5 VDC on D/A 0 and a rising sawtooth on D/A 1. After 20 seconds, the MAX518 is placed in the power down mode

' Program MAX518_1.Bas
'
' Illustrates how to use MAX518 Dual D/A.
'
' Program outputs a constant voltage on D/A 0 and a sawtooth on D/A 1
' for 20 seconds and then puts MAX518 in power down mode.
'
'    BX24				MAX518
'
' RC6 (term 6) ------------------- SDA (term 4) ----- To Other
' RC7 (term 5) ------------------- SCL (term 3) ----- I2C Devices
'
' Note that the slave address is 0101 1 AD1 AD0 where AD1 and AD0
' correspond to terminals 6 and 5, respectively.  In this program
' they are strapped to ground and thus the slave address is 0x58.
'
' The Maxim data sheet indicates that pullup resistors on the SDA
' and SCL leads are not required. That is, they are internal.  However,
' I found external 4.7K resistors were neccessary.
'
' In command byte;
'          RST (bit 4) set to 1 resets both D/As
'	   PD (bit 3) set to one for power down
'          A0 (bit 0) identifies whether data is for D/A0 or D/A1
'
' Compile with I2C_BX24.Bas which includes the low level I2C routines.
'
' copyright, Peter H. Anderson, Baltimore, MD, Jan, '00

Public Const SDA_PIN as Byte = 6	' terminals 5 and 6
Public Const SCL_PIN as Byte = 5

' Note that constants must be Public as SDA_PIN and SCL_PIN are used
' in I2C_BX24.Bas

Sub Main()
' Generate a sawtooth on D/A 1 and a constant value on D/A 0 for 20.0 secs
' and then power down the MAX518   

   Dim N as Integer

   Call OpenSerialPort(1, 19200)	' used for debugging

   Call PutTime(0, 0, 0.0)		' initialize clock

   Call Max518DtoAOut(0, 0, 128)        ' output a constant 2.50 VDC
					' on D/A 0

   Do					' output sawtooth on D/A 1
      For N = 0 to 255
         Call Max518DtoAOut(0, 1, CByte(N))                   
      Next
   Loop Until (Timer > 20.0)	' output for 20 secs
     
   Call Max518PowerDown(0)	' and then power down
End Sub  

Sub Max518DtoAOut(ByVal DevAdr as Byte, _
                  ByVal DANum as Byte, ByVal Dat as Byte)

' DevAdr is AD1, AD0 strapping (0-3), DANum is either 0 or 1, Dat 
' is data to be output.

   Call I2C_start()
   Call I2C_out_byte(&H58 OR (DevAdr * 2))	' address the device
   Call I2C_nack()
   Call I2C_out_byte(DANum) 	' selects D/A.  
				' Note that PD Bit is set to zero
   Call I2C_nack()
   Call I2C_out_byte(Dat)	' D/A data
   Call I2C_nack()
   Call I2C_stop()
End Sub

Sub Max518PowerDown(ByVal DevAdr as Byte)
   Call I2C_start()
   Call I2C_out_byte(&H58 OR (DevAdr * 2))	' address the device
   Call I2C_nack()
   Call I2C_out_byte(&H08) 	' sets PD bit of command register to one
   Call I2C_nack()
   Call I2C_stop()
End Sub

Program MAX518_2.Bas

In this routine, the ouputs of four D/As are set to defined voltages. This can easily be expanded to eight D/As (four MAX518s).

These defined voltages are passed in an array which leads to a bit of confusion in that the D/As lend to being defined as 0 through 7, but an array can only be passed by reference if its lowest element is one. Thus, the array is refered to as elements 1 through 8 which correspond to D/As 0 though 7.

Thus, the specific MAX518 is determined as (N-1)\2 and the D/A on the device as (N-1) MOD 2.

' Program MAX518_2.C
'
' Illustrates how to use up to four MAX518 Dual D/A so as to realize 
' up to 8 D/A outputs.
'
' Program sets four outputs (two MAX518s) to constant values.
'
'    BX24				MAX518
'
' RC6 (term 6) ------------------- SDA (term 4) ----- To Other
' RC7 (term 5) ------------------- SCL (term 3) ----- I2C Devices
'
' Note that the slave address is 0101 1 AD1 AD0 where AD1 and AD0
' correspond to terminals 6 and 5, respectively.  In this program it is
' assumed that one MAX518 is strapped for 00 and the second for 01.
'
' In command byte;
'          RST (bit 4) set to 1 resets both D/As
'	   PD (bit 3) set to one for power down
'          A0 (bit 0) identifies whether data is for D/A0 or D/A1
'
' Compile with I2C_BX24.Bas which includes the low level I2C routines.
'
' copyright, Peter H. Anderson, Baltimore, MD, Jan, '00

Public Const SDA_PIN as Byte = 6	' terminals 5 and 6
Public Const SCL_PIN as Byte = 5

' Note that constants must be Public as SDA_PIN and SCL_PIN are used
' in I2C_BX24.Bas

Sub Main()

   Dim OutputVoltages(1 to 4) as Single

   ' set voltage outputs
   OutputVoltages(1) = 5.00	' note that this is OUT0 on MAX518 0
   OutputVoltages(2) = 3.84     ' OUT1 on MAX518 0
   OutputVoltages(3) = 1.02	' OUT0 on MAX518 1
   OutputVoltages(4) = 2.50	' OUT1 on MAX518 1

   ' Call OpenSerialPort(1, 19200)  ' used for debugging

   Call Max518OutputVoltages(OutputVoltages, 4)	
      ' output the four voltages     
End Sub  

Sub Max518OutputVoltages(ByRef OutputVoltages() as Single, _
                         ByVal NumDtoAs as Integer)

   Dim N as Integer, DevAdr as Byte, DANum as Byte, Dat as Byte
   Dim BandSize as Single

   BandSize = 5.0 / 256.0   ' this could alternatively be a constant
  
   For N = 1 to NumDtoAs
      Dat = CByte(OutputVoltages(N) / BandSize)    ' compute D/A val
      DevAdr = CByte((N-1)\2)			' determine adr of MAX518
      DANum = CByte((N-1) MOD 2)		' which D/A on that MAX518	
      Call Max518DtoAOut(DevAdr, DANum, Dat)
   Next
End Sub    
   
Sub Max518DtoAOut(ByVal DevAdr as Byte, _
                  ByVal DANum as Byte, ByVal Dat as Byte)

' DevAdr is AD1, AD0 strapping, DANum is either 0 or 1, Dat is data
' to be output

   Call I2C_start()
   Call I2C_out_byte(&H58 OR (DevAdr * 2))	' address the device
   Call I2C_nack()
   Call I2C_out_byte(DANum) 	' selects D/A. 
				' Note that PD Bit is set to zero
   Call I2C_nack()
   Call I2C_out_byte(Dat)	' D/A data
   Call I2C_nack()
   Call I2C_stop()
End Sub