1. 程式人生 > >Linux 高精度定時器hrtimers簡單介紹和應用場景

Linux 高精度定時器hrtimers簡單介紹和應用場景

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亮度有些不穩定。(此外還有一種方法是啟動一個執行緒,來同步產生控制訊號)