色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

i.MX6ULL時(shí)間管理和內(nèi)核定時(shí)器深入研究

玩轉(zhuǎn)單片機(jī) ? 來源:玩轉(zhuǎn)單片機(jī) ? 2023-11-04 10:17 ? 次閱讀

學(xué)習(xí)過 UCOSFreeRTOS 的同學(xué)應(yīng)該知道,UCOS 或 FreeRTOS 是需要一個(gè)硬件定時(shí)器提供系統(tǒng)時(shí)鐘,一般使用 Systick 作為系統(tǒng)時(shí)鐘源。

同理,Linux 要運(yùn)行,也是需要一個(gè)系統(tǒng)時(shí)鐘的,至于這個(gè)系統(tǒng)時(shí)鐘是由哪個(gè)定時(shí)器提供的,有興趣的讀者可以去研究一下 Linux 內(nèi)核。不過對(duì)于Linux 驅(qū)動(dòng)編寫者來說,不需要深入研究這些具體的實(shí)現(xiàn),只需要掌握相應(yīng)的 API 函數(shù)即可。

Linux 內(nèi)核中有大量的函數(shù)需要時(shí)間管理,比如周期性的調(diào)度程序、延時(shí)程序、對(duì)于我們驅(qū)動(dòng)編寫者來說最常用的定時(shí)器。硬件定時(shí)器提供時(shí)鐘源,時(shí)鐘源的頻率可以設(shè)置, 設(shè)置好以后就周期性地產(chǎn)生定時(shí)中斷,系統(tǒng)使用定時(shí)中斷來計(jì)時(shí)。

中斷周期性產(chǎn)生的頻率就是系統(tǒng)頻率,也叫做節(jié)拍率(tick rate)(有的資料也叫系統(tǒng)頻率),比如 1000Hz,100Hz 等等說的就是系統(tǒng)節(jié)拍率。

系統(tǒng)節(jié)拍率是可以設(shè)置的,單位是 Hz,在編譯 Linux 內(nèi)核的時(shí)候可以通過圖形化界面設(shè)置系統(tǒng)節(jié)拍率,按照如下路徑打開配置界面:

->KernelFeatures
->Timerfrequency([=y])

效果圖:

0ff22374-7aa6-11ee-939d-92fbcf53809c.png

在內(nèi)核文件路徑通過輸入:make menuconfig指令打開圖形化配置界面!

100beb38-7aa6-11ee-939d-92fbcf53809c.png

可以在.config文件中找到對(duì)應(yīng)的配置,在內(nèi)核文件路徑通過輸入:gedit .config指令打開:

10184338-7aa6-11ee-939d-92fbcf53809c.png

CONFIG_HZ 為 100, Linux 內(nèi)核會(huì)使用 CONFIG_HZ 來設(shè)置自己的系統(tǒng)時(shí)鐘。打開文件 include/asm-generic/param.h,有如下內(nèi)容:

#ifndef__ASM_GENERIC_PARAM_H
#define__ASM_GENERIC_PARAM_H

#include

#undefHZ
#defineHZCONFIG_HZ/*Internalkerneltimerfrequency*/
#defineUSER_HZ100/*someuserinterfacesare*/
#defineCLOCKS_PER_SEC(USER_HZ)/*in"ticks"liketimes()*/
#endif/*__ASM_GENERIC_PARAM_H*/

宏 HZ 就是 CONFIG_HZ,因此 HZ=100,后面編寫 Linux驅(qū)動(dòng)的時(shí)候會(huì)常常用到 HZ,因?yàn)?HZ 表示一秒的節(jié)拍數(shù),也就是頻率。

高節(jié)拍率會(huì)提高系統(tǒng)時(shí)間精度,如果采用 100Hz 的節(jié)拍率,時(shí)間精度就是 10ms,采用1000Hz 的話時(shí)間精度就是 1ms,精度提高了 10 倍。

高精度時(shí)鐘能夠以更高的精度運(yùn)行,時(shí)間測(cè)量也更加準(zhǔn)確。高節(jié)拍率會(huì)導(dǎo)致中斷的產(chǎn)生更加頻繁,頻繁的中斷會(huì)加劇系統(tǒng)的負(fù)擔(dān), 1000Hz 和 100Hz的系統(tǒng)節(jié)拍率相比,系統(tǒng)要花費(fèi) 10 倍的“精力”去處理中斷。

中斷服務(wù)函數(shù)占用處理器的時(shí)間增加,但是現(xiàn)在的處理器性能都很強(qiáng)大,所以采用 1000Hz 的系統(tǒng)節(jié)拍率并不會(huì)增加太大的負(fù)載壓力。

根據(jù)自己的實(shí)際情況,選擇合適的系統(tǒng)節(jié)拍率,本教程全部采用默認(rèn)的 100Hz 系統(tǒng)節(jié)拍率。

Linux 內(nèi)核使用全局變量 jiffies 來記錄系統(tǒng)從啟動(dòng)以來的系統(tǒng)節(jié)拍數(shù),系統(tǒng)啟動(dòng)的時(shí)候會(huì)將 jiffies 初始化為 0,jiffies 定義在文件 include/linux/jiffies.h 中,定義如下:

1035f522-7aa6-11ee-939d-92fbcf53809c.png

jiffies_64 和 jiffies 其實(shí)是同一個(gè)東西, jiffies_64 用于 64 位系統(tǒng),而 jiffies 用于 32 位系統(tǒng)。當(dāng)訪問 jiffies 的時(shí)候其實(shí)訪問的是 jiffies_64 的低 32 位,使用 get_jiffies_64 這個(gè)函數(shù)可以獲取 jiffies_64 的值。

在 32 位的系統(tǒng)上讀取 jiffies 的值,在 64 位的系統(tǒng)上 jiffes 和 jiffies_64表示同一個(gè)變量,因此也可以直接讀取 jiffies 的值。所以不管是 32 位的系統(tǒng)還是 64 位系統(tǒng),都可以使用 jiffies。

