adafruit / Adafruit_Blinka

Add CircuitPython hardware API and libraries to MicroPython & CPython devices
https://learn.adafruit.com/circuitpython-on-raspberrypi-linux
MIT License
439 stars 328 forks source link

Add PulseIn to BeagleBone #140

Open jrobparsons opened 4 years ago

jrobparsons commented 4 years ago

Installed these libraries on my Beaglebone Black

pip3 install adafruit-blinka pip3 install adafruit-circuitpython-dht

Running this test code (Python 3.5)

import time
import board
import adafruit_dht

# Initial the dht device, with data pin connected to:
dhtDevice = adafruit_dht.DHT22(board.P8_11)

while True:
    try:
        # Print the values to the serial port
        temperature_c = dhtDevice.temperature
        temperature_f = temperature_c * (9 / 5) + 32
        humidity = dhtDevice.humidity
        print("Temp: {:.1f} F / {:.1f} C    Humidity: {}% "
              .format(temperature_f, temperature_c, humidity))

    except RuntimeError as error:
        # Errors happen fairly often, DHT's are hard to read, just keep going
        print(error.args[0])

    time.sleep(2.0)

Getting this message

Traceback (most recent call last): File "/var/lib/cloud9/Python/dht_simpletst.py", line 6, in dhtDevice = adafruit_dht.DHT22(board.P8_11) File "/usr/local/lib/python3.5/dist-packages/adafruit_dht.py", line 255, in init super().init(False, pin, 1000) File "/usr/local/lib/python3.5/dist-packages/adafruit_dht.py", line 66, in init self.pulse_in = pulseio.PulseIn(self._pin, 81, True) AttributeError: module 'pulseio' has no attribute 'PulseIn'

Beaglebone Black Debian/Linux versions

BeagleBoard.org Debian Image 2018-03-05 Linux beaglebone 4.9.82-ti-r102 #1 SMP PREEMPT Thu Feb 22 01:16:12 UTC 2018 armv Debian GNU/Linux 9 (stretch)

Blinka test code works

import board
import digitalio
import busio

print("Hello blinka!")

# Try to create a Digital input
pin = digitalio.DigitalInOut(board.P8_11)
print("Digital IO ok!")

# Try to create an I2C device
i2c = busio.I2C(board.SCL, board.SDA)
print("I2C ok!")

# Try to create an SPI device
spi = busio.SPI(board.SCLK, board.MOSI, board.MISO)
print("SPI ok!")

print("done!")

Hello blinka! Digital IO ok! I2C ok! SPI ok! done!

The instructions I am following

https://learn.adafruit.com/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging?view=all

makermelissa commented 4 years ago

Most likely this is because the BBB board hasn't had PulseIn added yet, whereas the Raspberry Pi has. Are you interested in adding it?

jrobparsons commented 4 years ago

Yes. I would like to add it. I will start looking at the code.

On Mon, Jul 22, 2019, 7:43 PM Melissa LeBlanc-Williams < notifications@github.com> wrote:

Most likely this is because the BBB board hasn't had PulseIn added yet, whereas the Raspberry Pi has. Are you interested in adding it?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_Blinka/issues/140?email_source=notifications&email_token=AAVRFUAVFI3ZKHHD5T6HHKLQAZAZJA5CNFSM4IF5635KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2RPGGI#issuecomment-513995545, or mute the thread https://github.com/notifications/unsubscribe-auth/AAVRFUF5TN6BCSZMLBNYMULQAZAZJANCNFSM4IF5635A .

ladyada commented 4 years ago

it should be possible to do what we do for raspi, which is to use a pulsein helper https://github.com/adafruit/libgpiod_pulsein we include the binary and then call it - check https://github.com/adafruit/Adafruit_Blinka/tree/master/src/adafruit_blinka/microcontroller/bcm283x/pulseio and try cloning it into the bb

jrobparsons commented 4 years ago

Are there guidelines for developers of adafruit repositories.

I cloned the Adafruit_blinka repository. Making updates. I assume I just commit my changes then submit a pull request to start discussion.

