Following up on the last post “How to get started with Embedded Android on the Wandboard”, this article shows how to use the GPIO Pins of the Wandboard. It is based on the Android setup, however the generic part should run under other Linux based systems as well.
Finding the right GPIO Pin Number
In the userspace you are able to access GPIO functionality through the sysclass interface.
root@android:/ # ll /sys/class/gpio/ --w------- root root 4096 2013-06-20 10:57 export lrwxrwxrwx root root 2013-06-20 10:57 gpio101 -> ../../devices/virtual/gpio/gpio101 lrwxrwxrwx root root 2013-06-20 10:57 gpio200 -> ../../devices/virtual/gpio/gpio200 lrwxrwxrwx root root 2013-06-20 10:57 gpio24 -> ../../devices/virtual/gpio/gpio24 lrwxrwxrwx root root 2013-06-20 10:57 gpio72 -> ../../devices/virtual/gpio/gpio72 lrwxrwxrwx root root 2013-06-20 10:57 gpio75 -> ../../devices/virtual/gpio/gpio75 lrwxrwxrwx root root 2013-06-20 10:57 gpio90 -> ../../devices/virtual/gpio/gpio90 lrwxrwxrwx root root 2013-06-20 10:57 gpio91 -> ../../devices/virtual/gpio/gpio91 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip128 -> ../../devices/virtual/gpio/gpiochip128 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip160 -> ../../devices/virtual/gpio/gpiochip160 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip192 -> ../../devices/virtual/gpio/gpiochip192 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64 lrwxrwxrwx root root 2013-06-20 10:57 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96 --w------- root root 4096 2013-06-20 10:57 unexport
Take for instance “gpio101”. The number is set together by a Macro in the Kernel:
//file arch/arm/plat-mxc/include/mach/gpio.h #define IMX_GPIO_NR(bank, nr) (((bank) - 1) * 32 + (nr))
By having a look at the Schematic of the Wandbaord, the GPIO’s available are found on JP4
In the Kernel the File board-wand.c gives further clues to which of the gpios are available in user space:
static __init void wand_init_external_gpios(void) { wand_mux_pads_init_external_gpios(); gpio_request(IMX_GPIO_NR(3, 11), "external_gpio_0"); gpio_export(IMX_GPIO_NR(3, 11), true); gpio_request(IMX_GPIO_NR(3, 27), "external_gpio_1"); gpio_export(IMX_GPIO_NR(3, 27), true); gpio_request(IMX_GPIO_NR(6, 31), "external_gpio_2"); gpio_export(IMX_GPIO_NR(6, 31), true); gpio_request(IMX_GPIO_NR(1, 24), "external_gpio_3"); gpio_export(IMX_GPIO_NR(1, 24), true); gpio_request(IMX_GPIO_NR(7, 8), "external_gpio_4"); gpio_export(IMX_GPIO_NR(7, 8), true); gpio_request(IMX_GPIO_NR(3, 26), "external_gpio_5"); gpio_export(IMX_GPIO_NR(3, 26), true); gpio_request(IMX_GPIO_NR(3, 8), "external_gpio_6"); gpio_export(IMX_GPIO_NR(3, 8), true); gpio_request(IMX_GPIO_NR(4, 5), "external_gpio_7"); gpio_export(IMX_GPIO_NR(4, 5), true); }
It seems like the schematic might not be entirely up to date as it would make a lot of sense if those 8 gpios exported would actually match all of those 8 pins on the right side of JP4.
After some testing it looks like this is the case and the correct mapping looks something like this:
# JP4.04 => /sys/class/gpio/gpio75 (3,11) # JP4.06 => /sys/class/gpio/gpio91 (3,27) # JP4.08 => /sys/class/gpio/gpio191 (6,31) # JP4.10 => /sys/class/gpio/gpio24 (1,24) # JP4.12 => /sys/class/gpio/gpio200 (7, 8) # JP4.14 => /sys/class/gpio/gpio90 (3,26) # JP4.16 => /sys/class/gpio/gpio72 (3, 8) # JP4.18 => /sys/class/gpio/gpio101 (4, 5)
(again for refernece the pins)
Configuring a GPIO as Back Key
There are cases where using a GPIO as an input key can be quite practical on an Embedded System. For this to work there need to be a few adjustments in the Kernel.
Have a look at the file “arch/arm/mach-mx6/board-wand.c”.
In there a few modifications need to made. They are based on the SABRE board from Freescale.
//this code goes right after #include "board-wand.h" #include <linux/input.h> #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) #define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake) \ { \ .gpio = gpio_num, \ .type = EV_KEY, \ .code = ev_code, \ .active_low = act_low, \ .desc = "btn " descr, \ .wakeup = wake, \ } static struct gpio_keys_button ard_buttons[] = { GPIO_BUTTON(IMX_GPIO_NR(6, 31), KEY_BACK, 1, "back", 0) }; static struct gpio_keys_platform_data ard_android_button_data = { .buttons = ard_buttons, .nbuttons = ARRAY_SIZE(ard_buttons), }; static struct platform_device ard_android_button_device = { .name = "gpio-keys", .id = -1, .num_resources = 0, .dev = { .platform_data = &ard_android_button_data, } }; static void __init wand_add_android_device_buttons(void) { platform_device_register(&ard_android_button_device); } #else static void __init wand_add_android_device_buttons(void) {} #endif
The upper code sets up a function to map IMX_GPIO_NR(6, 31) as BACK key. Again this implementation is almost directly copy-pasted from the SABRE Board. This relates to JP4.08 on the physical board.
Now the init function needs to be called during the board setup.
// this goes into the wand_board_init() function wand_init_external_gpios(); wand_add_android_device_buttons();//<= new wand_init_spi();
To be able to use the GPIO(6, 31) as key, we need to remove it from the exported gpios.
static __init void wand_init_external_gpios(void) { wand_mux_pads_init_external_gpios(); gpio_request(IMX_GPIO_NR(3, 11), "external_gpio_0"); gpio_export(IMX_GPIO_NR(3, 11), true); gpio_request(IMX_GPIO_NR(3, 27), "external_gpio_1"); gpio_export(IMX_GPIO_NR(3, 27), true); //gpio_request(IMX_GPIO_NR(6, 31), "external_gpio_2"); //gpio_export(IMX_GPIO_NR(6, 31), true); gpio_request(IMX_GPIO_NR(1, 24), "external_gpio_3"); gpio_export(IMX_GPIO_NR(1, 24), true); gpio_request(IMX_GPIO_NR(7, 8), "external_gpio_4"); gpio_export(IMX_GPIO_NR(7, 8), true); gpio_request(IMX_GPIO_NR(3, 26), "external_gpio_5"); gpio_export(IMX_GPIO_NR(3, 26), true); gpio_request(IMX_GPIO_NR(3, 8), "external_gpio_6"); gpio_export(IMX_GPIO_NR(3, 8), true); gpio_request(IMX_GPIO_NR(4, 5), "external_gpio_7"); gpio_export(IMX_GPIO_NR(4, 5), true); }
Following the first compile in the article “How to get started with Embedded Android on the Wandboard”, the Kernel can be rebuilt and copied to the SD-Card.
cd /opt/android/ export ARCH=arm export CROSS_COMPILE=/opt/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- make -j4 uImage # this will take a while sudo cp arch/arm/boot/uImage /media/user/BOOT/ sync && umount /media/user/*
Plug your SD-Card back into your Wandboard and hook up two wires: one to JP4.20 (GND) and one to JP4.08 (our gpio). If you touch the two wires, a “BACK” action on Android will be executed.
Using GPIOs from Userspace to catch Interrupts
In the big picture we would like to create an Android Application built on a GPIO driven Interrupt. In order to do so, we next create a C Application for the Android target using the Android NDK. With the NDK build script we create a “gpio” binary that “polls” a GPIO Pin and on a falling edge writes out the current value 1 or 0 to the Android Log.
First of all, the Android NDK is required. It can be optained from the Android Developer Website. Download and export it to your home directory to “ndk”.
cd ~ mv Downloads/ndk-..../ ndk
Now let’s create a directory for the C-Application.
cd ~ mkdir gpio cd gpio mkdir jni cd jni
By creating a jni directory we are tricking the NDK build script into thinking we have an actual Android Application (which we don’t need just yet).
In the jni/ directory we create a small setup for our application. Most important is our source file “gpio.c”. It will contain a small routine to listen to a gpio interrupt.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <poll.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include "gpio.h" #define LOG_TAG "GPIO" #ifndef EXEC #include <android/log.h> #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #else #define LOGD(...) printf(">==< %s >==< ",LOG_TAG),printf(__VA_ARGS__),printf("\n") #endif void on_new_value(int val); int read_gpio(char *path, void (*callback)(int)); int main(int argc, char **argv){ LOGD("Hello!\n"); #ifdef HOST return 0; #endif if(argc == 2) return read_gpio(argv[1], on_new_value); else LOGD("missing argument path"); return -1; } int read_gpio(char *path, void (*callback)(int)){ int fd = open(path, O_RDONLY); char buf[11]; int res = 0; if(fd == -1){ perror("error opening file"); return -1; } struct pollfd gpio_poll_fd = { .fd = fd, .events = POLLPRI, .revents = 0 }; for(;;){ res = poll(&gpio_poll_fd,1,-1); if(res == -1){ perror("error polling"); break; } if((gpio_poll_fd.revents & POLLPRI) == POLLPRI){ LOGD("POLLPRI"); int off = lseek(fd, 0, SEEK_SET); if(off == -1) break; memset(&buf[0], 0, 11); size_t num = read(fd, &buf[0], 10*sizeof(char)); callback(atoi(buf)); } if((gpio_poll_fd.revents & POLLERR) == POLLERR){ //seems always to be true .. //LOGD("POLLERR"); } } return 0; } void on_new_value(int val){ LOGD("interrupt received, val: %d", val); }
In this code the function read_gpio is responsible to observe a gpio handle (for instance /sys/class/gpio/gpio91/value). The function poll will observe the file and every time an interrupt is triggered, the function returns with the resulting event in gpio_poll_fd.revents.
On what edge the interrupt should be triggered is defined by the value in “edge” (for instance /sys/class/gpio/gpio91/edge). It can be raising, falling or both. After the edge is triggered the value can be read using lseek on the opened file descriptor.
Let’s have a look at:
poll(&gpio_poll_fd,1,-1);
We theoretically could hand poll over a larger number of file descriptors to observe, however, for this sample one is enough. The third argument defines how long we block the process/thread until we get a timeout. We desire to be woken up as rarely as possible, this is why we chose to wait for an interrupt in the first place. By passing a value smaller than 0 we tell the underlying driver that we expect to wait an undefined time and therefore have no timeout at all.
The read_gpio function takes a function pointer that is called as soon as we read the new value. This way we have a modular way to later pass a function from a JNI module and can therefore separate the module nicely from the JNI functionality. For this main function “new_value” is the function that handles those callbacks, it only prints the current value of the gpio out.
The header file exports the “read_gpio” function to our future modules.
#ifndef _GPIO_H_ #define _GPIO_H_ int read_gpio(char *path, void (*callback)(int)); #endif
The last piece we require is an Android.mk file that defines how to build our project. This is one neat little trick to build a binary for Android instead of a library.
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gpio_test LOCAL_SRC_FILES := gpio.c LOCAL_LDLIBS += -llog LOCAL_CFLAGS += -DEXEC include $(BUILD_EXECUTABLE)
Note that BUILD_EXECUTABLE will actually build us an executable file called test_gpio that we can run on the wandboard.
Now the project can be built using the ndk-build script from the Android NDK.
With “-DEXEC” we define a flag which indicates that we are building an executable. By checking it in the code we can use different approaches for the library or for the executable.
cd ~/gpio/jni ~/ndk/ndk-build Compile thumb : gpio_test <= gpio.c Executable : gpio_test Install : gpio_test => libs/armeabi/gpio_test
Copy the gpio_test binary onto the device and change permissions and stats. We are using JP4.06 (gpio_91) for this example. Make sure you are connected via ADB to use adb push to transfer the file to the wandboard (see next section for further infos).
cd ~/gpio # make sure the rfs of the device is rw adb connect 192.168.1.100 # adjust the IP to your board # on the serial console use adb push libs/armeabi/gpio_test /system/bin/ adb shell chmod 755 /system/bin/gpio_test chown root.2000 /system/bin/gpio_test # make sure the gpio is an input # make sure the gpio is configured as interrupt echo in > /sys/class/gpio/gpio91/direction echo 1 > /sys/class/gpio/gpio91/active_low echo falling > /sys/class/gpio/gpio91/edge gpio_test /sys/class/gpio/gpio91/value
Each time a falling edge occurs on the gpio pin, a message should be printed out when you connect JP4.06 to GND and disconnect it again.
You can automate the setup process of the gpio by adding this to your init.wandboard.rc in the on boot part:
write /sys/class/gpio/gpio91/direction in write /sys/class/gpio/gpio91/edge falling write /sys/class/gpio/gpio91/active_low 1
Integrating the code into an Android Java Application
The desired Java Application will dedicate a Thread to listening to the interrupt of the GPIO. An Android Activity will change the background color of the screen, as soon as an edge is detected to a random color, and display the gpio value.
First an Android Application project is created with the Android ADT Bundle. For this example we apply the Namespace “ch.nexuscomputing.android.simplegpio” and the Application name “SimpleGpio”. It should be located in “~/workspace/SimpleGpio” to match the exercise.
Add a new Class called NativeGpio to the Project (adjust the namespace according to your needs).
package ch.nexuscomputing.android.simplegpio; public class NativeGpio { public static interface GpioInterruptCallback{ void onNewValue(int value); } public static native void readGpio(String path, GpioInterruptCallback callback); static{ System.loadLibrary("gpio"); } }
An interface for a callback function is defined. If the “readGpio” native function is called, it must be passed an actual implementation of the interface and its function “onNewValue”. The callback method will hence be called from native space and the code defined in the “onNewValue” Java method will be executed as soon as the C-side is calling it.
Note that a call to System.loadLibrary(“gpio”) is mandatory to let the native method to be called from Java space. Therefore a new native library must be created that contains the defined method.
In order to create the appropriate JNI C function the tool “javah” is used to generate a method header.
Assuming the Java Project is located in “~/workspace/SimpleGpio” do the following:
cd ~/workspace/SimpleGpio javah -classpath bin/classes ch.nexuscomputing.android.simplegpio.NativeGpio ls AndroidManifest.xml assets bin ch_nexuscomputing_android_simplegpio_NativeGpio_GpioInterruptCallback.h ch_nexuscomputing_android_simplegpio_NativeGpio.h gen ic_launcher-web.png obj proguard-project.txt project.properties res src
The file ch_nexuscomputing_android_simplegpio_NativeGpio_GpioInterruptCallback.h can be disregarded, it contains no relevant information.
The contents of the file ch_nexuscomputing_android_simplegpio_NativeGpio.h are on the other hand very relevant to the project.
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class ch_nexuscomputing_android_simplegpio_NativeGpio */ #ifndef _Included_ch_nexuscomputing_android_simplegpio_NativeGpio #define _Included_ch_nexuscomputing_android_simplegpio_NativeGpio #ifdef __cplusplus extern "C" { #endif /* * Class: ch_nexuscomputing_android_simplegpio_NativeGpio * Method: readGpio * Signature: (Ljava/lang/String;Lch/nexuscomputing/android/simplegpio/NativeGpio/GpioInterruptCallback;)V */ JNIEXPORT void JNICALL Java_ch_nexuscomputing_android_simplegpio_NativeGpio_readGpio (JNIEnv *, jclass, jstring, jobject); #ifdef __cplusplus } #endif #endif
Now copy the jni directory created before into the project. Move the created header into the jni as jni_gpio.c. Start editing it.
cd ~/workspace/SimpleGpio cp -a ~/gpio/jni . rm ch_nexuscomputing_android_simplegpio_NativeGpio_GpioInterruptCallback mv ch_nexuscomputing_android_simplegpio_NativeGpio.h jni/jni_gpio.c vim jni/jni_gpio.c
Follow the implementation of the jni part.
#include <jni.h> #include <stdlib.h> /* Header for class nativehelper_NativeGpio */ #include "gpio.h" #define LOG_TAG "GPIO" #ifndef HOST #include <android/log.h> #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #else #define LOGD(...) printf(">==< %s >==< ",LOG_TAG),printf(__VA_ARGS__),printf("\n") #endif #ifndef _Included_nativehelper_NativeGpio #define _Included_nativehelper_NativeGpio #ifdef __cplusplus extern "C" { #endif static void on_new_value(int val); static jmethodID cb_method_id; static jclass cb_class; static jobject cb_object; static JNIEnv *cb_save_env; /* * Class: nativehelper_NativeGpio * Method: readGpio * Signature: (Ljava/lang/String;Lnativehelper/NativeGpio/GpioInterruptCallback;)V */ JNIEXPORT void JNICALL Java_ch_nexuscomputing_android_simplegpio_NativeGpio_readGpio (JNIEnv *env, jclass cls, jstring path, jobject callback){ cb_class = (*env)->GetObjectClass(env, callback); if(cb_class == NULL){ LOGD("callback interface not found"); return; } cb_method_id = (*env)->GetMethodID(env, cb_class, "onNewValue", "(I)V"); if(cb_method_id == NULL){ LOGD("could not find callback method"); return; } cb_object = callback; cb_save_env = env; const char *fname = (*env)->GetStringUTFChars(env, path, NULL); LOGD("path is %s", fname); read_gpio((char *)fname, on_new_value); (*env)->ReleaseStringUTFChars(env, path, fname); } static void on_new_value(int val){ LOGD("interrupt received, val: %d", val); (*cb_save_env)->CallVoidMethod(cb_save_env, cb_object, cb_method_id, (jint)val); } #ifdef __cplusplus } #endif
In this code we start polling the gpio for interrupts. We pass as a callback the function on_new_value and in there we call the Java function out of the native C space. In order to do so, the environment needs to be cached, as well as the callback object and the method of the class thereof.
In order to create a library, the Android.mk needs to be adjusted. If -DEXEC is not defined, then the android log function is used, which makes much more sense if a library is created.
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gpio_test LOCAL_SRC_FILES := gpio.c LOCAL_LDLIBS += -llog LOCAL_CFLAGS += -DEXEC include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := libgpio LOCAL_SRC_FILES := gpio.c jni_gpio.c LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)
The module can be built using NDK-Build. Now additionally to the gpio_test binary, the library libgpio will be created.
cd ~/workspace/SimpleGpio/jni ~/ndk/ndk-build Compile thumb : gpio <= gpio.c Compile thumb : gpio <= jni_gpio.c SharedLibrary : libgpio.so Install : libgpio.so => libs/armeabi/libgpio.so Compile thumb : gpio_test <= gpio.c Executable : gpio_test Install : gpio_test => libs/armeabi/gpio_test
The native part is now created and now can be used from the Java side.
Modify from eclipse the activity_main.xml Layout (cosmetics).
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="40sp" android:textAlignment="center" android:gravity="center" android:id="@+id/gpio" android:text="@string/gpio" /> </RelativeLayout>
And now we create the final part of the Application. The Android Activity which calls from a separate Thread the blocking “readGpio”, while passing a callback object.
package ch.nexuscomputing.android.simplegpio; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import ch.nexuscomputing.android.simplegpio.NativeGpio.GpioInterruptCallback; import android.os.Bundle; import android.app.Activity; import android.graphics.Color; import android.view.Menu; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity { private static View sBackground; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sBackground = findViewById(android.R.id.content); if(sGpioThread == null){ sGpioThread = new Thread(mGpioRunnable, "GPIO-Thread"); sGpioThread.start(); } } @Override protected void onDestroy() { sBackground = null; super.onDestroy(); } private void updateView(){ runOnUiThread(mColorRunnable); } private final Runnable mColorRunnable = new Runnable() { private Random mRand = new Random(); @Override public void run() { int r = mRand.nextInt(256); int g = mRand.nextInt(256); int b = mRand.nextInt(256); if(sBackground != null){ sBackground.setBackgroundColor(Color.rgb(r, g, b)); sBackground.postInvalidate(); ((TextView)sBackground.findViewById(R.id.gpio)).setText( String.format("# interrupts %d\nvalue is %d", sInterruptCount, sCurrentValue.get())); } } }; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private static final AtomicInteger sCurrentValue = new AtomicInteger(0); private static int sInterruptCount = 0; private static Thread sGpioThread; private final Runnable mGpioRunnable = new Runnable() { @Override public void run() { while(true){ NativeGpio.readGpio("/sys/class/gpio/gpio91/value", new GpioInterruptCallback(){ @Override public void onNewValue(int value) { sInterruptCount++; sCurrentValue.set(value); updateView(); } }); } } }; }
The application is quite simple. A Thread is started polling “readGpio”. Whenever a new Value is received, the TextView and the Background are updated. By checking if sGpioThread == null, we assure that if the Thread is running already, it’s not started a second time (by closing and reopening the application).
Note that shutting down the application is not handled in this example, however is good practice in an actual implementation.
Liked this post? Add a comment below to let us know!
Looking for professional Android Training or Android Engineering? See Nexus-Computing for more.
Very good tutorial.
Thank you very much
Hello Manuel
I am very interested in the communication between a Wandboard and Arduino cards.
Is your book “Android mit Arduinoâ„¢ Due” is available in US language ? It seems very very attractive.
Regards
Manuel, Very good information.
Have you use a lcd touchscreen with the wandaboard?
it will be interesting to see a wandaboard + LCD + OsciPrime…. the ultimate pack.
Thx
Manuel,
The info is very helpful. I ahve a question. Where do you get the information that J4:16 is translated to IMX_GPIO_NR(3, 8) and gpio72 in Linux? From the wandboard schematic, the pin is called GPIO18 schematic. I want to add additional GPIOs that is not defined, how do I find from the schematic the needed pin number?
Thanks
Hello Norm,
Thank you very much. Hope the post got you off a good start 🙂
From the exported gpio’s in the Kernel it seemed to make sense, that all the 8 gpios exported (in that order) match the headers of the board. However, the schematic seems to be of an older version and some of the pins numbers seemed to be wrong in the schematic.
As for translating the pin numbers:
meaning: (3,8) = > (3-1)*32 + 8 = 72 => gpio_72
Be sure to double check that your custom pin is nowhere used in the Kernel.
Hope that answers your question 🙂
All the best
Manuel
Hello,
Could you set this GPIO code in an Android eclipse project online?
When I copy this code in a project, it can compile without errors,
but when running the code in Android, there are problems with loading the package.
Best regards,
Thanks so much for your code. It was help me a lot. But, additionaly I need a method to write in GPIO’s. Can you help me with it?
Hi Manuel,
Thanks for a solid tutorial.
I’m using your solution on another board (still with the IMX6SL). When I apply a voltage the GPIO pin’s value goes from 0 to 1 but when I remove the voltage it does not return to 0. Is this something you experienced?
I put a pulldown and solved that issue but the app only records the first interrupt