点击查看代码
/*
* Copyright (C) 2019 BNIS
* 用dmesg -c 查看
* 定时器测试,insmod 模块后,定时器1为每隔1秒钟触发一次!测试显示定时器分辨率精度, 定时器2为每隔2秒触发一次。
* Timer-api查看:
* https://xenomai.org/documentation/xenomai-3/html/xeno3prm/group__rtdm__timer.html
*/
//mydriver.c文件
#include <linux/module.h>
#include <rtdm/driver.h>
#include <rtdm/testing.h>
#define TIME_EXP 500000000ULL //500ms后触发timer1
#define TIME_EXP2 500000000ULL //500ms后触发timer2
#define TIME_INV 1000000000ULL //timer1间隔1000ms
#define TIME_INV2 2000000000ULL //timer2间隔2000ms
#define DEVICE_NAME "bnis_rtdm"
MODULE_DESCRIPTION("RTDM test helper module");
MODULE_AUTHOR("bniss@aliyun.com");
MODULE_VERSION("0.1.0");
MODULE_LICENSE("GPL");
struct rtdm_basic_context {
unsigned long number;
};
rtdm_timer_t test_timer;
long cnt = 0;
uint64_t nanoRead;
rtdm_timer_t test_timer2;
long cnt2 = 0;
static void test_timer_proc(rtdm_timer_t *timer)
{
uint64_t rcd = rtdm_clock_read() ;
if( timer == &test_timer) //定时器1
{
double acy = (rcd-nanoRead)*100.0/TIME_INV ;
printk("#test_timer_proc,cnt1 = %lu.dif = %ld nS, accuracy = %ld /n" ,
cnt++ ,
rcd-nanoRead,
(rcd-nanoRead)*10000/TIME_INV
);
//每次触发定时输出当前时间和上次的时间做差运算,作定时器精度计算。
nanoRead = rcd ;
}else if(timer == &test_timer2){ //定时器2
printk("#test_timer_proc,cnt2 = %lu ,current clock = %ld ",cnt2++ , rcd);
}
}
static int rtdm_bnis_open(struct rtdm_fd *fd, int oflags)
{
通过用户端调用rt_dev_open(DEVICE_NAME,0);触发
printk("#device_bnis is open .flag = %d. /n" , oflags );
return 0;
}
static void rtdm_bnis_close(struct rtdm_fd *fd)
{
通过用户端调用rt_dev_close(DEVICE_NAME);触发
printk("#device_bnis close. /n");
}
static struct rtdm_driver rtdm_bnis_driver = {
.profile_info = RTDM_PROFILE_INFO(rtdm_bnis_basic,
RTDM_CLASS_TESTING,
RTDM_SUBCLASS_RTDMTEST,
RTTST_PROFILE_VER),
.device_flags = RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
.device_count = 2,
.context_size = sizeof(struct rtdm_basic_context),
.ops = {
.open = rtdm_bnis_open,
.close = rtdm_bnis_close,
},
};
static struct rtdm_device myDevice = {
.driver = &rtdm_bnis_driver,
.label = DEVICE_NAME,
};
static int __init rtdm_test_init(void)
{
printk("======init test for rtdm=========/n");
rtdm_dev_register( &myDevice);
//test_timer为定时器句柄用于启停控制
//test_timer_proc为定时过程处理回调函数
rtdm_timer_init(&test_timer, test_timer_proc,"rtdm-timer");
nanoRead = rtdm_clock_read(); //获取当前Unix时间戳,用于时间对比
rtdm_timer_start(&test_timer,TIME_EXP,TIME_INV,RTDM_TIMERMODE_RELATIVE);//采用相对时间模式
//500ms 后触发定时器1,间隔1秒 (with define)
rtdm_timer_init(&test_timer2, test_timer_proc,"rtdm-timer2"); //定时器2和定时器1共用回调处理
rtdm_timer_start(&test_timer2,TIME_EXP+nanoRead,TIME_INV2,RTDM_TIMERMODE_REALTIME);//采用绝对时间戳
return 0;
}
static void __exit rtdm_test_exit(void)
{
printk("=======exit rtdm test =========/n");
rtdm_timer_destroy(&test_timer);//退出前销毁定时器资源
rtdm_timer_destroy(&test_timer2);
rtdm_dev_unregister(&myDevice); //注销设备释放资源
}
module_init(rtdm_test_init);
module_exit(rtdm_test_exit);
##################################################
xenomai3定时器api分析:
1)rtdm时钟函数与cobalt时钟函数对应
rtdm_clock_read()<=>xnclock_read_realtime()
rtdm_clock_read_monotonic()<=>xnclock_read_monotonic();
2)定时器启动函数原型:
int rtdm_timer_start(rtdm_timer_t *timer, nanosecs_abs_t expiry,
nanosecs_rel_t interval, enum rtdm_timer_mode mode);
第1参数timer为定时器句柄,用于定时器的启停控制.
第2参数expiry为定时器执行有效期,即从调用到首次触发执行的时长,时间单位纳秒.
第3参数interval为定时器循环间隔,若设置为0则执行一次定时.
第4参数interval为定时器模式,有3模式,分别为 RTDM_TIMERMODE_RELATIVE ,RTDM_TIMERMODE_ABSOLUTE ,RTDM_TIMERMODE_REALTIME.
3)定时器模式介绍:
RTDM_TIMERMODE_RELATIVE,此模式下首次触发执行的时间点相对于调用rtdm_timer_start().
RTDM_TIMERMODE_ABSOLUTE ,此模式下首次触发执行的时间点基于系统运行时间,用函数rtdm_clock_read_monotonic()获取.
RTDM_TIMERMODE_REALTIME,此模式下首次触发执行的时间点绝对的Unix时间戳,可用函数rtdm_clock_read()获取.此模式适合用于指定XX时XX分XX秒执行任务.
4)定时器回调处理函数原型static void (*handler)(rtdm_timer_t *timer), 对于多个定时器的处理方法,在初始化定时器时可指定同一个回调函数,在回调函数里通过结构体指针timer地址来区分是哪个定时器句柄触发.
##########内核层Makefile文件##############################
————————————————
版权声明:本文为CSDN博主「wabil」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wabil/article/details/104022708
点击查看代码
###### CONFIGURATION ######
### List of modules to be build
MODULES = mydriver
###### KERNEL MODULE BUILD (no change required normally) ######
ifneq ($(MODULES),)
### Default to sources of currently running kernel
KSRC ?= /lib/modules/$(shell uname -r)/build
OBJS := ${patsubst %, %.o, $(MODULES)}
CLEANMOD := ${patsubst %, .%*, $(MODULES)}
PWD := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
### Kernel 2.6 or 3.0
PATCHLEVEL:=$(shell sed 's/PATCHLEVEL = /(.*/)//1/;t;d' $(KSRC)/Makefile)
VERSION:=$(shell sed 's/VERSION = /(.*/)//1/;t;d' $(KSRC)/Makefile)
ifneq ($(VERSION).$(PATCHLEVEL),2.4)
obj-m := $(OBJS)
EXTRA_CFLAGS := -I$(KSRC)/include/xenomai -I$(KSRC)/include/xenomai/posix $(ADD_CFLAGS)
all::
$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules
@echo `date` "===========Finish-1===================="
### Kernel 2.4
else
ARCH ?= $(shell uname -i)
INCLUDE := -I$(KSRC)/include/xenomai -I$(KSRC)/include/xenomai/compat -I$(KSRC)/include/xenomai/posix
CFLAGS += $(shell $(MAKE) -s -C $(KSRC) CC=$(CC) ARCH=$(ARCH) SUBDIRS=$(PWD) modules) $(INCLUDE)
all:: $(OBJS)
@echo `date` "===========Finish-2===================="
endif
## Target for capturing 2.4 module CFLAGS
modules:
@echo "$(CFLAGS)"
clean::
$(RM) $(CLEANMOD) *.o *.ko *.mod.c Module*.symvers Module.markers modules.order
$(RM) -R .tmp*
endif
原创文章,作者:254126420,如若转载,请注明出处:https://blog.ytso.com/271878.html