C++编程:嵌入式Linux-ARM与外设中断交互的程序设计

文章目录

    • 0. 引言
    • 1. 设备与处理器中断交互机制
      • 1.1 交互时序图
      • 1.2 时序图说明
      • 1.3 用户空间中断处理方法
    • 2. 中断模块设计要点
    • 3. 代码说明
      • 3.1 `Interrupts` 类
      • 3.2 中断处理
      • 3.3 `start` 方法

0. 引言

本文介绍在 Linux-ARM 系统中利用中断与外设(如 DSP、DAC、扫描仪等)交互的模块,实现低延迟的中断响应服务。外设通过 UIO 驱动暴露 /dev/uio 设备节点,用户空间程序可以通过这些节点来处理中断。

本方案将使用到select,select的高效使用请:Linux编程:使用 select高效的 UART 通信

1. 设备与处理器中断交互机制

  • 设备侧(裸机程序/外设)

    • 当设备完成任务或发生事件时,触发硬件中断信号。
    • 中断信号通过硬件线路发送至中断控制器。
  • 处理器侧(运行操作系统)

    • 中断控制器接收信号,判断中断类型和优先级。
    • 操作系统内核处理并调度相应的中断服务程序(ISR)。
    • ISR 可能位于内核空间,也可能通过 /dev/uio 让用户空间程序处理。

1.1 交互时序图

设备 (裸机程序/外设) 中断控制器 处理器 (操作系统) 中断服务程序 设备运行裸机程序/外设 传递中断信号 发送中断请求 (IRQ) 中断处理入口 调用中断服务程序 (ISR) 处理中断事件 中断处理完成 通知中断处理完成 中断响应完成 设备继续执行 设备 (裸机程序/外设) 中断控制器 处理器 (操作系统) 中断服务程序

1.2 时序图说明

  • 设备触发中断:设备触发硬件中断信号,中断信号通过中断线传递给控制器
  • 中断控制器处理:控制器生成中断请求并发送给处理器。
  • 处理器接收中断:操作系统接收到中断请求并暂停当前任务。
  • 调用 ISR:操作系统调用对应的中断服务程序(ISR)。
  • 处理中断:ISR 执行预定义的处理逻辑。
  • 中断处理完成:ISR 处理完毕后,返回内核。
  • 通知控制器:处理器通知中断控制器处理完成。
  • 设备继续执行:设备得到响应后继续运行。

1.3 用户空间中断处理方法

在用户空间处理中断时,通常使用 UIO(Userspace I/O)机制。设备驱动将中断映射到 /dev/uioX 设备文件,用户空间程序通过 select 等系统调用来等待并处理中断。

