帶有定時器/線程的周期事件的驅動結構與帶有中斷的驅動程式結構類似,只是把其中的中斷處理函數換成定時器或線程處理函數,其模型如下圖所示。
周期性事件處理有兩種:定時器和線程。
使用定時器處理周期性事件
#include <linux/timer.h>
定義定時器
struct timer_list {
struct list_head list; // 用來形成鏈表,由核心管理
unsigned long expires; // 定時器到期時間,jiffies,HZ
unsigned long data; // 作為參數被傳入定時器處理函數
void (*function)(unsigned long);// 定時器處理函數
};
初始化定時器,實質是把鏈表的頭尾置空
void init_timer(struct timer_list *timer);
添加定時器
void add_timer(struct timer_list * timer);
刪除定時器
int del_timer(struct timer_list * timer);
定時器樣本
struct timer_list myTimer;
init_timer(&myTimer); //jiffies,核心的全域變數,系統定時
myTimer.expires = jiffies + 3 * HZ; //expires只執行一次,HZ 代表秒
myTimer.data = 0L;
myTimer.function = timerHandler; //定時到,處理的函數
add_timer(&myTimer); //添加到定時鏈表中
定時器處理函數
void timerHandler(unsigned long data)
{
// 如需重複執行, 需要重新初始化並啟動定時器
myTimer.expires = jiffies + 3 * HZ;
add_timer(&myTimer);
}
退出時一定要刪除定時器,否則系統崩潰
del_timer(myTimer);
使用核心線程處理周期性事件,這與普通的線程的使用方法基本一樣
#include <linux/kernel.h>
建立核心線程,設定 flags線程的屬性
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
執行個體:
kernel_thread(thread_function, (void*)thread_data, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
設定延時
set_current_state(TASK_UNINTERRUPTIBLE);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ * 5);
注意:模組退出時必須等待線程退出
schedule() // 讓出調度器
以下以定時器的周期事件為例。實驗平台:淩陽SPCE3200 實驗箱,對應的硬體裝置為pod。硬體串連:把JP32所有管腳短接。整個驅動分為三個模組:獲得pod索引值的模組Pod_Drv.c、FIFO隊列的模組/kernel/kerne/kfifo.c 、真正的pod驅動模組pod.c。這樣,在載入pod驅動時必先要載入kfifo.o和Pod_Drv.o模組。
/kernel/kerne/kfifo.c為核心中的函數模組,直接編譯就能使用。
Pod_Drv.c為自己寫的模組,該模組有三個檔案:POD_Config.h配置標頭檔、Pod_Drv.h對應Pod_Drv.c的標頭檔、Pod_Drv.c。具體代碼如下:
//POD_Config.h
#ifndef _POD_CONFIG_H_
#define _POD_CONFIG_H_
#include <asm/arch/S3C2410.h>
#define P_POD_GPIO_OE GPFCON // GPxCON寄存器
#define P_POD_GPIO_OUTPUT GPFDAT // GPxDAT寄存器
#define P_POD_GPIO_PULLUP GPFUP // GPxUP寄存器
#define P_POD_GPIO_INPUT GPFDAT // GPxDAT寄存器
#define POD_RDY_BIT 5 // RDY位
#define POD_CLK_BIT 4 // CLK位
#define POD_MISO_BIT 3 // MISO位
#define POD_MOSI_BIT 2 // MOSI位
#define POD_SS_BIT 1 // SS位
#define POD_CHG_BIT 0 // Change位
#define POD_RDY_Get() ( (P_POD_GPIO_INPUT & (0x00000001<<POD_RDY_BIT) ) ? 1 : 0 )
#define POD_CHG_Get() ( (P_POD_GPIO_INPUT & (0x00000001<<POD_CHG_BIT) ) ? 1 : 0 )
#define POD_CLK_Set() ( P_POD_GPIO_OUTPUT |= (0x00000001<<POD_CLK_BIT))
#define POD_CLK_Clr() (P_POD_GPIO_OUTPUT &= ~(0x00000001<<POD_CLK_BIT))
#define POD_MISO_Get() ((P_POD_GPIO_INPUT & (0x00000001<<POD_MISO_BIT))?1:0)
#define POD_MOSI_Set() (P_POD_GPIO_OUTPUT |= (0x00000001<<POD_MOSI_BIT))
#define POD_MOSI_Clr() (P_POD_GPIO_OUTPUT &= ~(0x00000001<<POD_MOSI_BIT))
#define POD_SS_Set() (P_POD_GPIO_OUTPUT |= (0x00000001<<POD_SS_BIT))
#define POD_SS_Clr() (P_POD_GPIO_OUTPUT &= ~(0x00000001<<POD_SS_BIT))
#endif
//Pod_Drv.h
#ifndef _POD_DRV_H_
#define _POD_DRV_H_
#include "POD_Config.h"
extern void POD_Init(void);