RK3568驱动指南|第六篇-平台总线-第54章 点亮LED灯实验

news2024/11/20 13:40:49

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第六期_平台总线_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第54章 点亮LED灯实验(平台总线) 

在上个章节中,我们成功在platform驱动程序中读取到了设备资源信息,在本章节将进行具体的项目实践,要求在上节platform驱动程序的基础上,加入控制LED灯相关的代码(这部分代码可以参考“第18章 点亮LED灯实验”)。

54.1 实验程序的编写

54.1.1 驱动程序编写

本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\43_platform_led\module

编写完成的platform_led.c代码如下所示,添加的代码已加粗表示。

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>

struct device_test{

    dev_t dev_num;  //设备号
     int major ;  //主设备号
    int minor ;  //次设备号
    struct cdev cdev_test; // cdev
    struct class *class;   //类
    struct device *device; //设备
    char kbuf[32];
    unsigned int *vir_gpio_dr;
};

struct  device_test dev1;


/*打开设备函数*/
static int cdev_test_open(struct inode *inode, struct file *file)
{
    file->private_data=&dev1;//设置私有数据
    printk("This is cdev_test_open\r\n");

    return 0;
}

/*向设备写入数据函数*/
static ssize_t cdev_test_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
     struct device_test *test_dev=(struct device_test *)file->private_data;

    if (copy_from_user(test_dev->kbuf, buf, size) != 0) // copy_from_user:用户空间向内核空间传数据
    {
        printk("copy_from_user error\r\n");
        return -1;
    }
    if(test_dev->kbuf[0]==1){   //如果应用层传入的数据是1,则打开灯
            *(test_dev->vir_gpio_dr) = 0x8000c040;   //设置数据寄存器的地址
              printk("test_dev->kbuf [0]  is %d\n",test_dev->kbuf[0]);  //打印传入的数据
    }
    else if(test_dev->kbuf[0]==0)  //如果应用层传入的数据是0,则关闭灯
    {
            *(test_dev->vir_gpio_dr) = 0x80004040; //设置数据寄存器的地址
            printk("test_dev->kbuf [0]  is %d\n",test_dev->kbuf[0]); //打印传入的数据
    }
    return 0;
}
/**从设备读取数据*/
static ssize_t cdev_test_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
    struct device_test *test_dev=(struct device_test *)file->private_data;
    if (copy_to_user(buf, test_dev->kbuf, strlen( test_dev->kbuf)) != 0) // copy_to_user:内核空间向用户空间传数据
    {
        printk("copy_to_user error\r\n");
        return -1;
    }

    printk("This is cdev_test_read\r\n");
    return 0;
}

static int cdev_test_release(struct inode *inode, struct file *file)
{
    printk("This is cdev_test_release\r\n");
    return 0;
}

/*设备操作函数*/
struct file_operations cdev_test_fops = {
    .owner = THIS_MODULE, //将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
    .open = cdev_test_open, //将open字段指向chrdev_open(...)函数
    .read = cdev_test_read, //将open字段指向chrdev_read(...)函数
    .write = cdev_test_write, //将open字段指向chrdev_write(...)函数
    .release = cdev_test_release, //将open字段指向chrdev_release(...)函数
};

static int my_platform_driver_probe(struct platform_device *pdev)
{
    struct resource *res_mem;
	int ret;
	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res_mem) {
        dev_err(&pdev->dev, "Failed to get memory resource\n");
        return -ENODEV;
    }

	/*注册字符设备驱动*/
    /*1 创建设备号*/
    ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name"); //动态分配设备号
    if (ret < 0)
    {
       goto err_chrdev;
    }
    printk("alloc_chrdev_region is ok\n");

    dev1.major = MAJOR(dev1.dev_num); //获取主设备号
   dev1.minor = MINOR(dev1.dev_num); //获取次设备号

    printk("major is %d \r\n", dev1.major); //打印主设备号
    printk("minor is %d \r\n", dev1.minor); //打印次设备号
     /*2 初始化cdev*/
    dev1.cdev_test.owner = THIS_MODULE;
    cdev_init(&dev1.cdev_test, &cdev_test_fops);

    /*3 添加一个cdev,完成字符设备注册到内核*/
   ret =  cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
    if(ret<0)
    {
        goto  err_chr_add;
    }
    /*4 创建类*/
  dev1. class = class_create(THIS_MODULE, "test");
    if(IS_ERR(dev1.class))
    {
        ret=PTR_ERR(dev1.class);
        goto err_class_create;
    }
    /*5  创建设备*/
  dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test");
    if(IS_ERR(dev1.device))
    {
        ret=PTR_ERR(dev1.device);
        goto err_device_create;
    }
    dev1.vir_gpio_dr=ioremap(res_mem->start,4);  //将物理地址转化为虚拟地址
    if(IS_ERR(dev1.vir_gpio_dr))
    {
        ret=PTR_ERR(dev1.vir_gpio_dr);  //PTR_ERR()来返回错误代码
        goto err_ioremap;
    }