// 用户空间中断处理示例
int fd = open("/dev/uio0", O_RDWR);
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN;while (true) {int ret = poll(&fds, 1, -1);if (ret > 0) {uint32_t info;read(fd, &info, sizeof(info));  // 读取中断信息// 处理中断事件// ...// 重新使能中断write(fd, &info, sizeof(info));}
}

2. 中断模块设计要点

中断管理模块的设计包括以下要点:

  1. 线程优先级设置:使用 sched_setscheduler 设置线程的优先级和调度策略。
  2. 实时线程:通过 SCHED_FIFOSCHED_RR 确保线程能够及时获得 CPU 时间片。
  3. 中断信号处理:确保实时线程能够正确处理中断信号,避免任务被不必要地打断。

以下展示了如何通过 /dev/uio 设备文件接收中断,并利用 select 等待中断。

#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
#include <thread>
#include <sched.h>
#include <sys/types.h>
#include <pthread.h>class Interrupts {public:// 构造函数,初始化成员变量Interrupts();// 中断初始化int init();// 启动中断处理线程void start();// 注册中断并连接到回调函数int registerInterrupt(const std::string& interrupt_name, std::function<void(void)> interrupt_handler);// 等待中断事件int waitForInterrupt();// 处理中断事件int processInterrupts();private:// 保存文件描述符与回调函数的映射std::unordered_map<int, std::function<void(void)>> interrupt_handlers_;// 最大文件描述符int max_interrupt_fd_;// 文件描述符集合fd_set master_set_;fd_set backup_set_;// 实时线程优先级static constexpr int kInterruptThreadPriority = 50;  // 设置线程优先级,假设为50(越高越优先)
};// 构造函数,初始化成员变量
Interrupts::Interrupts() : max_interrupt_fd_(-1) {FD_ZERO(&master_set_);FD_ZERO(&backup_set_);
}// 初始化中断源
int Interrupts::init() {std::function<void(void)> dma_handler = []() {fprintf(stdout, "DMA interrupt triggered!\n");};if (registerInterrupt("dma_irq", dma_handler) < 0) {fprintf(stderr, "Failed to register DMA interrupt!\n");return -1;}return 0;
}// 注册中断
int Interrupts::registerInterrupt(const std::string& interrupt_name, std::function<void(void)> interrupt_handler) {std::string interrupt_path = "/dev/" + interrupt_name;int fd = open(interrupt_path.c_str(), O_RDWR);if (fd < 0) {fprintf(stderr, "Failed to open interrupt device: %s\n", interrupt_path.c_str());return -1;  // 打开文件失败}uint32_t info = 1;  // 解锁中断if (write(fd, &info, sizeof(info)) != sizeof(info)) {fprintf(stderr, "Failed to unlock interrupt: %s\n", interrupt_path.c_str());close(fd);return -1;  // 写入失败}FD_SET(fd, &master_set_);if (fd > max_interrupt_fd_) {max_interrupt_fd_ = fd;}interrupt_handlers_[fd] = interrupt_handler;return 0;
}// 设置线程的调度策略和优先级
void Interrupts::setThreadPriority() {struct sched_param param;param.sched_priority = kInterruptThreadPriority;// 设置调度策略为 FIFOif (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {fprintf(stderr, "Failed to set thread priority!\n");exit(1);  // 设置失败,退出程序}
}// 等待中断事件
int Interrupts::waitForInterrupt() {backup_set_ = master_set_;if (select(max_interrupt_fd_ + 1, &backup_set_, nullptr, nullptr, nullptr) < 0) {if (errno != EINTR) {fprintf(stderr, "Error in select() while waiting for interrupt\n");return -1;  // select 出错}return 0;  // 被信号中断,继续等待}return 0;
}// 处理中断事件
int Interrupts::processInterrupts() {// 遍历所有已注册的中断处理器for (auto& entry : interrupt_handlers_) {int fd = entry.first;if (FD_ISSET(fd, &backup_set_)) {uint32_t info;if (read(fd, &info, sizeof(info)) != sizeof(info)) {fprintf(stderr, "Failed to read interrupt data from fd: %d\n", fd);continue;  // 读取失败,跳过此中断}entry.second();  // 调用中断处理器info = 1;  // 解除中断屏蔽if (write(fd, &info, sizeof(info)) != sizeof(info)) {fprintf(stderr, "Failed to write interrupt data back to fd: %d\n", fd);}}}return 0;
}// 启动中断处理线程
void Interrupts::start() {// 设置当前线程的优先级setThreadPriority();// 启动一个循环处理while (true) {if (waitForInterrupt() == 0) {if (processInterrupts() != 0) {fprintf(stderr, "Error processing interrupts\n");}}}
}

3. 代码说明

3.1 Interrupts

  • 构造函数 (Interrupts):初始化文件描述符集合和最大文件描述符。
  • init:初始化中断源,例如为 DMA 注册中断。
  • registerInterrupt:通过 /dev/uioX 设备文件注册外设中断,解除中断屏蔽并存储回调函数。
  • waitForInterrupt:通过 select 等待中断事件发生。
  • processInterrupts:处理触发的中断事件,调用对应的回调函数。

3.2 中断处理

当 DMA 中断触发时,会调用 dma_handler 来处理。例如,打印 "DMA interrupt triggered!"

3.3 start 方法

start 方法通过 sched_setschedulerSCHED_FIFO 设置线程优先级。它启动一个循环来等待中断并处理。

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

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

相关文章

Scala 的包及其导入

Scala使用包来创建用于模块化程序的命名空间。通过在Scala文件的顶部声明一个或多个包名称可以创建包&#xff0c;另一种声明包的方式是使用0&#xff0c;这种方式可以嵌套包&#xff0c;并且提供更好的范围与封装控制。对于包的导入&#xff0c;Scala与Java的区别之一便是&…

使用 HuggingFace 提供的 Elasticsearch 托管交叉编码器进行重新排名

作者&#xff1a;来自 Elastic Jeff Vestal 了解如何使用 Hugging Face 的模型在 Elasticsearch 中托管和执行语义重新排序。 在这篇简短的博文中&#xff0c;我将向你展示如何使用 Hugging Face 中的模型在搜索时在你自己的 Elasticsearch 集群中执行语义重新排序。我们将使用…

深究JS底层原理

一、JS中八种数据类型判断方法 在JavaScript中&#xff0c;数据类型分为两大类&#xff1a;基本&#xff08;原始&#xff09;数据类型和引用&#xff08;对象&#xff09;数据类型。 基本数据类型&#xff08;Primitive Data Types&#xff09; 基本数据类型是表示简单的数…

C++虚继承演示

在继承中如果出现&#xff1a; 这种情况&#xff0c;B和C都继承了A&#xff0c;D继承了B、C 在D中访问A的成员会出现&#xff1a; 这样的警告 是因为在继承时A出现两条分支&#xff1a;ABD、ACD 编译器不知道访问的A中的元素是经过B继承还是C继承 所以B、C在继承A时要用到…

【1】虚拟机安装

1.安装VMware WorkStation Pro VMware下载地址&#xff1a; 密钥&#xff1a;YF390-0HF8P-M81RQ-2DXQE-M2UT6 2.新建虚拟机 centos7下载地址&#xff1a;centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云

【机器学习】均方误差根(RMSE:Root Mean Squared Error)

均方误差根&#xff08;Root Mean Squared Error&#xff0c;RMSE&#xff09;是机器学习和统计学中常用的误差度量指标&#xff0c;用于评估预测值与真实值之间的差异。它通常用于回归模型的评价&#xff0c;以衡量模型的预测精度。 RMSE的定义与公式 给定预测值 和实际值 …

python可视化进阶

引用&#xff1a; 首先需要安装 plotnine from plotnine import* import joypy数据可视化进阶操作 3.1 类别数据可视化 【例3-1】——绘制简单条形图 【代码框3-1】——绘制简单条形图 # 图3-1的绘制代码 import pandas as pd import matplotlib.pyplot as plt from cvxpy …

玩的花,云产品也能拼团了!!!

说起拼单大家都不陌生&#xff0c;电商一贯的营销手段&#xff0c;不过确实可以给消费者省下一笔钱。双11到了&#xff0c;腾讯云产品也玩起了拼团&#xff0c;这明显是对开发人员和各企业的福利。 对于有云产品需求的个人或企业&#xff0c;这次绝对是难得的一次薅羊毛机会。…

设计模式-七个基本原则之一-开闭原则 + SpringBoot案例

开闭原则:(SRP) 面向对象七个基本原则之一 对扩展开放&#xff1a;软件实体&#xff08;类、模块、函数等&#xff09;应该能够通过增加新功能来进行扩展。对修改关闭&#xff1a;一旦软件实体被开发完成&#xff0c;就不应该修改它的源代码。 要看实际场景&#xff0c;比如组内…

Flutter 插件 sliding_up_panel 实现从底部滑出的面板

前言 sliding_up_panel 是一个 Flutter 插件&#xff0c;用于实现从底部滑出的面板。它在设计上非常灵活&#xff0c;能够适应多种 UI 场景&#xff0c;比如从底部滑出的菜单、可拖动的弹出面板等。以下是 sliding_up_panel 的详细用法&#xff0c;包括常用的参数说明和示例代…

出海企业如何借助云计算平台实现多区域部署?

云计算de小白 如需进一步了解&#xff0c;请单击链接了解有关 Akamai 云计算的更多信息 在本文中我们将告诉大家如何在Linode云计算平台上借助VLAN快速实现多地域部署。 首先我们需要明确一些基本概念和思想&#xff1a; 部署多区域 VLAN 为了在多区域部署中在不同的 VLAN …

Linux(CentOS)安装 JDK

CentOS版本&#xff1a;CentOS 7 JDK版本&#xff1a;JDK17 1、下载 JDK 官网&#xff1a;https://www.oracle.com/ 2、上传 JDK 文件到 CentOS 使用FinalShell远程登录工具&#xff0c;并且使用 root 用户连接登录&#xff08;注意这里说的root用户连接登录是指这样的&…

多边形电子围栏算法

在日常生活工作中&#xff0c;我们经常接触到电子围栏&#xff0c;大部分的电子围栏基本上都是圆形的&#xff0c;想要知道某一个点是否在圆形区域内&#xff0c;算法很简单&#xff0c;只需要知道这个圆形区域的圆心坐标和被测点的坐标的距离是否小于半径即可。两点的距离小于…

柯桥学日语J.TEST考试是什么?J.TEST考试报名

J.TEST考试是什么&#xff1f; J.TEST全称为实用日本语鉴定考试&#xff0c;在2007年获得了国家劳动和社会保障部的认可&#xff0c;作为面对母语为非日本语的人员进行的日本语能力测试&#xff0c;J.TEST被越来越多的日本企业所认可&#xff0c;由于其对日语的实际运用能力具有…

谈谈ssh-keygen进行多host配置及使用

背景 传统的Telnet、FTP协议都是使用明文传输数据&#xff0c;存在一定的安全风险&#xff0c;如果传输数据被截取&#xff0c;可能造成数据泄露风险&#xff0c;尤其对于敏感数据&#xff0c;泄露造成的损失无法估计。最近公司、github等平台都不再支持http方式进行代码下载工…

谷粒商城-高级篇-认证服务

1、环境搭建 1、创建gulimall-auth-server模块 2、导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schem…

独显装完ubuntu后启动黑屏显示/dev/sda:clean files blocks的解决方案

解决方案如下&#xff1a; 选中Ubuntu按E键 在编辑界面倒数第2行的linux那行&#xff08;后面有quiet splash选项&#xff09;的最后添加nomodeset 然后按F10保存重启 然后管理员权限打开/etc/modprobe.d/blacklist.conf&#xff0c;在文件末尾添加&#xff1a; blacklist…

ArcGIS 地理信息系统 任意文件读取漏洞复现

0x01 产品简介 ArcGIS是由美国Esri公司研发的地理信息系统(GIS)软件,它整合了数据库、软件工程、人工智能、网络技术、云计算等主流的IT技术,旨在为用户提供一套完整的、开放的企业级GIS解决方案,它包含了一套带有用户界面组件的Windows桌面应用。可以实现从简单到复杂的…

Linux 系统结构

Linux系统一般有4个主要部分&#xff1a;内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构&#xff0c;它们使得用户可以运行程序、管理文件并使用系统。 1. linux内核 内核是操作系统的核心&#xff0c;具有很多最基本功能&#xff0c;它…

SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”

SLF4J常见问题 1、SLF4J简介2、SLF4J实现原理3、SLF4J常见问题 1、SLF4J简介 SLF4J&#xff08;Simple Logging Facade for Java&#xff09;是一个为Java程序提供日志输出的统一接口&#xff0c;并不具备具体的日志实现方案&#xff0c;类似JDBC&#xff0c;SLF4J只做两件事&a…