RK3568驱动指南|第五期-中断-

瑞芯微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主板


第41章 中断下文tasklet实验 

在上一个章节中,我们申请GPIO中断,使用的是request_irq,但是request_irq绑定的中断服务程序指的是中断上文。在之前的中断视频中讲解了:中断分为俩个部分——中断上文和中断下文。本章节我们来学习中断下文的一种实现方式——tasklet。

41.1 什么是tasklet

在Linux内核中,tasklet是一种特殊的软中断机制,被广泛用于处理中断下文相关的任务。它是一种常见且有效的方法,在多核处理系统上可以避免并发问题。Tasklet绑定的函数在同一时间只能在一个CPU上运行,因此不会出现并发冲突。然而,需要注意的是,tasklet绑定的函数中不能调用可能导致休眠的函数,否则可能引起内核异常。

在Linux内核中,tasklet结构体的定义位于include/linux/interrupt.h头文件中。其原型如下:

struct tasklet_struct {struct tasklet_struct *next;unsigned long state;atomic_t count;void (*func)(unsigned long);unsigned long data;
};
typedef struct tasklet_struct tasklet_t;

tasklet_struct结构体包含以下成员:

  • next:指向下一个tasklet的指针,用于形成链表结构,以便内核中可以同时管理多个tasklet。
  • state:表示tasklet的当前状态。
  • count:用于引用计数,用于确保tasklet在多个地方调度或取消调度时的正确处理。
  • func:指向tasklet绑定的函数的指针,该函数将在tasklet执行时被调用。
  • data:传递给tasklet绑定函数的参数

此外,为了方便,还定义了tasklet_t类型作为struct tasklet_struct的别名。这样我们可以使用tasklet_t来声明tasklet变量,而不是直接使用struct tasklet_struct。

41.2 tasklet相关接口函数

41.2.1 静态初始化函数

在Linux内核中,有一个用于静态初始化tasklet的宏函数:DECLARE_TASKLET。这个宏函数可以帮助我们更方便地进行tasklet的静态初始化。

宏函数的原型如下:

#define DECLARE_TASKLET(name,func,data) \
struct tasklet_struct name = { NULL,0,ATOMIC_INIT(0),func,data} 

其中,name是tasklet的名称,func是tasklet的处理函数,data是传递给处理函数的参数。

初始化状态为使能状态。

如果tasklet初始化函数为非使能状态,使用以下宏定义:

#define DECLARE_TASKLET_DISABLED(name,func,data) \
struct tasklet_struct name = { NULL,0,ATOMIC_INIT(1),func,data} 

其中,name是tasklet的名称,func是tasklet的处理函数,data是传递给处理函数的参数。

初始化状态为非使能状态。

下面是一个示例,展示了如何使用DECLARE_TASKLET宏函数进行tasklet的静态初始化:

#include <linux/interrupt.h>// 定义tasklet处理函数
void my_tasklet_handler(unsigned long data)
{// Tasklet处理逻辑// ...
}// 静态初始化tasklet
DECLARE_TASKLET(my_tasklet, my_tasklet_handler, 0);
// 驱动程序的其他代码

在上述示例中,my_tasklet是tasklet的名称,my_tasklet_handler是tasklet的处理函数,0是传递给处理函数的参数。但是需要注意的是,使用DECLARE_TASKLET静态初始化的tasklet无法在运行时动态销毁,因此在不需要tasklet时,应该避免使用此方法。如果需要在运行时销毁tasklet,应使用tasklet_init和tasklet_kill函数进行动态初始化和销毁,接下来我们来学习动态初始化函数。

41.2.2 动态初始化函数

  在Linux内核中,可以使用tasklet_init函数对tasklet进行动态初始化。该函数原型为:

void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data);

其中,t是指向tasklet结构体的指针,func是tasklet的处理函数,data是传递给处理函数的参数

以下是一个示例,tasklet_init函数进行动态初始化如下所示:

#include <linux/interrupt.h>// 定义tasklet处理函数
void my_tasklet_handler(unsigned long data)
{// Tasklet处理逻辑// ...
}// 声明tasklet结构体
static struct tasklet_struct my_tasklet;// 初始化tasklet
tasklet_init(&my_tasklet, my_tasklet_handler, 0);
// 驱动程序的其他代码

在示例中,我们首先定义了my_tasklet_handler作为tasklet的处理函数。然后,声明了一个名为my_tasklet的tasklet结构体。接下来,通过调用tasklet_init函数,进行动态初始化。