return 0;

err_ioremap:
        iounmap(dev1.vir_gpio_dr);

 err_device_create:
        class_destroy(dev1.class);                 //删除类

err_class_create:
       cdev_del(&dev1.cdev_test);                 //删除cdev

err_chr_add:
        unregister_chrdev_region(dev1.dev_num, 1); //注销设备号

err_chrdev:
        return ret;
}

static int my_platform_driver_remove(struct platform_device *pdev)
{
    // 设备移除操作
    return 0;
}

static struct platform_driver my_platform_driver = {
    .driver = {
        .name = "my_platform_device", // 与 platform_device.c 中的设备名称匹配
        .owner = THIS_MODULE,
    },
    .probe = my_platform_driver_probe,
    .remove = my_platform_driver_remove,
};

static int __init my_platform_driver_init(void)
{
    int ret;

    ret = platform_driver_register(&my_platform_driver); // 注册平台驱动
    if (ret) {
        printk("Failed to register platform driver\n");
        return ret;
    }

    printk("Platform driver registered\n");
    return 0;
}

static void __exit my_platform_driver_exit(void)
{
        /*注销字符设备*/
    unregister_chrdev_region(dev1.dev_num, 1); //注销设备号
    cdev_del(&dev1.cdev_test);                 //删除cdev
    device_destroy(dev1.class, dev1.dev_num);       //删除设备
    class_destroy(dev1.class);                 //删除类
	platform_driver_unregister(&my_platform_driver); // 注销平台驱动
    printk("Platform driver unregistered\n");
}

module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");

54.1.2 编写测试 APP

本应用程序对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\43_platform_led\app

编写测试app,led驱动加载成功之后会生成/dev/test节点,应用程序APP通过操作/dev/test文件来完成对LED设备的控制。向/dev/test文件写入0表示关闭LED灯,写入1表示打开LED灯。编写完成的应用程序app.c代码如下所示:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])  
{
    int fd;
    char buf[32] = {0};   
    fd = open("/dev/test", O_RDWR);  //打开led驱动
    if (fd < 0)
    {
        perror("open error \n");
        return fd;
}
 // atoi()将字符串转为整型,这里将第一个参数转化为整型后,存放在 buf[0]中
buf[0] =atoi(argv[1]);  
write(fd,buf,sizeof(buf));  //向/dev/test文件写入数据
    close(fd);     //关闭文件
    return 0;
}

54.2 运行测试

54.2.1 编译驱动程序

在上一小节中的platform_led.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += platform_led.o    #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel    #这里是你的内核目录                                                                                                                            
PWD ?= $(shell pwd)
all:
    make -C $(KDIR) M=$(PWD) modules    #make操作
clean:
    make -C $(KDIR) M=$(PWD) clean    #make clean操作

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放platform_led.c和Makefile文件目录下,如下图(图54-1)所示:

图 54-1

然后使用命令“make”进行驱动的编译,编译完成如下图(图54-2)所示:

图 54-2

编译完生成platform_led.ko目标文件,如下图(图54-3)所示:

至此驱动模块就编译成功了。

54.2.2 编译应用程序

下面进行应用程序编译,因为测试APP是要在开发板上运行的,所以需要aarch64-linux-gnu-gcc来编译,输入以下命令,编译完成以后会生成一个app的可执行程序,如下图(图54-4)所示:

aarch64-linux-gnu-gcc app.c -o app

图 54-4

下面进行驱动程序的测试。

54.2.3 运行测试

本小节的测试要使用两个ko文件和一个测试应用程序,第一个ko文件为第53章编译出来的platform_device.ko驱动,第二个ko文件为在上一小节编译出的probe.ko驱动文件,应用程序为上一小节编译出来的app。

开发板启动之后,首先使用以下命令进行platform设备的注册,如下图(图54-5)所示:

insmod platform_device.ko

图 54-5

