GPIO, libpruio & dtbo Question

Hello all,

I have a BBB Python application (PCBA test fixture) where I am using libpruio, specifically for access to the eCAP pins. Libpruio requires that the universal cape be disabled, but when I needed a UART and I2C, I was able to add those back in using the existing dtbo files from /lib/firmware (shown below) in my uEnv.txt.

uboot_overlay_addr0=/lib/firmware/BB-I2C1-00A0.dtbo
uboot_overlay_addr1=/lib/firmware/BB-UART4-00A0.dtbo
uboot_overlay_addr2=/lib/firmware/DP-GPIO-PCBATest-00A0.dtbo (I talk about this below)

Now I want to add an “abort” button to the test fixture since the technicians have reported it takes a lot of time to reset if the board under test locks up. I expect that wiring a pushbutton to a GPIO with an interrupt is the way to handle this, and I’ve been thinking that there are two ways to get there.

  1. Include another dtbo file to add a single GPIO that I can then access with Adafruit_BBIO (this is where my efforts have focused so far), or
  2. Figure out how to work with the hardware-based IRQ of the PRU with libpruio (which I’ve been avoiding because it looks even more scary)

I’ve tried to make a custom dtbo by following an example from Derek Molloy (github.com/derekmolloy/boneDeviceTree) and while it compiled and booted OK, I still get the following error when I run a simple test program. The same error as when I tried running the program before I created the dtbo.

kapsul@beaglebone:~/pyDev$ sudo python3 abortTest.py
Traceback (most recent call last):
File “abortTest.py”, line 6, in
GPIO.setup(“P9_12”, GPIO.IN)
ValueError: Set gpio mode failed, missing file or invalid permissions.

Further, when I do the following (with or without the dtbo), I get the following…

kapsul@beaglebone:~/pyDev$ config-pin -q p9.12
P9_12 pinmux file not found!
Cannot read pinmux file: /sys/devices/platform/ocp/ocp*P9_12_pinmux/state

Any input would be appreciated, whether it is correcting me on path 1 or steering me towards path 2. I will happily provide any additional info, but I didn’t want to start uploading stuff until I know what, exactly, will be helpful.

Hello,

I literally am havin’ the same issue as you right now w/ a GPS module working w/ BB-UART2-00A0.dtbo and a grove connector. This is my error:

py_setup_uart(UART2): set_pin_mode() failed for pin=P9_22Traceback (most recent call last):
File “FirstGPS.py”, line 5, in
UART.setup(“UART2”)
ValueError: Set pin mode failed for uart channel.

I think things are changing at some point in some way at some level. Vague…yes. I can set up my source w/out the .dtbo and use config-pin to set my uart2 pins to have my source ‘work.’

Anyway, I will be following along to see how far you get b/c right now, I am a little stumped as to why what has worked no longer is viable.

Seth

You prompted me to recheck how I’m accessing the two peripherals I did get to install, the UART and the I2C. I’m only sending messages out over the UART using pyserial, although I do also use minicom to bi-directionally communicate with the board under test from the BBB Ubuntu command line. For the I2C I’m using the Adafruit char LCD library, which relies on busio from Circuit Python. Still an Adafruit product, but not technically the BBB_IO library, I guess.

If anyone can give tips on how to do a button-based interrupt (abort) without BBB_IO, I’m all ears. I guess I could just start programming the BBB in C. I already program embedded microcontrollers in that language, so why not SBC?

Hello,

I am receiving errors w/ the .dtbo only. I am too far from outside to communicate w/ my GPS and I am receiving no feedback w/ pyserial on my BBG (BeagleBone Green). I tried installing a serial lib. w/ sudo apt install python3-serial, also.

I just downloaded/installed the docs in .epub/html format on my hard drive. I am thinking it may or may not be Adafruit_BBIO. I am also thinking that it may be or may not be pyserial. The intallation w/ apt was faulty from the get-go.

I can use config-pin p9.21 uart && config-pin p9.22 uart and have that command turn successful.

It may be a faulty effort in an update from pyserial but I am not sure yet. If this means anything, please let me know:

^CTraceback (most recent call last):
File “./FirstGPS.py”, line 87, in
myGPS.read()
File “./FirstGPS.py”, line 47, in read
while ser.inWaiting() == 0:
File “/home/debian/.local/lib/python3.7/site-packages/serial/serialutil.py”, line 593, in inWaiting
def inWaiting(self):
KeyboardInterrupt

The above error is only when I make no call to config-pin w/out a .dtbo loaded. Also, pyserial is listed…

Now…this source below is after making a config-pin call to P9.21/22 and trying to exit my program:

^CTraceback (most recent call last):
File “./FirstGPS.py”, line 87, in
myGPS.read()
File “./FirstGPS.py”, line 47, in read
while ser.inWaiting() == 0:
File “/home/debian/.local/lib/python3.7/site-packages/serial/serialutil.py”, line 594, in inWaiting
return self.in_waiting
File “/home/debian/.local/lib/python3.7/site-packages/serial/serialposix.py”, line 549, in in_waiting
s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
KeyboardInterrupt

Both…are screaming to me about pyserial and those specific locations. I add print statements and receive nothing back. So, I think my source, which is an update from Python2 (from utf-8 to bytes) to Python3, is faulty.

I can show you in case you are wondering. I am just updating some source I found a while back.

Seth

Hello,

Are you using BBB_IO or Adafruit_BBIO?

Either way, here is a start w/ Adafruit_BBIO:

import serial
import Adafruit_BBIO.UART as UART
from time import sleep

UART.setup(“UART2”)

ser=serial.Serial("/dev/ttyS2", 9600)

class GPS:
def init(self)

and then…

If you want to add a button, just use a GPIO from Adafruit_BBIO again. So, that example will look like this:

import Adafruit_BBIO.GPIO as GPIO
from time import sleep

pinOne = 'P8_11’
GPIO.setup(pinOne, GPIO.IN)

while True:
if GPIO.input(pinOne):
print(“The Button Shall get pressed Again or whatever…”)
sleep(2)

That is a simplistic approach. I got that source from an older book: “Getting Started with BeagleBone (Richardson 2013).”

There are some neat examples in that book but nothing too complicated. It would be a refresher to see what was then and what has changed.

Anyway, I hope that works for you. That button function should just work. You can always do better and make it on an edge. Falling, Rising, or Both w/ that same lib.

Seth

Hello Sir,

Seth here. Here is an Adafruit_BBIO.GPIO example for handling a button (abort on Rising): I got it from “The BeagleBone Black Primer (McLaughlin 2015).”

import Adafruit_BBIO.GPIO as GPIO

Button = "P9_11"

GPIO.setup(Button, GPIO.IN)

if name==‘main’:
try:
while True:
GPIO.wait_for_edge(Button, GPIO.RISING)
except KeyboardInterrupt:
GPIO.cleanup()

This example is on page 174.

Seth

P.S. I hope this helps a bit. I paraphrased but this is the oomph of it all. If you are going to need other ideas, please let me know. I know, from my own personal experience, that the BUSIO source may not be able to be called w/ it working on this specific controller. I read, about a year back, about how Circuit Python is trying to branch out and how some people were trying to get it to work on the BBB. I am not convinced that it works yet but I will research this idea more.

Hello,

I know I am blowing up your feed here. I found out you are right. CircuitPython must work. >>> https://circuitpython.org/blinka

Seth

P.S. Nice!

I can use config-pin p9.21 uart && config-pin p9.22 uart and have that
command turn successful.

  So far as I've been able to determine, config-pin (and Adafruit_BBIO)
rely upon cape-universal to provide the pin-mux capability. The OP has
stated that his application disabled cape-universal. As a result,
config-pin, and any configuration required to be performed by Adafruit_BBIO
is likely to fail.

  Using CircuitPython libraries via the blinka adapter layer probably has
similar requirements.

  As for the OP's query:

If anyone can give tips on how to do a button-based interrupt (abort)
without BBB_IO, I'm all ears. I guess I could just start programming the
BBB in C. I already program embedded microcontrollers in that language, so
why not SBC?

  I've not heard of BBB_IO before. Adafruit_BBIO, OTOH, is common,
followed by using CircuitPython libraries (designed for Arduino-like
boards) via the adapter library "blinka", would be second.

  The trick with Adafruit_BBIO will be in the GPIO setup if
cape-universal is not present, since I believe it provides the system
"files" for the GPIOs that config-pin and Adafruit_BBIO require to
configure the pin.

  If you can get past, say

import Adafruit_BBIO.GPIO as GPIO

GPIO.setup("P8_14", GPIO.IN) <<<<<<<< may not work without cape

then setting up an "interrupt" would be something like (not a callback --
requires your application to have a polling loop)

GPIO.add_event_detect("P8_14", GPIO.FALLING)
#your amazing code here
#detect wherever:
if GPIO.event_detected("P8_14"):
    print "event detected!"

  Hmmm, according to