通过使用tasklet_init函数,我们可以在运行时动态创建和初始化tasklet。这样,我们可以根据需要灵活地管理和控制tasklet的生命周期。在不再需要tasklet时,可以使用tasklet_kill函数进行销毁,以释放相关资源。

41.2.3 关闭函数

在Linux内核中,可以使用tasklet_disabled函数来关闭一个已经初始化的tasklet。该函数的原型如下:

void tasklet_disable(struct tasklet_struct *t);

其中,t是指向tasklet结构体的指针。

以下是一个示例,使用tasklet_disable函数来关闭tasklet。

#include <linux/interrupt.h>// 定义tasklet处理函数
void my_tasklet_handler(unsigned long data)
{// Tasklet处理逻辑// ...
}
// 声明tasklet结构体
static struct tasklet_struct my_tasklet;
// 初始化tasklet
tasklet_init(&my_tasklet, my_tasklet_handler, 0);
// 关闭tasklet
tasklet_disable(&my_tasklet);
// 驱动程序的其他代码

在上述示例中,我们首先定义了my_tasklet_handler作为tasklet的处理函数。然后,声明了一个名为my_tasklet的tasklet结构体,并使用tasklet_init函数对其进行初始化。最后,通过调用tasklet_disable函数,我们关闭了my_tasklet。

关闭tasklet后,即使调用tasklet_schedule函数触发tasklet,tasklet的处理函数也不会再被执行。这可以用于临时暂停或停止tasklet的执行,直到再次启用(通过调用tasklet_enable函数)。

需要注意的是,关闭tasklet并不会销毁tasklet结构体,因此可以随时通过调用tasklet_enable函数重新启用tasklet,或者调用tasklet_kill函数来销毁tasklet。

41.2.4 使能函数

在Linux内核中,可以使用tasklet_enable函数来使能(启用)一个已经初始化的tasklet。该函数的原型如下

void tasklet_disable(struct tasklet_struct *t);

其中,t是指向tasklet结构体的指针。

以下是一个示例,展示如何使用tasklet_enable函数来使能tasklet:

#include <linux/interrupt.h>
// 定义tasklet处理函数
void my_tasklet_handler(unsigned long data)
{// Tasklet处理逻辑// ...
}// 声明tasklet结构体
static struct tasklet_struct my_tasklet;// 初始化tasklet
tasklet_init(&my_tasklet, my_tasklet_handler, 0);// 使能tasklet
tasklet_enable(&my_tasklet);
// 驱动程序的其他代码

在上述示例中,我们首先定义了my_tasklet_handler作为tasklet的处理函数。然后,声明了一个名为my_tasklet的tasklet结构体,并使用tasklet_init函数对其进行初始化。最后,通过调用tasklet_enable函数,我们使能(启用)了my_tasklet。

使能tasklet后,如果调用tasklet_schedule函数触发tasklet,则tasklet的处理函数将会被执行。这样,tasklet将开始按计划执行其处理逻辑。

需要注意的是,使能tasklet并不会自动触发tasklet的执行,而是通过调用tasklet_schedule函数来触发。同时,可以使用tasklet_disable函数来临时暂停或停止tasklet的执行。如果需要永久停止tasklet的执行并释放相关资源,则应调用tasklet_kill函数来销毁tasklet。

41.2.5 调度函数

在Linux内核中,可以使用tasklet_schedule函数来调度(触发)一个已经初始化的tasklet执行。该函数的原型如下:

void tasklet_schedule(struct tasklet_struct *t);

其中,t是指向tasklet结构体的指针。

以下是一个示例,展示如何使用tasklet_schedule函数来调度tasklet执行:

#include <linux/interrupt.h>
// 定义tasklet处理函数
void my_tasklet_handler(unsigned long data)
{	// Tasklet处理逻辑// ...
}// 声明tasklet结构体
static struct tasklet_struct my_tasklet;// 初始化tasklet
tasklet_init(&my_tasklet, my_tasklet_handler, 0);
// 调度tasklet执行
tasklet_schedule(&my_tasklet);
// 驱动程序的其他代码

在上述示例中,我们首先定义了my_tasklet_handler作为tasklet的处理函数。然后,声明了一个名为my_tasklet的tasklet结构体,并使用tasklet_init函数对其进行初始化。最后,通过调用tasklet_schedule函数,我们调度(触发)了my_tasklet的执行。

