2025-03-27
Linux hrtimer(高分辨率定时器)是Linux内核提供的一种高精度定时机制,用于支持微秒(μs)甚至纳秒(ns)级别的定时操作,相比传统的定时器(如timer_list
)具有更高的精度和灵活性。
高分辨率:基于硬件时钟(如 TSC、HPET),提供纳秒级精度,适用于实时性要求高的场景。传统定时器(如jiffies)依赖系统tick,精度通常为毫秒(ms)级。
动态时钟基础:使用CLOCK_MONOTONIC
或CLOCK_REALTIME
等时间源,避免系统时间调整带来的影响。
灵活的回调机制:通过回调函数执行定时任务,支持单次触发或周期性触发。
可扩展性:适用于内核驱动、调度器、性能分析等需要高精度定时的场景。
// test.dts
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
// 模拟数据
gpioe:gpio@50006000 {
#gpio-cells = <0x2>;
reg = <0x50006000 0x4 0x50006014 0x4 0x50000a28 0x4>;
};
breathing_led {
compatible = "breathing-led-001";
breathing-led-gpios = <&gpioe 10 0>;
status = "okay";
};
};
// simple.c
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#define PLATFORM_DEVICE_BASENAME "my_device"
#define PLATFORM_DEVICE_NAME_PWM "breathing-led-001"
static int gpio_id;
static u32 duty_ns; // 占用比
static u32 period_ns; // 周期
static ktime_t jifies; // 超时时间
static struct hrtimer timer; // 产生超时时钟
static struct work_struct work; // 工作队列
static enum hrtimer_restart _hrtiemr_cb(struct hrtimer *timer) {
schedule_work(&work);
return HRTIMER_NORESTART;
}
static void _work_cb(struct work_struct *work) {
static u32 counter = 0;
counter++;
if (counter >= period_ns) {
counter = 0;
}
// 通过占空比调整led亮度
if (counter < duty_ns) {
gpio_set_value(gpio_id, 1);
} else {
gpio_set_value(gpio_id, 0);
}
// 将定时器的超时时间延后,并重新开始定时器
hrtimer_forward_now(&timer, jifies);
hrtimer_start(&timer, jifies, HRTIMER_MODE_REL);
}
static int _probe(struct platform_device *device) {
pr_info("platform_driver_probe\n");
gpio_id = of_get_named_gpio(device->dev.of_node, "breathing-led-gpios", 0);
if (gpio_id < 0) {
pr_err("of_get_named_gpio failed\n");
return -ENODEV;
}
devm_gpio_request(&device->dev, gpio_id, "breathing-led-gpios");
gpio_direction_output(gpio_id, 0);
gpio_set_value(gpio_id, 0);
// 初始化高级定时器
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
// 设置定时器超时时间, 每1微秒执行1次回调函数
jifies = ktime_set(0, 1000);
// 超时回调函数
timer.function = _hrtiemr_cb;
// 初始化工作队列
INIT_WORK(&work, _work_cb);
// 占空比为60%
period_ns = 1000000; // 1毫秒
duty_ns = min(60 * 10000, period_ns);
hrtimer_start(&timer, jifies, HRTIMER_MODE_REL);
return 0;
}
// 当平台设备驱动卸载时,会自动调用该函数
static int _remove(struct platform_device *device) {
pr_info("platform_driver_remove\n");
hrtimer_cancel(&timer);
gpio_set_value(gpio_id, 0);
cancel_work_sync(&work);
return 0;
}
// 会与设备树安装的platform_device进行匹配(一般用在嵌入式linux开发中)
struct of_device_id of_node_match_table[] = {
[0] = {.compatible = PLATFORM_DEVICE_NAME_PWM}, [1] = {}, // 空元素代表结束
};
struct platform_driver my_platform_driver = {
.probe = _probe,
.remove = _remove,
// 通过id_table匹配, 实现一个驱动对多个设备
.driver =
{
.name = PLATFORM_DEVICE_BASENAME,
// 设备树的匹配方式
.of_match_table = of_node_match_table,
},
};
static int __init pwm_driver_init(void) {
pr_info("pwm_driver_init\n");
int ret = platform_driver_register(&my_platform_driver);
if (ret < 0) {
pr_err("platform_driver_register failed\n");
return -1;
}
return 0;
}
static void __exit pwm_driver_exit(void) {
pr_info("pwm_driver_exit\n");
platform_driver_unregister(&my_platform_driver);
}
module_init(pwm_driver_init);
module_exit(pwm_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("heng30");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple pwm_driver kernel module");
#!/bin/sh
top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build
obj-m += simple.o
all: dt driver
driver:
make -C $(kernel-dir) modules M=$(top-dir)
dt:
dtc -@ -I dts -O dtb -o test.dtbo test.dts
clean:
rm -f *.o *.ko *.mod *.mod.c *.order *.symvers *.dtbo
make -C $(kernel-dir) clean m=$(top-dir)