RE: SPI and Adafruit_BBIO, the TRM for the BBB, and Me!

195 views
Skip to first unread message

Mala Dies

unread,
Nov 10, 2019, 12:19:35 AM11/10/19
to BeagleBoard
Hello,

I am running a python3 program that has to do w/ SPI on the BBBW and the Adafruit_BBIO library. I set up my pins, set up the source, and ran the code.

...

I got back some odd numbers that mean nothing. I was following some ideas from Rpi stuff and transferring data to the BBBW via the Adafruit_BBIO library to make things work.

So...

from LDRII import MCP3008 #I found this source online and I cannot figure out what site I found it at currently. Anyway...if this is your source, say so! I will give you credit.

adc = MCP3008()

print(adc.read(channel = 0))

is the source I run from this library...

from Adafruit_BBIO.SPI import SPI

SPI0_CS0  = "P9_17"
SPI0_D0   = "P9_21"
SPI0_D1   = "P9_18"
SPI0_SCLK = "P9_22"

spi = SPI(1, 0)

class MCP3008:
    def __init__(self, bus = 0, device = 0):
        self.bus, self.device = bus, device
        self.spi = SPI()
        self.open()

    def open(self):
        self.spi.open(self.bus, self.device)

    def read(self, channel = 0):
        adc = self.spi.xfer2([1, (8 + channel) << 4, 0])
        data = ((adc[1] & 3) << 8) + adc[2]
        return data

    def close(self):
        self.spi.close()

Now, what I figured would happen, happened and I cannot explain it (yet).

Do you see my error in computation here?

Seth

P.S. I have to use config-pin to set up the pins for use but I receive variable numerical values every time I run the source from above. Please send some advice if you have time.

Mala Dies

unread,
Nov 10, 2019, 5:55:38 PM11/10/19
to BeagleBoard
Hello Again,

I am receiving now, what I think are voltage levels, some levels from some simple math added to the source.

Seth

P.S. Here: 


voltage:         0.0032258064516129032
16
voltage:         0.0032258064516129032
16
voltage:         0.0032258064516129032
0
voltage:         0.0032258064516129032
24
voltage:         0.0032258064516129032
10
voltage:         0.0032258064516129032
1
voltage:         0.0032258064516129032
24


The line below voltage is the original numerical value w/ what I think is the a voltage to the right of voltage. Here is the updated source to the library:

from LDRII import MCP3008
import time

adc = MCP3008()

while True:
    Vref = 3.3
    Voltage = (Vref / 1023)
    print("voltage: \t", Voltage)
    print(adc.read(channel = 0))
    time.sleep(4)

Dennis Lee Bieber

unread,
Nov 10, 2019, 7:52:42 PM11/10/19
to Beagleboard
On Sat, 9 Nov 2019 21:19:35 -0800 (PST), in
gmane.comp.hardware.beagleboard.user Mala Dies
<functt-Re5JQEe...@public.gmane.org> wrote:

>
>from LDRII import MCP3008 #I found this source online and I cannot figure
>out what site I found it at currently. Anyway...if this is your source, say
>so! I will give you credit.
>
Based on Google, the MCP3008 is a multichannel ADC. The Raspberry Pi
examples require it because the R-Pi only has binary GPIO.

The BBB has internal ADC (though limited to 1.8V peak, so one often
needs a voltage divider to reduce 3.3V (or 5V) data to fit into 0..1.8V)
(for safety, one might want to limit the peak to 1.7V, and adjust the
conversion equation somewhat).

https://www.linux.com/tutorials/how-get-analog-input-beaglebone-black/
https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/adc

>
>from LDRII import MCP3008 #I found this source online and I cannot figure
>out what site I found it at currently. Anyway...if this is your source, say
>so! I will give you credit.
>
Based on Google, the MCP3008 is a multichannel ADC. The Raspberry Pi
examples require it because the R-Pi only has binary GPIO.

The BBB has internal ADC (though limited to 1.8V peak, so one often
needs a voltage divider to reduce 3.3V (or 5V) data to fit into 0..1.8V)
(for safety, one might want to limit the peak to 1.7V, and adjust the
conversion equation somewhat).

https://www.linux.com/tutorials/how-get-analog-input-beaglebone-black/
https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/adc
--
Dennis L Bieber

evilwulfie