需要注意的是,调度tasklet只是将tasklet标记为需要执行,并不会立即执行tasklet的处理函数。实际的执行时间取决于内核的调度和处理机制。

41.2.6 销毁函数

在Linux内核中,可以使用tasklet_kill函数来销毁一个已经初始化的tasklet,释放相关资源。该函数的原型如下:

void tasklet_kill(struct tasklet_struct *t);

其中,t是指向tasklet结构体的指针。

以下是一个示例,展示如何使用tasklet_kill函数来销毁tasklet:

#include <linux/interrupt.h>// 定义tasklet处理函数
void my_tasklet_handler(unsigned long data)
{	// Tasklet处理逻辑// ...
}// 声明tasklet结构体
static struct tasklet_struct my_tasklet;// 初始化tasklet
tasklet_init(&my_tasklet, my_tasklet_handler, 0);
tasklet_disable(&my_tasklet);// 销毁tasklet
tasklet_kill(&my_tasklet);// 驱动程序的其他代码

在上述示例中,我们首先定义了my_tasklet_handler作为tasklet的处理函数。然后,声明了一个名为my_tasklet的tasklet结构体,并使用tasklet_init函数对其进行初始化。最后,通过调用tasklet_kill函数,我们销毁了my_tasklet。

调用tasklet_kill函数会释放tasklet所占用的资源,并将tasklet标记为无效。因此,销毁后的tasklet不能再被使用。

需要注意的是,在销毁tasklet之前,应该确保该tasklet已经被停止(通过调用tasklet_disable函数)。否则,销毁一个正在执行的tasklet可能导致内核崩溃或其他错误。

一旦销毁了tasklet,如果需要再次使用tasklet,需要重新进行初始化(通过调用tasklet_init函数)。在下一小节中我们将使用上述tasklet函数相关接口函数进行相应的实验。

41.3 实验程序的编写

41.3.1 驱动程序编写

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

本实验将实现注册显示屏触摸中断,每按当触摸LCD显示屏就会触发中断服务函数,在中断服务函数中调度中断下文tasklet处理函数,打印“This id test_interrupt”和“data is 1”。

在驱动程序中的模块初始化函数中,我们将GPIO转换为中断号,并使用request_irq函数请求中断,然后对tasklet进行初始化。在中断处理函数中,我们调度tasklet执行,使得当中断触发时,tasklet会被调度执行。在模块退出函数中,我们释放中断资源,并使能tasklet销毁tasklet。

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

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
// #include <linux/delay.h>int irq;
struct tasklet_struct mytasklet;// 定义tasklet处理函数
void mytasklet_func(unsigned long data)
{printk("data is %ld\n", data);// msleep(3000);
}// 中断处理函数
irqreturn_t test_interrupt(int irq, void *args)
{printk("This id test_interrupt\n");tasklet_schedule(&mytasklet); // 调度tasklet执行return IRQ_RETVAL(IRQ_HANDLED);
}
// 模块初始化函数
static int interrupt_irq_init(void)
{int ret;irq = gpio_to_irq(101); // 将GPIO转换为中断号printk("irq is %d\n", irq);// 请求中断ret = request_irq(irq, test_interrupt, IRQF_TRIGGER_RISING, "test", NULL);if (ret < 0){printk("request_irq is error\n");return -1;}// 初始化tasklettasklet_init(&mytasklet, mytasklet_func, 1);return 0;
}
// 模块退出函数
static void interrupt_irq_exit(void)
{free_irq(irq, NULL);tasklet_enable(&mytasklet); // 使能tasklet(可选)tasklet_kill(&mytasklet);   // 销毁taskletprintk("bye bye\n");
}module_init(interrupt_irq_init); // 指定模块的初始化函数
module_exit(interrupt_irq_exit); // 指定模块的退出函数MODULE_LICENSE("GPL");   // 模块使用的许可证
MODULE_AUTHOR("topeet"); // 模块的作者

41.4 运行测试

41.4.1 编译驱动程序

在上一小节中的interrupt.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:对于Makefile的内容注释已在上图添加,保存退出之后,来到存放interrupt.c和Makefile文件目录下,如下图(图41-1)所示:

图 41-1

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

图 41-2

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

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

41.4.2 运行测试

开发板启动之后,使用以下命令进行驱动模块的加载,如下图(图 41-4)所示:

insmod interrupt.ko

图 41-4