On Mon, Jul 22, 2019, 8:11 PM ladyada notifications@github.com wrote:

it should be possible to do what we do for raspi, which is to use a pulsein helper https://github.com/adafruit/libgpiod_pulsein we include the binary and then call it - check https://github.com/adafruit/Adafruit_Blinka/tree/master/src/adafruit_blinka/microcontroller/bcm283x/pulseio and try cloning it into the bb

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_Blinka/issues/140?email_source=notifications&email_token=AAVRFUBZTTRK2BG4MQYLAJ3QAZEDXA5CNFSM4IF5635KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2RQTNI#issuecomment-514001333, or mute the thread https://github.com/notifications/unsubscribe-auth/AAVRFUB7J6I5N2LOCPAGYNLQAZEDXANCNFSM4IF5635A .

makermelissa commented 4 years ago

The basic procedure is fork, clone, make changes, commit to your repo, then submit a PR. Here's a guide on the subject: https://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github.

jrobparsons commented 4 years ago

I am getting things to work, but...

PulseIn.py sets up a call to libgpiod_pulsein

(I cloned the 'libgpiod_pulsein' repository and created the executable by 'making' on my Beaglebone Black)

This does not work

$ gpioinfo

gpiochip1 - 32 lines:
        line  13:  "GPMC_AD13"      "P8_11"   input  active-high [used]

$ gpiofind "GPMC_AD13"
gpiochip1 13

$ gpioget gpiochip1 13
gpioget: error reading GPIO values: Device or resource busy

$ ./libgpiod_pulsein gpiochip1 13
Unable to set line 13 to input

This works

import time
import Adafruit_BBIO.GPIO as GPIO

PIN = "P8_11"

def cleanup():
    GPIO.cleanup()

def setup():
    GPIO.setup(PIN, GPIO.IN)

def getbutton():
    return GPIO.input(PIN)

cleanup()
setup()

while True:
    print(getbutton())
    time.sleep(.5)

Any thoughts?

makermelissa commented 4 years ago

Perhaps there's some kind of extra check in there when it's getting called directly?

jrobparsons commented 4 years ago

It is related to ownership of the GPIO pins. When the Beaglebone Black boots up, device tree overlays are installed to configure hardware. The GPIO pins are configured when the universal cape overlay is installed giving ownership to the pinmux driver (or something like that) then exporting the pins (/sys/class/gpio) to user space where applications can access via the sysfs interface. This is the interface that Adafruit_BBIO.GPIO uses. I can disable installation of the universal cape overlay by editing /boot/uEnv.txt. Access to P8_11 via the libgpiod interface succeeds and polling the DHT22 sensor data line via libgpiod_pulsein works (sort of works). The timing of the polling appears to be a little off. Temperature and humidity values are returned sometimes but mostly invalid checksum or timeout occurs. I will scope the data line and try to figure out what is happening.

ladyada commented 4 years ago

yeah sysfs is probably not fast enough to read DHT from, since it goes thru the filesys. having errors once in a while is normal, this is not a real time system, sometimes the kernel will interrupt you. just run it till you get valid data :)

jrobparsons commented 4 years ago

Something running on the BBB is interrupting libgpiod_pulsein polling.

dht

DIO 1 is monitoring the DHT22 data line that is connected to GPIO P8_11. DIO 2 is monitoring the 'FOLLOW_PULSE' pin (GPIO P8_12) that libgpiod_pulsein is driving.

ladyada commented 4 years ago

yep looks good (as good as it gets)

jrobparsons commented 4 years ago

Been out of town for a few days. I am now back on this.

I am investigating how to instruct the user to free up a pin (P8_11 in the example above) for use by libgpiod_pulsein.

As mentioned in an earlier comment, when the universal cape device tree overlay is loaded during bootup, all the GPIO pins are exported and only available via the sysfs interface. I have to disable loading this overlay by commenting out (or set to 0) the 'enable_uboot_cape_universal=1' line in /boot/uEnv.txt.