unread,
Nov 10, 2019, 8:03:26 PM11/10/19
to beagl...@googlegroups.com
On 11/10/2019 5:52 PM, Dennis Lee Bieber wrote:
> On Sat, 9 Nov 2019 21:19:35 -0800 (PST), in
> gmane.comp.hardware.beagleboard.user Mala Dies
> <functt-Re5JQEe...@public.gmane.org> wrote:
>
> >from LDRII import MCP3008 #I found this source online and I cannot figure
>> out what site I found it at currently. Anyway...if this is your source, say
>> so! I will give you credit.
>>
> Based on Google, the MCP3008 is a multichannel ADC. The Raspberry Pi
> examples require it because the R-Pi only has binary GPIO.
>
> The BBB has internal ADC (though limited to 1.8V peak, so one often
> needs a voltage divider to reduce 3.3V (or 5V) data to fit into 0..1.8V)
> (for safety, one might want to limit the peak to 1.7V, and adjust the
> conversion equation somewhat).
>
> https://www.linux.com/tutorials/how-get-analog-input-beaglebone-black/
> https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/adc
>
> >from LDRII import MCP3008 #I found this source online and I cannot figure
>> out what site I found it at currently. Anyway...if this is your source, say
>> so! I will give you credit.
>>
> Based on Google, the MCP3008 is a multichannel ADC. The Raspberry Pi
> examples require it because the R-Pi only has binary GPIO.
>
> The BBB has internal ADC (though limited to 1.8V peak, so one often
> needs a voltage divider to reduce 3.3V (or 5V) data to fit into 0..1.8V)
> (for safety, one might want to limit the peak to 1.7V, and adjust the
> conversion equation somewhat).
Using an opamp is much safer

> https://www.linux.com/tutorials/how-get-analog-input-beaglebone-black/
> https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/adc

Dennis Lee Bieber

unread,
Nov 10, 2019, 8:09:59 PM11/10/19
to Beagleboard
On Sun, 10 Nov 2019 14:55:38 -0800 (PST), in
gmane.comp.hardware.beagleboard.user Mala Dies
<functt-Re5JQEe...@public.gmane.org> wrote:

>
>
>The line below voltage is the original numerical value w/ what I think is
>the a voltage to the right of voltage. Here is the updated source to the
>library:
>
>from LDRII import MCP3008
>import time
>
>adc = MCP3008()
>
>while True:
> Vref = 3.3
> Voltage = (Vref / 1023)
> print("voltage: \t", Voltage)
> print(adc.read(channel = 0))
> time.sleep(4)
>
>

That code is doing NOTHING with the ADC readings.

What you have calculated as "Voltage" is just the STEP value for the
ADC and it will never change. You have to multiply the step value by the
ADC reading to get the measured voltage. NOTE: you are defining Vref as 3.3
on EVERY pass of the loop: IT, and the STEP should be constants defined
outside the loop.

NOTE: those numbers you were reporting look a lot like noise on a
grounded signal pin. A reading of 16 is just 0.0516 volts.

You might want to look at
https://github.com/adafruit/Adafruit_CircuitPython_MCP3xxx/
(Adafruit is phasing out system specific libraries for CircuitPython -- and
provides the blinka library to map regular Python [as found on R-Pi and
BBB] to the CircuitPython API)

https://learn.adafruit.com/circuitpython-on-raspberrypi-linux?view=all
(also applies to BBB if you follow the required install instructions for
blinka)


--
Dennis L Bieber

Mala Dies

unread,
Nov 10, 2019, 9:17:13 PM11/10/19
to BeagleBoard
Hey and Hello,

I got the info. more suited to abide by actual rules instead of guessing like I did do earlier in my source.

...

Thank you for the links. I did get some help on Freenode too. I will look over the links. I have them up now.

Seth

P.S. Here is a setup maybe worth while?

from LDRone import MCP3008
import time

adc = MCP3008(bus=0, device=0, vref=3.3)

try:
    while True:
        voltage = adc.read(channel=0)                   # across resistor
        current = voltage * 10000                       # through resistor and LDR
        resistance = (adc.vref - voltage) / current     # of LDR
        print("voltage: \t", voltage)
        print("current: \t", current)
        print("resistance: \t", resistance)
    time.sleep(4)

except:
    print("Get gone!")
    pass


Here is LDRone.py

from Adafruit_BBIO.SPI import SPI

class MCP3008:
    def __init__(self, bus, device, vref):
        self.vref = vref
        self.spi = SPI(bus, device)

    def read(self, channel):
        data = self.spi.xfer2([1, (8 + channel) << 4, 0])
        value = ((data[1] & 3) << 8) + data[2]
        return value * self.vref / 1023

    def close(self):
        self.spi.close()