看到驱动加载之后,可以看到申请的中断号(113)被打印了出来,然后用手触摸连接的LVDS 7寸屏幕,触发中断服务程序,打印如下图(41-5)所示:

图 41-5

在上图中,可以看到打印中断处理函数中添加的打印“This is test_interrupt”和tasklet处理函数中添加的打印“data is 1”,说明成功执行了中断下文tasklet处理函数。

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

rmmod interrupt

 

之前的理论章节我们强调说tasklet函数中不能调用休眠的函数,在此我们在上述驱动实验的基础上实验一下,驱动文件中添加休眠函数,如下(图 41-7)所示:

图 41-7

同理,进行编译驱动模块,卸载掉之前的驱动模块后,加载新编译的驱动模块,如下图(图 41-8)所示:

图 41-8

然后用手触摸连接的LVDS 7寸屏幕,打印如下图(41-9)所示,内核会崩溃。

图 41-9

至此,中断下文tasklet实验就完成了。


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

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

相关文章

瑞芯微:基于RK3568的ocr识别

光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;是指对文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的过程。亦即将图像中的文字进行识别&#xff0c;并以文本的形式返回。OCR的应用场景 卡片证件识别类&#xff1a;大陆、港澳…

如何通过AI视频智能分析技术,构建着装规范检测/工装穿戴检测系统?

众所周知&#xff0c;规范着装在很多场景中起着重要的作用。违规着装极易增加安全隐患&#xff0c;并且引发安全事故和质量问题&#xff0c;例如&#xff0c;在化工工厂中&#xff0c;倘若员工没有穿戴符合要求的特殊防护服和安全鞋&#xff0c;将有极大可能受到有害物质的侵害…

Doxygen在vs code配置

找到这个 就在这里面配置&#xff0c;如果要在原有的下面添加别忘了后面加个逗号&#xff0c;我在他前面加的所以我在上面加了个 //基础设置 “doxdocgen.c.triggerSequence”: “/", “doxdocgen.c.firstLine”: "/", “doxdocgen.c.commentPrefix”: &quo…

〔023〕Stable Diffusion 之 界面主题 篇

✨ 目录 🎈 系统内置主题🎈 kitchen Theme 主题🎈 Catppuccin Theme 主题🎈 Cozy Nest 主题🎈 系统内置主题 可以通过命令行修改主题,在 webui-user.bat 文件中 set COMMANDLINE_ARGS 参数后面添加 --theme dark 来设置深色主题当然,系统设置里面也自带了很多的主题…

C++ 异常处理学习笔记

一、使用情况 1、数组越界&#xff1a;包括数组索引小于0&#xff0c;或者大于数组长度 2、空指针 可以抛出(throw)各种类型的异常&#xff0c;catch的地方接收就可以

一款非常容易上手的报表工具,简单操作实现BI炫酷界面数据展示,驱动支持众多不同类型的数据库,可视化神器,免开源了

一款非常容易上手的报表工具&#xff0c;简单操作实现BI炫酷界面数据展示&#xff0c;驱动支持众多不同类型的数据库&#xff0c;可视化神器&#xff0c;免开源了。 在互联网数据大爆炸的这几年&#xff0c;各类数据处理、数据可视化的需求使得 GitHub 上诞生了一大批高质量的…

for forin forof forEach map区别

一、总结 相同点&#xff1a;都是串行遍历。不同点&#xff1a; 二、for of循环 设计目的&#xff1a;遍历所有数据结构的统一方法。原理&#xff1a;会调用数据结构的Symbol.iterator方法。 只要数据结构定义了Symbol.iterator属性&#xff0c;就能用for of遍历它的成员。…

短剧解说小程序搭建,短剧解说小程序源码

短剧解说小程序搭建&#xff0c;短剧解说小程序源码 可定制开发小程序&#xff0c;H5&#xff0c;APP等系统 有需要可定制可出源码&#xff0c;这个是啥你懂的(VVVVVVVVVVV)&#xff1a;二五四九七八九零五九 需要源码或搭建可看上面的数字信息 短剧解说小程序搭建 小程序使用…

自定义协议、序列化与反序列化

在编写TCP和UDP程序的时候&#xff0c;我们很自然的就使用了读取的函数对数据进行获取&#xff0c;对于UDP来说提供的是无连接的以数据报的形式进行传输&#xff0c;对于TCP来说是面向数据流的&#xff0c;在之前的程序中我们只是进行了读取的操作&#xff0c;但是并没有对读取…