|繞回

前面說了 HZ 表示每秒的節(jié)拍數(shù),jiffies 表示系統(tǒng)運(yùn)行的 jiffies 節(jié)拍數(shù),所以 jiffies/HZ 就是系統(tǒng)運(yùn)行時(shí)間,單位為秒。

不管是 32 位還是 64 位的 jiffies,都有溢出的風(fēng)險(xiǎn),溢出以后會(huì)重新從 0 開始計(jì)數(shù),相當(dāng)于繞回來了,因此有些資料也將這個(gè)現(xiàn)象也叫做繞回。

假如 HZ 為最大值 1000 的時(shí)候,32 位的 jiffies 只需要 49.7 天就發(fā)生了繞回,對(duì)于 64 位的 jiffies 來說大概需要5.8 億年才能繞回,因此 jiffies_64 的繞回忽略不計(jì)。處理 32 位 jiffies 的繞回顯得尤為重要,Linux 內(nèi)核提供了如表 50.1.1.1 所示的幾個(gè) API 函數(shù)來處理繞回。

1058b134-7aa6-11ee-939d-92fbcf53809c.png

可以在這個(gè)文件中找到定義:

1073b13c-7aa6-11ee-939d-92fbcf53809c.png

如果 unkown 超過 known 的話,time_after 函數(shù)返回真,否則返回假。如果 unkown 沒有超過 known 的話 time_before 函數(shù)返回真,否則返回假。time_after_eq 函數(shù)和 time_after 函數(shù)類似,只是多了判斷等于這個(gè)條件。同理,time_before_eq 函數(shù)和 time_before 函數(shù)也類似。比如要判斷某段代碼執(zhí)行時(shí)間有沒有超時(shí),此時(shí)就可以使用如下所示代碼:

unsignedlongtimeout;
timeout=jiffies+(2*HZ);/*超時(shí)的時(shí)間點(diǎn)*/

/*************************************
具體的代碼
************************************/

/*判斷有沒有超時(shí)*/
if(time_before(jiffies,timeout))
{
/*超時(shí)未發(fā)生*/
}
else
{
/*超時(shí)發(fā)生*/
}

timeout 就是超時(shí)時(shí)間點(diǎn),比如我們要判斷代碼執(zhí)行時(shí)間是不是超過了 2 秒,那么超時(shí)時(shí)間點(diǎn)就是 jiffies+(2*HZ),如果 jiffies 大于 timeout 那就表示超時(shí)了,否則就是沒有超時(shí)。

為了方便開發(fā),Linux 內(nèi)核提供了幾個(gè) jiffies 和 ms、us、ns 之間的轉(zhuǎn)換函數(shù):

1097d378-7aa6-11ee-939d-92fbcf53809c.png

| 定時(shí)器

定時(shí)器是一個(gè)很常用的功能,需要周期性處理的工作都要用到定時(shí)器。定時(shí)器大體分兩類,一個(gè)是硬件定時(shí)器,一個(gè)是軟件定時(shí)器,而軟件定時(shí)器需要硬件定時(shí)器做基礎(chǔ),通過軟件的方式使用無限拓展(理論上)的軟件定時(shí)器,使用了操作系統(tǒng)后,往往是使用軟件定時(shí)器,可以不需要再對(duì)硬件定時(shí)器進(jìn)行初始化配置。

Linux 內(nèi)核定時(shí)器使用很簡(jiǎn)單,只需要提供超時(shí)時(shí)間(相當(dāng)于定時(shí)值)和定時(shí)處理函數(shù)即可,當(dāng)超時(shí)時(shí)間到了以后設(shè)置的定時(shí)處理函數(shù)就會(huì)執(zhí)行,和我們使用硬件定時(shí)器的套路一樣,只是使用內(nèi)核定時(shí)器不需要做一大堆的寄存器初始化工作。

在使用內(nèi)核定時(shí)器的時(shí)候要注意一點(diǎn),內(nèi)核定時(shí)器并不是周期性運(yùn)行的,超時(shí)以后就會(huì)自動(dòng)關(guān)閉,因此如果想要實(shí)現(xiàn)周期性定時(shí),那么就需要在定時(shí)處理函數(shù)中重新開啟定時(shí)器。Linux 內(nèi)核使用 timer_list 結(jié)構(gòu)體表示內(nèi)核定時(shí)器,timer_list 定義在文件include/linux/timer.h 中,定義如下(省略掉條件編譯):

structtimer_list{
structlist_headentry;
unsignedlongexpires;
structtvec_base*base;/*定時(shí)器超時(shí)時(shí)間,單位是節(jié)拍數(shù)*/
void(*function)(unsignedlong);/*定時(shí)處理函數(shù)*/
unsignedlongdata;/*要傳遞給function函數(shù)的參數(shù)*/
intslack;
};

要使用內(nèi)核定時(shí)器首先要先定義一個(gè) timer_list 變量,表示定時(shí)器,tiemr_list 結(jié)構(gòu)體的expires 成員變量表示超時(shí)時(shí)間,單位為節(jié)拍數(shù)。比如現(xiàn)在需要定義一個(gè)周期為 2 秒的定時(shí)器,那么這個(gè)定時(shí)器的超時(shí)時(shí)間就是 jiffies+(2*HZ),因此 expires=jiffies+(2*HZ)。function 就是定時(shí)器超時(shí)以后的定時(shí)處理函數(shù),要做的工作或處理就放到這個(gè)函數(shù)里面,需要根據(jù)需求編寫這個(gè)定時(shí)處理函數(shù)。

API函數(shù)

init_timer 函數(shù)

init_timer 函數(shù)負(fù)責(zé)初始化 timer_list 類型變量,當(dāng)我們定義了一個(gè) timer_list 變量以后一定要先用 init_timer 初始化一下。init_timer 函數(shù)原型如下:

/*
timer:要初始化定時(shí)器。
返回值:沒有返回值。
*/
voidinit_timer(structtimer_list*timer)

add_timer 函數(shù)

add_timer 函數(shù)用于向 Linux 內(nèi)核注冊(cè)定時(shí)器,使用 add_timer 函數(shù)向內(nèi)核注冊(cè)定時(shí)器以后,定時(shí)器就會(huì)開始運(yùn)行,函數(shù)原型如下:

/*
timer:要注冊(cè)的定時(shí)器。
返回值:沒有返回值。
*/
voidadd_timer(structtimer_list*timer)

del_timer 函數(shù)

del_timer 函數(shù)用于刪除一個(gè)定時(shí)器,不管定時(shí)器有沒有被激活,都可以使用此函數(shù)刪除。在多處理器系統(tǒng)上,定時(shí)器可能會(huì)在其他的處理器上運(yùn)行,因此在調(diào)用 del_timer 函數(shù)刪除定時(shí)器之前要先等待其他處理器的定時(shí)處理器函數(shù)退出。del_timer 函數(shù)原型如下:

/*
timer:要?jiǎng)h除的定時(shí)器。
返回值:0,定時(shí)器還沒被激活;1,定時(shí)器已經(jīng)激活
*/
intdel_timer(structtimer_list*timer)

del_timer_sync 函數(shù)

del_timer_sync 函數(shù)是 del_timer 函數(shù)的同步版,會(huì)等待其他處理器使用完定時(shí)器再刪除,del_timer_sync 不能使用在中斷上下文中。del_timer_sync 函數(shù)原型如下所示:

/*
timer:要?jiǎng)h除的定時(shí)器。
返回值:0,定時(shí)器還沒被激活;1,定時(shí)器已經(jīng)激活。
*/
intdel_timer_sync(structtimer_list*timer)

mod_timer 函數(shù)

mod_timer 函數(shù)用于修改定時(shí)值,如果定時(shí)器還沒有激活的話,mod_timer 函數(shù)會(huì)激活定時(shí)器!函數(shù)原型如下:

/*
timer:要修改超時(shí)時(shí)間(定時(shí)值)的定時(shí)器。
expires:修改后的超時(shí)時(shí)間。
返回值:0,調(diào)用 mod_timer 函數(shù)前定時(shí)器未被激活;1,調(diào)用 mod_timer 函數(shù)前定時(shí)器已被激活。
*/
intmod_timer(structtimer_list*timer,unsignedlongexpires)

內(nèi)核定時(shí)器一般的使用流程如下所示:

structtimer_listtimer;/*定義定時(shí)器*/

/*定時(shí)器回調(diào)函數(shù)*/
voidfunction(unsignedlongarg)
{
/*
*定時(shí)器處理代碼
*/

/*如果需要定時(shí)器周期性運(yùn)行的話就使用mod_timer
*函數(shù)重新設(shè)置超時(shí)值并且啟動(dòng)定時(shí)器。
*/

mod_timer(&dev->timertest,jiffies+msecs_to_jiffies(2000));
}

/*初始化函數(shù)*/
voidinit(void)
{
init_timer(&timer);/*初始化定時(shí)器*/

timer.function=function;/*設(shè)置定時(shí)處理函數(shù)*/
timer.expires=jffies+msecs_to_jiffies(2000);/*超時(shí)時(shí)間2秒*/
timer.data=(unsignedlong)&dev;/*將設(shè)備結(jié)構(gòu)體作為參數(shù)*/

add_timer(&timer);/*啟動(dòng)定時(shí)器*/
}

/*退出函數(shù)*/
voidexit(void)
{
del_timer(&timer);/*刪除定時(shí)器*/
/*或者使用*/
del_timer_sync(&timer);
}

Linux 內(nèi)核短延時(shí)函數(shù)

有時(shí)候需要在內(nèi)核中實(shí)現(xiàn)短延時(shí),尤其是在 Linux 驅(qū)動(dòng)中。Linux 內(nèi)核提供了毫秒、微秒和納秒延時(shí)函數(shù):

10a6185c-7aa6-11ee-939d-92fbcf53809c.png

| LED閃爍

通過設(shè)置一個(gè)定時(shí)器來實(shí)現(xiàn)周期性的閃爍 LED 燈,通過這個(gè)案例來學(xué)習(xí)定時(shí)器的基本使用,這個(gè)實(shí)驗(yàn)不需要看應(yīng)用層。

簡(jiǎn)單使用型:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
//#include

#defineCHRDEVBASE_CNT1/*設(shè)備號(hào)個(gè)數(shù)*/
#defineCHRDEVBASE_NAME"chrdevbase"/*名字*/

/*chrdevbase設(shè)備結(jié)構(gòu)體*/
structnewchr_dev{
dev_tdevid;/*設(shè)備號(hào)*/
structcdevcdev;/*cdev*/
structclass*class;/*類*/
structdevice*device;/*設(shè)備*/
intmajor;/*主設(shè)備號(hào)*/
intminor;/*次設(shè)備號(hào)*/
structdevice_node*nd;/*設(shè)備節(jié)點(diǎn)*/
intled_gpio;/*led所使用的GPIO編號(hào)*/

structtimer_listtimer;/*定義一個(gè)定時(shí)器*/
};

structnewchr_devchrdevbase;/*自定義字符設(shè)備*/

