View Full Version : MAX1247 4-Channel, 12-Bit ADC
  
Atom058
- 16th November 2006, 00:34
Hello All!
Has anyone had any experience with this chip?  Any PBP code snippets would be greatly appreciated (Spec sheet is not much help w/PBP)!
Thanks!
Atom058
- 17th November 2006, 23:32
I have scoured all of my resources and have come up with the following code but I seem to be missing something.  Can anyone provide some insight?
' Set compiler to use HS (20 mHz)
@ DEVICE HS_OSC
    DEFINE OSC 20 'resonator frequency at 20 Mhz
    ' Define the LCD Hookup parameters
    ' data pins D4-D7 are hooked to pins C.0-C.3, respectively
   	define LCD_DREG     PORTC   'Data Port = PORTC
   	define LCD_DBIT     0           'Data starting bit = 0
   	define LCD_RSREG    PORTC   'Register Select Port = PORTC
   	define LCD_RSBIT    4           'RS bit = PortC.4
   	define LCD_EREG     PORTC   'Enable Port = PORTC
   	Define LCD_EBIT     5           'Enable Bit = PortC.5
   	define LCD_BITS     4           'LCD Bus Size = 4
   	define LCD_LINES    2           'Number of lines on LCD
   	
   	define SHIFT_PAUSEUS 1000   '
	Pause 1000 ' Wait for LCD to startup
	Lcdout $FE, $80, "MAX1247"
	lcdout $FE, $C0, "Example"
	pause 1000
    'Variables for ADC
   	CB	var	byte
   	CB0	var	Byte
   	CB1 	var	Byte
   	CB2 	var	Byte
   	CB3	var	Byte
	
	ADResult 	    var word ' contains the result of the read
	X               var byte ' counter
'Control Byte Setup:
' Bit 7:  Start Bit = 1
' Bit 6:  Channel Select Bit 2 (SEL2)	-See Channel Selection Below
' Bit 5:  SEL1
' Bit 4:  SEL0
' Bit 3:  UNI/BIP - 1=Unipolar  0=Bipolar
' Bit 2:  SNGL/DIF - 1=Single Ended  0=Differential
' Bit 1:  PD1 - Sets clock and power down mode
' Bit 0:  PD0 - Sets clock and power down mode
'Channel Selection:
'           SEL2       SEL1       SEL0
'CH0	 0	  0	   1 
'CH1	 1	  0	   1
'CH2	 0	  1	   0
'CH3	 1	  1	   0
' To read channel 0 in Unipolar, single ended, external clock mode,
'  Control Byte (CB) = 10011111
             CB0 = %10011111 'To Read Channel 0
   	CB1 = %11011111 'To read channel 1
   	CB2 = %10101111 'To read Channel 2
   	CB3 = %11101111 'To read Channel 3
    
    ' Set up MAX1247 4-channel 12-bit ADC 
	CLKpin		var PORTA.0	'SPI clock pin	
	CSpin		var PORTA.1	'DAC chip select
	DINpin		var PORTA.2	'Data in pin
	DOUTpin		var PORTA.3          'Data Out Pin
    'set up Max1247 pins
	TRISA.0 = 0 'CLKpin as output
	TRISA.1 = 0 'CSpin as output
	TRISA.2 = 0 'DINpin as output
	TRISA.3 = 1 'DOUTpin as input
    'Take Reading
	CB = CB0 'Read Channel 0
Loop:
	CSpin = 1 'keep max1247 off until called
	clkpin = 0 'keep clock low until ready
	gosub ReadADC
	Lcdout $FE, 1 ' Clear LCD screen
	Lcdout $FE, $80, #ADresult
	
	pause 330
	goto loop
ReadADC:
    'Send Control Byte
    low CSpin 'cs going low starts the conversion process
    shiftout doutpin, clkpin, 1, [cb\8]
    high cspin
    pause 10
    
    'Read Result
    adresult = 0
    low cspin
    shiftin dinpin, clkpin, 0, [adresult\12]
    high cspin
    
    return
    