修复Ripro主题扫码后空白或null或array的问题

WordPress Ripro主题使用的人比较多&#xff0c;绝大部分用的盗版主题&#xff0c;RiPro主题使用虎皮椒V3支付接口在使用弹窗支付的时候&#xff0c;微信或者支付宝扫码后出现null或array&#xff0c;会发生在ripro所有版本中。下面是修复方法&#xff1a; 打开ripro主题inc目…

安科瑞为工业能效提升行动计划提供EMS解决方案-安科瑞黄安南

摘要: 2022年6月29日工信部、发改委、财政部、生态环境部、国资委、市场监管总局六部门联合下发《关于印发工业能效提升行动计划的通知》&#xff08;工信部联节〔2022〕76号&#xff0c;以下简称《行动计划》&#xff09;&#xff0c;主要目的是为了提高工业领域能源利用效率&…

Hbase分布式集群部署

目录 一、环境说明 二、部署Hbase 2.1 解压Hbase 2.2 移动解压包 2.3 修改 hbase-env.sh文件 2.4 修改环境变量 2.5 修改hbase-site.xml文件 2.6 修改regionservers 文件 2.7 分发hbase 2.7.1 分发hbase包 2.7.2 分发环境配置 2.8 启动hbase服务 2.8.1 环境生效 …

Tungsten Fabric数据量过大问题处理初探

开源SDN系统Tungsten Fabric面临数据产生过多问题。 经排查&#xff0c;产生数据多出自analytics组件的Cassandra数据库()。很多分析数据会存储至Cassandra库&#xff0c;并持久化处理。 没有特殊调整的话&#xff0c;目录在 /var/lib/docker/volumes/analytics_database_an…

抗锯齿的线

抗锯齿的线 右下角的时候h是0,到顶部 h是1&#xff0c;然后中间y相距4个像素&#xff0c;那dy就是0.25 如果让h abs(fract(h - 0.5) - 0.5) 中间一行0.5&#xff0c;第一行 第三行都是0.25&#xff0c;两端都是0 根据插值来看 这里是 如果用h/dy 那么第一行以上&#xff0…

【ROS入门】创建工作空间与功能包

文章结构 工作空间文件结构创建工作空间流程创建工作空间编译工作空间设置环境变量/创建功能包创建功能包编译功能包 检查环境变量 工作空间文件结构 工作空间(workspace)是一个存放工程开发相关文件的文件夹&#xff0c;类似于在windows中使用IDE创建的工程。主要分为以下四个…

【element-ui】form表单动态修改rules校验项

在项目开发过程中&#xff0c;该页面有暂存和提交两个按钮&#xff0c;其中暂存和提交必填项校验不一样&#xff0c;此时需要动态增减必填项校验 &#xff0c;解决方法如下&#xff1a; 增加rules校验项 this.$set(this.formRules,name,[{required:true,message:请输入名称,t…

Layui快速入门之第十三节 日期与时间选择器

目录 一&#xff1a;基本用法 API 渲染 属性 弹出提示 2.8 获取实例 2.8 解除实例绑定 2.8 关闭日期面板 2.7 获取某月的最后一天 二&#xff1a;常规用法 三&#xff1a;多类型选择器 四&#xff1a;范围选择 五&#xff1a;直接静态显示 六&#xff1a;更多功能…

断点测试怎么做?一文教你用Charles 工具做好接口测试!

在测试工作过程中&#xff0c;我们经常会在程序的某一行或者某一环节设置断点&#xff0c;在程序请求的过程中&#xff0c;修改断点处的参数、请求或者响应&#xff0c;借此定位问题&#xff0c;这就是所谓的断点测试。这类断点测试主要用于接口测试。 断点测试可以通过查看接…

C语言关于自定义字符函数和字符串函数的相关笔试题(找工作必看)

本篇字符函数和字符串函数 求字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数介绍 strncpy strncat strncmp 字符串查找 strstr strtok 错误信息报告 strerror 内存操作函数 memcpy memmove memset memcmp 在我们笔试时&#xff0c;很…

mysql限制用户登录失败次数,限制时间

mysql用户登录限制设置 mysql 需要进行用户登录次数限制,当使用密码登录超过 3 次认证链接失败之后,登录锁住一段时间,禁止登录这里使用的 mysql: 8.1.0 这种方式不用重启数据库. 配置: 首先进入到 mysql 命令行:然后需要安装两个插件: 在 mysql 命令行中执行: mysql> INS…