0

Voltage Divider 100k Pot added to mcp3004 channel 1Implemented a generic Pi/MCP3004 sketch to read a Thermistor with Channel 0 ... this has been working great for well over 3 years in an unattended mountaintop radio shack (providing remote monitoring of the shack temperature) ... today we added a 100k Pot ... Input Voltage (VBat) on one end of the pot the other end is Ground with the wiper attached to Channel 1 input (pin 2) ... the wiper was pre-adjusted to 3.3 V with a 20V input voltage (approx 16k to Gnd) ... the MCP3004 Vref is 3.3V ... the expectation was any reading from Channel 1 would provide VBat as (chn1 reading)/1024*20 to provide the actual voltage ... the Battery Voltage is expected in the range of 12.4V to 16V (Victron lower/upper cutoffs) ... the issue: as soon as I attach the battery to VBat (top of pot) both the Thermistor (chn0) and (chn1) read 0 ... Physical Channel Voltage readings are 1.2V and 2.2V respectively (2.2 V on Chn 1 should correspond to Vbat of 13.6V) ... the Python function that reads the chip hasn't changed ... it only requires a Port # as a parameter (code attached below) ... removal of the + Vbat from pot connected to chn1 restores readings on chn0

The MCP3004 documentation indicates there is a distinct AGnd for the channel inputs ... looking at the implemented schematic it appears AGnd and DGnd were tied together ... the expectation is separating grounds is typically done for Noisy environments ... there are other details regarding Single-ended vs Differential ... this failure suggests the chip may be in Differential mode ... The code below indicates the channels should be in single-ended mode ... SO ... the big question is: how/why is Vbat wiping out Channel 0 and not providing a reading for Channel 1 ... has anyone experienced a failure like this?

Python Code

#----------------- readADC( Channel# ) ---------------------------------------
# Microchip ADC MCP300X family has 3 variations; 2, 4 or 8 Channel 10bit A/D
# all 3 use a Serial Data Pin to Clock in Commands & Clock out Digital Data
# representing the Analog values
#
def readAdc(iChn): # MCP3004 has 4 Channels: 0 to 3

ensure both pgl and pg don't attempt to read adc at the same time

bArf = GPIO.input(ARF[_PIN]) # is there a Read in Progress while bArf == 1: bArf = GPIO.input(ARF[_PIN])

wend

GPIO.output(ARF[_PIN], GPIO.HIGH) # set Read in Progress

Datasheet says chip select must be pulled high between conversions

GPIO.output(CS[_PIN], GPIO.HIGH)

Start the read with clock high and chip select low

GPIO.output(CS[_PIN], GPIO.LOW) GPIO.output(CLK[_PIN], GPIO.HIGH)

ADC commands are 5 bits long:

start bit = 1

single-ended comparison = 1 (vs. pseudo-differential = 0)

channel num bit 2 (MSB) (for MCP3004 this is always 0)

channel num bit 1

channel num bit 0 (LSB)

ie for single-ended channel 0 this command should be 1 1 0 0 0 or 0x18

iAdcCmd = 0x18 # base command for Channel 0 iAdcCmd |= iChn # add Channel to command

for iBit in range(5):

output MSB bit: HI or LO

if iAdcCmd & 0x10: # is MSB HI? GPIO.output(MOSI[_PIN], GPIO.HIGH) else: GPIO.output(MOSI[_PIN], GPIO.LOW)

endif

Shift next bit to MSB

iAdcCmd <<= 1

Send a clock pulse HI then immediately LO

GPIO.output(CLK[_PIN], GPIO.HIGH) GPIO.output(CLK[_PIN], GPIO.LOW)

next

iAdcVal = 0

for iBit in range(12):

Pulse clock pin

GPIO.output(CLK[_PIN], GPIO.HIGH) GPIO.output(CLK[_PIN], GPIO.LOW)

Read 1 data bit in

if GPIO.input(MISO[_PIN]): iAdcVal |= 0x1

endif

Shift in next bit

iAdcVal <<= 1

next

Divide by two to drop the stop bit

iAdcVal = (iAdcVal/2) iAdcVal &= 0x3FF

Set chip select high to end the read

GPIO.output(CS[_PIN], GPIO.HIGH) GPIO.output(CS[_PIN], GPIO.LOW)

GPIO.output(ARF[_PIN], GPIO.LOW) # clear Read in Progress return iAdcVal

end readACD

bxdobs
  • 9
  • 2

1 Answers1

0

Solved

The original code was using the clock (CLK) incorrectly causing the COMMAND logic to drop the START bit which results in the CHIP being configured to Differential Mode ... command 0x18 is incorrectly being clocked in as 0x10 ... Any "unmatched" input on ch 1 in Differential mode basically wipes out both the Ch 0 and 1 readings (ADC output is meaningless)

Corrected code:

def readAdc(iChn): # MCP3004 has 4 Channels: 0 to 3
 # ensure both pgl and pg don't attempt to read the ADC at the same time
 # if CS is low then an ADC read is in progress 
 bArf = 0
 while bArf == 0:
  bArf = GPIO.input(CS[_PIN])
 # end while

Start the read with clock high and chip select low

GPIO.output(CLK[_PIN], GPIO.HIGH) GPIO.output(CS[_PIN], GPIO.LOW)

ADC commands are 5 bits long:

start bit = 1

single-ended comparison = 1 (vs. pseudo-differential = 0)

channel num bit 2 (MSB) (for MCP3004 this is always 0)

channel num bit 1

channel num bit 0 (LSB)

ie for single-ended channel 0 this command should be 1 1 0 0 0 or 0x18

iAdcCmd = 0x18 # base command for Channel 0 iAdcCmd |= iChn # add Channel to command

Write Command

for iBit in range(5):

Write out 1 bit of data to Pi GPIO pin connected to Din

output MSB bit: HI or LO

if iAdcCmd & 0x10: # is MSB HI? GPIO.output(MOSI[_PIN], GPIO.HIGH) else: GPIO.output(MOSI[_PIN], GPIO.LOW)

endif

Shift next bit to MSB

iAdcCmd <<= 1

Falling Clock Edge to move to next bit

GPIO.output(CLK[_PIN], GPIO.LOW)

Rising Clock Edge to clock in the data waiting on Din

GPIO.output(CLK[_PIN], GPIO.HIGH)

next

iAdcVal = 0

Read Data

for iBit in range(12):

Falling Clock Edge to move to next bit

GPIO.output(CLK[_PIN], GPIO.LOW)

Rising Clock Edge to clock out the data from Dout

GPIO.output(CLK[_PIN], GPIO.HIGH)

Read in 1 data bit from Dout

if GPIO.input(MISO[_PIN]): iAdcVal |= 0x1

endif

Shift in next bit

iAdcVal <<= 1

next

Divide by two to drop the stop bit (there is no stop bit!)

leave this code in place to provide a buffer between reads

iAdcVal = (iAdcVal/2) iAdcVal &= 0x3FF

Set chip select high to end the read

GPIO.output(CS[_PIN], GPIO.HIGH)

return iAdcVal

end readACD

bxdobs
  • 9
  • 2