fmql之Linux内核定时器

news2024/9/29 7:12:02

内容依然来自于正点原子。

Linux内核时间管理

内容包括:

  • 系统频率设置
  • 节拍率:高节拍率的优缺点
  • 全局变量jiffies
  • 绕回的概念(溢出)
  • API函数(处理绕回)

HZ为每秒的节拍数

Linux内核定时器

内容包括:

  • 内核定时器的使用:设置超时时间
  • 内核定时器特点:超时后会自动关闭
  • timer_list结构体表示内核定时器,expires成员变量为超时时间(单位为节拍数),function为定时处理函数
  • 初始化定时器的API函数
  • 内核定时器的使用流程代码

Linux内核短延时函数

代码

timer.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/kern_levels.h>
// #include <linux/semaphore.h>

#define LED_COUNT 		1			// 设备个数
#define LED_NAME		"led"		// 设备名称

/* ioctl函数命令定义 */
#define CMD_LED_CLOSE	(_IO(0xEF,0x1))		/* turn off led */
#define CMD_LED_OPEN	(_IO(0xEF,0x2))		/* turn on led */
#define CMD_SET_PERIOD	(_IO(0xEF,0x3))		/* set LED闪烁频率 */

struct led_dev {
	dev_t	devid;				// 设备号
	struct	cdev	cdev;		// cdev
	struct	class	*class;		// class
	struct	device	*device;	// devie
	int		major;				// major
	int		minor;				// minor
	struct	device_node	*nd;	// device_node
	int		led_gpio;			// led_gpio

	int			period;				/* period (ms) */
	struct		timer_list	timer;	/* timer */
	spinlock_t	spinlock;			/* spinlock */
};

static struct led_dev led;

static int led_open(struct inode * inode, struct file *filp){
	return 0;
}

static ssize_t led_read(struct file *filp, char __user *buf,
			size_t cnt, loff_t *offt){
	return 0;
}

static ssize_t led_write(struct file *filp, char __user *buf,
			size_t cnt, loff_t *offt){
	return 0;
}

static int led_release(struct inode * inode, struct file *filp){
	return 0;
}

/* ioctl函数 */
static long led_unlocked_ioctl(struct file *filp, unsigned int cmd,
			unsigned long arg){
	unsigned long flags;

	spin_lock_irqsave(&led.spinlock, flags);		// 自旋锁上锁

	switch(cmd){	// 应用程序发来的命令
		case CMD_LED_CLOSE:
			del_timer_sync(&led.timer);
			gpio_set_value(led.led_gpio, 0);
			break;

		case CMD_LED_OPEN:
			del_timer_sync(&led.timer);
			gpio_set_value(led.led_gpio, 1);
			break;

		case CMD_SET_PERIOD:
			led.period = arg;
			mod_timer(&led.timer, jiffies + msecs_to_jiffies(arg));
			break;

		default:
			break;
	}

	spin_unlock_irqrestore(&led.spinlock, flags);	// 自旋锁解锁
	
	return 0;
}

static struct file_operations led_fops = {		// 设备操作函数
	.owner		= THIS_MODULE,
	.open		= led_open,
	.release	= led_release,
	.read		= led_read,
	// .write		= led_write,
	.unlocked_ioctl	= led_unlocked_ioctl,		/* ioctl函数 */
};

/*  定时器回调函数 */
static void led_timer_function(struct timer_list *unused){
	static bool on = 1;
	unsigned long flags;

	on = !on;		/* 取反,实现LED反转 */

	spin_lock_irqsave(&led.spinlock, flags);	// 上锁

	gpio_set_value(led.led_gpio, on);			// 设置led-gpio电平状态

	/* 重启timer */
	mod_timer(&led.timer, jiffies + msecs_to_jiffies(led.period));

	spin_unlock_irqrestore(&led.spinlock, flags);	// 解锁
}

