GPIO Pins and Java


12 posts
by rorosaurus » Thu Nov 01, 2012 10:27 pm
Hello!

I'm working on a project that involves (very fast) manipulation of the GPIO pins using Java.

I had originally planned on using the rpi-gpio-java library recommended on the elinux.org wiki.
But when I returned to the Google code site to look up some documentation, I saw that the library is no longer accessible at http://code.google.com/p/rpi-gpio-java/. Does anyone know what happened to that project?

I have since moved onto using the enum from the Google code project "fr-drd-raspberrypi-gpio". (http://code.google.com/p/fr-drd-raspberrypi-gpio/)
This project claims to be able to achieve around 30kHz max frequency, which would be excellent for my project.

Another library I have heard some talk about is the Pi4J project. I intend to look into that project more this weekend.

Something that I've noticed is that all these libraries choose to approach the different PCB revisions. The first library appears to have no support for it, and it labeled (if I remember correctly) Pin 5 as NOT a GPIO pin, so it wouldn't let me output from it. I'm hoping these other two libraries have better support in this area. For this type of information, I mainly referred to the diagrams from http://www.raspberrypi-spy.co.uk/2012/06/simple-guide-to-the-rpi-gpio-header-and-pins/, is this advisable?

With that setup, I can finally get to my questions.
I'm currently testing some basic flipping of a couple output pins and I"m running into some strange behavior. My main function performs the following (again, using the fr-drd-raspberrypi-gpio library at the moment):
Code: Select all
        GPIO stepPin = GPIO.GPIO_0;
        GPIO directionPin = GPIO.GPIO_1;


        stepPin.open();
        directionPin.open();

        stepPin.setDirection(GPIO.SENS.out);
        directionPin.setDirection(GPIO.SENS.out);

        directionPin.output(true);
        for(int i=0; i<100; i++){
            stepPin.output(true);
            stepPin.output(false);
        }
        directionPin.output(false);
        for(int i=0; i<100; i++){
            stepPin.output(true);
            stepPin.output(false);
        }

        stepPin.close();
        directionPin.close();

When I first execute this code on a freshly-booted RPi, it completes the execution successfully with no exceptions. I only appear to receive one toggle output, however. I have yet to confirm whether this is due to a poor physical wire connection.
Either way, after the first execution, subsequent executions fail, throwing
Code: Select all
java.io.IOException: Device or resource busy


It's my understanding that if the first execution completed successfully, the connections to the files that control the GPIO pins should be closed.
Am I missing some fundamental understanding of how GPIO pins work on the RPi?
Is there a simple way to close those files via terminal instead of restarting my RPi?
Posts: 8
Joined: Mon Sep 10, 2012 2:27 pm
by savageautomate » Fri Nov 02, 2012 3:57 am
Hi rorosaurus,

The Pi4J project used same pin number scheme as the WiringPi project. It's not the same numbering as the hardware GPIO pin numbers on the Pi, but this abstraction helps to isolate the consuming program from board revisions changes. In theory (and thus far this has held true) the GPIO pin numbering on the hardware can change, but the WiringPi (and thus Pi4J) deal with the changes under the hood so your program does not have to be modified for using the same physical pins on the P1 header. Please see this link for more information on the pin numbering scheme:
http://pi4j.com/usage.html#Pin_Numbering

I have not tested the maximum frequency capabilities but thought I could suggest a few tips to help tune your Pi for maximize speed.

- I would install the Debian Wheezy soft-float distribution (so you can install Oracle JVM)

- I would configure the system to use the minimum amount of memory for the video core via the raspi_config tool.

- I would enable turbo mode to safely overclock the system: http://www.raspberrypi.org/archives/2008

- I would install and run with the Oracle JDK instead of the OpenJDK
benchmarks: http://www.savagehomeautomation.com/projects/raspberry-pi-java-virtual-machine-benchmarks.html
installation: http://www.savagehomeautomation.com/projects/raspberry-pi-installing-oracle-java-development-kit-jdk-170u.html

I think these things will give the best results for a Java running (non-GUI) app on the Raspberry Pi.
Last edited by savageautomate on Fri Nov 02, 2012 4:15 am, edited 1 time in total.
Robert Savage | Follow me @savageautomate
http://www.pi4j.com | http://www.pislices.com
http://www.savagehomeautomation.com
User avatar
Posts: 187
Joined: Thu Aug 16, 2012 3:20 pm
Location: USA
by savageautomate » Fri Nov 02, 2012 4:08 am
When you go to test with the Pi4J project, please be aware that there are two ways to access and control GPIO state from this library.

The source code examples and documentation on the website all describe using classes in the "com.pi4j.io.gpio" namespace for accessing and controlling GPIO on the Raspberry Pi.

However, there are also direct static classes to the JNI wrappers to access the WiringPi native library directly. You may be able to obtain better hi-speed performance by skipping the OO friendly abstraction layers and accessing the WiringPi library functions directly.
Here is a source example cycling thru pins states using the WiringPi static JNI function wrappers:
https://github.com/Pi4J/pi4j/blob/master/pi4j-example/src/main/java/com/pi4j/example/wiringpi/WiringPiGpioExample.java

Using the WiringPi wrapper functions will skip several Java class layers and communicate with the native code as fast as possible. This approach will probably achieve the fastest results possible using Java since all the real work happens down in native C code. To better understand the WiringPi function, you may need to visit Gordon's site: https://projects.drogon.net/raspberry-pi/wiringpi/

Thanks, Robert
Robert Savage | Follow me @savageautomate
http://www.pi4j.com | http://www.pislices.com
http://www.savagehomeautomation.com
User avatar
Posts: 187
Joined: Thu Aug 16, 2012 3:20 pm
Location: USA
by rorosaurus » Fri Nov 02, 2012 5:11 am
savageautomate wrote:- I would install the Debian Wheezy soft-float distribution (so you can install Oracle JVM)

- I would configure the system to use the minimum amount of memory for the video core via the raspi_config tool.

- I would enable turbo mode to safely overclock the system: http://www.raspberrypi.org/archives/2008

- I would install and run with the Oracle JDK instead of the OpenJDK
benchmarks: http://www.savagehomeautomation.com/projects/raspberry-pi-java-virtual-machine-benchmarks.html
installation: http://www.savagehomeautomation.com/projects/raspberry-pi-installing-oracle-java-development-kit-jdk-170u.html

I think these things will give the best results for a Java running (non-GUI) app on the Raspberry Pi.


Hello Robert,

Thank you for all of the advice! I'm already running the Devian Wheezy distro, and I have installed Oracle's embedded JVM. According to that benchmark you linked, that appears to be the fastest, too! I will also look into running turbo mode - I certainly imagine our application could benefit from the boost!

I will be sure to look into Pi4J this weekend. Thank you again for all of that information - I imagine most if not all of it will prove useful to me when I look into this more!

Thanks again,
Rory
Posts: 8
Joined: Mon Sep 10, 2012 2:27 pm
by fruitloaf » Fri Nov 02, 2012 6:41 pm
Definitely try Pi4J - its certainly faster than the google code project. I setup a 16x2 character lcd and the google code library simply couldn't get the commands out reliably for it to display anything but Pi4J could. I've not done any benchmarks but the other wrapper I've used is by framboos. Again though this a wiringpi wrapper so there probably isn't any speed difference unless you are using the JNI static methods.
Posts: 84
Joined: Sun Feb 05, 2012 11:41 am
by rorosaurus » Sun Nov 04, 2012 9:39 pm
Hello again,

I'm tinkering around with using Pi4J and I'm running into the following error.

Code: Select all
-- EXPORTING PIN [8] to mode [output]
Warning: File not present: /sys/class/gpio/gpio0/edge


When I cd into /sys/class/gpio/gpio0, I find
active_low direction power subsystem uevent value
But no "edge"!

I'm wondering if this issue is related to me running a slightly old version of Wheezy. I intend to install a new version soon. Any advice would be appreciated!

Thank you,
Rory
Posts: 8
Joined: Mon Sep 10, 2012 2:27 pm
by fivdi » Sun Nov 04, 2012 10:02 pm
I don't actually use Pi4J but if gpio0 is being exported to user space as an output then the edge file will not exist. It only exists for gpios that are exported as inputs.
Posts: 21
Joined: Sun Sep 23, 2012 8:09 pm
by rorosaurus » Mon Nov 05, 2012 12:03 am
fivdi wrote:I don't actually use Pi4J but if gpio0 is being exported to user space as an output then the edge file will not exist. It only exists for gpios that are exported as inputs.


I wonder why Pi4J is trying to access the edge file, then. Perhaps I have set something up wrong. I will attach the code here.
Code: Select all
GpioController gpio = GpioFactory.getInstance();

        GpioPinDigitalOutput stepPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_08,"stepPin", PinState.LOW);
        GpioPinDigitalOutput directionPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_09,"directionPin", PinState.LOW);

        directionPin.setState(true);
        for(int i=0; i<100; i++){
            stepPin.toggle();
        }

        directionPin.setState(false);
        for(int i=0; i<100; i++){
            stepPin.toggle();
        }
