1. 程式人生 > >android jni控制gpio (rk3288)

android jni控制gpio (rk3288)

inode short output c語言實現 drive name mic 鏈接庫 start

1.添加驅動程序

2.編寫jni c程序編譯為庫給java調用

3.app調用jni靜態鏈接庫操作底層驅動

 1.添加驅動程序

 修改/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/drivers/Makefile
添加一行obj-y += carroll/

將carroll文件夾添加至此目錄下/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/drivers/
文件夾包含驅動源碼及Makefile
# carroll
obj-y = test_led.o

 test_led.源碼

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h> 
#include <linux/delay.h>
#include <linux/gpio.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#endif

#include <linux/fb.h>
#include 
<linux/device.h> #include <linux/miscdevice.h> #define INVALID_GPIO -1 int led1_gpio = INVALID_GPIO; int led2_gpio = INVALID_GPIO; int led_gpio_active = 0; static int led_open(struct inode *inode, struct file *file) { printk("carroll led_open ok \n"); return 0; } static int led_release(struct
inode *inode, struct file *file) { printk("carroll led_close \n"); return 0; } /* app : ioctl(fd, cmd, arg) */ static long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /* 根據傳入的參數設置GPIO */ /* cmd : 0-off, 1-on */ /* arg : 0-1, which led */ if ((cmd != 0) && (cmd != 1)) return -EINVAL; if (arg > 4) return -EINVAL; if(arg == 0) { if(led1_gpio != INVALID_GPIO) gpio_set_value(led1_gpio, !cmd); } else if(arg == 1) { if(led2_gpio != INVALID_GPIO) gpio_set_value(led2_gpio, !cmd); } printk("carroll led_ioctl: %d \n", cmd); return 0; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .unlocked_ioctl = led_ioctl, }; static struct miscdevice led_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "test_led", .fops = &led_fops, }; static int firefly_led_probe(struct platform_device *pdev) { int ret = -1; enum of_gpio_flags flags; struct device_node *hello_node = pdev->dev.of_node; printk("%s-%d: carroll \n",__FUNCTION__,__LINE__); /* register test_led dev file */ ret = misc_register(&led_dev); if (ret < 0){ printk("carroll led register err!\n"); return ret; } /* led1 init */ led1_gpio = of_get_named_gpio_flags(hello_node,"led1", 0,&flags); if (!gpio_is_valid(led1_gpio)){ printk("carroll: invalid gpio : %d\n",led1_gpio); return -1; } ret = gpio_request(led1_gpio, "test_led"); if (ret != 0) { gpio_free(led1_gpio); printk("carroll: led1_gpio free\n"); return -EIO; } gpio_direction_output(led1_gpio, !led_gpio_active); /* led2 init */ led2_gpio = of_get_named_gpio_flags(hello_node,"led2", 0,&flags); if (!gpio_is_valid(led2_gpio)){ printk("carroll: invalid gpio : %d\n",led2_gpio); return -1; } ret = gpio_request(led2_gpio, "test_led"); if (ret != 0) { gpio_free(led2_gpio); printk("carroll: led2_gpio free\n"); return -EIO; } gpio_direction_output(led2_gpio, !led_gpio_active); gpio_set_value(led1_gpio, led_gpio_active); gpio_set_value(led2_gpio, led_gpio_active); mdelay(500); gpio_set_value(led1_gpio, !led_gpio_active); gpio_set_value(led2_gpio, !led_gpio_active); return 0; //return Ok } static int firefly_led_remove(struct platform_device *pdev) { return 0; } #ifdef CONFIG_OF static const struct of_device_id of_firefly_led_match[] = { { .compatible = "firefly,test_led" }, { /* Sentinel */ } }; #endif static struct platform_driver firefly_led_driver = { .probe = firefly_led_probe, .remove = firefly_led_remove, .driver = { .name = "test_led", .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = of_firefly_led_match, #endif }, }; static int major; static struct class *cls; static int __init led_init(void) { printk(KERN_INFO "carroll register led dev %s\n", __FUNCTION__); return platform_driver_register(&firefly_led_driver); } static void __exit led_exit(void) { platform_driver_unregister(&firefly_led_driver); printk(KERN_INFO "carroll unregister led dev %s\n", __FUNCTION__); } subsys_initcall(led_init); module_exit(led_exit); MODULE_AUTHOR("carroll <[email protected]>"); MODULE_DESCRIPTION("carroll led driver"); MODULE_LICENSE("GPL");

  


修改/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/arch/arm/boot/dts/firefly-rk3288.dts
firefly-led{
compatible = "firefly,led";
led-work = <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
led-power = <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
//carrol add start
status = "disabled";
};

test-led{
compatible = "firefly,test_led";
led1= <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
led2= <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
status = "okay";
};
//carrol add end
編譯內核燒錄即可

 內核啟動過程中閃爍一次,並產生/dev/test_led文件
添加可執行權限
su
chmod 777 /dev/test_led

2.編寫jni c程序編譯為庫給java調用

  hardcontrol.c源碼

#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <android/log.h>  /* liblog */

//__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ...");

 
#if 0
typedef struct {
    char *name;          /* Java裏調用的函數名 */
    char *signature;    /* JNI字段描述符, 用來表示Java裏調用的函數的參數和返回值類型 */
    void *fnPtr;          /* C語言實現的本地函數 */
} JNINativeMethod;
#endif

static jint fd;

jint ledOpen(JNIEnv *env, jobject cls)
{
    fd = open("/dev/test_led", O_RDWR);
    __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledOpen /dev/test_led: %d", fd);
    if (fd >= 0)
        return 0;
    else
        return -1;
}

void ledClose(JNIEnv *env, jobject cls)
{
    __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledClose ...");
    close(fd);
}


jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
    int ret = ioctl(fd, status, which);
    __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d, %d", which, status, ret);
    return ret;
}