On Sunday, November 10, 2019 at 6:52:42 PM UTC-6, Dennis Bieber wrote:
On Sat, 9 Nov 2019 21:19:35 -0800 (PST), in
gmane.comp.hardware.beagleboard.user Mala Dies

Mala Dies

unread,
Nov 10, 2019, 9:18:29 PM11/10/19
to BeagleBoard
Hello, 

Yes...I know. I read earlier from a book that the op amp is a goto source for handling this device, i.e. the LDR/photoresistor.

Seth

P.S. Thank you for the heads up. 


On Sunday, November 10, 2019 at 7:03:26 PM UTC-6, evilwulfie wrote:
On 11/10/2019 5:52 PM, Dennis Lee Bieber wrote:
> On Sat, 9 Nov 2019 21:19:35 -0800 (PST), in
> gmane.comp.hardware.beagleboard.user Mala Dies

Dennis Lee Bieber

unread,
Nov 11, 2019, 9:32:20 AM11/11/19
to Beagleboard
On Sun, 10 Nov 2019 18:17:13 -0800 (PST), in
gmane.comp.hardware.beagleboard.user Mala Dies
<functt-Re5JQEe...@public.gmane.org> wrote:

Just some stuff I scratched together -- all untested (read the
comments)

-=-=-=- adc-1.py
#!/usr/bin/env python3
"""
adc-1.py ADC example using MCP3008 and mysterious LDRII library
November 11, 2019 Dennis L Bieber

*** UNTESTED **
Not only do I not have access to an MCP3008 ADC chip, I have not
been able to find the LDRII (Light Dependent Resistor?) library
supporting said chip.
The API used is based upon postings in comp.lang.python by one
"Mala Dies" who, it seems, is having a truly bad day

This code reads all 8 channels of the MCP3008. It may be worth
checking the data sheet for the chip to determine which state
draws the least current and using a 10KOhm or higher resister to
pull-up/pull-down the unused inputs.
"""

import time
from LDRII import MCP3008

#constants from spec sheets
ADC_BITS = 10
ADC_REF = 3.3
ADC_CHANNELS = 8

T_DELTA = 5.0

#derived constants
ADC_MAX = (2 ** ADC_BITS) - 1
ADC_VSTEP = ADC_REF / ADC_MAX

#create ADC instance
adc = MCP3008()

t0 = t = time.time()
while True:
print("\nT: %16.2f" % (time.time() - t0))
for channel in range(ADC_CHANNELS):
raw = adc.read(channel = channel)
print("\tChannel: %2d\tCount: %4d\tVoltage: %6.3f"
% (channel, raw, raw * ADC_VSTEP))
t += T_DELTA
time.sleep(t - time.time())
-=-=-=-
-=-=-=- adc-2.py
#!/usr/bin/env python3
"""
adc-2.py ADC example using MCP3008 and Adafruit_Blinka
and Adafruit_CircuitPython_MCP3xxx libraries
November 11, 2019 Dennis L Bieber

*** UNTESTED **
I do not have access to an MCP3008 ADC chip

*** PREREQUISITES ***
sudo pip3 install adafruit_blinka (might be adafruit-blinka)
sudo pip3 install adafruit-circuitpython-mcp3xxx

This code reads all 8 channels of the MCP3008. It may be worth
checking the data sheet for the chip to determine which state
draws the least current and using a 10KOhm or higher resister to
pull-up/pull-down the unused inputs.
"""

import time

import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn

#constants from spec sheets
ADC_REF = 3.3
ADC_CHANNELS = 8

T_DELTA = 5.0

#create the SPI bus and ChipSelect
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
cs = digitalio.DigitalInOut(board.DS)

#create ADC instance (note: ref_voltage default is 3.3 if not supplied)
adc = MCP.MCP3008(spi, cs, ref_voltage = ADC_REF)

#create ADC channel instances -- relies on MCP.P0 = 0, etc.
channels = [ AnalogIn(adc, chan) for chan in range(ADC_CHANNELS) ]