然后继续使用以下命令加载platform_led.ko驱动,打印如下图(54-6)所示:

insmod platform_led.ko

图 54-6

可以看到led字符设备成功注册了,主设备号为236,次设备号为0,相应的test节点也成功创建了,如下图(54-7)所示:

图 54-7

默认情况下led灯的状态为常亮,然后输入“./app 0”命令LED灯熄灭,如下图(图 54-8)所示:

图 54-8

图 54-9

然后输入“./app 0”,LED灯点亮,如下图(图 54-10)所示:

 图 54-10

 

图 54-11

最后可以使用以下命令进行驱动的卸载,如下图(图54-12)所示:

rmmod platform_led.ko

rmmod platform_device.ko

图 54-12

至此,使用平台总线的点亮LCD灯实验就完成了。


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1098783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

流量渠道分析

文章目录 流量渠道分析一、为什么需要流量渠道分析1.了解流量来源&#xff0c;制定营销策略2.发现流量缺失点&#xff0c;提高转化率3.提高用户体验&#xff0c;增加用户留存 二、流量渠道分析方法1.确定分析目标2.选择分析工具3.设置分析参数4.收集数据5.数据分析6.制定优化方…

2024上海国际智慧城市展览会(世亚智博会)智慧城市,数字中国

在数字化、智能化的时代背景下&#xff0c;智慧城市成为了全球瞩目的焦点。而作为智慧城市领域的重要盛会&#xff0c;2024上海国际智慧城市展览会&#xff08;简称&#xff1a;世亚智博会&#xff09;则将再次汇聚全球目光。此次展览将于2024年3月26日至28日在上海跨国采购会展…

解决java.lang.IllegalArgumentException: servlet映射中的<url pattern>[demo1]无效

当我使用tomcat启动使用servlet项目时&#xff0c;出现了报错&#xff1a; java.lang.IllegalArgumentException: servlet映射中的<url pattern>[demo1]无效 显示路径错误&#xff0c;于是去检查Web.xml中的配置&#xff0c;发现是配置文件的路径写错了&#xff0c;少写了…

【Python第三方包】快速获取硬件信息和使用情况(psutil、platform)

文章目录 前言一、psutil包1.1 安装psutil包1.2 psutil 使用方式获取CPU使用率获取内存使用情况将内存的获取的使用情况变成GB和MB获取磁盘使用情况磁盘内存进行转换获取网络信息网络info 二、platform2.1 platform的介绍2.2 platform 使用方式获取操作系统的名称获取架构的名称…

unapp项目发布h5 详细操作流程以及注意事项 (hash模式)

首先需要在manifest.json文件中的web配置中 这里因为公司项目都是hash模式 所以写的./ 接下来看源码视图会发现多了一个配置项&#xff1a; 接下来点击hbx上面的 发行》网站-PC Web或手机H5(仅适用于uni-app)(H) 此时查看控制台会显示打包后的存放路径 接下来就直接给后端同…

Windows下Redis3.0主从模式架构搭建

redis版本&#xff1a;Redis-x64-3.0.504 复制相同文件 修改文件夹下redis.windows.conf 文件配置(注意&#xff1a;主有密码&#xff0c;从必须有密码且跟主相同) 修改端口&#xff1a; 主库&#xff1a;端口号6379 从库1&#xff1a;修改端口号为6380 从库2&#xff1a;修…

金融用户实践|分布式存储支持数据仓库业务系统性能验证

作者&#xff1a;深耕行业的 SmartX 金融团队 闫海涛 估值是指对资产或负债的价值进行评估的过程&#xff0c;这对于投资决策具有重要意义。每个金融公司资管业务人员都期望能够实现实时的业务估值&#xff0c;快速获取最新的数据和指标&#xff0c;从而做出更明智的投资决策。…

【学习笔记】RabbitMQ01:基础概念认识以及快速部署

参考资料 RabbitMQ官方网站RabbitMQ官方文档噼咔噼咔-动力节点教程 文章目录 一、认识RabbitMQ1.1 消息中间件&#xff08;MQ Message Queue 消息队列1.2 主流的消息中间件1.3 MQ的应用场景1.3.1 异步处理1.3.2 系统解耦1.3.3 流量削峰1.3.4 日志处理 二、RabbitMQ运行环境搭建…

Windows10不常用操作(录屏、开启超级管理员、关闭自动IP配置、Edge崩溃等)