end
mister_e
- 18th November 2006, 18:38
try..
ReadADC:
        'Send Control Byte
    low CSpin 'cs going low starts the conversion process
    shiftout doutpin, clkpin, 1, [cb\8]
        'Read Adc
    shiftin dinpin, clkpin, 0, [adresult\12]
    high cspin
    return
Atom058
- 18th November 2006, 22:13
Steve - Thanks for your reply (again).  Unfortunately, the suggestion did not work.  I have attached my board layout.  It is pretty straight forward - Do you see anything I am missing?  Ignore the other chip - it is a 12-bit D-A chip that works fine... Just can't get the input side of this to work.  You will see that I have a pot supplying a voltage to CH0 of the MAX1247.  I am trying to read this and display the result on the LCD.
Thanks!
mister_e
- 19th November 2006, 10:07
First observation, you have to disable ADCs on PORTA
ADCON1=7
and at the top, you should insert a short PAUSE (let's say 50) after
CSpin = 1
Just for safety sake
sorry i'm too lazy tonight to check the whole thing :D
Fortunately, someone else may have a deeper look to?
Atom058
- 19th November 2006, 20:36
Steve - I was really hoping that the ADCON1 thing was it as I missed that one, but still no go.  I did the 50 mS pause you recommended, too.
I can't help but think this is one of those "can't see the forest through the trees" thing.  I'm sure it's staring me right in the face.  I am using a 12 bit D/A (4-channel) chip (MAX525) on this board as well and it works perfectly.  Can't imagine why the A/D chip is giving me such a hard time...
Let me know if you think of anything else!  Thanks!
Atom058
- 19th November 2006, 21:41
This is out of the data sheet for the MAX1247:
"the simplest software interface requires only
three 8-bit transfers to perform a conversion (one 8-bit
transfer to configure the ADC, and two more 8-bit transfers
to clock out the 12-bit conversion result)." 
"Simple Software Interface
Make sure the CPU’s serial interface runs in master
mode so the CPU generates the serial clock. Choose a
clock frequency from 100kHz to 2MHz.
1) Set up the control byte for external clock mode and call it TB1. TB1 should be of the format: 1XXXXX11 binary, where the Xs denote the particular channel and conversion mode selected.
2) Use a general-purpose I/O line on the CPU to pull CS low.
3) Transmit TB1 and, simultaneously, receive a byte and call it RB1. Ignore RB1.
4) Transmit a byte of all zeros ($00 hex) and, simultaneously, receive byte RB2.
5) Transmit a byte of all zeros ($00 hex) and, simultaneously, receive byte RB3.
6) Pull CS high.
Figure 5 shows the timing for this sequence. Bytes RB2
and RB3 contain the result of the conversion, padded
with one leading zero and three trailing zeros. The total
conversion time is a function of the serial-clock frequency
and the amount of idle time between 8-bit
transfers. To avoid excessive T/H droop, make sure the
total conversion time does not exceed 120μs."
This seems to be telling me that I have to shift out 3 bytes (control, $00, $00) and I read back 3 bytes - the result is contained in the 2nd two bytes.  It also mentions choosing a clock frequency of 100kHz to 2MHz.  How do I do that?
I made a stab at the three out, three in routine but no result:
ReadADC:
    low CSpin 
    shiftout doutpin, clkpin, 1, [cb]   'Send Control Byte
    shiftin dinpin, clkpin, 0, [rb1]      'Read RB1 in and discard
    shiftout doutpin, clkpin, 1, [$00] 'Send a byte of zeros
    shiftin dinpin, clkpin, 0, [rb2]      'Read RB2
    shiftout doutpin, clkpin, 1, [$00] 'Send a byte of zeros
    shiftin dinpin, clkpin, 0, [rb3]      'Read RB3 - RB2&3 contain result
    high cspin
    return