https://adafruit-beaglebone-io-python.readthedocs.io/en/latest/GPIO.html
you CAN set up a callback function. Your choice is to detect
rising/falling/both so if you have a pull-up on the pin, and the button
takes it to ground, falling is likely what you'd use. You also need to
specify a "bouncetime" so the callback doesn't get triggered by button
bounces.

  https://circuitpython.readthedocs.io/projects/blinka/en/latest/
describes the blinka adapter for CircuitPython libraries. Off-hand, it
doesn't look favorable for "interrupt" on GPIO.

Hello Don Pancoe!

Why do you think you’ll need an IRQ for the “abort” button?

Drop Adafruit_BBIO! Just setup the GPIO in libpruio and poll the state in your main loop (or in a timered thread).

Regards

Hello everyone,

Thank you for all the input. It’s been a busy few days so I’m just getting back to it.

First, I was talking about AdafruitBB_IO. I was just being lazy and/or confused in typing BBB_IO, but I now see that BBBIO is a different C library for the Beaglebone Black. I do write C code for microcontrollers, so I don’t know why I felt like a program on an SBC should be in Python, but I don’t want to start over from scratch now.

The PCBA test program is a long series of while loops, if statements and timeout counters that wait for inputs and evaluate them, or move on if they’re taking too long. I was thinking of using an AdafruitBB_IO edge detect to watch for an abort button press, then having that trigger a function that handles any wrap-up tasks and calls a break function to pop out of the main test loop to another outer loop so that it returns to the top of the test. I’m actually doing this now to halt the test if the in-circuit programmer reports a flashing failure. The difference is: the programmer failure happens at a known point where I know to look for it, but the abort button should be able to be used at any time.

One idea I’ve had but not tested yet is to replace the sleep() functions I judiciously use for timing throughout the test with a custom function that breaks the sleep period (anywhere from 10 ms to 10 s) into smaller chunks interspersed with checking of the abort button GPIO. This I could do just with libpruio as suggested by TJF. Theoretically, I could wait for every subsequent while loop to time out at 60 seconds each, but that’s not practical for test throughput, or when you are billed for testing by the minute.

Somewhat separate from all this, though: I’ve been finding the device tree, overlays and pinmuxes to be some of the more difficult BBB/Linux topics to wrap my head around, so I would appreciate any recommended tutorials on the subject. There are tutorials that come up in Google searches, but with the changes to both Linux and Beaglebone over the years, it’s hard to know if they are pertinent to the state of my system right now (I’ve not updated to the latest kernel etc. because I don’t want to break any of my past work).

Thanks,

Hello Sir,

Look at this!

Those should get you updated on ideas.

Seth

P.S. The first bullet point is the DeviceTrees for the am335x, cape-universal, am5729, and so on… The second bullet point is the actual spec. w/ related info. Get one! The third bullet point is the overlay section and there is juicy info. in those files for adding support for the am335x and so on. Also, last but not least, uboot. I am sure there is something about uboot that needs to be incorporated in DeviceTree specs. So, I placed that in too. If you get bored, look here too: https://www.digikey.com/eewiki/display/linuxonarm/BeagleBone+Black .

If using Adafruit_BBIO edge detect with a call-back function, that
call-back probably should do nothing more than set a "global" flag.

  Your sleep() and loops would then include something like "while not
abortFlag".

  There is no easy way in Python to back out of multiple levels of loops
except via an exception (so something like "if abortFlag: raise
customAbortException"). You'd catch that exception at the outermost level,
and the handler does the clean-up. A one-level loop can be exited with
"break".

Why so complicated?

Your sleep() and loops would then include something like “while not
abortFlag”.

Replace

while not abortFlag

by

while pruio_gpio_Value(io, abortPIN)

and drop all that IRQ magic (which only makes sense when you can use the hardware debounce feature).

And drop all that device tree magic. Instead configure the abortPIN by libpruio as GPIO with pull-up resistor (PRUIO_GPIO_IN_1) and wire the other end of the button to ground.

Focus on your major target. Don’t waste your time by reading and testing a bunch of documentations, which are too modern (or outdated) for your current system.

Regards

But if I used the following, would it not evaluate only at the start of the while loop? The main loop of the whole test lasts on the order of minutes even if all sub-tests pass, so how would that capture a <1sec button press? Or is Python an event-driven language, where a change in the evaluated condition will break the loop at any point?

while pruio_gpio_Value(io, abortPIN)

Python is not event-driven -- Node.js/Bonescript MIGHT be such, but I
have never been able to make sense of even a short example where everything
seems to be written as a call-back function triggered by other
call-backs... I also have never been able to make sense of Python's asyncio
library either, for the same reason. Threads with some form of interprocess
(interthread) communication (Queue) is something I can work with.

  The only difference between the above "while" and my "while" is that
the above is reading the pin when called, whereas mine is reading a global
variable that gets set by a call-back when Adafruit_BBIO detects a state
change on the pin. So the above may only see the button pressed at one
point in the code, and the next test may not see it -- and if the code does
not poll the pin fast enough, one may even miss the button press. libpruio
does not seem to support such -- cf:
https://groups.google.com/g/beagleboard/c/3wphAPs9Uws (which is the
underlying C level, I doubt the Python interface adds any features)

  In both styles, you need to include a test (either "while" or "if") at
