Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lf282481431
linux驱动例程
提交
b263f70c
L
linux驱动例程
项目概览
lf282481431
/
linux驱动例程
通知
9
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
linux驱动例程
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b263f70c
编写于
6月 14, 2023
作者:
L
liaofei
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加GPIO输入捕获中断实验
上级
84db60ff
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
674 addition
and
0 deletion
+674
-0
05-interrupt/01-gpio_capture/Makefile
05-interrupt/01-gpio_capture/Makefile
+36
-0
05-interrupt/01-gpio_capture/app.c
05-interrupt/01-gpio_capture/app.c
+169
-0
05-interrupt/01-gpio_capture/gpio_capture.c
05-interrupt/01-gpio_capture/gpio_capture.c
+458
-0
05-interrupt/01-gpio_capture/gpio_capture.dts
05-interrupt/01-gpio_capture/gpio_capture.dts
+11
-0
未找到文件。
05-interrupt/01-gpio_capture/Makefile
0 → 100644
浏览文件 @
b263f70c
ifeq
($(KERNELRELEASE),)
#第一次执行时 KERNELRELEASE 为空,执行此分支
#内核源码目录,需要先编译内核源码,在编译源码外的内核模块
KERNELDIR
?=
/home/lf/workspace/source/my_source/linux/linux-5.4.31
#NFS跟文件系统目录
ROOTFS
?=
/home/lf/workspace/rootfs
#当前目录
PWD
:=
$(
shell
pwd
)
#$(MAKE) 相当于 make
#-C $(KERNELDIR) 执行 KERNELDIR 目录的Makefile
#M=$(PWD) 内核源码树之外的一个目录
#modules 只编译模块
all
:
$(MAKE)
-C
$(KERNELDIR)
ARCH
=
arm
CROSS_COMPILE
=
arm-none-linux-gnueabihf-
M
=
$(PWD)
modules
arm-none-linux-gnueabihf-gcc
-oapp
.out app.c
-std
=
gnu99
-D_GNU_SOURCE
module
:
$(MAKE)
-C
$(KERNELDIR)
ARCH
=
arm
CROSS_COMPILE
=
arm-none-linux-gnueabihf-
M
=
$(PWD)
modules
app
:
arm-none-linux-gnueabihf-gcc
-oapp
.out app.c
-std
=
gnu99
-D_GNU_SOURCE
copy
:
# 因为采用insmod加载模块,所以拷贝到NFS跟文件系统的root目录即可
cp
*.ko
$(ROOTFS)/root/
cp
*.out
$(ROOTFS)/root/
install
:
# 若采用modprobe加载模块,则需要进行安装操作
$(MAKE)
-C
$(KERNELDIR)
ARCH
=
arm
CROSS_COMPILE
=
arm-none-linux-gnueabihf-
M
=
$(PWD)
INSTALL_MOD_PATH
=
$(ROOTFS)
modules_install
cp
*.out
$(ROOTFS)/root/
clean
:
rm
-rf
*
.o .
*
.cmd
*
.mod.
*
*
.mod modules.order Module.symvers .tmp_versions
else
#当从源码目录的 Makefile 再次进入时 KERNELRELEASE 已经赋值,执行此分支
#obj-m 表示编译成模块
obj-m
:=
gpio_capture.o
endif
05-interrupt/01-gpio_capture/app.c
0 → 100644
浏览文件 @
b263f70c
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : ap3216cApp.c
作者 : 正点原子Linux团队
版本 : V1.0
描述 : ap3216c设备测试APP。
其他 : 无
使用方法 :./ap3216cApp /dev/ap3216c
论坛 : www.openedv.com
日志 : 初版V1.0 2021/03/19 正点原子Linux团队创建
***************************************************************/
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <signal.h>
struct
pulse_par
{
//周期,在上升沿时刻结合上一个上升沿的时间一起计算周期
long
long
period
;
//脉宽,在下降沿时刻结合上一个上升沿的时间一起计算脉宽
long
long
width
;
};
static
int
dev_fd
=
-
1
;
void
sig_handler
(
int
signum
,
siginfo_t
*
siginfo
,
void
*
p
)
{
int
ret
;
struct
pulse_par
pulse_par
;
if
(
signum
==
SIGIO
)
{
if
(
siginfo
->
si_band
&
POLLIN
)
{
//设备有数据可读
ret
=
read
(
dev_fd
,
&
pulse_par
,
sizeof
(
pulse_par
));
if
(
ret
==
sizeof
(
pulse_par
))
printf
(
"period: %lld, width: %lld
\r\n
"
,
pulse_par
.
period
,
pulse_par
.
width
);
else
printf
(
"read failed
\r\n
"
);
}
}
}
void
noblock_test
(
char
*
file
)
{
int
flag
;
struct
sigaction
act
;
printf
(
"noblock mode
\r\n
"
);
/* 1、注册信号处理函数 */
if
(
sigaction
(
SIGIO
,
NULL
,
&
act
)
<
0
)
//获取之前的信号处理方式
{
perror
(
"error"
);
return
;
}
sigemptyset
(
&
act
.
sa_mask
);
//清空信号集
sigaddset
(
&
act
.
sa_mask
,
SIGIO
);
//添加SIGIO到信号集,处理过程中要屏蔽SIGIO
act
.
sa_sigaction
=
sig_handler
;
//信号处理函数
act
.
sa_flags
=
SA_SIGINFO
;
//使用sa_sigaction的信号处理函数
if
(
sigaction
(
SIGIO
,
&
act
,
NULL
)
<
0
)
//设置信号处理方式
{
perror
(
"error"
);
return
;
}
/* 2、打开设备文件 */
dev_fd
=
open
(
file
,
O_RDWR
|
O_NONBLOCK
);
if
(
dev_fd
<
0
)
{
perror
(
"error"
);
return
;
}
/* 3、设置在此文件描述符上接收信号的进程标识 */
if
(
fcntl
(
dev_fd
,
F_SETOWN
,
getpid
())
<
0
)
{
perror
(
"error"
);
close
(
dev_fd
);
return
;
}
/* 4、设置标识输入输出可进行的信号 */
if
(
fcntl
(
dev_fd
,
F_SETSIG
,
SIGIO
)
<
0
)
{
perror
(
"error"
);
close
(
dev_fd
);
return
;
}
/* 5、设置文件的FASYNC标志 */
flag
=
fcntl
(
dev_fd
,
F_GETFL
);
if
(
flag
<
0
)
{
perror
(
"error"
);
close
(
dev_fd
);
return
;
}
if
(
fcntl
(
dev_fd
,
F_SETFL
,
flag
|
FASYNC
)
<
0
)
{
perror
(
"error"
);
close
(
dev_fd
);
return
;
}
//等待信号被触发
while
(
1
)
{
sleep
(
100
);
}
}
void
block_test
(
char
*
file
)
{
int
ret
;
struct
pulse_par
pulse_par
;
printf
(
"block mode
\r\n
"
);
dev_fd
=
open
(
file
,
O_RDWR
);
if
(
dev_fd
<
0
)
{
printf
(
"can't open file %s
\r\n
"
,
file
);
return
;
}
while
(
1
)
{
ret
=
read
(
dev_fd
,
&
pulse_par
,
sizeof
(
pulse_par
));
if
(
ret
==
sizeof
(
pulse_par
))
printf
(
"period: %lld, width: %lld
\r\n
"
,
pulse_par
.
period
,
pulse_par
.
width
);
else
printf
(
"read failed,erron %d
\r\n
"
,
ret
);
}
}
/*
* @description : main主程序
* @param - argc : argv数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int
main
(
int
argc
,
char
*
argv
[])
{
if
(
argc
<
2
)
{
printf
(
"Error Usage!
\r\n
"
);
return
-
1
;
}
if
((
argc
>=
3
)
&&
!
strncmp
(
argv
[
2
],
"NOBLOCK"
,
7
))
noblock_test
(
argv
[
1
]);
else
block_test
(
argv
[
1
]);
return
0
;
}
05-interrupt/01-gpio_capture/gpio_capture.c
0 → 100644
浏览文件 @
b263f70c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#define CAPTURE_NUMBER 5
struct
pulse_par
{
//周期,在上升沿时刻结合上一个上升沿的时间一起计算周期
long
long
period
;
//脉宽,在下降沿时刻结合上一个上升沿的时间一起计算脉宽
long
long
width
;
};
struct
capture_handle
{
//确保设备只被打开一次
atomic_t
flag
;
//输入信号所使用的GPIO
struct
gpio_desc
*
gpio
;
//GPIO的中断号
int
irq
;
//工作队列,用于中断后半部
struct
work_struct
work
;
//等待队列,在未采集到一个新的脉冲周期时用于挂起线程
wait_queue_head_t
wait_queue
;
//采集完成标志
int
update
;
//用于向应用层发送信号
struct
fasync_struct
*
fasync
;
//记录上一个上升沿时间,
long
long
last_rising
;
//上一次的按键状态
int
last_state
;
//脉冲参数
struct
pulse_par
pulse_par
;
//设备的ID号,这里作为设备的次设备号
uint32_t
id
;
//链表节点
struct
list_head
node
;
};
//设备号,即第一个脉冲捕获设备的设备号
static
dev_t
capture_num
;
//cdev对象
static
struct
cdev
capture_cdev
;
//class对象
static
struct
class
*
capture_class
;
//capture句柄列表
static
struct
list_head
capture_list
=
LIST_HEAD_INIT
(
capture_list
);
//根据ID查找设备句柄
static
struct
capture_handle
*
find_capture_handle
(
uint32_t
id
)
{
struct
capture_handle
*
pos
;
struct
capture_handle
*
n
;
struct
capture_handle
*
capture_handle
;
capture_handle
=
NULL
;
list_for_each_entry_safe
(
pos
,
n
,
&
capture_list
,
node
)
{
if
(
pos
->
id
==
id
)
{
capture_handle
=
pos
;
break
;
}
}
return
capture_handle
;
}
//分配一个ID
static
int32_t
alloc_id
(
void
)
{
int32_t
id
;
//按从小到大顺序生成ID
for
(
id
=
0
;
find_capture_handle
(
id
)
&&
(
id
<
CAPTURE_NUMBER
);
id
++
)
{
;
}
//ID必须小于注册的最大ID号
if
(
id
>=
CAPTURE_NUMBER
)
return
-
EINVAL
;
return
id
;
}
//将设备添加到链表
static
void
add_capture
(
struct
capture_handle
*
capture_handle
)
{
list_add
(
&
capture_handle
->
node
,
&
capture_list
);
}
//将设备从链表中移除
static
void
remove_capture
(
struct
capture_handle
*
capture_handle
)
{
list_del
(
&
capture_handle
->
node
);
}
//打开设备,应用层执行open时调用
static
int
capture_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
uint32_t
id
;
struct
capture_handle
*
capture_handle
;
//提取次设备号,次设备号即ID
id
=
MINOR
(
inode
->
i_rdev
);
//以次设备号作为ID去查找设备句柄
capture_handle
=
find_capture_handle
(
id
);
if
(
!
capture_handle
)
{
printk
(
"find capture handle failed
\r\n
"
);
return
-
EINVAL
;
}
if
(
atomic_dec_and_test
(
&
capture_handle
->
flag
))
{
//设置文件私有数据
file
->
private_data
=
(
void
*
)
capture_handle
;
return
0
;
}
else
{
//设备处于打开状态
printk
(
"device busy
\r\n
"
);
atomic_inc
(
&
capture_handle
->
flag
);
return
-
EBUSY
;
}
}
static
int
capture_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
capture_handle
*
capture_handle
=
file
->
private_data
;
//复位原子变量
atomic_set
(
&
capture_handle
->
flag
,
1
);
return
0
;
}
//初始化 fasync_struct 结构体指针变量,在应用层设置FASYNC标志时会执行驱动的 capture_fasync 函数
static
int
capture_fasync
(
int
fd
,
struct
file
*
file
,
int
on
)
{
struct
capture_handle
*
capture_handle
=
file
->
private_data
;
return
fasync_helper
(
fd
,
file
,
on
,
&
capture_handle
->
fasync
);
}
//读数据函数,应用层执行read时调用
static
ssize_t
capture_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
len
,
loff_t
*
pos
)
{
struct
capture_handle
*
capture_handle
=
file
->
private_data
;
//以阻塞式打开,且脉冲参数没有更新,则加入等待队列并休眠
if
((
!
(
file
->
f_flags
&
O_NONBLOCK
))
&&
(
!
capture_handle
->
update
))
{
if
(
wait_event_interruptible
(
capture_handle
->
wait_queue
,
capture_handle
->
update
))
return
-
ERESTARTSYS
;
}
//将脉冲参数拷贝到应用层
if
(
copy_to_user
(
buf
,
&
capture_handle
->
pulse_par
,
sizeof
(
struct
pulse_par
)))
return
-
EFAULT
;
capture_handle
->
update
=
0
;
return
sizeof
(
capture_handle
->
pulse_par
);
}
//工作队列函数
static
void
capture_work
(
struct
work_struct
*
w
)
{
int
input_state
;
long
long
cur_rising
;
struct
capture_handle
*
capture
=
container_of
(
w
,
struct
capture_handle
,
work
);
//读取GPIO电平,电平为有效值返回1,有效值在设备树中指定
input_state
=
gpiod_get_value
(
capture
->
gpio
);
//检查GPIO状态是否改变,若未改变则认为是误触发
if
(
capture
->
last_state
==
input_state
)
return
;
if
(
input_state
==
1
)
{
//上升沿捕获周期
//记录上升沿时间
cur_rising
=
ktime_get_boottime_ns
();
if
(
capture
->
last_rising
!=
0
)
{
//计算周期
capture
->
pulse_par
.
period
=
cur_rising
-
capture
->
last_rising
;
//发送信号通知相应进程
kill_fasync
(
&
capture
->
fasync
,
SIGIO
,
POLL_IN
);
//唤醒正在等待脉冲捕获事件的进程
capture
->
update
=
1
;
wake_up_interruptible
(
&
capture
->
wait_queue
);
}
//更新last_rising
capture
->
last_rising
=
cur_rising
;
}
else
{
//下降沿捕获脉宽
//计算脉宽
if
(
capture
->
last_rising
!=
0
)
capture
->
pulse_par
.
width
=
ktime_get_boottime_ns
()
-
capture
->
last_rising
;
}
//记录按键状态
capture
->
last_state
=
input_state
;
}
//中断处理函数
static
irqreturn_t
capture_handler
(
int
irq
,
void
*
dev
)
{
struct
capture_handle
*
capture
=
(
struct
capture_handle
*
)
dev
;
//调度工作队列
schedule_work
(
&
capture
->
work
);
//返回IRQ_HANDLED,表示中断被成功处理
return
IRQ_HANDLED
;
}
//设备和驱动匹配成功执行
static
int
capture_probe
(
struct
platform_device
*
pdev
)
{
int
result
;
int32_t
id
;
uint32_t
irq_flags
;
const
char
*
label
;
struct
device
*
device
;
struct
capture_handle
*
capture
;
printk
(
"%s
\r\n
"
,
__FUNCTION__
);
//分配一个ID
id
=
alloc_id
();
if
(
id
<
0
)
return
id
;
//读取标签,确定设备文件名
result
=
of_property_read_string
(
pdev
->
dev
.
of_node
,
"label"
,
&
label
);
if
(
result
!=
0
)
{
printk
(
"get config info failed
\r\n
"
);
return
result
;
}
//设置平台设备ID
pdev
->
id
=
id
;
//分配设备句柄,devm表示模块卸载时自动释放
capture
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
capture_handle
),
GFP_KERNEL
);
if
(
!
capture
)
{
printk
(
"alloc memory failed
\r\n
"
);
return
-
ENOMEM
;
}
//复位capture设备句柄
memset
(
capture
,
0
,
sizeof
(
struct
capture_handle
));
capture
->
last_state
=
-
1
;
//绑定ID
capture
->
id
=
id
;
//初始化等待队列
init_waitqueue_head
(
&
capture
->
wait_queue
);
//初始化工作队列
INIT_WORK
(
&
capture
->
work
,
capture_work
);
//获取GPIO,并设置为输入(devm表示模块卸载时自动释放)
capture
->
gpio
=
devm_gpiod_get_index
(
&
pdev
->
dev
,
"input"
,
0
,
GPIOD_IN
);
if
(
IS_ERR
(
capture
->
gpio
))
{
printk
(
"get gpio failed
\r\n
"
);
return
PTR_ERR
(
capture
->
gpio
);
}
//获取中断号
capture
->
irq
=
of_irq_get
(
pdev
->
dev
.
of_node
,
0
);
if
(
capture
->
irq
<=
0
)
{
printk
(
"irq get failed"
);
return
capture
->
irq
;
}
//获取中断触发方式
irq_flags
=
irq_get_trigger_type
(
capture
->
irq
);
if
(
irq_flags
==
IRQF_TRIGGER_NONE
)
irq_flags
=
IRQF_TRIGGER_FALLING
|
IRQF_TRIGGER_RISING
;
//注册中断
result
=
devm_request_irq
(
&
pdev
->
dev
,
capture
->
irq
,
capture_handler
,
irq_flags
,
"capture"
,
(
void
*
)
capture
);
if
(
result
!=
0
)
{
printk
(
"request irq failed
\r\n
"
);
return
result
;
}
//设置原子变量为1,表示只能被一个进程打开一次
atomic_set
(
&
capture
->
flag
,
1
);
//添加capture到链表
add_capture
(
capture
);
//设置平台设备的驱动私有数据
pdev
->
dev
.
driver_data
=
(
void
*
)
capture
;
//创建设备文件,将ID作为此设备的次设备号
printk
(
"device major %d, device minor %d, device file name = %s
\r\n
"
,
MAJOR
(
capture_num
+
capture
->
id
),
MINOR
(
capture_num
+
capture
->
id
),
label
);
device
=
device_create
(
capture_class
,
NULL
,
capture_num
+
capture
->
id
,
NULL
,
label
);
if
(
IS_ERR
(
device
))
{
remove_capture
(
capture
);
printk
(
"device create failed"
);
return
PTR_ERR
(
device
);
}
return
0
;
}
//设备或驱动卸载时执行
static
int
capture_remove
(
struct
platform_device
*
pdev
)
{
struct
capture_handle
*
capture
;
printk
(
"%s
\r\n
"
,
__FUNCTION__
);
//提取平台设备的驱动私有数据
capture
=
(
struct
capture_handle
*
)
pdev
->
dev
.
driver_data
;
//删除设备文件
device_destroy
(
capture_class
,
capture_num
+
capture
->
id
);
//从设备句柄链表中删除capture设备
remove_capture
(
capture
);
return
0
;
}
/* 匹配列表,用于设备树和平台驱动匹配 */
static
const
struct
of_device_id
capture_of_match
[]
=
{
{.
compatible
=
"atk,gpio_capture"
},
{
/* Sentinel */
}
};
//平台驱动
struct
platform_driver
capture_drv
=
{
.
driver
=
{
.
name
=
"gpio_capture"
,
.
owner
=
THIS_MODULE
,
.
pm
=
NULL
,
.
of_match_table
=
capture_of_match
,
},
.
probe
=
capture_probe
,
.
remove
=
capture_remove
,
};
static
struct
file_operations
capture_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
capture_open
,
.
release
=
capture_release
,
.
read
=
capture_read
,
.
fasync
=
capture_fasync
,
};
static
int
__init
plt_drv_init
(
void
)
{
int
result
;
printk
(
"%s
\r\n
"
,
__FUNCTION__
);
//根据次设备号起始值动态分配并注册字符设备号
result
=
alloc_chrdev_region
(
&
capture_num
,
0
,
CAPTURE_NUMBER
,
"csdn,capture"
);
if
(
result
<
0
)
{
printk
(
"alloc chrdev failed
\r\n
"
);
return
result
;
}
printk
(
"first device major %d, first device minor %d
\r\n
"
,
MAJOR
(
capture_num
),
MINOR
(
capture_num
));
//初始化CDEV对象
cdev_init
(
&
capture_cdev
,
&
capture_ops
);
//向系统添加CDEV对象
result
=
cdev_add
(
&
capture_cdev
,
capture_num
,
CAPTURE_NUMBER
);
if
(
result
<
0
)
{
unregister_chrdev_region
(
capture_num
,
CAPTURE_NUMBER
);
printk
(
"add cdev failed
\r\n
"
);
return
result
;
}
//创建class对象
capture_class
=
class_create
(
THIS_MODULE
,
"capture,class"
);
if
(
IS_ERR
(
capture_class
))
{
cdev_del
(
&
capture_cdev
);
unregister_chrdev_region
(
capture_num
,
CAPTURE_NUMBER
);
printk
(
"class create failed"
);
return
PTR_ERR
(
capture_class
);
}
//注册平台驱动
result
=
platform_driver_register
(
&
capture_drv
);
if
(
result
<
0
)
{
class_destroy
(
capture_class
);
cdev_del
(
&
capture_cdev
);
unregister_chrdev_region
(
capture_num
,
CAPTURE_NUMBER
);
printk
(
"add cdev failed
\r\n
"
);
return
result
;
}
return
0
;
}
static
void
__exit
plt_drv_exit
(
void
)
{
printk
(
"%s
\r\n
"
,
__FUNCTION__
);
//注销平台驱动
platform_driver_unregister
(
&
capture_drv
);
//销毁class对象
class_destroy
(
capture_class
);
//从系统删除CDEV对象
cdev_del
(
&
capture_cdev
);
//注销字符设备号
unregister_chrdev_region
(
capture_num
,
CAPTURE_NUMBER
);
}
module_init
(
plt_drv_init
);
module_exit
(
plt_drv_exit
);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"csdn"
);
MODULE_DESCRIPTION
(
"pled_dev"
);
05-interrupt/01-gpio_capture/gpio_capture.dts
0 → 100644
浏览文件 @
b263f70c
//在顶层设备树根节点中加入如下节点
gpio_capture@0 {
compatible = "atk,gpio_capture"; /* 用于设备树与驱动进行匹配 */
status = "okay"; /* 状态 */
label = "gpio_capture0"; /* 标签,对应设备文件名 */
input-gpios = <&gpiog 3 GPIO_ACTIVE_LOW>; /* 中断所使用的引脚 */
interrupt-parent = <&gpiog>; /* 节点的父中断控制器 */
interrupts = <3 IRQ_TYPE_EDGE_BOTH>; /* 中断源 */
};
//用make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs -j8编译设备树
//用新的.dtb文件启动系统
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录