Am I using the right modes for shiftin and out?
arniepj
- 19th November 2006, 23:26
Attached is code used with a 16F877 and Max 1270 a/d,similar I believe.
Atom058
- 19th November 2006, 23:48
Arniepj - Thanks for the code!  I will give it a try (with some modifications, of course).  I will let you know how it goes...
Thanks!
Atom058
- 20th November 2006, 00:58
Arniepj - Tried your code and am now actually able to get a reading!!!  It is off by about 200 mV but it might be because I am using a 4.096 Vref reference (were you using one?).  I will play with this a little more to tweek it so that it is accurate and post the final code.  What I have now that works is posted below.  The other thing that I changed based on your code was going from an external to internal clock on the Control Byte for the chip.
Thanks a million!!!
(and thanks to you too, Steve!)
' Set compiler to use HS (20 mHz)
@ DEVICE HS_OSC
    DEFINE OSC 20 'resonator frequency at 20 Mhz
    ADCON1 = 7 ' Disable PORTA Analog 
    
    ' Define the LCD Hookup parameters
    ' data pins D4-D7 are hooked to pins C.0-C.3, respectively
   	define LCD_DREG     PORTC   'Data Port = PORTC
   	define LCD_DBIT     0       'Data starting bit = 0
   	define LCD_RSREG    PORTC   'Register Select Port = PORTC
   	define LCD_RSBIT    4       'RS bit = PortC.4
   	define LCD_EREG     PORTC   'Enable Port = PORTC
   	Define LCD_EBIT     5       'Enable Bit = PortC.5
   	define LCD_BITS     4       'LCD Bus Size = 4
   	define LCD_LINES    2       'Number of lines on LCD
	Pause 1000 ' Wait for LCD to startup
	Lcdout $fe, $80, "MAX1247"
	lcdout $fe, $C0, "Example"
	pause 1000
	Lcdout $FE, 1 ' Clear LCD screen
	
    'Variables for ADC
   	CB	    var	byte
   	CB0	    var	Byte
   	CB1 	    var	Byte
   	CB2 	    var	Byte
   	CB3	    var	Byte
'Control Byte Setup:
' Bit 7:  Start Bit = 1
' Bit 6:  Channel Select Bit 2 (SEL2)	-See Channel Selection Below
' Bit 5:  SEL1
' Bit 4:  SEL0
' Bit 3:  UNI/BIP - 1=Unipolar  0=Bipolar
' Bit 2:  SNGL/DIF - 1=Single Ended  0=Differential
' Bit 1:  PD1 - Sets clock and power down mode
' Bit 0:  PD0 - Sets clock and power down mode
'   00 - full power down
'   01 - fast power down
'   10 - internal clock mode
'   11 - external clock mode
'Channel Selection:
'           SEL2        SEL1       SEL0
'CH0	 0	  0	   1 
'CH1	 1	  0	   1
'CH2	 0	  1	   0
'CH3	 1	  1	   0
' To read channel 0 in Unipolar, single ended, internal clock mode,
'  Control Byte (CB) = 10011110
             CB0 = %10011110 'To read Channel 0
   	CB1 = %11011110 'To read Channel 1
   	CB2 = %10101110 'To read Channel 2
   	CB3 = %11101110 'To read Channel 3
    ' Set up MAX1247 4-channel 12-bit ADC 
	CLKpin		var PORTA.0	'SPI clock pin	
	CSpin		var PORTA.1	'DAC chip select
	DINpin		var PORTA.2	'Data in pin
	DOUTpin		var PORTA.3         'Data Out Pin
    'set up Max1247 pins
	TRISA.0 = 0 'CLKpin as output
	TRISA.1 = 0 'CSpin as output
	TRISA.2 = 0 'DIpin as output
	TRISA.3 = 1 'DOpin as input
' ******** Declarations *******************************
    Voltage1        var word
    Voltage2        var word
    Voltage3        var word
    Voltage4        var word
    SerialDataOut  var byte		' Serial data out to Max1247 A/D
    SerialDataIn    var word		' Serial data in from Max1247 A/D
    Indexer          var byte		' Loop indexer for data in	
' ********* Presets ****************************
    SerialDataOut = cb0						
    SerialDataIn = 0
    clkpin = 0		' Clock signal
    cspin = 0		' Chip select: low selects
    dinpin = 0	      	' Serial data out 
    doutpin = 0		' Serial data in