###pru_uio (4.4.x-ti, 4.14.x-ti & mainline/bone kernel)
#uboot_overlay_pru=/lib/firmware/AM335X-PRU-UIO-00A0.dtbo
###
###Cape Universal Enable
**enable_uboot_cape_universal=1**
###
###Debug: disable uboot autoload of Cape
#disable_uboot_overlay_addr0=1
#disable_uboot_overlay_addr1=1

After disabling universal cape loading, libgpiod_pulsin can use P8_11 and the DHT_22 can now be accessed.

I am looking for a simpler solution to freeing up a GPIO pin that is exported when the universal cape is loaded.

jrobparsons commented 4 years ago

Here is what I have learned so far...

I see from the univ-bbb-Exx-00A0.dts that the cape-universal node uses the "gpio-of-helper" device driver to configure and export the GPIO pins.

    fragment@2 {
        target = <&ocp>;
        __overlay__ {
            cape-universal {
                compatible = "gpio-of-helper";

What I do not know, yet, is how to access the "gpio-of-helper" device driver from user space to 'unexport' a pin.

Is there documentation that describes how to use the API supported by the "gpio-of-helper" device driver?

FYI

I am also working the issue here: https://github.com/beagleboard/bb.org-overlays/issues/134 and here: https://beagleboard.org/Community/Forums?place=msg%2Fbeaglebone%2F_yle1VeYp0Y%2FaPrl2u4fCgAJ

jrobparsons commented 4 years ago

Took a major side-trip into understanding device tree overlay and loadable kernel module development...

1. The sysfs/libgpiod playground

In order to free up a pin for use by libgpiodpulseio (via libgpiod interface) and leave pins for use by Adafruit* modules (via sysfs interface), the universal cape overlay that is loaded during boot-up must be edited, compiled, then copied back into /lib/firmware where available for next boot-up.

In my system, the overlay being loaded is,

univ-bbb-EVA-00A0.dtbo univ-bbb-EVx-00A0.dtbo univ-bbb-Exx-00A0.dtbo univ-bbb-xVA-00A0.dtbo univ-bbb-xVx-00A0.dtbo univ-bbb-xxx-00A0.dtbo

and is determined by my /boot/uEnv.txt configuration.

I edited the corresponding DTS file in "/opt/source/bb.org-overlays/src/arm/", compiled it using "/opt/source/bb.org-overlays/make src/arm/univ-bbb-Exx-00A0.dtbo", then copied the DTBO file to "/lib/firmware".

I edited the DTS file by disabling all configuration of pin P8_11 (the one used in the dht_simpletst.py example) by following what was done to disable pins P9_19 and P9_20 (the pins supporting the cape I2C EEPROM bus).

Now...

Both "blinkatest.py" and "dht_simpletst.py" run successfully.

2. libgpiod_pulseio CPU hog!!

I am running "dht_simpletst.py" with a 10 second sleep between attempts to read temperature and humidity.

The CPU utilization by libgpiod_pulseio remains pegged at a constant 98% even while the python program is sleeping!

top - 14:04:35 up 32 min,  2 users,  load average: 1.17, 0.84, 0.67
Tasks: 102 total,   2 running, 100 sleeping,   0 stopped,   0 zombie
%Cpu(s): 19.5 us, 80.5 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   495588 total,   274928 free,   110764 used,   109896 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   367568 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 1822 debian    20   0    1448    976    904 R 97.1  0.2   0:53.91 libgpiod_pulsei
 1772 debian    20   0    7192   2900   2344 R  1.6  0.6   0:03.28 top
 1821 debian    20   0   13104   9328   5580 S  1.0  1.9   0:00.94 python
    4 root      20   0       0      0      0 D  0.3  0.0   0:13.51 kworker/0:0
  821 www-data  20   0  228992   3172   1780 S  0.3  0.6   0:02.00 apache2
 1491 root      20   0       0      0      0 S  0.3  0.0   0:00.46 kworker/0:2
    1 root      20   0   25496   5000   3904 S  0.0  1.0   0:03.42 systemd

More later...