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

news2025/1/14 2:41:34

瑞芯微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;
  }
  // 初始化tasklet
  tasklet_init(&mytasklet, mytasklet_func, 1);
  return 0;
}
// 模块退出函数
static void interrupt_irq_exit(void)
{

  free_irq(irq, NULL);
  tasklet_enable(&mytasklet); // 使能tasklet(可选)
  tasklet_kill(&mytasklet);   // 销毁tasklet
  printk("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.coloradmin.cn/o/1029911.html

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

相关文章

债券风险价值类

声明 本文是学习GB-T 42815-2023 债券价格指标产品描述规范. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了债券价格指标产品各要素的定义、范围、框架及输出口径。 本文件适用于债券价格指标产品的编制发布机构及使用机构。 …

Rsync学习笔记1

企业架构Web服务器的文件及时同步&#xff1a; 1&#xff09;能够理解为何要服务器的文件同步&#xff1b; 2&#xff09;能够简单描述实现文件同步的几种方式&#xff1b; 3&#xff09;能够实现服务器文件实时同步的案例&#xff1b; 服务器同步文件的必要性&#xff1a; …

求二维子数组的和(剖析)

文章目录 &#x1f412;个人主页&#x1f3c5;JavaSE系列专栏&#x1f4d6;前言&#xff1a;本篇剖析一下二维子数组求和规则&#xff1a; &#x1f412;个人主页 &#x1f3c5;JavaSE系列专栏 &#x1f4d6;前言&#xff1a;本篇剖析一下二维子数组求和 规则&#xff1a; 这…

阿里员工曝光,跳槽提供流水,将28K改成38K,成功率高吗?

在这位员工的曝光中&#xff0c;他声称通过提供虚假简历&#xff0c;将自己的工作经验和技能水平夸大&#xff0c;以获得更高的薪资。此外&#xff0c;他还提供了虚假的流水&#xff0c;使自己的收入看起来更高。然而&#xff0c;这一行为无疑是违反道德和诚信原则的&#xff0…

向表中针对全部列插入数据

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法格式: insert into 表名 values(); 我们来查看test01表里面有几列 mysql> show databases; -------------------- | Database …

学习记忆——宫殿篇——记忆宫殿——记忆桩——学校

教室 桶 走道 桌子 暖气 窗台 后背 窗帘 监视器 白盒子 教师 讲台 表 投影仪 音响 窗 喇叭 黑板 门 栏杆 椅子 食堂 桶 刷卡器 柱子 桌子 风扇 灯罩 一列椅子 地面 大门空间 电视 活动室 盘子 纸盒 油桶 称 水桶 展牌 帘子 消防栓 毯子 储物箱 宿舍 梯子 坐垫 挂件 吊兰 君子…

zabbix学习3--zabbix6.x-proxy

文章目录 proxy proxy # 安装mysql 8.0# 获取源码包【https://www.zabbix.com/cn/download_sources】 mkdir -p /data/zabbix_proxy/{data,install,logs,php} mkdir -p /var/run/zabbix_proxy tar xf zabbix-6.4.3.tar.gz -C /data/zabbix_proxy/install/ cd /data/zabbix_pro…

华为坤灵再上新,助力中小企业转型“易”见未来

中小企业&#xff0c;堪称国民经济发展的毛细血管&#xff0c;数量众多、分布广泛却又无比重要。 随着数字经济成为各行各业的主战场&#xff0c;数字化转型已是中小企业打开高质量发展之门的那把关键钥匙。《数字中国建设整体布局规划》就明确指出&#xff0c;推动数字技术和…

argparse的用法

目录 一、使用argparse 二、参数详解 参考 一、使用argparse argparse 模块是 Python 内置的用于命令项选项与参数解析的模块&#xff0c;argparse 模块可以让人轻松编写用户友好的命令行接口&#xff0c;能够帮助程序员为模型定义参数。 argparse定义包括四个步骤&#xff…

线路中故障电弧产生了应该如何治理?-安科瑞黄安南

故障电弧的危害 故障电弧是指由于电气线路或设备中绝缘老化破损、电气连接松动、空气潮湿、电压电流急剧升高等原因引起空气击穿所导致的气体游离放电现象。故障电弧发生时&#xff0c;其中心温度可高达3000 ℃左右&#xff0c;并伴随有金属喷溅物&#xff0c;足以引燃任何可燃…

【AD】【规则设置】关于绿色报错的消除

关于绿色报错的消除 1、打开 在上面工具栏的 Tools - Design Rule Checker2、这两列&#xff0c;分别右键 选择 Batch DRC - All Off 取消掉所有的打钩3、再点击左侧的Electrical 把右边的这几个都打钩 每天进步一点点 如果我的学习记录有帮到你&#xff0c;可否赏点买辣条的钱…

提高接口自动化测试效率:使用 JMESPath 实现断言和数据提取!

前言 做接口自动化&#xff0c;断言是比不可少的。如何快速巧妙的提取断言数据就成了关键&#xff0c;当然也可以提高用例的编写效率。笔者在工作中接触到了JMESPath&#xff0c;那到底该如何使用呢&#xff1f;带着疑惑一起往下看。 JMESPath是啥&#xff1f; JMESPath 是一…

安达发APS|生产计划部门如何提升产量?

在当下制造业中&#xff0c;生产计划的制定和执行对于提高产量、降低成本、保证交货期等方面具有重要意义。随着科技的发展&#xff0c;越来越多的企业开始使用APS生产排程软件来优化生产计划&#xff0c;提高生产效率。本文将从以下几个方面介绍如何利用APS生产排程软件提升产…

外滩大会观察|重估蚂蚁!

点击关注 文丨刘雨琦&#xff0c;编丨王一粟 “不同品种的小狗排队通过‘实名认证’、刷脸识别不仅能识别人&#xff0c;还能识别狗”。“人脸、虹膜、掌纹都已经不算黑科技&#xff0c;脑纹识别才是真的不可替代。” 2023年上海外滩大会上&#xff0c;6G、无人安全检测实验室…

学Python的漫画漫步进阶 -- 第十四步.网络通信

学Python的漫画漫步进阶 -- 第十四步.网络通信 十四、网络通信14.1 基本的网络知识14.1.1 TCP/IP14.1.2 IP地址14.1.3 端口14.1.4 HTTP/HTTPS 14.2 搭建自己的Web服务器14.3 urllib.request模块14.3.1 发送GET请求14.3.2 发送POST请求 14.4 JSON数据14.4.1 JSON文档的结构14.4.…

方案:TSINGSEE青犀智能分析网关皮带撕裂算法的场景应用

在工地矿山等现实场景中&#xff0c;皮带运输在生产过程中是必不可少的&#xff0c;然而&#xff0c;由于长时间高强度的运转&#xff0c;皮带很容易发生撕裂、破损、跑偏等问题。这些问题会严重影响生产速度&#xff0c;甚至会导致严重的安全事故。为了有效预防此类安全事故发…

短视频抖音账号矩阵系统源码开发者自研(四)

抖音是一款备受欢迎的短视频APP&#xff0c;拥有数亿的用户&#xff0c;其中包括了大量的粉丝。为了让更多的人能够发现和观看到你的视频&#xff0c;抖音SEO是必不可少的一环&#xff0c;特别是对于拥有企业或个人品牌的用户来说。在这个过程中&#xff0c;抖音SEO源码的开源部…

不要动 WindowsApps 文件夹的权限以及更新 win10 版本

前言&#xff1a; 先简单说几句&#xff0c;本来打算开始写论文的&#xff0c;装个 mathtype 到 word 中&#xff0c;word 的安装路径在 WindowsApps 文件夹中&#xff0c;修改权限后导致 wsl 不能使用、微软自带的软件报错&#xff08;参数错误&#xff09;以及微软商店不能使…

区块链交易平台开发流程

随着区块链技术的日益发展&#xff0c;越来越多的金融机构和创业公司开始探索开发区块链交易平台的潜力。以下是一篇关于区块链交易平台开发流程的指南。 一、理解区块链技术 在开发区块链交易平台之前&#xff0c;必须深入理解区块链技术的内在机制和原理。区块链是一…

大数据之-Flink学习笔记

Flink Apache Flink — 数据流上的有状态计算。 Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算处理。 任何类型的数据都以事件流的形式生成。信用卡交易、传感器测量、机器日志或网站或移动应用程序 2上的用户交互&#xff0c;…