static int __init led_init(void){
	int ret = 0;
	int val;
	const char *str;

	spin_lock_init(&led.spinlock);				// 初始化自旋锁

	led.nd = of_find_node_by_path("/led3");		// 获取设备节点
	if(led.nd == NULL){
		printk(KERN_ERR "key: Failed to get led node\r\n");
		return -EINVAL;
	} 

	ret = of_property_read_string(led.nd, "status", &str);		// 获取status属性
	if(!ret){
		if(strcmp(str, "okay"))
			return -EINVAL;
	}

	ret = of_property_read_string(led.nd, "compatible", &str);	// 获取compatible属性
	if(ret < 0){
		printk(KERN_ERR "led: Failed to get compatible property\r\n");
		return -EINVAL;
	}

	if(strcmp(str, "fmql,led")){		// 匹配compatible属性
		printk(KERN_ERR "led: compatible math failed\r\n");
		return -EINVAL;
	}

	printk(KERN_INFO "led: device matches succeed\r\n");

	led.led_gpio = of_get_named_gpio(led.nd, "led-gpio", 0);	// 获取led使用的gpio编号
	if(!gpio_is_valid(led.led_gpio)){
		printk(KERN_ERR "led: Failed to get led-gpio\r\n");
		return -EINVAL;
	}

	printk(KERN_INFO "led: led-gpio num = %d\r\n", led.led_gpio);

	ret = gpio_request(led.led_gpio, "LED GPIO");	// 向GPIO子系统申请使用GPIO
	if(ret){
		printk(KERN_ERR "led: Failed to request led-gpio\r\n");
		return ret;
	}

	ret = of_property_read_string(led.nd, "default-state", &str);	// 设置led初始状态
	if(!ret){
		if(!strcmp(str, "on"))
			val = 1;
		else
			val = 0;
	} else 
		val = 0;
	gpio_direction_output(led.led_gpio, val);

	/* 注册字符设备驱动 */
	if(led.major){		// 创建设备号
		led.devid = MKDEV(led.major, 0);
		ret = register_chrdev_region(led.devid, LED_COUNT, LED_NAME);
		if(ret)
			goto out1;
	} else {
		ret = alloc_chrdev_region(&led.devid, 0, LED_COUNT, LED_NAME);
		if(ret)
			goto out1;
		led.major = MAJOR(led.devid);
		led.minor = MINOR(led.devid);
	}
	printk(KERN_INFO "led: major = %d, minor = %d\r\n", led.major, led.minor);

	led.cdev.owner = THIS_MODULE;
	cdev_init(&led.cdev, &led_fops);	// 初始化cdev
	ret = cdev_add(&led.cdev, led.devid, LED_COUNT);	// 添加cdev
	if(ret)
		goto out2;
	
	led.class = class_create(THIS_MODULE, LED_NAME);	// 创建类
	if(IS_ERR(led.class)){
		ret = PTR_ERR(led.class);
		goto out3;
	}

	led.device = device_create(led.class, NULL, led.devid, NULL, LED_NAME);	//创建设备
	if(IS_ERR(led.device)){
		ret = PTR_ERR(led.device);
		goto out4;
	}

	/* 初始化timer
	 * 绑定function函数
	 * 未设置周期:不会激活timer
	 */
	timer_setup(&led.timer, led_timer_function, 0);

	return 0;

out4:
	class_destroy(led.class);
out3:
	cdev_del(&led.cdev);
out2:
	unregister_chrdev_region(led.devid, LED_COUNT);
out1:
	gpio_free(led.led_gpio);

	return ret;
}

static void __exit led_exit(void){

	/* delete timer */
	del_timer_sync(&led.timer);

	// 注销: 设备,类,cdev,设备号
	// 释放GPIO
	device_destroy(led.class, led.devid);
	class_destroy(led.class);
	cdev_del(&led.cdev);
	unregister_chrdev_region(led.devid, LED_COUNT);
	gpio_free(led.led_gpio);
}

module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("Skylar <Skylar@33.com>");
MODULE_DESCRIPTION("FMQL Timer");
MODULE_LICENSE("GPL");

timerAPP.c

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

/* ioctl命令 */
#define CMD_LED_CLOSE	(_IO(0xEF,0x1))
#define CMD_LED_OPEN	(_IO(0xEF,0x2))
#define CMD_SET_PERIOD	(_IO(0xEF,0x3))

