Pi4J / pi4j-v2

Pi4J Version 2.0

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Multipurpose (Input & Output) GPIO

treitmaier opened this issue · comments

The Context
I'm in the process of porting the libraries of Skywriter & Flick I2C gesture sensing boards from python to Java/pi4j. Both boards utilise the MGC3130 chipset.

The Problem
The MGC3130 chipset requires the transfer pin (BCM 27) to be used as both input and output within each polling cycle. At the start of the cycle the library waits for a low transfer line (input). However, the library then reconfigures the same pin (BCM27) as a low output to assert that the MGC3130 does not update data buffers before reading from them.

The Issue
Does pi4j-v2 support Multipurpose GPIO that can be reconfigured to work as input and output?

Thanks for your question! And nice to see you are working on these libraries using Pi4J!

As you can see in https://github.com/Pi4J/pi4j-v2/tree/master/pi4j-core/src/main/java/com/pi4j/io/gpio/digital currently we only have input or output types. Would it be an idea to reconfigure the I/O in your library itself between each action? I've not done this myself before so no idea what the behavior would be and if this happens fast enough.

FYI, under the hood, Pi4J V2 is using http://abyz.me.uk/rpi/pigpio/ so anything supported by that library should also be available in Pi4J or could be added.

I remember something like this in Pi4J V1.
See: https://github.com/Pi4J/pi4j/search?q=GpioPinDigitalMultipurpose&unscoped_q=GpioPinDigitalMultipurpose

We probably should consider this for V2 as well.

Thanks for your comments @savageautomate & @FDelporte . It looks like pigpio would support Multipurpose GPIOs through its gpioGetMode and gpioSetMode methods.

An unscoped code search for GpioPinDigitalMultipurpose reveal broad use-cases that would motivate such a feature in pi4j-v2. In particular matrix keypad drivers -- at least the more sophisticated ones -- need to switch between input and output modes while scanning for keypresses.

The driver I ported to pi4j-v2 seems to be working OK just leaving the transfer line in input mode and ignoring the spec to switch it to output mode while reading from the chipset buffer. So there is no direct need from my end. However, I'd be happy to test any implementation on the driver I ported as well as on a matrix keypad that I have from on old project.

I have added API support for Multipurpose pins in this branch:
https://github.com/Pi4J/pi4j-v2/tree/issue/%2326

TODO: Still needs to be implemented in PIGPIO provider plugin.

Added PIGPIO plugin implementation for Multipurpose GPIO pins.

TODO: Still needs to be tested on hardware.

Thanks for all the hard work implementing the feature so quickly @savageautomate. I started to test it, but then ran into unhandled signal 11 errors, especially on aarch64 systems. Yesterday I saw that you had addressed a similar issue in the master branch. This morning I ran tests on the driver I'm implementing using the following pi4j-v2 libraries:

git checkout issue/#26
git rebase master
mvn clean install -Pnative,cross-compile

No more unhandled signal 11 errors and anecdotally my driver seems to function more robustly. In my particular use case switching the MultipurposePin from Input to Output (low) asserts that buffers aren't updated before the I2C read operation completes.

Looking at the implementation of the python driver, they switch the GPIO back to input (PULL_UP) after the I2C read operation completes.

I noticed that on your API I can switch to the DigitalMultipurpose back to input multipurpose.input(), but there isn't a way to specify pull up/down resistance at this point. I guess I can set the resistance initially like so:

var multipurpose = DigitalMultipurpose.newConfigBuilder(pi4j)
        .id("transfer")
        .name("transfer")
        .address(5)
        .mode(DigitalMode.INPUT)
        .pull(PullResistance.PULL_UP)
        .provider(PiGpioPlugin.DIGITAL_MULTIPURPOSE_PROVIDER_ID);

but am wondering if this configuration persists even after switching the multipurpose pin between input and output.

@treitmaier ,

Just a note on mvn clean install -Pnative,cross-compile .. this won't currently build proper binaries for 32-bit armhf for ARMv6 devices. (See Issue #28)

The following will if you run from an amd64/x86_64 based machine with Docker installed:

`mvn clean install -Pnative,docker`

This may not matter to you since you are working on aarch64, but just wanted you to be aware.


I noticed that on your API I can switch to the DigitalMultipurpose back to input multipurpose.input(), but there isn't a way to specify pull up/down resistance at this point. I guess I can set the resistance initially like so:

That's a good question. Pi4J V2 will only explicitly configure the digital input pin with its PULL config at the time of initialization. Switching to OUTPUT mode then back to INPUT does not re-apply the PULL config (or DEBOUNCE config) ... at least not in Pi4J code.

try {
// if configured, set GPIO pin pull resistance
switch(config.pull()){
case PULL_DOWN:{
this.piGpio.gpioSetPullUpDown(pin, PiGpioPud.DOWN);
break;
}
case PULL_UP:{
this.piGpio.gpioSetPullUpDown(pin, PiGpioPud.UP);
break;
}
}
// if configured, set GPIO debounce
if(this.config.debounce() != null) {
int steadyInterval = 0;
if(this.config.debounce() > 300000){
steadyInterval = 300000;
} else{
steadyInterval = this.config.debounce().intValue();
}
this.piGpio.gpioNoiseFilter(pin, 0, 0);
this.piGpio.gpioGlitchFilter(pin, steadyInterval);

So I don't technically know if the mode change by the underlying PiGPIO library will modify PULL resistance or the DEBOUNCE settings. Do you think we should just go ahead and manually re-apply these settings anytime the multipurpose pin is returned to the INPUT mode?