/*
*@description:LED硬件初始化
*@param:無
*@return:無
*/
staticintled_hal_init(void)
{
intret=0;

/*設(shè)置LED所使用的GPIO*/
/* 1、獲取設(shè)備節(jié)點(diǎn):gpioled */
chrdevbase.nd=of_find_node_by_path("/gpioled");
if(chrdevbase.nd==NULL){
printk("chrdevbasenodecantnotfound!
");
return-EINVAL;
}else{
printk("chrdevbasenodehasbeenfound!
");
}

/*2、獲取設(shè)備樹中的gpio屬性,得到LED所使用的LED編號(hào)*/
chrdevbase.led_gpio=of_get_named_gpio(chrdevbase.nd,"led-gpio",0);
if(chrdevbase.led_gpioprivate_data=&chrdevbase;/*設(shè)置私有數(shù)據(jù)*/
return0;
}

/*
*@description:從設(shè)備讀取數(shù)據(jù)
*@param-filp:要打開的設(shè)備文件(文件描述符)
*@param-buf:返回給用戶空間的數(shù)據(jù)緩沖區(qū)
*@param-cnt:要讀取的數(shù)據(jù)長(zhǎng)度
*@param-offt:相對(duì)于文件首地址的偏移
*@return:讀取的字節(jié)數(shù),如果為負(fù)值,表示讀取失敗
*/
staticssize_tchrdevbase_read(structfile*filp,char__user*buf,size_tcnt,loff_t*offt)
{
printk("chrdevbaseread!
");
return0;
}

/*
*@description:向設(shè)備寫數(shù)據(jù)
*@param-filp:設(shè)備文件,表示打開的文件描述符
*@param-buf:要寫給設(shè)備寫入的數(shù)據(jù)
*@param-cnt:要寫入的數(shù)據(jù)長(zhǎng)度
*@param-offt:相對(duì)于文件首地址的偏移
*@return:寫入的字節(jié)數(shù),如果為負(fù)值,表示寫入失敗
*/
staticssize_tchrdevbase_write(structfile*filp,constchar__user*buf,size_tcnt,loff_t*offt)
{
printk("chrdevbasewrite!
");
return0;
}

/*
*@description:關(guān)閉/釋放設(shè)備
*@param-filp:要關(guān)閉的設(shè)備文件(文件描述符)
*@return:0成功;其他失敗
*/
staticintchrdevbase_release(structinode*inode,structfile*filp)
{
printk("[BSP]release!
");
return0;
}

/*
*設(shè)備操作函數(shù)結(jié)構(gòu)體
*/
staticstructfile_operationschrdevbase_fops={
.owner=THIS_MODULE,
.open=chrdevbase_open,
.read=chrdevbase_read,
.write=chrdevbase_write,
.release=chrdevbase_release,
};

/*定時(shí)器回調(diào)函數(shù)*/
voidtimer_function(unsignedlongarg)
{
structnewchr_dev*dev=(structnewchr_dev*)arg;
staticintsta=1;

sta=!sta;/*每次都取反,實(shí)現(xiàn)LED燈反轉(zhuǎn)*/
gpio_set_value(dev->led_gpio,sta);

/*重啟定時(shí)器*/
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(500));
}

/*
*@description:驅(qū)動(dòng)入口函數(shù)
*@param:無
*@return:0成功;其他失敗
*/
staticint__initchrdevbase_init(void)
{
/*初始化硬件*/
led_hal_init();

/*注冊(cè)字符設(shè)備驅(qū)動(dòng)*/
/*1、創(chuàng)建設(shè)備號(hào)*/
if(chrdevbase.major){/*定義了設(shè)備號(hào)*/
chrdevbase.devid=MKDEV(chrdevbase.major,0);
register_chrdev_region(chrdevbase.devid,CHRDEVBASE_CNT,CHRDEVBASE_NAME);
}else{/*沒有定義設(shè)備號(hào)*/
alloc_chrdev_region(&chrdevbase.devid,0,CHRDEVBASE_CNT,CHRDEVBASE_NAME);/*申請(qǐng)?jiān)O(shè)備號(hào)*/
chrdevbase.major=MAJOR(chrdevbase.devid);/*獲取主設(shè)備號(hào)*/
chrdevbase.minor=MINOR(chrdevbase.devid);/*獲取次設(shè)備號(hào)*/
}
printk("newcheledmajor=%d,minor=%d
",chrdevbase.major,chrdevbase.minor);

/*2、初始化cdev*/
chrdevbase.cdev.owner=THIS_MODULE;
cdev_init(&chrdevbase.cdev,&chrdevbase_fops);

/*3、添加一個(gè)cdev*/
cdev_add(&chrdevbase.cdev,chrdevbase.devid,CHRDEVBASE_CNT);

/*4、創(chuàng)建類*/
chrdevbase.class=class_create(THIS_MODULE,CHRDEVBASE_NAME);
if(IS_ERR(chrdevbase.class)){
returnPTR_ERR(chrdevbase.class);
}

/*5、創(chuàng)建設(shè)備*/
chrdevbase.device=device_create(chrdevbase.class,NULL,chrdevbase.devid,NULL,CHRDEVBASE_NAME);
if(IS_ERR(chrdevbase.device)){
returnPTR_ERR(chrdevbase.device);
}

/*6、初始化timer*/
init_timer(&chrdevbase.timer);
chrdevbase.timer.function=timer_function;
chrdevbase.timer.expires=jiffies+msecs_to_jiffies(500);
chrdevbase.timer.data=(unsignedlong)&chrdevbase;
add_timer(&chrdevbase.timer);

return0;
}

/*
*@description:驅(qū)動(dòng)出口函數(shù)
*@param:無
*@return:無
*/
staticvoid__exitchrdevbase_exit(void)
{
gpio_set_value(chrdevbase.led_gpio,1);/*卸載驅(qū)動(dòng)的時(shí)候關(guān)閉LED*/
del_timer_sync(&chrdevbase.timer);/*刪除timer*/

/*注銷字符設(shè)備*/
cdev_del(&chrdevbase.cdev);/*刪除cdev*/
unregister_chrdev_region(chrdevbase.devid,CHRDEVBASE_CNT);/*注銷設(shè)備號(hào)*/

device_destroy(chrdevbase.class,chrdevbase.devid);/*銷毀設(shè)備*/
class_destroy(chrdevbase.class);/*銷毀類*/

printk("[BSP]chrdevbaseexit!
");
}

/*
*將上面兩個(gè)函數(shù)指定為驅(qū)動(dòng)的入口和出口函數(shù)
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

/*
*LICENSE和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

套路分析:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#defineCHRDEVBASE_CNT1/*設(shè)備號(hào)個(gè)數(shù)*/
#defineCHRDEVBASE_NAME"chrdevbase"/*名字*/

/*chrdevbase設(shè)備結(jié)構(gòu)體*/
structnewchr_dev{
....
structtimer_listtimer;/*定義一個(gè)定時(shí)器*/
};

structnewchr_devchrdevbase;/*自定義字符設(shè)備*/

/*
*@description:LED硬件初始化
*@param:無
*@return:無
*/
staticintled_hal_init(void)
{
......
return0;
}

/*
*@description:打開設(shè)備
*@param-inode:傳遞給驅(qū)動(dòng)的inode
*@param-filp:設(shè)備文件,file結(jié)構(gòu)體有個(gè)叫做private_data的成員變量
*一般在open的時(shí)候?qū)rivate_data指向設(shè)備結(jié)構(gòu)體。
*@return:0成功;其他失敗
*/
staticintchrdevbase_open(structinode*inode,structfile*filp)
{
......
return0;
}

/*
*@description:從設(shè)備讀取數(shù)據(jù)
*@param-filp:要打開的設(shè)備文件(文件描述符)
*@param-buf:返回給用戶空間的數(shù)據(jù)緩沖區(qū)
*@param-cnt:要讀取的數(shù)據(jù)長(zhǎng)度
*@param-offt:相對(duì)于文件首地址的偏移
*@return:讀取的字節(jié)數(shù),如果為負(fù)值,表示讀取失敗
*/
staticssize_tchrdevbase_read(structfile*filp,char__user*buf,size_tcnt,loff_t*offt)
{
......
return0;
}

/*
*@description:向設(shè)備寫數(shù)據(jù)
*@param-filp:設(shè)備文件,表示打開的文件描述符
*@param-buf:要寫給設(shè)備寫入的數(shù)據(jù)
*@param-cnt:要寫入的數(shù)據(jù)長(zhǎng)度
*@param-offt:相對(duì)于文件首地址的偏移
*@return:寫入的字節(jié)數(shù),如果為負(fù)值,表示寫入失敗
*/
staticssize_tchrdevbase_write(structfile*filp,constchar__user*buf,size_tcnt,loff_t*offt)
{
......
return0;
}

/*
*@description:關(guān)閉/釋放設(shè)備
*@param-filp:要關(guān)閉的設(shè)備文件(文件描述符)
*@return:0成功;其他失敗
*/
staticintchrdevbase_release(structinode*inode,structfile*filp)
{
......
return0;
}

/*
*設(shè)備操作函數(shù)結(jié)構(gòu)體
*/
staticstructfile_operationschrdevbase_fops={
.owner=THIS_MODULE,
.open=chrdevbase_open,
.read=chrdevbase_read,
.write=chrdevbase_write,
.release=chrdevbase_release,
};

/*定時(shí)器回調(diào)函數(shù)*/
voidtimer_function(unsignedlongarg)
{
structnewchr_dev*dev=(structnewchr_dev*)arg;
staticintsta=1;

sta=!sta;/*每次都取反,實(shí)現(xiàn)LED燈反轉(zhuǎn)*/
gpio_set_value(dev->led_gpio,sta);

/*重啟定時(shí)器*/
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(500));
}

/*
*@description:驅(qū)動(dòng)入口函數(shù)
*@param:無
*@return:0成功;其他失敗
*/
staticint__initchrdevbase_init(void)
{
/*初始化硬件*/
led_hal_init();

/*注冊(cè)字符設(shè)備驅(qū)動(dòng)*/
/*1、創(chuàng)建設(shè)備號(hào)*/
......

/*2、初始化cdev*/
......

/*3、添加一個(gè)cdev*/
......

/*4、創(chuàng)建類*/
......

/*5、創(chuàng)建設(shè)備*/
......

/*6、初始化timer*/
init_timer(&chrdevbase.timer);
chrdevbase.timer.function=timer_function;
chrdevbase.timer.expires=jiffies+msecs_to_jiffies(500);
chrdevbase.timer.data=(unsignedlong)&chrdevbase;
add_timer(&chrdevbase.timer);

return0;
}

/*
*@description:驅(qū)動(dòng)出口函數(shù)
*@param:無
*@return:無
*/
staticvoid__exitchrdevbase_exit(void)
{
gpio_set_value(chrdevbase.led_gpio,1);/*卸載驅(qū)動(dòng)的時(shí)候關(guān)閉LED*/
del_timer_sync(&chrdevbase.timer);/*刪除timer*/

/*注銷字符設(shè)備*/
cdev_del(&chrdevbase.cdev);/*刪除cdev*/
unregister_chrdev_region(chrdevbase.devid,CHRDEVBASE_CNT);/*注銷設(shè)備號(hào)*/

device_destroy(chrdevbase.class,chrdevbase.devid);/*銷毀設(shè)備*/
class_destroy(chrdevbase.class);/*銷毀類*/

printk("[BSP]chrdevbaseexit!
");
}

/*
*將上面兩個(gè)函數(shù)指定為驅(qū)動(dòng)的入口和出口函數(shù)
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

/*
*LICENSE和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

| ioctl

上邊那個(gè)定時(shí)器案例是固定周期, 可用借助ioctl來動(dòng)態(tài)修改定時(shí)器周期!

驅(qū)動(dòng):

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#defineCHRDEVBASE_CNT1/*設(shè)備號(hào)個(gè)數(shù)*/
#defineCHRDEVBASE_NAME"chrdevbase"/*名字*/

#defineCLOSE_CMD(_IO(0xEF,0x01))/*關(guān)閉定時(shí)器*/
#defineOPEN_CMD(_IO(0xEF,0x02))/*打開定時(shí)器*/
#defineSETPERIOD_CMD(_IO(0xEF,0x03))/*設(shè)置定時(shí)器周期命令*/

#defineLEDON1/*開燈*/
#defineLEDOFF0/*關(guān)燈*/

/*chrdevbase設(shè)備結(jié)構(gòu)體*/
structnewchr_dev{
dev_tdevid;/*設(shè)備號(hào)*/
structcdevcdev;/*cdev*/
structclass*class;/*類*/
structdevice*device;/*設(shè)備*/
intmajor;/*主設(shè)備號(hào)*/
intminor;/*次設(shè)備號(hào)*/
structdevice_node*nd;/*設(shè)備節(jié)點(diǎn)*/
intled_gpio;/*led所使用的GPIO編號(hào)*/

inttimeperiod;/*定時(shí)周期(ms)*/
structtimer_listtimer;/*定義一個(gè)定時(shí)器*/
};

structnewchr_devchrdevbase;/*自定義字符設(shè)備*/

/*
*@description:LED硬件初始化
*@param:無
*@return:無
*/
staticintled_hal_init(void)
{
intret=0;

/*設(shè)置LED所使用的GPIO*/
/*1、獲取設(shè)備節(jié)點(diǎn):gpioled*/
chrdevbase.nd=of_find_node_by_path("/gpioled");
if(chrdevbase.nd==NULL){
printk("chrdevbasenodecantnotfound!
");
return-EINVAL;
}else{
printk("chrdevbasenodehasbeenfound!
");
}

/*2、獲取設(shè)備樹中的gpio屬性,得到LED所使用的LED編號(hào)*/
chrdevbase.led_gpio=of_get_named_gpio(chrdevbase.nd,"led-gpio",0);
if(chrdevbase.led_gpioprivate_data=&chrdevbase;/*設(shè)置私有數(shù)據(jù)*/
chrdevbase.timeperiod=1000;/*默認(rèn)周期為1s*/
ret=led_hal_init();/*初始化LEDIO*/
return0;
}

/*
*@description:ioctl函數(shù),
*@param–filp:要打開的設(shè)備文件(文件描述符)
*@param-cmd:應(yīng)用程序發(fā)送過來的命令
*@param-arg:參數(shù)
*@return:0成功;其他失敗
*/
staticlongtimer_unlocked_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
{
structnewchr_dev*dev=(structnewchr_dev*)filp->private_data;
inttimerperiod;

switch(cmd){
caseCLOSE_CMD:/*關(guān)閉定時(shí)器*/
//等待其他處理器使用完定時(shí)器再刪除
del_timer_sync(&dev->timer);
break;
caseOPEN_CMD:/*打開定時(shí)器*/
timerperiod=dev->timeperiod;
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(timerperiod));
break;
caseSETPERIOD_CMD:/*設(shè)置定時(shí)器周期*/
dev->timeperiod=arg;
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(arg));
break;
default:
break;
}
return0;
}
/*
*設(shè)備操作函數(shù)結(jié)構(gòu)體
*/
staticstructfile_operationschrdevbase_fops={
.owner=THIS_MODULE,
.open=chrdevbase_open,
.unlocked_ioctl=timer_unlocked_ioctl,
};

/*定時(shí)器回調(diào)函數(shù)*/
voidtimer_function(unsignedlongarg)
{
structnewchr_dev*dev=(structnewchr_dev*)arg;
staticintsta=1;

sta=!sta;/*每次都取反,實(shí)現(xiàn)LED燈反轉(zhuǎn)*/
gpio_set_value(dev->led_gpio,sta);

/*重啟定時(shí)器*/
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timeperiod));
}

/*
*@description:驅(qū)動(dòng)入口函數(shù)
*@param:無
*@return:0成功;其他失敗
*/
staticint__initchrdevbase_init(void)
{
/*注冊(cè)字符設(shè)備驅(qū)動(dòng)*/
/*1、創(chuàng)建設(shè)備號(hào)*/
if(chrdevbase.major){/*定義了設(shè)備號(hào)*/
chrdevbase.devid=MKDEV(chrdevbase.major,0);
register_chrdev_region(chrdevbase.devid,CHRDEVBASE_CNT,CHRDEVBASE_NAME);
}else{/*沒有定義設(shè)備號(hào)*/
alloc_chrdev_region(&chrdevbase.devid,0,CHRDEVBASE_CNT,CHRDEVBASE_NAME);/*申請(qǐng)?jiān)O(shè)備號(hào)*/
chrdevbase.major=MAJOR(chrdevbase.devid);/*獲取主設(shè)備號(hào)*/
chrdevbase.minor=MINOR(chrdevbase.devid);/*獲取次設(shè)備號(hào)*/
}
printk("newcheledmajor=%d,minor=%d
",chrdevbase.major,chrdevbase.minor);

/*2、初始化cdev*/
chrdevbase.cdev.owner=THIS_MODULE;
cdev_init(&chrdevbase.cdev,&chrdevbase_fops);

/*3、添加一個(gè)cdev*/
cdev_add(&chrdevbase.cdev,chrdevbase.devid,CHRDEVBASE_CNT);

/*4、創(chuàng)建類*/
chrdevbase.class=class_create(THIS_MODULE,CHRDEVBASE_NAME);
if(IS_ERR(chrdevbase.class)){
returnPTR_ERR(chrdevbase.class);
}

/*5、創(chuàng)建設(shè)備*/
chrdevbase.device=device_create(chrdevbase.class,NULL,chrdevbase.devid,NULL,CHRDEVBASE_NAME);
if(IS_ERR(chrdevbase.device)){
returnPTR_ERR(chrdevbase.device);
}

/*6、初始化timer*/
init_timer(&chrdevbase.timer);
chrdevbase.timer.function=timer_function;
chrdevbase.timer.expires=jiffies+msecs_to_jiffies(500);
chrdevbase.timer.data=(unsignedlong)&chrdevbase;
//add_timer(&chrdevbase.timer);

return0;
}

/*
*@description:驅(qū)動(dòng)出口函數(shù)
*@param:無
*@return:無
*/
staticvoid__exitchrdevbase_exit(void)
{
gpio_set_value(chrdevbase.led_gpio,1);/*卸載驅(qū)動(dòng)的時(shí)候關(guān)閉LED*/
del_timer_sync(&chrdevbase.timer);/*刪除timer*/

/*注銷字符設(shè)備*/
cdev_del(&chrdevbase.cdev);/*刪除cdev*/
unregister_chrdev_region(chrdevbase.devid,CHRDEVBASE_CNT);/*注銷設(shè)備號(hào)*/

device_destroy(chrdevbase.class,chrdevbase.devid);/*銷毀設(shè)備*/
class_destroy(chrdevbase.class);/*銷毀類*/

printk("[BSP]chrdevbaseexit!
");
}

/*
*將上面兩個(gè)函數(shù)指定為驅(qū)動(dòng)的入口和出口函數(shù)
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

/*
*LICENSE和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

應(yīng)用:

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"sys/stat.h"
#include"fcntl.h"
#include"stdlib.h"
#include"string.h"
#include"linux/ioctl.h"

/*命令值*/
#defineCLOSE_CMD(_IO(0XEF,0x1))/*關(guān)閉定時(shí)器*/
#defineOPEN_CMD(_IO(0XEF,0x2))/*打開定時(shí)器*/
#defineSETPERIOD_CMD(_IO(0XEF,0x3))/*設(shè)置定時(shí)器周期命令*/

/*
*@description:main主程序
*@param-argc:argv數(shù)組元素個(gè)數(shù)
*@param-argv:具體參數(shù)
*@return:0成功;其他失敗
*/
intmain(intargc,char*argv[])
{
intfd,ret;
char*filename;
unsignedintcmd;
unsignedintarg;
charwritebuf[100];
unsignedcharstr[100];

if(argc!=2){
printf("[APP]ErrorUsage!
");
return-1;
}

filename=argv[1];

/*打開驅(qū)動(dòng)文件*/
fd=open(filename,O_RDWR);
if(fd

使用:

10b6b360-7aa6-11ee-939d-92fbcf53809c.png

上文就是簡(jiǎn)單介紹了一下定時(shí)器, 簡(jiǎn)單使用了一下定時(shí)器, 后邊根據(jù)各自需求進(jìn)一步深入學(xué)習(xí).







審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3250

    瀏覽量

    114859
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    484

    瀏覽量

    62195
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21653
  • 時(shí)鐘源
    +關(guān)注

    關(guān)注

    0

    文章

    93

    瀏覽量

    15975
  • 定時(shí)中斷
    +關(guān)注

    關(guān)注

    0

    文章

    19

    瀏覽量

    8576

原文標(biāo)題:i.MX6ULL|時(shí)間管理和內(nèi)核定時(shí)器

文章出處:【微信號(hào):玩轉(zhuǎn)單片機(jī),微信公眾號(hào):玩轉(zhuǎn)單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux驅(qū)動(dòng)開發(fā)-內(nèi)核定時(shí)器

    內(nèi)核定時(shí)器內(nèi)核用來控制在未來某個(gè)時(shí)間點(diǎn)(基于jiffies(節(jié)拍總數(shù)))調(diào)度執(zhí)行某個(gè)函數(shù)的一種機(jī)制,相關(guān)函數(shù)位于 和 kernel/timer.c 文件
    的頭像 發(fā)表于 09-17 15:06 ?1475次閱讀

    移植NXP官方linux 5.4內(nèi)核i.MX6ULL開發(fā)板

    本文描述移植NXP官方 linux 5.4 內(nèi)核i.MX6ULL開發(fā)板。
    發(fā)表于 12-19 11:10 ?2054次閱讀

    i.MX6UL/i.MX6ULL開發(fā)常見問題】單獨(dú)編譯內(nèi)核,uboot生成很多文件,具體用哪一個(gè)?

    i.MX6UL/i.MX6ULL開發(fā)常見問題》基于米爾電子 i.MX6UL/i.MX6ULL產(chǎn)品(V.10)2.3單獨(dú)編譯內(nèi)核,uboot
    發(fā)表于 07-01 17:50

    I.MX6ULL終結(jié)者開發(fā)板裸機(jī)仿真jlink調(diào)試

    I.MX6ULL‘終結(jié)者’開發(fā)板預(yù)留了JTAG仿真接口,并給出了開發(fā)文檔,可以實(shí)現(xiàn)在JLINK仿真條件下的單步跟蹤、斷點(diǎn)調(diào)試等功能,使得開發(fā)研究i.MX6ULL處理
    發(fā)表于 07-07 10:56

    i.MX6ULL核心板資源

    路多功能音頻通道多路 SPI、IIC、定時(shí)器、PWM、DMA、RTC、看門狗等常用外設(shè)規(guī)格參數(shù):核心板配置CPU 型號(hào) NXP i.MX6ULL(MCIMX6Y2C),ARM Cortex A7
    發(fā)表于 07-12 17:50

    Linux內(nèi)核i.mx6ull中的編譯運(yùn)行

    Linux內(nèi)核i.mx6ull的編譯運(yùn)行編譯Linux Kernel需要使用lzop庫(kù),所以需要安裝,否則編譯內(nèi)核會(huì)失敗!!!sudo apt-get install lzop一、Linux
    發(fā)表于 11-05 07:14

    初識(shí) i.MX6ULL 寄存

    裸機(jī)開發(fā)_L1_匯編LED實(shí)驗(yàn)0. 本節(jié)目標(biāo)1. 硬件層電路2. 初識(shí) i.MX6ULL 寄存2.1 i.MX6ULL 時(shí)鐘控制寄存2.2 i.
    發(fā)表于 12-20 07:13

    ARM裸機(jī)篇之i.MX6ULL處理資料分享

    1、i.MX6ULL處理啟動(dòng)過程i.MX6ULL是NXP基于ARM Cortex-A7內(nèi)核的單核處理家族,主頻可以高900MHz。
    發(fā)表于 04-14 16:42

    飛凌i.MX6ULL開發(fā)板的評(píng)測(cè),再次進(jìn)階擁有更高的性價(jià)比

    MCIMX6Y2開發(fā)設(shè)計(jì),采用先進(jìn)的ARMCortex-A7內(nèi)核,運(yùn)行速度高達(dá)800MHz。i.MX6ULL應(yīng)用處理包括一個(gè)集成的電源管理
    發(fā)表于 10-27 11:55 ?1491次閱讀
    飛凌<b class='flag-5'>i.MX6ULL</b>開發(fā)板的評(píng)測(cè),再次進(jìn)階擁有更高的性價(jià)比

    基于NXP i.MX6ULL處理的FETMX6ULL-C核心板

    “性價(jià)比高,功能接口豐富,資料齊全,穩(wěn)定性強(qiáng)”這是許多用戶對(duì)飛凌FETMX6ULL-S核心板的評(píng)價(jià)。作為NXP公司一顆經(jīng)典的MPU,i.MX6ULL的市場(chǎng)認(rèn)可度無需多言。而作為NXP公司的金牌
    發(fā)表于 04-11 15:05 ?1156次閱讀
    基于NXP <b class='flag-5'>i.MX6ULL</b>處理<b class='flag-5'>器</b>的FETMX<b class='flag-5'>6ULL</b>-C核心板

    基于i.MX6ULL應(yīng)用處理的FETMX6ULL-C核心板

    NXP i.MX6ULL擴(kuò)展了i.MX6系列,它是一個(gè)高性能、超高效、低成本處理子系列,采用先進(jìn)的ARM Cortex-A7內(nèi)核,運(yùn)行速度高達(dá)800MHz。
    發(fā)表于 04-29 14:37 ?1343次閱讀
    基于<b class='flag-5'>i.MX6ULL</b>應(yīng)用處理<b class='flag-5'>器</b>的FETMX<b class='flag-5'>6ULL</b>-C核心板

    Linux內(nèi)核定時(shí)器

    在Linux內(nèi)核中,也可以通過定時(shí)器來完成定時(shí)功能。但和單片機(jī)不同的是,Linux內(nèi)核定時(shí)器是一種基于未來時(shí)間點(diǎn)的計(jì)時(shí)方式,它以當(dāng)前時(shí)刻為啟
    的頭像 發(fā)表于 09-22 08:56 ?1956次閱讀
    Linux<b class='flag-5'>內(nèi)核定時(shí)器</b>

    【北京迅為】i.MX6ULL開發(fā)板移植 Debian 文件系統(tǒng)

    【北京迅為】i.MX6ULL開發(fā)板移植 Debian 文件系統(tǒng)
    的頭像 發(fā)表于 02-10 15:34 ?1153次閱讀
    【北京迅為】<b class='flag-5'>i.MX6ULL</b>開發(fā)板移植 Debian 文件系統(tǒng)

    基于i.MX6ULL的掉電檢測(cè)設(shè)計(jì)與軟件測(cè)試

    基于i.MX6ULL的掉電檢測(cè)設(shè)計(jì)與軟件測(cè)試基于i.MX6ULL平臺(tái)設(shè)計(jì)實(shí)現(xiàn)掉電檢測(cè)功能,首先選擇一路IO,利用IO電平變化觸發(fā)中斷,在編寫驅(qū)動(dòng)時(shí)捕獲該路GPIO的中斷,然后在中斷響應(yīng)函數(shù)中發(fā)
    的頭像 發(fā)表于 11-09 10:40 ?866次閱讀
    基于<b class='flag-5'>i.MX6ULL</b>的掉電檢測(cè)設(shè)計(jì)與軟件測(cè)試

    【迅為電子】i.MX6UL和i.MX6ULL芯片區(qū)別與開發(fā)板對(duì)比

    【迅為電子】i.MX6UL和i.MX6ULL芯片區(qū)別與開發(fā)板對(duì)比
    的頭像 發(fā)表于 11-28 14:31 ?408次閱讀
    【迅為電子】<b class='flag-5'>i.MX6</b>UL和<b class='flag-5'>i.MX6ULL</b>芯片區(qū)別與開發(fā)板對(duì)比
    主站蜘蛛池模板: 性春院| 日本在线免费播放| 欧美黄色一级| 樱桃BT在线观看| 国产成人精品男人的天堂网站| 免费久久狼人香蕉网| 亚洲人成色777777老人头| 国产精品俺来也在线观看| 日本不卡免免费观看| 99久久香蕉| 嗯啊好爽视频| 97人妻无码AV碰碰视频| 啦啦啦影院视频在线看高清...| 亚洲国产韩国欧美在线不卡| 国产激情文学| 性肥胖BWBWBW| 国色天香社区视频免费高清3 | 日本福利片午夜免费观着| av天堂网站avtt2017| 欧美亚洲国产专区在线| yy8090韩国理伦片在线| 三叶草成人| 国产精品资源网站在线观看| 新图解av吧| 精品一区二区三区AV天堂| 中文在线观看| 翘臀少妇被扒开屁股日出水爆乳| 草民电影网午夜伦理电影网| 日美一级毛片| 国产在线精彩视频| 一品道门在线视频| 美女快播第一网| 被肉日常np高h| 性欧美videos俄罗斯| 精品国产国产精2020久久日| 重口味av| 色久久久综合88一本道| 国产剧情在线精品视频不卡| 野花韩国免费高清电影| 男人女人边摸边吃奶边做| 俄罗斯性xxxx|