Reading data out of an ADC (MCP3001) with python (SPI)
Question: I try to read some data from an ADC with python, but unfortunatly it doesn't
work. I hope someone has a hint for me, because my script creates only chaos-
data. But I don't see the mistake with the bits...

I've updated the script below as I'm reading 16 bits and cut of the first and
the last 3 bits. I need the 10 middle bits for the data - if I understand the
datasheet correctly...

**Datasheet MCP3001:** (Page 15)
<http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf>

    
    
    import time
    import RPi.GPIO as GPIO
    
    GPIO.setmode(GPIO.BCM)
    
    HIGH = True
    LOW  = False
    
    def readAnalogData(SCLKPin, MOSIPin, MISOPin, CSPin):
        GPIO.output(CSPin,   HIGH)    
        GPIO.output(CSPin,   LOW)
        GPIO.output(SCLKPin, LOW)
    
        adcvalue = 0
        for i in range(16):
            GPIO.output(SCLKPin, HIGH)
            GPIO.output(SCLKPin, LOW)
            adcvalue <<= 1
            if(GPIO.input(MISOPin)):
                adcvalue |= 0x01
        adcvalue >>= 3
        adcvalue &= 0x3ff
        time.sleep(0.5)
    
        return adcvalue
    
    SCLK        = 11 # Serial-Clock
    MOSI        = 10 # Master-Out-Slave-In
    MISO        = 9 # Master-In-Slave-Out
    CS          = 17 # Chip-Select
    
    GPIO.setup(SCLK, GPIO.OUT)
    GPIO.setup(MOSI, GPIO.OUT)
    GPIO.setup(MISO, GPIO.IN)
    GPIO.setup(CS,   GPIO.OUT)
    
    while True:
        print readAnalogData(SCLK, MOSI, MISO, CS) 
    


Answer: From a cursory read of the data sheet and your code, it looks like you're
trying to discard the data from the initial 3 clock cycles by converting to a
`str` and using `str` slicing

    
    
    adcvalue = str(adcvalue)
    adcvalue = adcvalue[3:12]
    adcvalue = int(adcvalue)
    

If so, this will not work. `adcvalue` is an `int` and converting it to a `str`
will produce a decimal (base 10) string. Instead, either don't sample data
during the first three cycles, or use a bit mask to strip it from the integer
(ie `adcvalue &= 0x1ff`)

In addition, you seem to be sampling data on the negative clock edge, however
this is when the data is in a transient state. I suspect you either need to
put in a delay here, or sample on the +ve clock edge when the data has
stabilized.

**EDIT**

As stated above, try sampling on the +ve clock edge. Figure 6-1 on pg.16 of
the datasheet shows this. Also it looks like it pumps out 9 bits in MSB
format, then repeats the data in LSB format (see Fig 6-2), so I don't think
you want to keep 10 bits. You probably only need to clock out a total of
12bits, then discard the first 3.

Something like (untested):

    
    
    def readAnalogData(SCLKPin, MOSIPin, MISOPin, CSPin):
        GPIO.output(CSPin,   HIGH)    
        GPIO.output(CSPin,   LOW)
    
        adcvalue = 0
        for i in range(12):
            GPIO.output(SCLKPin, LOW) # reverse order of hi/lo here
            GPIO.output(SCLKPin, HIGH)
            adcvalue <<= 1
            if(GPIO.input(MISOPin)):
                adcvalue |= 0x01
        adcvalue >>= 3
        # adcvalue &= 0x3ff <- commented out this line as should be no longer necessary
    
        return adcvalue
    