'******Main Program ********************************
DataOut:
	gosub DataAcquisition	'Read data from Max1247		
	Voltage1 = SerialDataIn * 2	' Convert data to voltage
	Voltage2 = (SerialDataIn * 4)/10	' Convert data to voltage
	Voltage3 = (SerialDataIn * 4)/100	' Convert data to voltage	
	Voltage4 = Voltage1 + Voltage2 + Voltage3 + 9	' Convert data to voltage
	lcdout $FE, $80, #Voltage4, "   "        ' Display data
	SerialDataIn = 0
	goto Dataout
'************ Data Acquisition ***************************
DataAcquisition:
	for Indexer = 7 to 0 step -1		' Output data,8 clock pulses
	    dinpin = SerialDataOut.0[Indexer]	' Output data port
	    pulsout clkpin,5			' Output clock pulse
	next Indexer		' Next data bit,next clock pulse
	for Indexer = 1 to 12		' Read data,12 clock pulses
	    SerialDataIn = SerialDataIn * 2	' Shift each bit to the left
	    SerialDataIn = SerialDataIn + doutpin	' Data in port
	    pulsout clkpin,5			' Output clock pulse
	next Indexer		' Next data bit,next clock pulse
	return
end
Atom058
- 21st November 2006, 01:00
Hello All - Here is the final version of the software.  Note that I am using a 2.5V Vref with the MAX1247, so you will have to change the voltage calculation if you are using a different Vref or none at all.
Enjoy!
' Set compiler to use HS (20 mHz)
@ DEVICE HS_OSC
	DEFINE OSC 20 'resonator frequency at 20 Mhz
    ADCON1 = 7 ' Disable PORTA Analog 
    
    ' Define the LCD Hookup parameters
    ' data pins D4-D7 are hooked to pins C.0-C.3, respectively
   	define LCD_DREG     PORTC   'Data Port = PORTC
   	define LCD_DBIT     0       'Data starting bit = 0
   	define LCD_RSREG    PORTC   'Register Select Port = PORTC
   	define LCD_RSBIT    4       'RS bit = PortC.4
   	define LCD_EREG     PORTC   'Enable Port = PORTC
   	Define LCD_EBIT     5       'Enable Bit = PortC.5
   	define LCD_BITS     4       'LCD Bus Size = 4
   	define LCD_LINES    2       'Number of lines on LCD
	Pause 1000 ' Wait for LCD to startup
	Lcdout $fe, $80, "MAX1247"
	lcdout $fe, $C0, "Example"
	pause 1000
	Lcdout $FE, 1 ' Clear LCD screen
	
    'Variables for ADC
   	CB	    var	byte
   	CB0	    var	Byte
   	CB1 	var	Byte
   	CB2 	var	Byte
   	CB3	    var	Byte
'Control Byte Setup:
' Bit 7:  Start Bit = 1
' Bit 6:  Channel Select Bit 2 (SEL2)	-See Channel Selection Below
' Bit 5:  SEL1
' Bit 4:  SEL0
' Bit 3:  UNI/BIP - 1=Unipolar  0=Bipolar
' Bit 2:  SNGL/DIF - 1=Single Ended  0=Differential
' Bit 1:  PD1 - Sets clock and power down mode
' Bit 0:  PD0 - Sets clock and power down mode
'   00 - full power down
'   01 - fast power down
'   10 - internal clock mode
'   11 - external clock mode
'Channel Selection:
'	    SEL2 SEL1 SEL0
'CH0	 0	  0	   1 
'CH1	 1	  0	   1
'CH2	 0	  1	   0
'CH3	 1	  1	   0
' To read channel 0 in Unipolar, single ended, internal clock mode,
'  Control Byte (CB) = 10011110
    CB0 = %10011110 'To read Channel 0
   	CB1 = %11011110 'To read Channel 1
   	CB2 = %10101110 'To read Channel 2
   	CB3 = %11101110 'To read Channel 3
    ' Set up MAX1247 4-channel 12-bit ADC 
	CLKpin		var PORTA.0	'SPI clock pin	
	CSpin		var PORTA.1	'DAC chip select
	DINpin		var PORTA.2	'Data in pin
	DOUTpin		var PORTA.3 'Data Out Pin
    'set up Max1247 pins
	TRISA.0 = 0 'CLKpin as output
	TRISA.1 = 0 'CSpin as output
	TRISA.2 = 0 'DIpin as output
	TRISA.3 = 1 'DOpin as input