Win10家庭版开启超级管理员 Win10家庭版开启或禁用超级管理员账户步骤如下&#xff1a; 在搜索框中输入CMD&#xff0c;右键以管理员方式运行。 开启 net user administrator /active:yes禁用 net user administrator /active:no Win10关闭自动IP配置 win10设置完静态ip&am…

微服务架构 | 超时管理

INDEX LSA 级别与全年停机时间速查表LSA 级别实战TP 性能超时时间设计原则 LSA 级别与全年停机时间速查表 计算公式&#xff1a;60 * 60 * 24 * 365 * (1-LSA) 31,536,000‬ * (1-LSA) 系统级别LSA级别全年停机时间099.999%5分钟099.99%52分钟199.9%8.8小时299%3.65 天 LSA…

QT学习day1

一、思维导图 二、作业&#xff1a;实现登录界面 #include "widget.h" #include<QDebug> #include<QIcon>Widget::Widget(QWidget *parent): QWidget(parent) {/**********************窗口******************///设置窗口图标this->setWindowTitle…

C++多线程编程(第四章 案例1,C++11和C++17 多核并行计算样例)

目录 4.1手动实现多核base16编码4.1.1 实现base16编码4.1.2无多线程代码4.1.3 C 11多线程代码4.1.4 C 17多线程并发4.1.5 所有测试代码汇总 4.1手动实现多核base16编码 4.1.1 实现base16编码 二进制转换为字符串 一个字节8位&#xff0c;拆分为两个4位字节&#xff08;最大值…

产品经理必备的14款需求管理工具推荐!

产品管理需求在产品经理的日常工作中扮演着至关重要的角色&#xff0c;这一关键任务为产品开发工作和资源投入提供了坚实的基础&#xff0c;它是创造杰出产品的必不可少前提。 面对各式各样的需求&#xff0c;产品经理可以使用专业的需求管理工具来进行集中收集和管理&#xf…

VulnHub Alice

一、信息收集 发现开发了22、80 2.访问ip&#xff0c;右击查看源代码 发现需要利用X-Forwarded-For 火狐插件&#xff1a;X-Forwarded-For Header 挂上代理后&#xff1a; 出现以下页面&#xff1a; 先注册一个账户&#xff0c;然后再登录 发现有参数进行传参 发现传参&a…

网站如何有效防止网络攻击

互联网上的网站和应用程序受到各种威胁&#xff0c;如黑客、恶意软件和数据泄漏。因此&#xff0c;了解如何解决网站被攻击的问题至关重要。本文将介绍一些简单的步骤&#xff0c;帮助您提高您的网站的安全性。 确认攻击 要解决网站被攻击的问题&#xff0c;首先需要识别是否遭…

MES管理系统的设计与实施

随着制造业的快速发展&#xff0c;MES生产管理系统逐渐成为企业提高生产效率和管理水平的重要工具。然而&#xff0c;在实施MES管理系统的过程中&#xff0c;如何确保其有效性和可持续性成为了一个亟待解决的问题。本文将从以终为始、自我完善与适应变化三个方面探讨MES管理系统…

数据结构与算法课后题-第五章(树、森林)

1、 2、 3、 4、 5、 6、 7、 8、 9、

Studio One6.5最新版本新增了对Linux的支持

音乐制作人们&#xff0c;这是你们翘首以待的消息。数字音频工作站&#xff08;DAW&#xff09;已经成为音乐制作专业人士重要工具之一。 遗憾的是&#xff0c;对于 Linux 用户而言&#xff0c;选择十分有限。最受欢迎的选择通常是开源 DAW&#xff0c;如 Ardour、Audacity和闭…

SSM - Springboot - MyBatis-Plus 全栈体系(二十九)

第六章 SpringBoot 五、SpringBoot3 整合 MyBatis 1. MyBatis 整合步骤 导入依赖&#xff1a;在您的 Spring Boot 项目的构建文件&#xff08;如 pom.xml&#xff09;中添加 MyBatis 和数据库驱动的相关依赖。例如&#xff0c;如果使用 MySQL 数据库&#xff0c;您需要添加 …

Pulsar Manager配置自定义认证插件访问

Pulsar Manager配置自定义认证插件访问 Pulsar Manager和dashboard部署和启用认证 pulsar自定义认证插件开发 前面博客讲了以token方式访问pulsar 这节博客讲如何配置自定义认证插件的方式访问pulsar #启动pulsar-manager docker run --name pulsar-manager -dit \-p 9527:…