嵌入式LinuxV3s led驱动开发
原理图
方式一:sysfs的GPIO方式控制LED灯
PG1是SDC1的SDC1_CMD口
直接操作sysfs的GPIO控制失败了,应该是设备树里面有声明了!
# echo 193 > /sys/class/gpio/export
[96509.628703] sun8i-v3s-pinctrl 1c20800.pinctrl: pin PG1 already requested by 1c10000.mmc; cannot claim for 1c20800.pinctrl:193
[96509.641625] sun8i-v3s-pinctrl 1c20800.pinctrl: pin-193 (1c20800.pinctrl:193) status -22
sh: write error: Invalid argument
所以需要注释掉:
/*
&mmc1 {
broken-cd;
bus-width = <4>;
vmmc-supply = <®_vcc3v3>;
status = "okay";
};
*/
使用arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
文件中的原有配置,就不用改了:
但是还需要打开:arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dts
leds {
status = "okay";
};
再运行一下就可以了
# echo 193 > /sys/class/gpio/export
[ 152.427408] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pg not found, using dummy regulator
# ls /sys/class/gpio
export gpio193 gpiochip0 unexport
# echo out > /sys/class/gpio/gpio193/direction # 设置引脚为输出模式
# echo 0 > /sys/class/gpio/gpio193/value # 打开LED灯
# echo 1 > /sys/class/gpio/gpio193/value # 关闭LED灯
可以,控制灯光没有问题。
方式二:设备驱动的方式
编写led驱动模块
led_dev.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/io.h> //含有 ioremap 函数 iounmap 函数
#include <linux/uaccess.h> //含有 copy_from_user 函数和含有 copy_to_user 函数
#include <linux/device.h> //含有类相关的设备函数
#include <linux/cdev.h>
#define GPIOG_CFG0 (0x01C208D8)
#define GPIOG_CFG1 (0x01C208DC)
#define GPIOG_DATA (0x01C208E8)
#define GPIOG_PUL0 (0x01C208F4)
static dev_t led_dev_num; //定义一个设备号
static struct cdev *led_dev; //定义一个设备管理结构体指针
static struct class *led_class; //定义一个设备类
static struct device *led0; //定义一个设备
size_t *gpiog_cfg0; //存储虚拟地址到物理地址映射
size_t *gpiog_cfg1; //存储虚拟地址到物理地址映射
size_t *gpiog_data; //存储虚拟地址到物理地址映射
size_t *gpiog_pul0; //存储虚拟地址到物理地址映射
static int led_open(struct inode *inode, struct file *file)
{
/* GPIOG 配置 */
*((volatile size_t*)gpiog_cfg1) &= ~(7<<16); //清除配置寄存器
*((volatile size_t*)gpiog_cfg1) |= (1<<1); //配置 GPIOG1 为输出模式
*((volatile size_t*)gpiog_pul0) &= ~(3<<16); //清除上/下拉寄存器
*((volatile size_t*)gpiog_pul0) |= (1<<1); //配置 GPIOG1 为上拉模式
printk(KERN_DEBUG"open led!!!\n");
return 0;
}
static int led_close(struct inode *inode, struct file *filp)
{
printk(KERN_DEBUG"close led!!!\n");
return 0;
}
static int led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
int ret;
size_t status = ((*((volatile size_t*)gpiog_data))>>1)&0x01;//获取 GPIOG1 状态
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间 buff
if(ret < 0)
printk(KERN_DEBUG"read error!!!\n"); //输出信息linux 驱动开发指南 | 李山文 著
else
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
return 0;
}
static int led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
int ret;
size_t status;
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的 status
if(ret < 0)
printk(KERN_DEBUG"write error!!!\n"); //输出信息
else
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
*((volatile size_t*)gpiog_data) &= ~(1<<1) ;//清除 GPIOG1 状态
if(status)
*((volatile size_t*)gpiog_data) |= (1<<1);//设置 GPIOG1 状态 1
return 0;
}
static struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_close,
};
static int __init led_init(void)
{
int ret;
led_dev = cdev_alloc(); //动态申请一个设备结构体
if(led_dev == NULL)
{
printk(KERN_WARNING"cdev_alloc failed!\n");
return -1;
}
ret = alloc_chrdev_region(&led_dev_num,0,1,"led"); //动态申请一个设备号
if(ret !=0)
{
printk(KERN_WARNING"alloc_chrdev_region failed!\n");
return -1;
}
led_dev->owner = THIS_MODULE; //初始化设备管理结构体的 owner 为 THIS_MODULE
led_dev->ops = &led_ops; //初始化设备操作函数指针为 led_ops 函数
cdev_add(led_dev,led_dev_num,1); //将设备添加到内核中
led_class = class_create(THIS_MODULE, "led_class"); //创建一个名为 led_class 的类linux 驱动开发指南 | 李山文 著
if(led_class == NULL)
{
printk(KERN_WARNING"led_class failed!\n");
return -1;
}
led0 = device_create(led_class,NULL,led_dev_num,NULL,"led0");//创建一个设备名为 led0
if(IS_ERR(led0))
{
printk(KERN_WARNING"device_create failed!\n");
return -1;
}
gpiog_cfg0 = ioremap(GPIOG_CFG0,4); //将 GPIOG_CFG0 物理地址映射为虚拟地址
gpiog_cfg1 = ioremap(GPIOG_CFG1,4); //将 GPIOG_CFG1 物理地址映射为虚拟地址
gpiog_data = ioremap(GPIOG_DATA,4); //将 GPIOG_DATA 物理地址映射为虚拟地址
gpiog_pul0 = ioremap(GPIOG_PUL0,4); //将 GPIOG_PUL0 物理地址映射为虚拟地址
return 0;
}
static void __exit led_exit(void)
{
cdev_del(led_dev); //从内核中删除设备管理结构体
unregister_chrdev_region(led_dev_num,1); //注销设备号
device_destroy(led_class,led_dev_num); //删除设备节点
class_destroy(led_class); //删除设备类
iounmap(gpiog_cfg0); //取消 GPIOG_CFG0 映射
iounmap(gpiog_cfg1); //取消 GPIOG_CFG1 映射
iounmap(gpiog_data); //取消 GPIOG_DATA 映射
iounmap(gpiog_pul0); //取消 GPIOG_PUL0 映射
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
MODULE_AUTHOR("liefyuan@qq.com"); //作者
MODULE_VERSION("0.1"); //版本
MODULE_DESCRIPTION("led_dev"); //简单的描述
Makefile
KERN_DIR = /home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y
all:
make -C $(KERN_DIR) M=$(shell pwd) modules
clean:
rm -rf *.order *o *.symvers *.mod.c *.mod *.ko
obj-m = led_dev.o
编译成驱动模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
liefyuan@ubuntu:~/Liefyuan/bingpi-v3s/drivers/led$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
make -C /home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y M=/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led modules
make[1]: Entering directory '/home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y'
CC [M] /home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.mod.o
LD [M] /home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.ko
make[1]: Leaving directory '/home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y'
scp命令拷贝模块到开发板上去
scp led_dev.ko root@192.168.1.103:/home
加载模块
insmod led_dev.ko
如下出现了led0节点。
# insmod led_dev.ko
[ 4514.268184] led_dev: loading out-of-tree module taints kernel.
# ls /dev
bus ptyvb ttyda
console ptyvc ttydb
cpu_dma_latency ptyvd ttydc
fb0 ptyve ttydd
fd ptyvf ttyde
full ptyw0 ttydf
gpiochip0 ptyw1 ttye0
i2c-0 ptyw2 ttye1
input ptyw3 ttye2
kmsg ptyw4 ttye3
led0 ptyw5 ttye4
log ptyw6 ttye5
mem ptyw7 ttye6
memory_bandwidth ptyw8 ttye7
mmcblk0 ptyw9 ttye8
mmcblk0p1 ptywa ttye9
mmcblk0p2 ptywb ttyea
network_latency ptywc ttyeb
network_throughput ptywd ttyec
null ptywe ttyed
ptmx ptywf ttyee
pts
编写led测试应用
led_app.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd;
char* filename=NULL;
int val;
filename = argv[1];
fd = open(filename, O_RDWR);//打开 dev/设备文件
if (fd < 0)//小于 0 说明没有成功
{
printf("error, can't open %s\n", filename);
return 0;
}
if(argc !=3)
{
printf("usage: ./led_app.elf [device] [on/off]\n"); //打印用法
}
if(!strcmp(argv[2], "on")) //如果输入等于 on,则 LED 亮
val = 0;
else if(!strcmp(argv[2], "off")) //如果输入等于 off,则 LED 灭
val = 1;
else
goto error;
write(fd, &val, 4);//操作 LED
close(fd);
return 0;
error:
printf("usage: ./led_app.elf [device] [on/off]\n"); //打印用法
close(fd);
return -1;
}
编译应用
arm-linux-gnueabihf-gcc led_app.c -o led_app.elf
拷贝应用到开发板进行测试
liefyuan@ubuntu:~/Liefyuan/bingpi-v3s/drivers/led$ scp led_app.elf root@192.168.1.103:/home
root@192.168.1.103's password:
led_app.elf 100% 10KB 10.4KB/s 00:00
- 开灯:
./led_app.elf /dev/led0 on
- 关灯:
./led_app.elf /dev/led0 off
完结!
问题记录:
编译ko出错:error: implicit declaration of function ‘copy_from_user’ [-Werror=implicit-function-declaration]
liefyuan@ubuntu:~/Liefyuan/bingpi-v3s/drivers/led$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
make -C /home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y M=/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led modules
make[1]: Entering directory '/home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y'
CC [M] /home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.o
/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.c: In function ‘led_read’:
/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.c:52:2: error: implicit declaration of function ‘copy_to_user’ [-Werror=implicit-function-declaration]
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间 buff
^
/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.c: In function ‘led_write’:
/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.c:64:2: error: implicit declaration of function ‘copy_from_user’ [-Werror=implicit-function-declaration]
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的 status
^
cc1: some warnings being treated as errors
scripts/Makefile.build:284: recipe for target '/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.o' failed
make[2]: *** [/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led/led_dev.o] Error 1
Makefile:1612: recipe for target '_module_/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led' failed
make[1]: *** [_module_/home/liefyuan/Liefyuan/bingpi-v3s/drivers/led] Error 2
make[1]: Leaving directory '/home/liefyuan/Liefyuan/bingpi-v3s/linux-zero-5.2.y'
Makefile:3: recipe for target 'all' failed
make: *** [all] Error 2
解决办法:
将头文件#include <asm/uaccess.h>
改为#include <linux/uaccess.h>
编译ko文件的方法需要指定架构和交叉编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
scp命令拷贝出现问题
liefyuan@ubuntu:~/Liefyuan/bingpi-v3s/drivers/led$ scp led_dev.ko root@192.168.1.103:/home
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:Ecz1YO43FOYFccOT J5WVNVVsyAv6QjrdPacppIWLFE.
Please contact your system administrator.
Add correct host key in /home/liefyuan/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/liefyuan/.ssh/known_hosts:3
remove with:
ssh-keygen -f "/home/liefyuan/.ssh/known_hosts" -R 192.168.1.103
ECDSA host key for 192.168.1.103 has changed and you have requested strict checking.
Host key verification failed.
lost connection
编辑文件vi /home/liefyuan/.ssh
选择know_hosts选项回车,进入另一个文件界面,然后把最后一行秘钥删除,然后保存,退出。就可以了。
liefyuan@ubuntu:~/Liefyuan/bingpi-v3s/drivers/led$ scp led_dev.ko root@192.168.1.103:/home
The authenticity of host '192.168.1.103 (192.168.1.103)' can't be established.
ECDSA key fingerprint is SHA256:Ecz1YO43FOYFccOT J5WVNVVsyAv6QjrdPacppIWLFE.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.103' (ECDSA) to the list of known hosts.
root@192.168.1.103's password:
led_dev.ko 100% 7068 6.9KB/s 00:00
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfhehcj
系列文章
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13