Linux 高精度定时器hrtimers简单介绍和应用场景

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/armwind/article/details/78317176

hrtimer:high-resolution kernel timers:

  hrtimers的诞生是由于内核开发者在使用过程中发现,原始的定时器kernel/timers.c,已经可以满足所有场景的,但是在实际的大量测试中发现还是无法满足所有场景,所以hrtimers就诞生了。这里简单介绍下关键结构体和一个应用场景,具体远离下篇博客再来分析。

1.结构体简单介绍

1.struct hrtimer

这个是高精度对象的成员变量,内核注释已经很详细了,具体细节下篇来说,这里重点关注的是function,这个是我们需要实现的方法。

/**
 * struct hrtimer - the basic hrtimer structure
 * @node:   timerqueue node, which also manages node.expires,
 *      the absolute expiry time in the hrtimers internal
 *      representation. The time is related to the clock on
 *      which the timer is based. Is setup by adding
 *      slack to the _softexpires value. For non range timers
 *      identical to _softexpires.
 * @_softexpires: the absolute earliest expiry time of the hrtimer.
 *      The time which was given as expiry time when the timer
 *      was armed.
 * @function:   timer expiry callback function
 * @base:   pointer to the timer base (per cpu and per clock)
 * @state:  state information (See bit values above)
 * @start_pid: timer statistics field to store the pid of the task which
 *      started the timer
 * @start_site: timer statistics field to store the site where the timer
 *      was started
 * @start_comm: timer statistics field to store the name of the process which
 *      started the timer
 *
 * The hrtimer structure must be initialized by hrtimer_init()
 */
struct hrtimer {
    struct timerqueue_node      node;
    ktime_t             _softexpires;
    enum hrtimer_restart        (*function)(struct hrtimer *);
    struct hrtimer_clock_base   *base;
    unsigned long           state;
#ifdef CONFIG_TIMER_STATS
    int             start_pid;
    void                *start_site;
    char                start_comm[16];
#endif
};

2.ktime_t

这个用来表示时间,单位为纳米。在启动定时器之前,需要设定一个时间来决定何时调用回调函数。

typedef union ktime ktime_t;

/*
 * ktime_t:
 *
 * A single 64-bit variable is used to store the hrtimers
 * internal representation of time values in scalar nanoseconds. The
 * design plays out best on 64-bit CPUs, where most conversions are
 * NOPs and most arithmetic ktime_t operations are plain arithmetic
 * operations.
 *
 */
union ktime {
    s64 tv64;
};

2.hrtimers应用场景

1).创建定时器对象&设置首次触发时间

最近在做一个Camera的flash驱动,该camera需要pwm来控制亮度,而硬件上该GPIO口,没有pwm功能,所以只能来模拟pwm了。

本地flash控制对象中嵌套的有hrtimer对象:

struct flash_gpio_ctrl {
    struct hrtimer *flash_timer;
    ktime_t kt;
    int flash_level;
    int IsFlash_stop;
    int loop_count;
    uint32_t gpio_enf;
    uint32_t gpio_enm; //pwm
};

创建定时器以及启动定时器:

static void flash_pwm_start(void)
{
    hrtimer_init(flash_gpio_ctrl.flash_timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
    flash_gpio_ctrl.flash_timer->function = hrtimer_handler;                                                                                                                    
    flash_gpio_ctrl.kt = ktime_set(0, 10000);
    hrtimer_start(flash_gpio_ctrl.flash_timer,flash_gpio_ctrl.kt,HRTIMER_MODE_REL);
    pr_err("timer_start");
}
  • 1.hrtimer_init:这个是用来创建timer定时器对象,由内核封装好了,具体细节先不用关系,只需要把定时器对象嵌套进我们定义的结构体中就行了。

  • 2.function:这个就是回调函数指针,这里注册回调函数。

  • 3.ktime_set(0, 10000):设置首次触发时间,这里我设置了10ms。

  • 4.hrtimer_start();这里传入定时器对象,和触发时间,就开启定时器了。

2).回调函数预览

static enum hrtimer_restart  hrtimer_handler(struct hrtimer *timer)
{
    flash_flag = !flash_flag;

    gpio_direction_output(flash_gpio_ctrl.gpio_enm, 0);
    if(flash_gpio_ctrl.loop_count != 1){
        if (flash_flag) {
            gpio_direction_output(flash_gpio_ctrl.gpio_enm, 1);
            flash_gpio_ctrl.kt = ktime_set(0, BASE_TIME * (flash_gpio_ctrl.flash_level) * 1000);
            hrtimer_forward_now(flash_gpio_ctrl.flash_timer, flash_gpio_ctrl.kt);
            //pr_err("pulse low level:%d",flash_gpio_ctrl.flash_level);
        } else {
            gpio_direction_output(flash_gpio_ctrl.gpio_enm, 0);
            flash_gpio_ctrl.kt = ktime_set(0, 50000 - (BASE_TIME * (flash_gpio_ctrl.flash_level) * 1000));
            hrtimer_forward_now(flash_gpio_ctrl.flash_timer, flash_gpio_ctrl.kt);
            //pr_err("pulse high levle");
        }
        flash_gpio_ctrl.loop_count--;
        pr_err("flash_timer out\n");
        return HRTIMER_RESTART;
    }else{
        flash_gpio_ctrl.loop_count--;
        return HRTIMER_NORESTART;
    }
}
  • 1.loop_count:这里我设置的是一个循环触发的定时器,所以为了不让定时器无休止的进行下去,设置一个触发次数。次数减为0,则推出定时器。

  • 2.HRTIMER_RESTART:这个返回值告诉定时器核心,这里是定时器会重新触发,而且上面又重新设置了触发的时间。

  • 3.hrtimer_forward_now:重新设置定时器触发的时间。

至此定时器就已经运行起来了,每割一定时间都会触发回调函数。而且产生的pwm能使flash亮起来,但是由于占空比不是很准确,所以flash亮度有些不稳定。(此外还有一种方法是启动一个线程,来同步产生控制信号)

猜你喜欢

转载自blog.csdn.net/armwind/article/details/78317176
今日推荐