我想使用hrtimer
來控制兩個硬件gpio引腳,以實現一些總線信號。我成立了一個hrtimer內核模塊在這樣爲什麼我的hrtimer回調在轉發之後返回太早?
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#define PIN_A_HIGH_TO_A_LOW_US 48 /* microseconds */
#define PIN_A_LOW_TO_B_LOW_US 24 /* microseconds */
static struct kt_data {
struct hrtimer timer;
ktime_t period;
} *data;
typedef enum {
eIdle = 0,
eSetPinALow,
eSetPinBLow,
} teControlState;
static enum hrtimer_restart TimerCallback(struct hrtimer *var);
static void StopTimer(void);
static teControlState cycle_state = eIdle;
static enum hrtimer_restart TimerCallback(struct hrtimer *var)
{
local_irq_disable();
switch (cycle_state) {
case eSetPinALow:
SetPinA_Low();
data->period = ktime_set(0, PIN_A_LOW_TO_B_LOW_US * 1000);
cycle_state = eSetPinBLow;
break;
case eSetPinBLow:
SetPinB_Low();
/* Do Stuff */
/* no break */
default:
cycle_state = eIdle;
break;
}
if (cycle_state != eIdle) {
hrtimer_forward_now(var, data->period);
local_irq_enable();
return HRTIMER_RESTART;
}
local_irq_enable();
return HRTIMER_NORESTART;
}
void StartBusCycleControl(void)
{
SetPinA_High();
SetPinB_High();
data->period = ktime_set(0, PIN_A_HIGH_TO_A_LOW_US * 1000);
cycle_state = eSetPinALow;
hrtimer_start(&data->timer, data->period, HRTIMER_MODE_REL);
}
int InitTimer(void)
{
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (data) {
hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
data->timer.function = TimerCallback;
printk(KERN_INFO DRV_NAME
": %s hr timer successfully initialized\n", __func__);
return 0;
} else {
printk(KERN_CRIT DRV_NAME
": %s failed to initialize the hr timer\n", __func__);
return -ENOMEM;
}
}
這樣的想法是,
- 兩個引腳高點開始
- hrtimer設置後48微秒 到期
- 在回調函數中,引腳A被拉低
- 計時器被向前推進24微秒
- 回調引發了第二次的時候,銷B被拉低
我使用BeagleBoneBlack與內核4.1.2與RT-搶佔補丁。
我在範圍內看到的第一個計時器的工作原理就像一個約65-67微秒的魅力(我可以忍受這一點)。 但是轉發似乎失靈,因爲我測量的引腳A變低和引腳B變低的時間在2到50微秒之間。 所以本質上,第二次觸發回調有時會發生在我定義的24微秒之前之前。 而且這個時間對我的用例不起作用。
任何指向我在做什麼錯?
'我測量的引腳A低電平和引腳B低電平之間的時間在2到50微秒之間。「 - **這個時間你如何測量?請清理你提供的代碼:'StartBusCycleControl'永遠不會被使用,'StopTimer'也不會被使用。另一方面,使用'SetPinA_Low'和'SetPinB_Low',但從未定義。 – Tsyvarev
它們用示波器測量。代碼當然是不完整的。 setpin函數只寫入一些將gpio引腳拉低或拉高的寄存器。 – TabascoEye
我認爲這是由於基礎時鐘硬件的更新週期。雖然當啓用高分辨率定時器時,內核中的hrtimer支持的分辨率爲1 ns,但記錄時間的硬件寄存器不一定每1 ns更新一次。如果它們每N納秒更新一次,那麼從hrtimer讀取的「now」值可能會過時達N納秒。因此,當你調用'hrtimer_forward_now(var,data-> period)'時,更新的失效時間可能會相差最多N納秒。 –