• Content count

  • Joined

  • Last visited

  1. testers wanted ArmbianIO API proposal

    I agree, and maybe just use a sizeof since the arrays are static. Then there's no need for an array of number of pins.
  2. After a lot of work and testing I have produced the User Space IO project! It provides Python 3 and Java 8 bindings for Linux user space GPIO, SPI, I2C and Serial interfaces. This allows cross SBC and cross language development using a common API. I took two best of breed C APIs for Linux user space libgpiod and c-periphery and produced CFFI bindings for Python and JNA bindings for Java. Since all the bindings closely match the C API it's easy to move from language to language. The side effect of using the Java library is that it should work with many different JVM based languages. How about creating your programs in Kotlin or Scala for instance? GPIO access uses the new gpiod interface and not the deprecated sysfs interface using libgpiod v1.1 (head from git repo). GPIO, SPI, I2C and serial interfaces expose all the low level functionality. I have added some helper methods for handling repetitive functions like building I2C messages, reading words from two registers, etc. You can of course go as low level as you need to. Please use Github to post any issues, pull requests, etc. I have tested Nano Pi Duo for 32 bit and NanoPi Neo +2 for 64 bit compatibility. I'll test more SBCs as I have time. Also, I have deleted since User Space IO supersedes it. Based of some of the questions I had in the past please note the following: gpiod_ctxless_event_loop_multiple can handle GPIO interrupts Miscellaneous GPIO request flags GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW Non-root access using rc.local.
  3. Did you look at the C header? /** * @brief Miscellaneous GPIO request flags. */ enum { GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN = GPIOD_BIT(0), /**< The line is an open-drain port. */ GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE = GPIOD_BIT(1), /**< The line is an open-source port. */ GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW = GPIOD_BIT(2), /**< The active state of the line is low (high is the default). */ }; Common GPIO Properties ====================== These properties are met through all the other documents of the GPIO interface and it is useful to understand them, especially if you need to define GPIO mappings. Active-High and Active-Low -------------------------- It is natural to assume that a GPIO is "active" when its output signal is 1 ("high"), and inactive when it is 0 ("low"). However in practice the signal of a GPIO may be inverted before is reaches its destination, or a device could decide to have different conventions about what "active" means. Such decisions should be transparent to device drivers, therefore it is possible to define a GPIO as being either active-high ("1" means "active", the default) or active-low ("0" means "active") so that drivers only need to worry about the logical signal and not about what happens at the line level. Open Drain and Open Source -------------------------- Sometimes shared signals need to use "open drain" (where only the low signal level is actually driven), or "open source" (where only the high signal level is driven) signaling. That term applies to CMOS transistors; "open collector" is used for TTL. A pullup or pulldown resistor causes the high or low signal level. This is sometimes called a "wire-AND"; or more practically, from the negative logic (low=true) perspective this is a "wire-OR". One common example of an open drain signal is a shared active-low IRQ line. Also, bidirectional data bus signals sometimes use open drain signals. Some GPIO controllers directly support open drain and open source outputs; many don't. When you need open drain signaling but your hardware doesn't directly support it, there's a common idiom you can use to emulate it with any GPIO pin that can be used as either an input or an output: LOW: gpiod_direction_output(gpio, 0) ... this drives the signal and overrides the pullup. HIGH: gpiod_direction_input(gpio) ... this turns off the output, so the pullup (or some other device) controls the signal. The same logic can be applied to emulate open source signaling, by driving the high signal and configuring the GPIO as input for low. This open drain/open source emulation can be handled transparently by the GPIO framework. If you are "driving" the signal high but gpiod_get_value(gpio) reports a low value (after the appropriate rise time passes), you know some other component is driving the shared signal low. That's not necessarily an error. As one common example, that's how I2C clocks are stretched: a slave that needs a slower clock delays the rising edge of SCK, and the I2C master adjusts its signaling rate accordingly.
  4. There's a lot different in the DTS. I really do not have time to see if it's just certain sections, but I'd just go with the FriendlyElec DTB. The DTS is attached. sun8i-h2-plus-nanopi-duo-friendlyelec.dts
  5. I tried modifying the existing DTS as described, but it didn't work. I'll do a diff when I have some time.
  6. I do exactly this with my ARM server rack to backup each server. My crontab (runs on machine to back up) looks something like: # Backup root file system 00 01 * * 0 tar -cvpzf /backuppath/servname.backup.`date +\%Y\%m\%d_\%H\%M\%S`.tar.gz --one-file-system /. > /backuppath/servname.backup.log 2>&1
  7. On my journey to finding the best solution for cross SBC/cross language GPIO support I went through the same issues as Python by the C side author did it seems and landed on CFFI. This is faster than ctypes and seem more natural to program with. ctypesgen (the code generator) doen't really support Python 3, so I've hit a dead end there. It seems like JNA is still the best choice for Java bindings, so I'm sticking with that for now. In any event I threw together a button press app that uses CFFI and libgrpiod. I'll be updating my bindings project to support this soon. libgpiod version 1.1.devel Name: gpiochip1, label: 1f02c00.pinctrl, lines: 32 Press button within 5 seconds Falling edge timestamp 02/10/2018 19:49:05 """ Test blocking event using built in button ------------- Should work on any board with a button built in. Just change chip and line value as needed. """ import sys, time from argparse import * from cffi import FFI parser = ArgumentParser() parser.add_argument("--chip", help="GPIO chip number (default 1 '/dev/gpiochip1')", type=int, default=1) parser.add_argument("--line", help="GPIO line number (default 3 button on NanoPi Duo)", type=int, default=3) args = parser.parse_args() ffi = FFI() # Specify each C function, struct and constant you want a Python binding for # Copy-n-paste with minor edits ffi.cdef(""" enum { GPIOD_LINE_EVENT_RISING_EDGE, GPIOD_LINE_EVENT_FALLING_EDGE, }; struct timespec { long tv_sec; long tv_nsec; }; struct gpiod_line { unsigned int offset; int direction; int active_state; bool used; bool open_source; bool open_drain; int state; bool up_to_date; struct gpiod_chip *chip; int fd; char name[32]; char consumer[32]; }; struct gpiod_chip { struct gpiod_line **lines; unsigned int num_lines; int fd; char name[32]; char label[32]; }; struct gpiod_line_event { struct timespec ts; int event_type; }; const char *gpiod_version_string(void); struct gpiod_chip *gpiod_chip_open_by_number(unsigned int num); struct gpiod_line *gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset); int gpiod_line_request_falling_edge_events(struct gpiod_line *line, const char *consumer); int gpiod_line_event_wait(struct gpiod_line *line, const struct timespec *timeout); int gpiod_line_event_read(struct gpiod_line *line, struct gpiod_line_event *event); void gpiod_line_release(struct gpiod_line *line); void gpiod_chip_close(struct gpiod_chip *chip); """) lib = ffi.dlopen("") print "libgpiod version %s" % ffi.string(lib.gpiod_version_string()) gpiod_chip = lib.gpiod_chip_open_by_number(args.chip) # Make sure GPIO chip opened if gpiod_chip != ffi.NULL: print("Name: %s, label: %s, lines: %d" % (ffi.string(, ffi.string(gpiod_chip.label), gpiod_chip.num_lines)) gpiod_line = lib.gpiod_chip_get_line(gpiod_chip, args.line) # Verify we have line if gpiod_line != ffi.NULL: consumer = sys.argv[0][:-3] if lib.gpiod_line_request_falling_edge_events(gpiod_line, consumer) == 0: timespec ="struct timespec*") timespec.tv_sec = 5 print("Press button within 5 seconds") rc = lib.gpiod_line_event_wait(gpiod_line, timespec) if rc == 0: print("Timed out") elif rc == 1: event ="struct gpiod_line_event*") # Read event off queue lib.gpiod_line_event_read(gpiod_line, event) if event.event_type == lib.GPIOD_LINE_EVENT_RISING_EDGE: print("Rising edge timestamp %s" % time.strftime('%m/%d/%Y %H:%M:%S', time.localtime(event.ts.tv_sec))) else: print("Falling edge timestamp %s" % time.strftime('%m/%d/%Y %H:%M:%S', time.localtime(event.ts.tv_sec))) else: print("Unable request falling edge for line %d" % args.line) lib.gpiod_line_release(gpiod_line) else: print("Unable to get line %d" % args.line) lib.gpiod_chip_close(gpiod_chip) else: print("Unable to open chip %d" % args.chip)
  8. Replying to last item of @chwe post.
  9. sysfs is not a good solution with all the context switching, losing events, etc. I've already switched to libgpiod (see It wouldn't be difficult to add Larry's concept of a common pin mapping since that's just done with pin arrays (at the C level, so the wrappers just need to be generated for Python and Java). I just added I2C support and SPI support is coming. This will be the user space way to do things on Linux, so it will not be just for Armbian. There are other things missing like PWM, but the big three (GPIO, I2C and SPI) will be implemented. Any ways, this is all scripted already, so I'm not sure I'd include it in Armbian. Plus I'm moving at a rapid pace, so it's best to pull from master to get the latest changes/fixes.
  10. And the Java thread example
  11. Just finished up the JNA Java bindings. LedTest for Java now works!
  12. OK, I whipped up a simple Python program using a thread to wait for an edge event while the main program is doing something else. You can pass --chip with GPIO chip number and --line for the line (pin) where your built in button is located. Really no need for IRQs since the events are queued and the thread is waiting on the edge to happen. You can use the thread to do a callback using OOP and an Observer pattern. This is more elegant than having C callback to Python, Java, etc.
  13. If it runs on mainline and you see something listed using ls /dev/gpiochip* then there's a good chance it will work, so you'll have to test it yourself. libgpiod is written in C, but the author said he's working on C++ 11 bindings. Right now I have one C example and a few Python ones in my project For now you'll need to do blocking callbacks (built in) or just stick a wait for edge in a thread. gpiod queues events, so you will not miss any like sysfs. I'll have a Python threaded callback example soon.
  14. I noticed the Neo+ 2 has a blue LED: line 10: unnamed "nanopi:green:pwr" output active-high [used] line 20: unnamed "nanopi:blue:status" output active-high [used] It's not doing the heartbeat flash like the NanoPi Duo. uname -a Linux nanopineoplus2 4.14.15-sunxi64 #95 SMP Wed Jan 24 10:55:45 CET 2018 aarch64 GNU/Linux
  15. OK, finally watched the video and it all makes sense now (I emailed the author to confirm the use of the consumer arg). The Python wrapper I generate is solid now. I needed to add a couple ctypes Structures to an include file and it works on 32 bit and 64 bit platforms. I've given up on sysfs for good! now accepts command line arguments, so it's easy to run on any SBC. I shows you how to safely open the GPIO chip and get the line without suffering a Segmentation Fault! Once I'm done't with the basic demos I'll work on using threads in Python to handle non-blocking callbacks. I kind of like the idea of handling threads in the bindings instead of using C pthreads. Then you have more control.