' ******************************** Declarations ********************************************
    Voltage         var word
    SerialDataOut   var byte		' Serial data out to Max1247 A/D
    SerialDataIn    var word		' Serial data in from Max1247 A/D
    Indexer         var byte		' Loop indexer for data in	
' ******************************** Presets ************************************************
    SerialDataOut = cb0						
    SerialDataIn = 0
    clkpin = 0						' Clock signal
    cspin = 0				  		' Chip select: low selects
    dinpin = 0				       	' Serial data out 
    doutpin = 0						' Serial data in
'********************************* Main Program *********************************************
DataOut:
	gosub DataAcquisition							' Read data from Max1247		
	lcdout $FE, $80, #Serialdatain, "  "		    ' Display data
	lcdout $FE, $C0, #voltage, "  "                 ' Display calculated voltage
	goto Dataout
'******************************** Data Acquisition ***************************
DataAcquisition:
	SerialDataIn = 0
	for Indexer = 7 to 0 step -1					' Output data,8 clock pulses
		dinpin = SerialDataOut.0[Indexer]			' Output data port
	    pulsout clkpin,5							' Output clock pulse
	next Indexer									' Next data bit,next clock pulse
	for Indexer = 1 to 12							' Read data,12 clock pulses
		SerialDataIn = SerialDataIn * 2				' Shift each bit to the left
		SerialDataIn = SerialDataIn + doutpin		' Data in port
	    pulsout clkpin,5							' Output clock pulse
	next Indexer									' Next data bit,next clock pulse
    SerialDataIn = SerialDataIn * 2                 ' Shift each bit to the left
    'Using a 2.5V Reference with ADC, therefore, 2500 / 4096 = 0.6 mV per step
    'Multiply the result (SerialDataIn) by 6
    voltage = serialdatain * 6
    voltage = voltage / 10 'shift decimal point
	return
end
arniepj
- 21st November 2006, 02:22
Atom050,
Glad to help.An alternative is to use the hardware spi,but since you had a board already,changing i/o might not be possible.
Atom058
- 14th December 2006, 20:39
Hello - I'm back with a question.  I was testing my design and code with a power supply that can deliver precise mV outputs in the 0.00 to 102.00 mV range.  I was looking to see if my design would work all the way down to 0 mV.  Well, I am getting about a 14 mV difference in my readings.  In otherwords, my LCD displays 0 mV when 14 mV or below is input.  All readings above that are good but off by 14 mV.  If I didn't need to measure below 14 mV, I would just add 14 to the value that was being displayed by my LCD and call it good.  But I need to see below 14... Anyone have an idea why that might be?  And how I might correct it?
Atom058
Darrel Taylor
- 15th December 2006, 01:53
I would tend to believe the problem is with the power supply.
Or more specificaly, the measurement of the power supply's voltage.
A simple test is to use a voltage that you don't need to "read" to know what it is. And the easiest way to do that is with a simple voltage divider.
With 2 resistors 100k to Vdd(+5V) and 220 ohms to Vss. you will get approximately 11mv at the junction. Of course it depends on the tolerance of the resistors you use, but it will still be very close even with 5%.
With 12 bits and 2.5Vref, that should give an A/D value of 22, and due to integer truncating should read 10 mv after the *6/10.
So if it reads 10mv, then the problem is the difference between the actual power supply voltage and the external measuement of that voltage.
<br>
Atom058
- 15th December 2006, 23:38
Darrell - Thanks for your suggestion... Although I was verifying the voltage being output with another meter, I will give it a try (I'll try anything right about now) and let you know what happens.
Atom058
 
Powered by vBulletin® Version 4.1.7 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.