添加设备记录
gpio
1.用到gedit编辑器
2.在 kernel/drivers 路径下创建自己的drivers文件夹 rk3399-ZK-drivers/gpio
3.创建自己的dts文件夹并添加dts文件
添加设备树文件
路径 kernel/arch/arm64/boot/dts/rockchip
添加
rk3399-ZK.dtsi 文件
添加设备树节点
gpio_demo: gpio_demo {
status = "okay";
compatible = "ZK,ZK-gpio";
ZK-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; /* GPIO0_B4 */
ZK-irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>; /* GPIO4_D5 */
};
在Makefile中添加要编译成.dtb的设备树文件
路径 kernel/arch/arm64/boot/dts/rockchip
添加
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-ZK.dtb
4.添加驱动文件
在kernel/drivers路径下添加自己的驱动文件夹rk3399-ZK-drivers
修改本路径下Makefle,Konfig 文件
Kconfig添加
#ZK drivers.
source "drivers/rk3399-ZK-drivers/Kconfig"
Makefile添加
#rk3399 ZK drivers
obj-y += rk3399-ZK-drivers/
在kernel/drivers/rk3399-ZK-drivers路径下添加gpio文件
添加Makefle,Konfig 文件
Kconfig添加
menu "rk3399-ZK-drivers Drivers"
source "drivers/rk3399-ZK-drivers/gpio/Kconfig"
endmenu
Makefile添加
obj-y += gpio/
在kernel/drivers/rk3399-ZK-drivers/gpio路径下创建rk3399-ZK-gpio-demo.c驱动文件
添加Makefle,Konfig 文件
Kconfig添加
config CONFIG_GPIO_DEMO
tristate "leanr for config gpio driver"#y/m
help
test gpio driver
Makefile添加
obj-$(CONFIG_GPIO_DEMO) += rk3399-ZK-gpio-demo.o
5.编写驱动程序
我这里复制了官方的demo修改成自己的驱动程序
了解常用gpio控制函数
#include <linux/gpio.h>
#include <linux/of_gpio.h>
enum of_gpio_flags {
OF_GPIO_ACTIVE_LOW = 0x1,
};
/*获取io口号*/
int of_get_named_gpio_flags(struct device_node *np, const char *propname,int index, enum of_gpio_flags *flags);
/*测试gpio端口是否合法*/
int gpio_is_valid(int gpio);
/*申请gpio口的使用,若申请成功,则说明gpio口未被使用*/
int gpio_request(unsigned gpio, const char *label);
/*释放gpio口*/
void gpio_free(unsigned gpio);
/*设置gpio为输入功能*/
int gpio_direction_input(int gpio);
/*设置gpio为输出功能*/
int gpio_direction_output(int gpio, int v);
将match_table 的compatible改成与设备树的compatible一致
还留有一个疑问,根文件下的compatible 怎么改?
static struct of_device_id ZK_match_table[] = {
{ .compatible = "ZK,ZK-gpio",},
{},
};
实现rpobe函数
6.修改menuconfig配置
7.编译调试
编译编译到内核
切换到root下编译
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar
make -j8 ARCH=arm64 rk3399-firefly.img
烧录kerne.img 跟resource.img
//执行脚本打包.img文件// sdk根目录执行:./mkimage.sh
踩坑:
1.查看 .config 看宏有没有被打开
.c文件没有被编译
原因:
Kconfig
config CONFIG_GPIO_DEMO 这样是错的
config GPIO_DEMO 这样才能编译
Makefile
obj-$(CONFIG_GPIO_DEMO) += rk3399-ZK-gpio-demo.o
2.报错
Error during update of the configuration
切换到root下编译
logcat *:E 开机信息查看错误信息
编译模块(sdk暂时不知道怎么改)
https://blog.csdn.net/qq_28992301/article/details/52287792
http://www.t-firefly.com/doc/product/info/id/56.html#420E4BFAEE694B920parameter20E69687E4BBB6
1.make menuconfig 中选择驱动为m ,编译成模块
2.编译模块:make modules ,在.c路径下生产.ko文件
3.挂载nfs
开发板端:
busybox mount -o remount, rw /
创建nfs文件夹:在开发板/data路径下创建一个nfs文件夹 /data/nfs
挂载nfs:busybox mount -t nfs -o nolock 192.168.163.128:/home/book/nfs_rootfs /data/nfs
andriod 下要加busybox,linux下不用
4.拷贝ko文件并执行
拷贝.ko文件
ubuntu端:拷贝.ko 文件到nfs路径下
开发板:
执行读写权限 busybox mount -o remount, rw /
从nfs中拷贝.img到根目录下
5.装载模块
加载模块
busybox insmod usbtest.ko
insmod: can't insert 'rk3399-zk-sim-gpio.ko': Operation not permitted ??
查看模块
busybox lsmod | grep "usbtest
卸载模块
busybox rmmod usbtest.ko
错误: mmod: can't change directory to '/lib/modules': No such file or directory
解决方法:执行读写权限 busybox mount -o remount, rw /
mkdir /lib/modules
打印dbug信息:dmesg
9.查看设备是否装载成功
- 查看设备跟设备号 cat /proc/devices
- 查看设备文件是否存在并查看主设备号跟次设备号 ls -l /dev/
10.编译应用程序
知识储备链接:
https://www.cnblogs.com/rootshaw/p/12938167.html
https://blog.csdn.net/SlowIsFastLemon/article/details/102776526
https://blog.csdn.net/u011913612/article/details/51878356?utm_medium=distribute.pc_relevant_right.none-task-blog-BlogCommendFromBaidu-3.channel_param_right&depth_1-utm_source=distribute.pc_relevant_right.none-task-blog-BlogCommendFromBaidu-3.channel_param_right
安卓编译应用程序的基本方式:https://blog.csdn.net/kuishao1314aa/article/details/80689735
Andriod.mk 的常用写法:http://blog.chinaunix.net/uid-12348673-id-3079508.html
第一步:编译条件
在/home/book/proj/firefly-rk3399-Industry/external 路径下创建自己的app模块文件夹zk_sim_app
在文件夹里面创建rk3399-zk-sim-gpio-app.c 文件
修改Android.mk 文件
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
#LOCAL_SRC_FILES :=$(call all-subdir-c-files)
LOCAL_SRC_FILES :=rk3399-zk-sim-gpio-app.c #source files
LOCAL_MODULE := zk-sim-app #module name
LOCAL_MODULE_TAGS := optional #user \ eng \ tests \ optional
#LOCAL_SHARED_LIBRARIES :=libc liblog libselinux libext2_blkid
#LOCAL_CFLAGS += -Wno-error
include $(BUILD_EXECUTABLE)
#include $(BUILD_EXECUTABLE) 以一个可执行程序的方式进行编译
#include $(BUILD_STATIC_LIBRARY) 编译静态库
#include $(BUILD_SHARED_LIBRARY) 编译动态库
第二步:编译
编译方法:
1.source build/envsetup.sh
2.lunch 你产品分支数字
3.make [模块名(Android.mk中模块名字)]
第三步:拷贝app程序到开发板执行
我这里写一个脚本install_app.sh在sdk根目录下 ,执行脚本将编译好的app拷贝到nfs共享目录nfsrootfs文件夹下
#!/bin/bash
a=$1
b="img"
if [ "$a" = "$b" ]
then
cd /home/book/proj/firefly-rk3399-Industry/kernel
make -j8 ARCH=arm64 rk3399-firefly.img
printf "make img success\n"
cp -r ./*.img /home/book/proj/image/
printf "copy img to samba success\n"
else
cd /home/book/proj/firefly-rk3399-Industry
source build/envsetup.sh
lunch 8
make -j8 $1
cp -r /home/book/proj/firefly-rk3399-Industry/out/target/product/rk3399_all/system/bin /home/book/nfs_rootfs/
printf "copy app to nfs success\n"
fi
第四步:开发板挂载nfs并执行app程序
su
文件系统读写权限:busybox mount -o remount, rw /
创建挂载路径:mkdir /data/nfs
修改驱动权限:busybox chmod 777 dev/ioctrl
ifconfig 192.168.163.123
挂载nfs:busybox mount -t nfs -o nolock 192.168.163.128:/home/book/nfs_rootfs /data/nfs
安装应用程序: ./data/nfs/bin/zk_sim_app_share
andriod 下要加busybox,linux下不用
添加安卓开机脚本
方法1(未成功)
参考链接:https://blog.csdn.net/u012975242/article/details/83274693
https://blog.csdn.net/qq_39048075/article/details/103176332
https://zhuanlan.zhihu.com/p/48968590
1.在device/rockchip/rk3399/路径下创建zkstartboot.sh文件
2.system/core/rootdir/init.rc中添加
service zkstartboot /system/bin/zkstartboot.sh
class main
user root
group root
oneshot
seclabel u:r:zkstartboot:s0
on property:persist.sys.boot_completed=1
start zkstartboot
注意!!服务的名字不要有下划线‘_’,没完全理解,请不要另类
3.将自己写的脚本文件拷贝到system/bin/ 目录(编译的时候还生成)
实际最终是被拷贝到/home/book/proj/firefly-rk3399-Industry/out/target/product/rk3399_firefly/system/bin
在device/rockchip/rk3399/device.mk中添加
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/zkstartboot.sh:system/bin/zkstartboot.sh \
4.seclabel u:r:zk_start:s0 一起的还需要在 system/sepolicy/file_contexts中添加
/system/bin/zkstartboot u:object_r:zkstartboot_exec:s0
5.在system/sepolicy/目录下新建一个文件——zkstartboot.te
type zkstartboot, domain;
type zkstartboot_exec, exec_type, file_type;
init_daemon_domain(zkstartboot)
6.编译安卓系统,重新烧录
make installclean
source build/envsetup.sh
lunch 你产品分支数字
//整体编译
./FFTools/make.sh -j8 -d rk3399-firefly -l rk3399_firefly-userdebug
//make -j8
./mkimage.sh
方法2(成功)
https://blog.csdn.net/u010164190/article/details/84532951
1.开机修改为:Permissive模式启动(sdk已经是这个模式)
2.在device/rockchip/rk3399/路径下创建zkstartboot.sh文件
#!/bin/bash
#ip rule add from all lookup main pref 9999
#setprop persist.sys.boot_completed 1
#on property:persist.sys.boot_completed=1
echo "*******************************"
echo "test zk_startboot success\n"
echo "*******************************"
su
busybox mount -o remount, rw /
mkdir /data/nfs
#chmod 777 /data/nfs
#mkdir /data/install_app
#busybox cp /data/nfs/bin /data/install_app
chmod 777 dev/ioctrl
ifconfig eth0 192.168.163.123
busybox mount -t nfs -o nolock 192.168.163.128:/home/book/nfs_rootfs /data/nfs
echo "*******************************"
echo "busybox mount -t nfs -o nolock 192.168.163.128:/home/book/nfs_rootfs /data/nfs \n"
echo "*******************************"
3.system/core/rootdir/init.rc中添加
service zkstartboot /system/bin/busybox sh /system/bin/zkstartboot.sh
#service zkstartboot /system/bin/zkstartboot.sh
class main
user root
# group root
oneshot
# seclabel u:r:zkstartboot:s0
on property:persist.sys.boot_completed=1
start zkstartboot
注意!!服务的名字不要有下划线‘_’,没完全理解,请不要另类
4.将自己写的脚本文件拷贝到system/bin/ 目录(编译的时候还生成)
实际最终是被拷贝到/home/book/proj/firefly-rk3399-Industry/out/target/product/rk3399_firefly/system/bin
在device/rockchip/rk3399/device.mk中添加
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/zkstartboot.sh:system/bin/zkstartboot.sh \
注意:make installclean 必须执行不然编译报错
5.编译安卓系统,重新烧录
安卓如何调用c/c++
1.andriod studio创建一个native c++ 工程,拷贝怎么cpp文件到自己的app工程
2.添加并修改自己的c/c++代码
3.创建native调用函数并把c/c++的的数据放入这个native函数
JNIEXPORT jint JNICALL
Java_com_example_myapplication_MainActivity_testJNI(JNIEnv *env, jobject thiz) {
// test(0 ,"/dev/contrl");
return 0;
}
函数命名规则:
com_example_myapplication package名 package com.example.myapplication;
MainActivity 类的名字
testJNI native函数名 public native int testJNI();
注意,这个函数名一定要跟自己的package一致
4.修改CMakeLists.tx
add_library( # Sets the name of the library.
lib-test //生成的库的名字
SHARED //共享库
# Provides a relative path to your source file(s).
test.c //生成库的源文件
)
include_directories(src/main/cpp/)//包含文件路径
target_link_libraries( # Specifies the target library.
lib-test //cmake链接的库的名字
${log-lib} )
5.修改src目录下的build.gradle
添加
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
/*******添加*******/
externalNativeBuild {
cmake {
cppFlags ""
}
}
/***************************/
}
android {
下添加
/***********************************/
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"//cmakelists 的路径
version "3.10.2"
}
}
/*********************************/
6.c/c++的实现
JNIEXPORT jint
JNICALL
Java_com_example_myapplication_ZKnative_InstallZKDEV(JNIEnv *env, jobject thiz) {
if (fd <= 0)fd = open("/dev/ioctrl", O_RDWR | O_NDELAY | O_NOCTTY);
// if (fd <= 0)fd = open("/dev/contrl", O_RDWR );
__android_log_print(ANDROID_LOG_INFO, "kernel_c", "open dev %d successful !", fd);
return 0;
}
JNIEXPORT jint
JNICALL
Java_com_example_myapplication_ZKnative_led(JNIEnv *env, jobject thiz, jint lednumber,
jstring led_status) {
char *ledops;
//const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);
ledops = (char*)(*env)->GetStringUTFChars(env,led_status, NULL);//将jstring类型装换成char类型
int led;
if (lednumber == 1) {
led = ZK_SIM_LED_R;
}
if (fd <= 0)fd = open("/dev/ioctrl", O_RDWR | O_NDELAY | O_NOCTTY);
else {
__android_log_print(ANDROID_LOG_INFO, "kernel_c", "in led ops!!!");
if (strcmp("open", ledops) == 0 || strcmp("OPEN", ledops) == 0) {
ioctl(fd, led, OPEN); //call the output fu
// nction to off LEDs
__android_log_print(ANDROID_LOG_INFO, "kernel_c", "OPEN %d led!");
printf("OPEN %d led!\n", led);
} else if (strcmp("close", ledops) == 0 || strcmp("CLOSE", ledops) == 0) {
ioctl(fd, led, CLOSE); //call the
__android_log_print(ANDROID_LOG_INFO, "kernel_c", "CLOSE %d led!");
printf("CLOSE %d led!\n", led);
} else {
__android_log_print(ANDROID_LOG_INFO, "kernel_c", "unknown led command !");
__android_log_print(ANDROID_LOG_INFO, "kernel_c", " ledops %s" ,ledops);
printf("unknown led command !");
}
}
return 0;
}
7.app调用
这里创建一个类
package com.example.myapplication;
public class ZKnative {
static {
System.loadLibrary("lib-test");
}
// public native String stringFromJNI();
public native int InstallZKDEV();
public native int led(int lednumber,String led_status);
}
程序调用类
public void aaa(View v) {
new ZKnative().led(1,"open");
//Log.d("jni",""+new ZKnative().testJNI());
//Toast.makeText(MainActivity.this,"开灯",Toast.LENGTH_SHORT).show();
}
public void bbb(View v) {
new ZKnative().led(1,"close");
//Toast.makeText(this,"关灯",Toast.LENGTH_LONG).show();
}
遗留问题:
3.如何快速地位日志信息
其他记录:
烧录app路径:/home/book/nfs_rootfs
烧录驱动路径:/home/book/proj/firefly-rk3399-Industry/kernel
/home/book/proj/firefly-rk3399-Industry/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-gcc-4.9 test.c -o haha
#export ARCH=arm64
#export CROSS_COMPILE=aarch64-linux-gnu-
#export PATH=$PATH:/home/book/proj/firefly-rk3399-Industry/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
git
$ git push -u origin master
/home/book/proj/firefly-rk3399-Industry/out/target/product/rk3399_firefly/system/lib64#