Posts: 8
Joined: Mon Sep 10, 2012 2:27 pm
by savageautomate » Mon Nov 05, 2012 3:03 am
That could be a minor defect. I'll test it out over the next couple of days and make the fix.

Thanks, Robert
Robert Savage | Follow me @savageautomate
http://www.pi4j.com | http://www.pislices.com
http://www.savagehomeautomation.com
User avatar
Posts: 187
Joined: Thu Aug 16, 2012 3:20 pm
Location: USA
by savageautomate » Wed Nov 07, 2012 1:14 am
Ok, I thought there may have been a bug in Pi4J when exporting a pin, but after reviewing and testing it here, I don't think this is a Pi4J defect. I think upgrading your system to one of the later distributions may help.

When I use the gpio utility and export an output pin manually, an edge file does get created for the pin.
Here are the steps I tried.

First, I unexported all pins:
Code: Select all
gpio unexport all

Next, I exported GPIO pin #0 as an output pin:
Code: Select all
gpio export 0 out

Next, I listed the directory contents of " /sys/class/gpio/gpio0"
Code: Select all
 ls /sys/class/gpio/gpio0

An "edge" file was included in the results:
Code: Select all
 active_low  direction  edge  power  subsystem  uevent  value

Finally, I used this command to display the contents of the edge file:
Code: Select all
sudo cat /sys/class/gpio/gpio0/edge