t0 = t = time.time()
while True:
print("\nT: %16.2f" % (time.time() - t0))
for channel in channels:
#while a 10-bit ADC chip, the raw counts are scaled to 65472
raw, voltage = channels[channel].value, channels[channel].voltage
print("\tChannel: %2d\tCount: %4d\tVoltage: %6.3f"
% (channel, raw, voltage))
t += T_DELTA
time.sleep(t - time.time())
-=-=-=-
-=-=-=- adc-3.py
#!/usr/bin/env python3
"""
adc-3.py ADC example using native BBB ADC and
adafruit_bbio library
November 11, 2019 Dennis L Bieber

*** UNTESTED **
While I do have BBB, I have not taken time to wire a circuit

*** WARNING ***
BBB ADC inputs can be damaged by signals greater than 1.8V
It would perhaps be best to use a voltage divider circuit
with the 3.3V yielding a maximum of 1.65V [giving up a few
counts for the last 0.15V]

This code reads all 7 channels of the BBB. It may be worth
checking the data sheet for the chip to determine which state
draws the least current and using a 10KOhm or higher resister to
pull-up/pull-down the unused inputs.
"""

import time
import Adafruit_BBIO.ADC as ADC

#constants from spec sheets
ADC_REF = 1.8

#pins equivalent to AIN0..AIN6
CHANNELS = [ "P9_39", "P9_40", "P9_37",
"P9_38", "P9_33", "p9_36",
"P9_35" ]

T_DELTA = 5.0

#initialize ADC system
ADC.setup()

t0 = t = time.time()
while True:
print("\nT: %16.2f" % (time.time() - t0))
for channel in channels:
#a documented bug in ADC driver recommends one needs to
#read twice to get latest value, I'm presuming that does
#not mean both .read() and .read_raw() need to be repeated
jnk = ADC.read(channel)
raw, voltage = ADC.read_raw(channel), ADC.read(channel)
#"voltage" is scaled 0.0 .. 1.0, so multiply by reference
print("\tChannel: %2d\tCount: %4d\tVoltage: %6.3f"
% (channel, raw, voltage * ADC_REF))
t += T_DELTA
time.sleep(t - time.time())
-=-=-=-
--
Dennis L Bieber

Dennis Lee Bieber

unread,
Nov 11, 2019, 10:51:15 AM11/11/19
to Beagleboard
On Mon, 11 Nov 2019 09:32:07 -0500, in gmane.comp.hardware.beagleboard.user
Dennis Lee Bieber <dennis.l.bieber-Re5...@public.gmane.org>
wrote:
WHOOPS...
> raw, voltage = channels[channel].value, channels[channel].voltage
raw, voltage = channel.value, channel.voltage

> print("\tChannel: %2d\tCount: %4d\tVoltage: %6.3f"
> % (channel, raw, voltage))
> t += T_DELTA
> time.sleep(t - time.time())
>-=-=-=-
--
Dennis L Bieber

Dennis Lee Bieber

unread,
Nov 11, 2019, 10:56:47 AM11/11/19
to Beagleboard
On Mon, 11 Nov 2019 09:32:07 -0500, in gmane.comp.hardware.beagleboard.user
Dennis Lee Bieber <dennis.l.bieber-Re5...@public.gmane.org>
wrote:

Actually, forget the immediately prior correction for adc-2
Replace following...

> for channel in channels:
> #while a 10-bit ADC chip, the raw counts are scaled to 65472
> raw, voltage = channels[channel].value, channels[channel].voltage
> print("\tChannel: %2d\tCount: %4d\tVoltage: %6.3f"
> % (channel, raw, voltage))

for ch, channel in enumerate(channels):
#while a 10-bit ADC chip, the raw counts are scaled to 65472
raw, voltage = channel.value, channel.voltage
print("\tChannel: %2d\tCount: %4d\tVoltage: %6.3f"
% (ch, raw, voltage))

> t += T_DELTA
> time.sleep(t - time.time())
>-=-=-=-
--
Dennis L Bieber

Mala Dies

unread,
Nov 12, 2019, 6:33:00 PM11/12/19
to BeagleBoard
Hello Mr. Dennis,

Seth here. Thank you again. It is nice to have people just away ideas like this one. I know you know more than I do on this subject. I am new to SPI and using in Linux Distros on the BBBW never crossed my path until this task.

...

So, I will put in your source and see how it works. Would you like to know the answer or terminal writing, I am sure you already have tested it, when I run the source?

Seth


On Monday, November 11, 2019 at 9:56:47 AM UTC-6, Dennis Bieber wrote:
On Mon, 11 Nov 2019 09:32:07 -0500, in gmane.comp.hardware.beagleboard.user
Reply all
Reply to author
Forward
0 new messages