static const JNINativeMethod methods[] = {
    {"ledOpen", "()I", (void *)ledOpen},
    {"ledClose", "()V", (void *)ledClose},
    {"ledCtrl", "(II)I", (void *)ledCtrl},
};




/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
    JNIEnv *env;
    jclass cls;

    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
        return JNI_ERR; /* JNI version not supported */
    }
    cls = (*env)->FindClass(env, "com/thisway/hardlibrary/HardControl");
    if (cls == NULL) {
        return JNI_ERR;
    }

    /* 2. map java hello <-->c c_hello */
    if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0)
        return JNI_ERR;

    return JNI_VERSION_1_4;
}

根據rk3288 android5.1 linux3.1編譯庫,必須使用arm-linux-gcc庫(也可采用android studio cmake或ndk編譯)

  arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/  -nostdlib /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-21/arch-arm/usr/lib/libc.so  -I /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include  /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so

沒有安裝arm-linux-gcc的可以按照以下方法

安裝交叉編譯工具

    sudo tar xvzf arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz -C /

    註意: C 後面有個空格,並且 C 是大寫的,它是英文單詞“ Change”的第一個字母,在此 是改變目錄的意思。
    執行該命令,將把 arm-linux-gcc 安裝到/opt/FriendlyARM/toolschain/4.5.1 目錄。

    Step2:把編譯器路徑加入系統環境變量,運行命令
    sudo gedit ~/.bashrc
    編輯 /root/.bashrc 文件, 註意“bashrc”前面有一個“.”,修改最後一行為
    export PATH=$PATH:/opt/FriendlyARM/toolschain/4.5.1/bin
    註意路徑一定要寫對,否則將不會有效。
    如圖,保存退出

編譯產生libhardcontrol.so庫文件,app將會使用到

3.app調用jni靜態鏈接庫操作底層驅動

android app包結構必須相同,上邊jni程序已經指定class名為 "com/thisway/hardlibrary/HardControl",

在app/libs/armeabi/目錄下添加編譯好的庫,沒有目錄自己新建目錄

技術分享圖片

MainActivity.java

package com.thisway.app_0001_leddemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;
import com.thisway.hardlibrary.*;

public class MainActivity extends AppCompatActivity {

    private boolean ledon = false;
    private Button button = null;
    private CheckBox checkBoxLed1 = null;
    private CheckBox checkBoxLed2 = null;
    private CheckBox checkBoxLed3 = null;
    private CheckBox checkBoxLed4 = null;

    class MyButtonListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            ledon = !ledon;
            if (ledon) {
                button.setText("ALL OFF");
                checkBoxLed1.setChecked(true);
                checkBoxLed2.setChecked(true);
                checkBoxLed3.setChecked(true);
                checkBoxLed4.setChecked(true);

                for (int i = 0; i < 4; i++)
                    HardControl.ledCtrl(i, 1);
            }
            else {
                button.setText("ALL ON");
                checkBoxLed1.setChecked(false);
                checkBoxLed2.setChecked(false);
                checkBoxLed3.setChecked(false);
                checkBoxLed4.setChecked(false);

                for (int i = 0; i < 4; i++)
                    HardControl.ledCtrl(i, 0);
            }
        }
    }

    public void onCheckboxClicked(View view) {
        // Is the view now checked?
        boolean checked = ((CheckBox) view).isChecked();

        // Check which checkbox was clicked
        switch(view.getId()) {
            case R.id.LED1:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(0, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(0, 0);
                }
                break;
            case R.id.LED2:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(1, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(1, 0);
                }
                break;

            case R.id.LED3:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(2, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED3 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(2, 0);
                }
                break;

            case R.id.LED4:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(3, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(3, 0);
                }
                break;
            // TODO: Veggie sandwich
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button) findViewById(R.id.BUTTON);

        HardControl.ledOpen();

        checkBoxLed1 = (CheckBox) findViewById(R.id.LED1);
        checkBoxLed2 = (CheckBox) findViewById(R.id.LED2);
        checkBoxLed3 = (CheckBox) findViewById(R.id.LED3);
        checkBoxLed4 = (CheckBox) findViewById(R.id.LED4);

        button.setOnClickListener(new MyButtonListener());
/*
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Perform action on click
                ledon = !ledon;
                if (ledon)
                    button.setText("ALL OFF");
                else
                    button.setText("ALL ON");
            }
        });
*/
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

HardControl.java

package com.thisway.hardlibrary;

public class HardControl {
    public static native int ledCtrl(int which, int status);
    public static native int ledOpen();
    public static native void ledClose();

    static {
        try {
            System.loadLibrary("hardcontrol");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然後就可通過app控制兩個gpio

android jni控制gpio (rk3288)