/*
 * @description         : main主程序
 * @param - argc        : argv数组元素个数
 * @param - argv        : 具体参数
 * @return              : 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, ret;
	unsigned int cmd;
	unsigned int period;

	/* 传递两个参数 */
	if(argc != 2){
		printf("Usage:\n"
				"\t.timerAPP /dev/key @ open LED device\n"
				);
		return -1;
	}

	fd = open(argv[1], O_RDWR);
	if(fd < 0){
		printf("ERROR: %s file open failed\r\n", argv[1]);
		return -1;
	}

	/* 通过命令控制LED设备 */
	for(;;){
		printf("Input CMD:");
		scanf("%d", &cmd);

		switch(cmd){
			case 0:
				cmd = CMD_LED_CLOSE; 
				break;

			case 1:
				cmd = CMD_LED_OPEN;
				break;

			case 2:
				cmd = CMD_SET_PERIOD;
				printf("Input Timer Period:");
				scanf("%d",&period);
				break;
		
			case 3:
				close(fd);
				return 0;

			default:
				//cmd = CMD_LED_CLOSE;
				break;
		}

		ioctl(fd, cmd, period);
	}

	//close(fd);
	//return 0;
}


运行结果

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

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

相关文章

3-1.Android Fragment 之创建 Fragment

Fragment Fragment 可以视为 Activity 的一个片段&#xff0c;它具有自己的生命周期和接收事件的能力&#xff0c;它有以下特点 Fragment 依赖于 Activity&#xff0c;不能独立存在&#xff0c;Fragment 的生命周期受 Activity 的生命周期影响 Fragment 将 Activity 的 UI 和…

BUUCTF蜘蛛侠呀

解压后发现是流量包&#xff0c;好多icmp包 发现icmp包尾部有$$STRAT打头16进制的字符串&#xff0c;好多重复得。我们只需要提取尾部这些字符串是当icmp的type0时上图标识为褐色的字符串&#xff0c;还需要把16进制的字符串转为对应的字符串&#xff08;bytes 类型&#xff09…

YOLOv8改进 | 融合篇,YOLOv8主干网络替换为MobileNetV3+CA注意机制+添加小目标检测层(全网独家首发,实现极限涨点)

原始 YOLOv8 训练结果: YOLOv8 + MobileNetV3改进后训练结果: YOLOv8 + MobileNetV3 + CA 注意机制 + 添加小目标检测层改进后训练结果(极限涨点): 摘要 小目标检测难点众多,导致很多算法对小目标的检测效果远不如大中型目标。影响算法性能的主要原因如下:第一,小目…

Windows暂停更新

目录 前言注册表设定参考 前言 不想Windows自动更新&#xff0c;同时不想造成Windows商店不可用&#xff0c;可以采用暂停更新的方案。 但是通过这里设定的时间太短了&#xff0c;所以我们去注册表设定。 注册表设定 win r 输入 regedit进入注册表 HKEY_LOCAL_MACHINE\SOFT…

python 02 List

Python 1-14 列表 第一课 1437. 是否所有 1 都至少相隔 k 个元素 class Solution:def kLengthApart(self, nums: List[int], k: int) -> bool:cnt k # 处理第一个 1for i, x in enumerate(nums):if x 1:if cnt < k: return Falsecnt 0 # 遇到 1 从新记数else: cnt …

解决银河麒麟V10中/data目录执行权限问题

解决银河麒麟V10中/data目录执行权限问题 1、问题描述2、解决方案步骤一&#xff1a;编辑fstab文件步骤二&#xff1a;重启系统步骤三&#xff1a;验证更改 3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在使用银河麒麟桌面操作系…

【零散技术】Odoo PDF 打印问题问题合集

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo PDF打印 是一个必备功能&#xff0c;但是总会遇到一些奇奇怪怪的问题&#xff0c;此帖仅做记录&#xff0c;方便查阅。 目录 1、样式丢失 2、部分结构丢失 3、没有中文字体 1、样式丢失 这种情况一般是由于 …

YOLOv8 Windows c++推理

#添加一个**yolov8\_。onx **和/或**yolov5\_。Onnx **模型(s)到ultralytics文件夹。 #编辑**main.cpp**来改变**projectBasePath**来匹配你的用户。#请注意&#xff0c;默认情况下&#xff0c;CMake文件将尝试导入CUDA库以与opencv dnn (cuDNN) GPU推理一起使用。 #如果你的Op…

【Power Query】三大容器及元素提取

三大容器 Table; List; Record 表 &#xff08;Table&#xff09;&#xff1a; Table一般是从外部导入的 如果非要手动生成&#xff0c;可以这样&#xff1a; #table({"学号","姓名","平时分"},{{1,"Alice",99},{2,"Beige&quo…