any point in the code where you can implement a break in execution. In both
styles, backing out from multiple levels of loops will require either a
custom exception which can be trapped at the point where you can clean-up
from the aborted loops, or some sort of "if" test immediately after a
single level "break".

while main-loop-conditional:
  if abortFlag: break
  while loop1-conditional:
    if abortFlag: break
    #do short bit of work
    if abortFlag: break
    #do more work
  if abortFlag:
    #clean up loop1 stuff
    break
  while loop2-conditional:
    if abortFlag: break
    #do short bit of work
    if abortFlag: break
    #do more work
  if abortFlag:
    #clean up loop2 stuff
    break
if abortFlag:
  #clean up main loop stuff
  #otherwise normal exit of main loop

  Note that the proposed in-line pruio_gpio_Value() version has the
problem that the state may change between reads -- so one might abort one
inner loop, but the next test finds the button is not pressed and doesn't
propagate the abort upwards.

OR using custom exception (but with 1-level cleanup)

while main-loop-conditional:
  try:
    if abortFlag: raise abortException
    while loop1-conditional:
      try:
        if abortFlag: raise abortException
        #do short bit of work
        if abortFlag: raise abortException
        #do more work
      except abortException:
        #clean up loop1 stuff
        #if you want to propagate the abort
        #reraise the exception
        raise
        #otherwise clear abortFlag to allow second loop to run
        #or just
        break
        #to move on
  while loop2-conditional:
      try:
        if abortFlag: raise abortException
        #do short bit of work
        if abortFlag: raise abortException
        #do more work
      except abortException:
        #clean up loop2 stuff
        #if you want to propagate the abort
        #reraise the exception
        raise
        #otherwise clear abortFlag to allow second loop to run
        #or just
        break
        #to move on
  except abortException:
  #clean up main loop stuff
  #otherwise normal exit of main loop

OR IF you can postpone all clean-up to the end

while main-loop-conditional:
  try:
    if abortFlag: raise abortException
    while loop1-conditional:
      if abortFlag: raise abortException
      #do short bit of work
      if abortFlag: raise abortException
      #do more work
    while loop2-conditional:
      if abortFlag: raise abortException
      #do short bit of work
      if abortFlag: raise abortException
      #do more work
  except abortException:
  #clean up main loop stuff
  break
  #otherwise normal exit of main loop

Non Sequitur: "TJF" is, as I recall, the author of that libpruio package,
and pushes it as the only solution for everything related to Beaglebone
GPIO.

https://groups.google.com/g/beagleboard/c/3wphAPs9Uws (which is the
underlying C level, I doubt the Python interface adds any features)

Nonsens! Use

io.IntcInit

to configure the interrupt table (IRQ[0-4,6,7]). And mask your event in the GPIO registers

LEVELDETECT[0,1]
RISINGDETECT
FALLINGDETECT

If need be also set the GPIO registers

DEBOUNCENABLE
DEBOUNCINGTIME

and then catch (and reset) the new IRQ in a thread. But this isn’t worth the effort!

As mentioned above, the while loop should get placed in a custom sleep function. And since the app does nothing in that sleep function, the abortPIN can get polled fast enough (20 to 100 Hz).

I don’t mean to start a fight here. You are all providing helpful information. I think I will proceed on one of the following paths.

  1. Dig in and understand the GPIO registers. I have seen those in the libpruio docs, but just haven’t groked them yet.
  2. Failing that, I can use libpruio to read the button during the customSleep() function, where it will both call a break right there as well as set an abort flag to notify any subsequent tests that they should also not execute.
  3. And lastly, really dive into the device tree more long-term per Seth’s info, because I think that would be useful knowledge for future projects.
    Thanks,
    Don

Hello @Don,

Seth here. Did you ever get up and running? Things get updated constantly. So, I get behind at times w/ ideas in Linux, the beagleboard.org world, and still trying to perform sourcery!

Seth

P.S. Anyway, if you get time, reply! Did the ideas work out or did you come up w/ your own game plan?