The edge file contained "none" indicating that no edge detection is enabled for this pin.

When Pi4J is instructed to export a pin, it does attempt to change the ownership rights of the "edge" file so that the current user can access and update the "edge" file. It does this even though its an output pin. It does this to allow you to switch an output to an input pin without having to re-export the pin, you can just change modes using setMode() if ever needed.

Thanks, Robert
Robert Savage | Follow me @savageautomate
http://www.pi4j.com | http://www.pislices.com
http://www.savagehomeautomation.com
User avatar
Posts: 187
Joined: Thu Aug 16, 2012 3:20 pm
Location: USA
by savageautomate » Wed Nov 07, 2012 2:55 am
rorosaurus wrote:Hello!

I'm working on a project that involves (very fast) manipulation of the GPIO pins using Java.
...
This project claims to be able to achieve around 30kHz max frequency, which would be excellent for my project.
...
Another library I have heard some talk about is the Pi4J project. I intend to look into that project more this weekend.

I ran some continuous loop tests using Pi4J and used my DMM to measure the frequency. Running on Raspian Wheezy (hard-float) using the OpenJDK 7 I was getting a reading of ~6.15 kHz. Then the same test on Debian Wheezy (soft-float) using Oracle JDK 7, I am getting a reading of ~143 kHz. That was certainly more of a jump than I expected :? I wish I has an oscilloscope here to verify the readings and see the waveform.

Here is my test program:
Code: Select all
    public static void main(String[] args)
    {
        System.out.println("<--Pi4J--> GPIO Example ... started.");
       
        // create gpio controller
        GpioController gpio = GpioFactory.getInstance();
       
        // provision gpio pin #01 as an output pin and turn on
        GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED-1", PinState.LOW);

        // continuous loop
        while(true)
        {
            pin.setState(true);
            pin.setState(false);
        }
    }
Robert Savage | Follow me @savageautomate
http://www.pi4j.com | http://www.pislices.com
http://www.savagehomeautomation.com
User avatar
Posts: 187
Joined: Thu Aug 16, 2012 3:20 pm
Location: USA
by rorosaurus » Wed Nov 07, 2012 5:31 am
Wow, thank you for the detailed reply! I am constantly blown away by this community!

I actually downloaded the newest version of Debian Wheezy (soft-float) the night I posted. I will have the embedded SE installed soon, I expect! I will be sure to report back here as soon as I do! (Sorry, this is a very busy week for me!)

Thank you again for your assistance! Cheers!
Posts: 8
Joined: Mon Sep 10, 2012 2:27 pm