Nacos 是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台,旨在帮助开发者更轻松地构建、部署和管理微服务应用。

Nacos 是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台&#xff0c;旨在帮助开发者更轻松地构建、部署和管理微服务应用。Nacos 提供了一系列的功能来支持服务注册与发现、配置管理、服务元数据管理、流量管理、服务健康检查等&#xff0c;是构建云原生应用和服务网…

【C++】— 类和对象(2)

文章目录 &#x1f49e;1.类的默认成员函数&#x1f49e;2.构造函数&#x1f49e;3.析构函数&#x1f49e;4.拷贝构造函数&#x1f49e;5.赋值运算符重载&#x1f49e;5.1 运算符重载&#x1f49e;5.2 赋值运算符重载 &#x1f49e;6.取地址运算符重载&#x1f49e;6.1const成员…

中国算力大会启幕,联想发布异构智算产业创新成果

9月27日&#xff0c;2024中国算力大会在河南郑州拉开帷幕。作为全球领先的算力基础设施和服务提供商&#xff0c;联想集团参会参展并携手异构智算产业联盟承办2024异构智算产业生态联盟技术论坛。 据「TMT星球」了解&#xff0c;论坛发布了新一代AI服务器、AI应用部署解决方案…

如何用AI完成毕业论文

一、利用 AI 辅助资料收集 AI 可以帮助你快速搜索大量与毕业论文相关的资料&#xff0c;节省时间和精力。 writehelp智能写作辅导&#xff1a;http://www.writehelp.vip/?sid17&#xff0c;限时免费提供开题报告、任务书和答辩PPT。 二、借助 AI 生成提纲 它能根据你的研究主…

【C++】继承,菱形继承,虚拟继承,组合详解

目录 1. 继承概念与定义 1.1 概念 1.2 定义 2. 父类与子类的赋值规则 3. 继承的作用域 4. 子类的默认成员函数 5. 继承与友元 6. 继承与静态成员 7. 菱形继承 7.1 继承关系 7.2 菱形继承的问题 7.3 虚拟继承 8. 继承与组合 1. 继承概念与定义 1.1 概念 1. 继承&a…

基于SpringCloud的微服务架构下安全开发运维准则

为什么要进行安全设计 微服务架构进行安全设计的原因主要包括以下几点&#xff1a; 提高数据保护&#xff1a;微服务架构中&#xff0c;服务间通信频繁&#xff0c;涉及到大量敏感数据的交换。安全设计可以确保数据在传输和存储过程中的安全性&#xff0c;防止数据泄露和篡改。…

物联网迎来下半场,国产 IoTOS 打造企业级智能硬件云服务平台

如有需求&#xff0c;文末联系小编 氦氪云 IoTOS 是一套先进的企业级物联网解决方案平台&#xff0c;为万物互联提供可靠安全稳定的终端接入、协议适配、消息路由、数据存储和分析、应用使能等核心功能。面向物联网领域中的终端设备商、系统集成商、应用服务商、能力提供商等&a…

定积分中静水压力问题

静水压力与定积分 静水压力问题是定积分在物理学中的一个重要应用。它利用积分的思想&#xff0c;将一个复杂的、连续变化的压力分布问题转化为一系列微小压力单元的累加&#xff0c;最终求出总压力。 基本原理&#xff1a; 静水压力是指静止液体对浸在其中的物体表面所施加…

BUG——IMX6ULL编译正点原子Linux内核报错

最初编译的是正点原子改过的Linux内核&#xff0c;可能是版本问题&#xff0c;一直报错&#xff0c;无法成功编译。然后换成NXP官方Linux内核6.6版本&#xff0c;初始编译虽然也报各种错&#xff0c;但都是缺少库或相关工具&#xff0c;全部安装后就可以成功编译出镜像了&#…

【RocketMQ】MQ与RocketMQ介绍

&#x1f3af; 导读&#xff1a;本文介绍了消息队列&#xff08;MQ&#xff09;的基本概念及其在分布式系统中的作用&#xff0c;包括实现异步通信、削峰限流和应用解耦等方面的优势&#xff0c;并对ActiveMQ、RabbitMQ、RocketMQ及Kafka四种MQ产品进行了对比分析&#xff0c;涵…