国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

這篇具有很好參考價(jià)值的文章主要介紹了嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

?

使用驅(qū)動(dòng)開(kāi)發(fā)的方式點(diǎn)亮一個(gè)LED燈??纯磧烧哂猩秴^(qū)別不?

一、先看原理圖

首先查看原理圖,看看我們的板子上的LED等接在哪一個(gè)IO口上面。

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

好了,看原理圖我們知道LED燈接在芯片的GPIO1的第三個(gè)引腳上面,也就是GPIO1_IO03。

二、IMX6UL的GPIO操作方法

先掌握三個(gè)名詞

  • CCM: Clock Controller Module (時(shí)鐘控制模塊)

  • IOMUXC : IOMUX Controller,IO復(fù)用控制器

  • GPIO: General-purpose input/output,通用的輸入輸出口

2.1 GPIO模塊結(jié)構(gòu)

參考芯片手冊(cè)《Chapter 26: General Purpose Input/Output (GPIO)》我們知道了IMX6UL一共有有5組GPIO(GPIO1~GPIO5),每組引腳最多有32個(gè),但是可能實(shí)際上并沒(méi)有那么多。

GPIO1有32個(gè)引腳:GPIO1_IO0~GPIO1_IO31;
GPIO2有22個(gè)引腳:GPIO2_IO0~GPIO2_IO21;
GPIO3有29個(gè)引腳:GPIO3_IO0~GPIO3_IO28;
GPIO4有29個(gè)引腳:GPIO4_IO0~GPIO4_IO28;
GPIO5有12個(gè)引腳:GPIO5_IO0~GPIO5_IO11;

我們知道IM6ULL有很多的引腳IO,但是并不是每一個(gè)引腳都能當(dāng)做GPIO使用,它可以復(fù)用為其他模式的,比如作為I2C的時(shí)鐘線I2C2_SCL等其他的用處。所以要向把某一IO當(dāng)做GPIO使用需要將其復(fù)用,在linux中負(fù)責(zé)復(fù)用功能的寄存器IOMUXC_SW_MUX。還有要打開(kāi)這個(gè)GPIO的時(shí)鐘,在linux中叫做CCM,跟STM32一樣還要設(shè)置它的IO口速度、上下拉電阻啊、驅(qū)動(dòng)能力啊、壓擺率(就是 IO 電平跳變所需要的時(shí)間,比如從0到1需要多少時(shí)間,時(shí)間越小波形就越陡,說(shuō)明壓擺率越高)啊等這些,在linux中是用IOMUXC_SW_PAD。

因此如果想要使用某一組GPIO,比如GPIO1_IO03。首先要打開(kāi)GPIO1的時(shí)鐘,然后將GPIO1_IO03設(shè)置為GPIO模式,而不是IIC模式。然后在設(shè)置一下GPIO1_IO03這個(gè)引腳的模式,速度、上下拉電阻、壓擺率等。然后再設(shè)置GPIO1_IO03為輸出模式。最后我們就可以向GPIO1_IO03的DR寄存器也就是數(shù)據(jù)寄存器寫(xiě)入0或者1,就可以輸出高低電平來(lái)控制LED等的亮滅了。

2.2 打開(kāi)的時(shí)鐘

根據(jù)芯片手冊(cè)我們可以看到,要想打開(kāi)GPIO1_IO03的時(shí)鐘就需要要去配置CCGR1這個(gè)寄存器的CG13這個(gè)位

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

而且我還知道了這個(gè)寄存器的地址是20C406CH,因此我們可以寫(xiě)一個(gè)宏定義。

#define?CCM_CCGR1_BASE????(0X020C406C)//這個(gè)寄存器用來(lái)打開(kāi)GPIO1的時(shí)鐘的
/*?1、使能GPIO1時(shí)鐘?*/
val?=?readl(IMX6U_CCM_CCGR1);
val?&=?~(3?<<?26);?/*?清楚以前的設(shè)置?*/
val?|=?(3?<<?26);?/*?設(shè)置新值?*/
writel(val,?IMX6U_CCM_CCGR1);

2.3 IOMUXC引腳復(fù)用和模式配置

參考資料:芯片手冊(cè)《Chapter 32: IOMUX Controller (IOMUXC)》。對(duì)于某個(gè)/某組引腳,IOMUXC中有2個(gè)寄存器用來(lái)設(shè)置它。

IOMUXC_SW_MUX_CTL_PAD_pad-name

IOMUXC_SW_MUX_CTL_PAD_<PADNAME>?:Mux pad xxx,選擇某個(gè)pad的功能
IOMUXC_SW_MUX_CTL_GRP_<GROUP NAME>:Mux grp xxx,選擇某組引腳的功能

某個(gè)引腳,或是某組預(yù)設(shè)的引腳,都有8個(gè)可選的模式(alternate (ALT) MUX_MODE),

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

比如我們要把這個(gè)GPIO1_IO03設(shè)置為GPIO模式,就要將這個(gè)寄存器的bit[0..3]設(shè)置為0101,也就是5.

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

然后也看到這個(gè)寄存器的地址位Address: 20E_0000h base + 68h offset = 20E_0068h

#define?SW_MUX_GPIO1_IO03_BASE??(0X020E0068)//這個(gè)寄存器是將GPIO1_IO03復(fù)用為GPIO的
/*?2、設(shè)置GPIO1_IO03的復(fù)用功能,將其復(fù)用為
?*??? GPIO1_IO03,最后設(shè)置IO屬性。
?*/
writel(5,?SW_MUX_GPIO1_IO03);

IOMUXC_SW_MUX_CTL_GRP_group-name

IOMUXC_SW_PAD_CTL_PAD_<PAD_NAME>:pad pad xxx,設(shè)置某個(gè)pad的參數(shù)
IOMUXC_SW_PAD_CTL_GRP_<GROUP NAME>:pad grp xxx,設(shè)置某組引腳的參數(shù)

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

比如:

2.4 GPIO模塊內(nèi)部

框圖如下:

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

我們暫時(shí)只需要關(guān)心3個(gè)寄存器:

① GPIOx_GDIR:設(shè)置引腳方向,每位對(duì)應(yīng)一個(gè)引腳,1-output,0-input

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

② GPIOx_DR:設(shè)置輸出引腳的電平,每位對(duì)應(yīng)一個(gè)引腳,1-高電平,0-低電平

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

③ GPIOx_PSR:讀取引腳的電平,每位對(duì)應(yīng)一個(gè)引腳,1-高電平,0-低電平

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

三、怎么編程

3.1 讀GPIO

① 設(shè)置CCM_CCGRx寄存器中某位使能對(duì)應(yīng)的GPIO模塊,默認(rèn)是使能的。② 設(shè)置IOMUX來(lái)選擇引腳用于GPIO。③ 設(shè)置GPIOx_GDIR中某位為0,把該引腳設(shè)置為輸入功能。④ 讀GPIOx_DR或GPIOx_PSR得到某位的值(讀GPIOx_DR返回的是GPIOx_PSR的值)

3.2 寫(xiě)GPIO

① 設(shè)置CCM_CCGRx寄存器中某位使能對(duì)應(yīng)的GPIO模塊,默認(rèn)是使能的。② 設(shè)置IOMUX來(lái)選擇引腳用于GPIO。③ 設(shè)置GPIOx_GDIR中某位為1,把該引腳設(shè)置為輸出功能。④ 寫(xiě)GPIOx_DR某位的值。

需要注意的是,你可以設(shè)置該引腳的loopback功能,這樣就可以從GPIOx_PSR中讀到引腳的有實(shí)電平;你從GPIOx_DR中讀回的只是上次設(shè)置的值,它并不能反應(yīng)引腳的真實(shí)電平,比如可能因?yàn)橛布收蠈?dǎo)致該引腳跟地短路了,你通過(guò)設(shè)置GPIOx_DR讓它輸出高電平并不會(huì)起效果。

有了上面的知識(shí),我們點(diǎn)亮led燈的流程基本就了解了。

四、GPIO寄存器操作方法

原則:不能影響到其他位。

4.1 直接讀寫(xiě)

讀出、修改對(duì)應(yīng)位、寫(xiě)入

  • 要設(shè)置bit n

val?=?data_reg;//讀出
val?=?val?|?(1<<n);//修改
data_reg?=?val;//寫(xiě)入
  • 要清除bit n

val?=?data_reg;//讀出
val?=?val?&?~(1<<n);//修改
data_reg?=?val;//寫(xiě)入

4.2 set-and-clear protocol

set_reg,clr_reg,data_reg 三個(gè)寄存器對(duì)應(yīng)的是同一個(gè)物理寄存器

  • 要設(shè)置 bit n:set_reg = (1<<n);

  • 要清除 bit n:clr_reg = (1<<n);

五、編寫(xiě)驅(qū)動(dòng)程序的套路

  • 1、確定主設(shè)備號(hào),也可以讓內(nèi)核分配。

  • 2、定義自己的file_operations結(jié)構(gòu)體。

  • 3、實(shí)現(xiàn)對(duì)應(yīng)的drv_open/drv_read/drv_write等函數(shù),填入file_operations結(jié)構(gòu)體。

  • 4、把file_operations結(jié)構(gòu)體告訴內(nèi)核:register_chrdev。

  • 5、誰(shuí)來(lái)注冊(cè)驅(qū)動(dòng)程序?。康糜幸粋€(gè)入口函數(shù):安裝驅(qū)動(dòng)程序時(shí),就會(huì)去調(diào)用這個(gè)入口函數(shù)。

  • 6、有入口函數(shù)就應(yīng)該有出口函數(shù):卸載驅(qū)動(dòng)程序時(shí),出口函數(shù)調(diào)用unregister_chrdev。

  • 7、其他完善:提供設(shè)備信息,自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn):class_create,device_create。

驅(qū)動(dòng)怎么操作硬件?

  • 通過(guò)ioremap映射寄存器的物理地址得到虛擬地址,讀寫(xiě)虛擬地址。

驅(qū)動(dòng)怎么和APP傳輸數(shù)據(jù)?

  • 通過(guò)copy_to_user、copy_from_user這 2 個(gè)函數(shù)。

六、地址映射

在編寫(xiě)驅(qū)動(dòng)之前,我們需要先簡(jiǎn)單了解一下 MMU 這個(gè)神器,MMU全稱叫做 Memory Manage Unit,也就是內(nèi)存管理單元。在老版本的Linux中要求處理器必須有MMU,但是現(xiàn)在Linux內(nèi)核已經(jīng)支持無(wú)MMU的處理器了。MMU主要完成的功能如下:

  • ①、完成虛擬空間到物理空間的映射。

  • ②、內(nèi)存保護(hù),設(shè)置存儲(chǔ)器的訪問(wèn)權(quán)限,設(shè)置虛擬存儲(chǔ)空間的緩沖特性。

我們重點(diǎn)來(lái)看一下第①點(diǎn),也就是虛擬空間到物理空間的映射,也叫做地址映射。首先了解兩個(gè)地址概念:虛擬地址(VA,Virtual Address)、物理地址(PA,Physcical Address)。對(duì)于 32 位的處理器來(lái)說(shuō),虛擬地址范圍是2^32=4GB,我們的開(kāi)發(fā)板上有512MB的DDR3,這512MB的內(nèi)存就是物理內(nèi)存,經(jīng)過(guò)MMU可以將其映射到整個(gè)4GB的虛擬空間

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

內(nèi)存映射

物理內(nèi)存只有512MB,虛擬內(nèi)存有4GB,那么肯定存在多個(gè)虛擬地址映射到同一個(gè)物理地址上去,虛擬地址范圍比物理地址范圍大的問(wèn)題處理器自會(huì)處理。

Linux內(nèi)核啟動(dòng)的時(shí)候會(huì)初始化MMU,設(shè)置好內(nèi)存映射,設(shè)置好以后CPU 訪問(wèn)的都是虛擬地址。比如 I.MX6ULL的GPIO1_IO03引腳的復(fù)用寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的地址為0X020E0068。如果沒(méi)有開(kāi)啟MMU的話直接向0X020E0068這個(gè)寄存器地址寫(xiě)入數(shù)據(jù)就可以配 GPIO1_IO03的復(fù)用功能?,F(xiàn)在開(kāi)啟了MMU,并且設(shè)置了內(nèi)存映射,因此就不能直接向0X020E0068這個(gè)地址寫(xiě)入數(shù)據(jù)了。我們必須得到 0X020E0068這個(gè)物理地址在Linux系統(tǒng)里面對(duì)應(yīng)的虛擬地址,這里就涉及到了物理內(nèi)存和虛擬內(nèi)存之間的轉(zhuǎn)換,需要用到兩個(gè)函數(shù):ioremap 和 iounmap

6.1 ioremap函數(shù)

ioremap函 數(shù)用于獲取指定物理地址空間對(duì)應(yīng)的虛擬地址空間,定義在arch/arm/include/asm/io.h文件中,定義如下:

#include<asm/io.h>
#define?ioremap(cookie,size)?__arm_ioremap((cookie),?(size),MT_DEVICE)

void?__iomem?*?__arm_ioremap(phys_addr_t?phys_addr,?size_t?size,unsigned?int?mtype)
{
?return?arch_ioremap_caller(phys_addr,?size,?mtype,__builtin_return_address(0));
}

ioremap 是個(gè)宏,有兩個(gè)參數(shù):cookie 和 size,真正起作用的是函數(shù)__arm_ioremap,此函數(shù)有三個(gè)參數(shù)和一個(gè)返回值,這些參數(shù)和返回值的含義如下:

  • phys_addr:要映射給的物理起始地址。

  • size:要映射的內(nèi)存空間大小。

  • mtype:ioremap 的類型,可以選擇 MT_DEVICE、MT_DEVICE_NONSHARED、MT_DEVICE_CACHED 和 MT_DEVICE_WC,ioremap 函數(shù)選擇 MT_DEVICE。

  • 返回值:__iomem 類型的指針,指向映射后的虛擬空間首地址。

假如我們要獲取I.MX6ULL的IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器對(duì)應(yīng)的虛擬地址,使用如下代碼即可:

#define?SW_MUX_GPIO1_IO03_BASE??(0X020E0068)
static?void?__iomem*?SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03?=?ioremap(SW_MUX_GPIO1_IO03_BASE,?4);

SW_MUX_GPIO1_IO03_BASE是寄存器物理地址,SW_MUX_GPIO1_IO03是映射后的虛擬地址。對(duì)于I.MX6ULL 來(lái)說(shuō)一個(gè)寄存器是4 字節(jié)(32 位)的,因此映射的內(nèi)存長(zhǎng)度為 4。映射完成以后直接對(duì)SW_MUX_GPIO1_IO03進(jìn)行讀寫(xiě)操作即可。實(shí)際上,它是按頁(yè)(4096 字節(jié))進(jìn)行映射的,是整頁(yè)整頁(yè)地映射的。所以說(shuō)雖然映射的是4字節(jié),實(shí)際上映射的是4096字節(jié)。

6.2 iounmap函數(shù)

卸載驅(qū)動(dòng)的時(shí)候需要使用iounmap函數(shù)釋放掉ioremap函數(shù)所做的映射,iounmap函數(shù)原型如下:

void?iounmap?(volatile?void?__iomem?*addr)

iounmap只有一個(gè)參數(shù)addr,此參數(shù)就是要取消映射的虛擬地址空間首地址。假如我們現(xiàn)在要取消掉IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器的地址映射,使用如下代碼即可:

iounmap(SW_MUX_GPIO1_IO03);

6.3 volatile的使用

① 編譯器很聰明,會(huì)幫我們做些優(yōu)化,比如:

int?a;
a?=?0;?//?這句話可以優(yōu)化掉,不影響?a?的結(jié)果
a?=?1;

② 有時(shí)候編譯器會(huì)自作聰明,比如:

int?*p?=?ioremap(xxxx,?4);?//?GPIO?寄存器的地址
*p?=?0;?//?點(diǎn)燈,但是這句話被優(yōu)化掉了
*p?=?1;?//?滅燈

③ 對(duì)于上面的情況,為了避免編譯器自動(dòng)優(yōu)化,需要加上 volatile,告訴它這是容易出錯(cuò)的,別亂優(yōu)化:

volatile?int?*p?=?ioremap(xxxx,?4);?//?GPIO?寄存器的地址
*p?=?0;?//?點(diǎn)燈,這句話不會(huì)被優(yōu)化掉
*p?=?1;?//?滅燈

七、I/O內(nèi)存訪問(wèn)函數(shù)

這里說(shuō)的I/O是輸入/輸出的意思,并不是我們學(xué)習(xí)單片機(jī)的時(shí)候講的GPIO引腳。這里涉及到兩個(gè)概念:I/O端口和I/O內(nèi)存。

當(dāng)外部寄存器或內(nèi)存映射到IO空間時(shí),稱為I/O端口。當(dāng)外部寄存器或內(nèi)存映射到內(nèi)存空間時(shí),稱為I/O內(nèi)存。

但是對(duì)于ARM來(lái)說(shuō)沒(méi)有 I/O 空間這個(gè)概念,因此ARM體系下只有I/O內(nèi)存(可以直接理解為內(nèi)存)。使用ioremap函數(shù)將寄存器的物理地址映射到虛擬地址以后,我們就可以直接通過(guò)指針訪問(wèn)這些地址,但是Linux內(nèi)核不建議這么做,而是推薦使用一組操作函數(shù)來(lái)對(duì)映射后的內(nèi)存進(jìn)行讀寫(xiě)操作

上面的話是啥意思呢?

我說(shuō)通俗一點(diǎn)就是:我現(xiàn)在知道了GPIO1_IO03它的時(shí)鐘寄存器地址是0X020C406C,但是你不能直接操作它

#define?CCM_CCGR1_BASE????(0X020C406C)

0X020C406C是它實(shí)際存在的也就是物理地址,但是呢在Linux內(nèi)核啟動(dòng)的時(shí)候會(huì)初始化MMU,設(shè)置好內(nèi)存映射,設(shè)置好以后CPU訪問(wèn)的都是虛擬地址,我們就不能操作實(shí)際的物理地址了。怎么辦呢?不用怕,Linux提供了ioremap內(nèi)存映射函數(shù),我知道了實(shí)際的物理地址,只要通過(guò)這個(gè)函數(shù)我們就自動(dòng)的獲取到了這個(gè)物理地址對(duì)應(yīng)的虛擬地址了

IMX6U_CCM_CCGR1?=?ioremap(CCM_CCGR1_BASE,?4);

現(xiàn)在我們就得到了0X020C406C對(duì)應(yīng)的虛擬地址IMX6U_CCM_CCGR1 ,但是呢,現(xiàn)在我們還不能直接操作這個(gè)虛擬地址。這又為啥呢?因?yàn)槭褂胕oremap函數(shù)將寄存器的物理地址映射到虛擬地址以后,按說(shuō)我們就可以直接通過(guò)指針訪問(wèn)這些地址,但是Linux內(nèi)核不建議這么做,而是推薦使用一組操作函數(shù)來(lái)對(duì)映射后的內(nèi)存進(jìn)行讀寫(xiě)操作。好家伙,Linux內(nèi)核它不建議這樣做,它又提供了讀寫(xiě)函數(shù)對(duì)這個(gè)虛擬地址進(jìn)行操作。那么我們用戶只能按照它建議的這樣做了。比如我想操作這個(gè)地址后4個(gè)字節(jié)的某幾個(gè)位,就需要下面這樣做,先把這個(gè)地址對(duì)應(yīng)的內(nèi)存空間讀出來(lái),然后修改,最后再把修改好的數(shù)據(jù)寫(xiě)入就可以了。

val?=?readl(IMX6U_CCM_CCGR1);
val?&=?~(3?<<?26);?/*?清楚以前的設(shè)置?*/
val?|=?(3?<<?26);?/*?設(shè)置新值?*/
writel(val,?IMX6U_CCM_CCGR1);

具體的讀操作和寫(xiě)操作函數(shù)如下:

1 、讀操作函數(shù)

讀操作函數(shù)有如下幾個(gè):

u8?readb(const?volatile?void?__iomem?*addr)//讀8bit
u16?readw(const?volatile?void?__iomem?*addr)//讀16bit
u32?readl(const?volatile?void?__iomem?*addr)//讀32bit

readb、readw 和readl這三個(gè)函數(shù)分別對(duì)應(yīng) 8bit、16bit 和 32bit讀操作,參數(shù)addr就是要讀取寫(xiě)內(nèi)存地址,返回值就是讀取到的數(shù)據(jù)。

2 、寫(xiě)操作函數(shù)

寫(xiě)操作函數(shù)有如下幾個(gè):

void?writeb(u8?value,?volatile?void?__iomem?*addr)//寫(xiě)8bit
void?writew(u16?value,?volatile?void?__iomem?*addr)//寫(xiě)16bit
void?writel(u32?value,?volatile?void?__iomem?*addr)//寫(xiě)32bit

writeb、writew 和 writel 這三個(gè)函數(shù)分別對(duì)應(yīng) 8bit、16bit 和 32bit 寫(xiě)操作,參數(shù)value是要寫(xiě)入的數(shù)值,addr是要寫(xiě)入的地址。

八、程序編寫(xiě)

8.1 編寫(xiě)驅(qū)動(dòng)程序

#include?<linux/types.h>
#include?<linux/kernel.h>
#include?<linux/delay.h>
#include?<linux/ide.h>
#include?<linux/init.h>
#include?<linux/module.h>
#include?<linux/errno.h>
#include?<linux/gpio.h>
#include?<asm/mach/map.h>
#include?<asm/uaccess.h>
#include?<asm/io.h>

/*

我們要配置某一個(gè)GPIO的引腳
1、先打開(kāi)這個(gè)GPIO的時(shí)鐘
2、在講這個(gè)GPIO復(fù)用為GPIO功能
3、設(shè)置這個(gè)GPIO的參數(shù)等
4、設(shè)置這個(gè)GPIO是輸入還是輸出
5、向這個(gè)GPIO的數(shù)據(jù)寄存器寫(xiě)數(shù)據(jù)就可以了
*/

#define?LED_MAJOR??200??/*?主設(shè)備號(hào)?*/
#define?LED_NAME??"led"??/*?設(shè)備名字?*/

#define?LEDOFF??0????/*?關(guān)燈?*/
#define?LEDON??1????/*?開(kāi)燈?*/
?
/*?寄存器物理地址?*/
#define?CCM_CCGR1_BASE????(0X020C406C)//這個(gè)寄存器用來(lái)打開(kāi)GPIO1的時(shí)鐘的
#define?SW_MUX_GPIO1_IO03_BASE??(0X020E0068)//這個(gè)寄存器是將GPIO1_IO03復(fù)用為GPIO的
#define?SW_PAD_GPIO1_IO03_BASE??(0X020E02F4)//這個(gè)寄存器是配置GPIO1_IO03的速度、驅(qū)動(dòng)能力、壓擺率等
#define?GPIO1_DR_BASE????(0X0209C000)//這個(gè)寄存器是GPIO1_IO03的數(shù)據(jù)寄存器
#define?GPIO1_GDIR_BASE????(0X0209C004)//這個(gè)寄存器是設(shè)置GPIO1_IO03的方向,輸入還是輸出


/*?映射后的寄存器虛擬地址指針?*/
static?void?__iomem?*IMX6U_CCM_CCGR1;
static?void?__iomem?*SW_MUX_GPIO1_IO03;
static?void?__iomem?*SW_PAD_GPIO1_IO03;
static?void?__iomem?*GPIO1_DR;
static?void?__iomem?*GPIO1_GDIR;

/*
?*?@description??:?LED打開(kāi)/關(guān)閉
?*?@param?-?sta??:?LEDON(0)?打開(kāi)LED,LEDOFF(1)?關(guān)閉LED
?*?@return????:?無(wú)
?*/
void?led_switch(u8?sta)
{
?u32?val?=?0;
?if(sta?==?LEDON)?{
??val?=?readl(GPIO1_DR);
??val?&=?~(1?<<?3);?
??writel(val,?GPIO1_DR);
?}else?if(sta?==?LEDOFF)?{
??val?=?readl(GPIO1_DR);
??val|=?(1?<<?3);?
??writel(val,?GPIO1_DR);
?}?
}

/*
?*?@description??:?打開(kāi)設(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?成功;其他?失敗
?*/
static?int?led_open(struct?inode?*inode,?struct?file?*filp)
{
?return?0;
}

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

/*
?*?@description??:?向設(shè)備寫(xiě)數(shù)據(jù)?
?*?@param?-?filp??:?設(shè)備文件,表示打開(kāi)的文件描述符
?*?@param?-?buf??:?要寫(xiě)給設(shè)備寫(xiě)入的數(shù)據(jù)
?*?@param?-?cnt??:?要寫(xiě)入的數(shù)據(jù)長(zhǎng)度
?*?@param?-?offt??:?相對(duì)于文件首地址的偏移
?*?@return????:?寫(xiě)入的字節(jié)數(shù),如果為負(fù)值,表示寫(xiě)入失敗
?*/
static?ssize_t?led_write(struct?file?*filp,?const?char?__user?*buf,?size_t?cnt,?loff_t?*offt)
{
?int?retvalue;
?unsigned?char?databuf[1];
?unsigned?char?ledstat;

?retvalue?=?copy_from_user(databuf,?buf,?cnt);
?if(retvalue?<?0)?{
??printk("kernel?write?failed!\r\n");
??return?-EFAULT;
?}

?ledstat?=?databuf[0];??/*?獲取狀態(tài)值?*/

?if(ledstat?==?LEDON)?{?
??led_switch(LEDON);??/*?打開(kāi)LED燈?*/
?}?else?if(ledstat?==?LEDOFF)?{
??led_switch(LEDOFF);?/*?關(guān)閉LED燈?*/
?}
?return?0;
}

/*
?*?@description??:?關(guān)閉/釋放設(shè)備
?*?@param?-?filp??:?要關(guān)閉的設(shè)備文件(文件描述符)
?*?@return????:?0?成功;其他?失敗
?*/
static?int?led_release(struct?inode?*inode,?struct?file?*filp)
{
?return?0;
}

/*?設(shè)備操作函數(shù)?*/
static?struct?file_operations?led_fops?=?{
?.owner???=?THIS_MODULE,
?.open???=?led_open,
?.read???=?led_read,
?.write???=?led_write,
?.release?=?led_release,
};

/*
?*?@description?:?驅(qū)動(dòng)出口函數(shù)
?*?@param???:?無(wú)
?*?@return???:?無(wú)
?*/
static?int?__init?led_init(void)
{
?int?retvalue?=?0;
?u32?val?=?0;

?/*?初始化LED?*/
?/*?1、寄存器地址映射?*/
?IMX6U_CCM_CCGR1?=?ioremap(CCM_CCGR1_BASE,?4);
?SW_MUX_GPIO1_IO03?=?ioremap(SW_MUX_GPIO1_IO03_BASE,?4);
?SW_PAD_GPIO1_IO03?=?ioremap(SW_PAD_GPIO1_IO03_BASE,?4);
?GPIO1_DR?=?ioremap(GPIO1_DR_BASE,?4);
?GPIO1_GDIR?=?ioremap(GPIO1_GDIR_BASE,?4);

?/*?2、使能GPIO1時(shí)鐘?*/
?val?=?readl(IMX6U_CCM_CCGR1);
?val?&=?~(3?<<?26);?/*?清楚以前的設(shè)置?*/
?val?|=?(3?<<?26);?/*?設(shè)置新值?*/
?writel(val,?IMX6U_CCM_CCGR1);

?/*?3、設(shè)置GPIO1_IO03的復(fù)用功能,將其復(fù)用為
??*??? GPIO1_IO03,最后設(shè)置IO屬性。
??*/
?writel(5,?SW_MUX_GPIO1_IO03);
?
?/*寄存器SW_PAD_GPIO1_IO03設(shè)置IO屬性
??*bit?16:0?HYS關(guān)閉
??*bit?[15:14]:?00?默認(rèn)下拉
?????*bit?[13]:?0?kepper功能
?????*bit?[12]:?1?pull/keeper使能
?????*bit?[11]:?0?關(guān)閉開(kāi)路輸出
?????*bit?[7:6]:?10?速度100Mhz
?????*bit?[5:3]:?110?R0/6驅(qū)動(dòng)能力
?????*bit?[0]:?0?低轉(zhuǎn)換率
??*/
?writel(0x10B0,?SW_PAD_GPIO1_IO03);

?/*?4、設(shè)置GPIO1_IO03為輸出功能?*/
?val?=?readl(GPIO1_GDIR);
?val?&=?~(1?<<?3);?/*?清除以前的設(shè)置?*/
?val?|=?(1?<<?3);?/*?設(shè)置為輸出?*/
?writel(val,?GPIO1_GDIR);

?/*?5、默認(rèn)關(guān)閉LED?*/
?val?=?readl(GPIO1_DR);
?val?|=?(1?<<?3);?
?writel(val,?GPIO1_DR);

?/*?6、注冊(cè)字符設(shè)備驅(qū)動(dòng)?*/
?retvalue?=?register_chrdev(LED_MAJOR,?LED_NAME,?&led_fops);
?if(retvalue?<?0){
??printk("register?chrdev?failed!\r\n");
??return?-EIO;
?}
?return?0;
}

/*
?*?@description?:?驅(qū)動(dòng)出口函數(shù)
?*?@param???:?無(wú)
?*?@return???:?無(wú)
?*/
static?void?__exit?led_exit(void)
{
?/*?取消映射?*/
?iounmap(IMX6U_CCM_CCGR1);
?iounmap(SW_MUX_GPIO1_IO03);
?iounmap(SW_PAD_GPIO1_IO03);
?iounmap(GPIO1_DR);
?iounmap(GPIO1_GDIR);

?/*?注銷字符設(shè)備驅(qū)動(dòng)?*/
?unregister_chrdev(LED_MAJOR,?LED_NAME);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhiguoxin");

有了上面的講解,代碼很簡(jiǎn)單就不用多說(shuō)了,就是按照那7步來(lái)操作的。

8.2 編寫(xiě)測(cè)試程序

#include?"stdio.h"
#include?"unistd.h"
#include?"sys/types.h"
#include?"sys/stat.h"
#include?"fcntl.h"
#include?"stdlib.h"
#include?"string.h"
/***************************************************************

使用方法??:
./ledtest?/dev/led??0???關(guān)閉LED
./ledtest?/dev/led??1???打開(kāi)LED??
***************************************************************/

#define?LEDOFF??0
#define?LEDON??1

/*
?*?@description??:?main主程序
?*?@param?-?argc??:?argv數(shù)組元素個(gè)數(shù)
?*?@param?-?argv??:?具體參數(shù)
?*?@return????:?0?成功;其他?失敗
?*/
int?main(int?argc,?char?*argv[])
{
?int?fd,?retvalue;
?char?*filename;
?unsigned?char?databuf[1];
?
?if(argc?!=?3){
??printf("Error?Usage!\r\n");
??return?-1;
?}

?filename?=?argv[1];

?/*?打開(kāi)led驅(qū)動(dòng)?*/
?fd?=?open(filename,?O_RDWR);
?if(fd?<?0){
??printf("file?%s?open?failed!\r\n",?argv[1]);
??return?-1;
?}

?databuf[0]?=?atoi(argv[2]);?/*?要執(zhí)行的操作:打開(kāi)或關(guān)閉?*/

?/*?向/dev/led文件寫(xiě)入數(shù)據(jù)?*/
?retvalue?=?write(fd,?databuf,?sizeof(databuf));
?if(retvalue?<?0){
??printf("LED?Control?Failed!\r\n");
??close(fd);
??return?-1;
?}

?retvalue?=?close(fd);?/*?關(guān)閉文件?*/
?if(retvalue?<?0){
??printf("file?%s?close?failed!\r\n",?argv[1]);
??return?-1;
?}
?return?0;
}

測(cè)試程序就很簡(jiǎn)單了,不用多說(shuō)。

3 8.編寫(xiě)Makefile

KERNELDIR?:=?/home/zhiguoxin/linux/IMX6ULL/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH?:=?$(shell?pwd)

obj-m?:=?led.o

build:?kernel_modules

kernel_modules:
?$(MAKE)?-C?$(KERNELDIR)?M=$(CURRENT_PATH)?modules
?$(CROSS_COMPILE)arm-linux-gnueabihf-gcc?-o?ledApp?ledApp.c?

clean:
?$(MAKE)?-C?$(KERNELDIR)?M=$(CURRENT_PATH)?clean
  • 第1行,KERNELDIR表示開(kāi)發(fā)板所使用的Linux內(nèi)核源碼目錄,使用絕對(duì)路徑,大家根據(jù)自己的實(shí)際情況填寫(xiě)。

  • 第2行,CURRENT_PATH表示當(dāng)前路徑,直接通過(guò)運(yùn)行pwd命令來(lái)獲取當(dāng)前所處路徑。

  • 第3行,obj-m表示將led.c這個(gè)文件編譯為led.ko模塊。

  • 第8行,具體的編譯命令,后面的modules表示編譯模塊,-C表示將當(dāng)前的工作目錄切換到指定目錄中,也就是KERNERLDIR目錄。M表示模塊源碼目錄,make modules命令中加入M=dir以后程序會(huì)自動(dòng)到指定的 dir 目錄中讀取模塊的源碼并將其編譯為.ko?文件。

  • 第9行,使用交叉編譯工具鏈將ledApp.c編譯成可以在arm板子上運(yùn)行的ledApp可執(zhí)行文件。

Makefile 編寫(xiě)好以后輸入make命令編譯驅(qū)動(dòng)模塊,編譯過(guò)程如圖所示

九、運(yùn)行測(cè)試

9.1 上傳程序到開(kāi)發(fā)板執(zhí)行

開(kāi)發(fā)板啟動(dòng)后通過(guò)NFS掛載Ubuntu目錄的方式,將相應(yīng)的文件拷貝到開(kāi)發(fā)板上。簡(jiǎn)單來(lái)說(shuō),就是通過(guò)NFS在開(kāi)發(fā)板上通過(guò)網(wǎng)絡(luò)直接訪問(wèn)ubuntu虛擬機(jī)上的文件,并且就相當(dāng)于自己本地的文件一樣。

因?yàn)槲业拇a都放在/home/zhiguoxin/myproject/alientek_drv_development_source這個(gè)目錄下,所以我們將這個(gè)目錄作為NFS共享文件夾。

Ubuntu IP為192.168.10.100,一般都是掛載在開(kāi)發(fā)板的mnt目錄下,這個(gè)目錄是專門用來(lái)給我們作為臨時(shí)掛載的目錄。

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

文件系統(tǒng)目錄簡(jiǎn)介

然后使用MobaXterm軟件通過(guò)SSH訪問(wèn)開(kāi)發(fā)板。

ubuntu?ip:192.168.10.100
windows?ip:192.168.10.200
開(kāi)發(fā)板ip:192.168.10.50

在開(kāi)發(fā)板上執(zhí)行以下命令就可以實(shí)現(xiàn)掛載了:

mount?-t?nfs?-o?nolock,vers=3?192.168.10.100:/home/zhiguoxin/myproject/alientek_drv_development_source?/mnt

就將開(kāi)飯的mnt目錄掛載在ubuntu的/home/zhiguoxin/myproject/alientek_drv_development_source目錄下了。這樣我們就可以在Ubuntu下修改文件,然后可以直接在開(kāi)發(fā)板上執(zhí)行可執(zhí)行文件了。當(dāng)然我這里的/home/zhiguoxin/myproject/windows之間是一個(gè)共享目錄,我也可以直接在windows上面修改文件,然后ubuntu和開(kāi)發(fā)板直接進(jìn)行文件同步了。

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

9.2 加載驅(qū)動(dòng)模塊

驅(qū)動(dòng)模塊led.koledApp可執(zhí)行文件都已經(jīng)準(zhǔn)備好了,接下來(lái)就是運(yùn)行測(cè)試。這里我是用掛載的方式將服務(wù)端的項(xiàng)目文件夾掛載到arm板的mnt目錄,進(jìn)入到/mnt/02_led目錄輸入如下命令加載led.ko驅(qū)動(dòng)文件:

insmod?led.ko

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

9.3 創(chuàng)建設(shè)備節(jié)點(diǎn)文件

驅(qū)動(dòng)加載成功需要在/dev目錄下創(chuàng)建一個(gè)與之對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)文件,應(yīng)用程序就是通過(guò)操作這個(gè)設(shè)備節(jié)點(diǎn)文件來(lái)完成對(duì)具體設(shè)備的操作。輸入如下命令創(chuàng)建/dev/led這個(gè)設(shè)備節(jié)點(diǎn)文件:

mknod?/dev/led?c?200?0

其中mknod是創(chuàng)建節(jié)點(diǎn)命令,/dev/hello_drv?是要?jiǎng)?chuàng)建的節(jié)點(diǎn)文件,c表示這是個(gè)字符設(shè)備,200是設(shè)備的主設(shè)備號(hào),0是設(shè)備的次設(shè)備號(hào)。創(chuàng)建完成以后就會(huì)存在/dev/led這個(gè)文件,可以使用ls /dev/led-l命令查看。

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

9.3 led設(shè)備操作測(cè)試

一切準(zhǔn)備就緒。使用ledtest?軟件操作led這個(gè)設(shè)備,看看是否可以正常打開(kāi)或關(guān)閉led。

./ledApp?/dev/led??0???關(guān)閉LED
./ledApp?/dev/led??1???打開(kāi)LED?

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

9.4 ?卸載驅(qū)動(dòng)模塊

如果不再使用某個(gè)設(shè)備的話可以將其驅(qū)動(dòng)卸載掉,比如輸入如下命令卸載掉hello_drv這個(gè)設(shè)備:

rmmod?led.ko

卸載以后使用lsmod命令查看led這個(gè)模塊還存不存在:

嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈

可以看出,此時(shí)系統(tǒng)已經(jīng)沒(méi)有任何模塊了,led這個(gè)模塊也不存在了,說(shuō)明模塊卸載成功。而且系統(tǒng)中也沒(méi)有了led這個(gè)設(shè)備。

至此,led這個(gè)設(shè)備的整個(gè)驅(qū)動(dòng)就驗(yàn)證完成了,驅(qū)動(dòng)工作正常。以后的字符設(shè)備驅(qū)動(dòng)實(shí)驗(yàn)基本都可以此為模板進(jìn)行編寫(xiě)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-428465.html

到了這里,關(guān)于嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)之點(diǎn)燈的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā) 04:基于設(shè)備樹(shù)的驅(qū)動(dòng)開(kāi)發(fā)

    嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā) 04:基于設(shè)備樹(shù)的驅(qū)動(dòng)開(kāi)發(fā)

    前面文章 《嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā) 03:平臺(tái)(platform)總線驅(qū)動(dòng)模型》 引入了資源和驅(qū)動(dòng)分離的概念,這篇文章將在前面基礎(chǔ)上更進(jìn)一步,引入設(shè)備樹(shù)的概念。 在平臺(tái)總線驅(qū)動(dòng)模型中資源和驅(qū)動(dòng)已經(jīng)從邏輯上和代碼組織上進(jìn)行了分離,但每次調(diào)整資源還是會(huì)涉及到內(nèi)核,所以現(xiàn)

    2024年02月16日
    瀏覽(27)
  • 正點(diǎn)原子嵌入式linux驅(qū)動(dòng)開(kāi)發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)

    正點(diǎn)原子嵌入式linux驅(qū)動(dòng)開(kāi)發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)

    網(wǎng)絡(luò)驅(qū)動(dòng)是linux里面驅(qū)動(dòng)三巨頭之一 ,linux下的網(wǎng)絡(luò)功能非常強(qiáng)大,嵌入式linux中也常常用到網(wǎng)絡(luò)功能。前面已經(jīng)講過(guò)了字符設(shè)備驅(qū)動(dòng)和塊設(shè)備驅(qū)動(dòng),本章就來(lái)學(xué)習(xí)一下linux里面的 網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng) 。 本次筆記中討論的都是有線網(wǎng)絡(luò)! 提起網(wǎng)絡(luò),一般想到的硬件就是“網(wǎng)卡”。在

    2024年01月17日
    瀏覽(25)
  • 【嵌入式Linux驅(qū)動(dòng)】驅(qū)動(dòng)開(kāi)發(fā)調(diào)試相關(guān)的關(guān)系記錄

    【嵌入式Linux驅(qū)動(dòng)】驅(qū)動(dòng)開(kāi)發(fā)調(diào)試相關(guān)的關(guān)系記錄

    https://www.processon.com/mindmap/64537772b546c76a2f37bd2f

    2024年02月02日
    瀏覽(27)
  • 嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)系列六:Makefile

    嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)系列六:Makefile

    Makefile是什么? gcc hello.c -o hello gcc aa.c bb.c cc.c dd.c ... make工具和Makefile make和Makefile是什么關(guān)系? make工具:找出修改過(guò)的文件,根據(jù)依賴關(guān)系,找出受影響的相關(guān)文件,最后按照規(guī)則單獨(dú)編譯這些文件。 Makefile文件:記錄依賴關(guān)系和編譯規(guī)則。 必須要學(xué)精Makefile嗎? 怎么學(xué)習(xí)Makefi

    2024年02月13日
    瀏覽(24)
  • 嵌入式linux驅(qū)動(dòng)開(kāi)發(fā)篇之設(shè)備樹(shù)

    嵌入式linux驅(qū)動(dòng)開(kāi)發(fā)篇之設(shè)備樹(shù)

    設(shè)備樹(shù)(Device Tree)是一種用于描述嵌入式系統(tǒng)硬件組件及其連接關(guān)系的數(shù)據(jù)結(jié)構(gòu)。它被廣泛用于嵌入式 Linux 系統(tǒng),尤其是針對(duì)使用多種不同架構(gòu)和平臺(tái)的嵌入式系統(tǒng)。它是一種與硬件描述相關(guān)的中間表示形式,將硬件信息抽象成一種可移植的格式,使得操作系統(tǒng)和引導(dǎo)加載

    2024年02月22日
    瀏覽(25)
  • 嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)(LCD屏幕專題)(一)

    嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)(LCD屏幕專題)(一)

    總的分辨率是 yres*xres。 以下三種方式表示顏色 每個(gè)屏幕都有一個(gè)內(nèi)存(framebuffer)如下圖,內(nèi)存中每塊數(shù)據(jù)對(duì)用屏幕上的一個(gè)像素點(diǎn),設(shè)置好LCD后,只需把顏色數(shù)據(jù)寫(xiě)入framebuffer即可。 Framebuffer驅(qū)動(dòng)屬于字符設(shè)備驅(qū)動(dòng),我們先說(shuō)字符設(shè)備驅(qū)動(dòng)框架如下圖: 驅(qū)動(dòng)主設(shè)備號(hào) 構(gòu)造

    2024年02月09日
    瀏覽(30)
  • 嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)(LCD屏幕專題)(三)

    嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)(LCD屏幕專題)(三)

    1. 硬件相關(guān)的操作 LCD驅(qū)動(dòng)程序的核心就是: 分配fb_info 設(shè)置fb_info 注冊(cè)fb_info 硬件相關(guān)的設(shè)置 硬件相關(guān)的設(shè)置又可以分為3部分: 引腳設(shè)置 時(shí)鐘設(shè)置 LCD控制器設(shè)置 2. 在設(shè)備樹(shù)里指定LCD參數(shù) 3. 編程 3.1 從設(shè)備樹(shù)獲得參數(shù) 時(shí)序參數(shù)、引腳極性等信息,都被保存在一個(gè)display_timi

    2024年02月09日
    瀏覽(33)
  • 嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā) 02:將驅(qū)動(dòng)程序添加到內(nèi)核中

    嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā) 02:將驅(qū)動(dòng)程序添加到內(nèi)核中

    在上一篇文章 《嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā) 01:基礎(chǔ)開(kāi)發(fā)與使用》 中我們已經(jīng)實(shí)現(xiàn)了最基礎(chǔ)的驅(qū)動(dòng)功能。在那篇文章中我們的驅(qū)動(dòng)代碼是獨(dú)立于內(nèi)核代碼存放的,并且我們的驅(qū)動(dòng)編譯后也是一個(gè)獨(dú)立的模塊。在實(shí)際使用中將驅(qū)動(dòng)代碼放在內(nèi)核代碼中,并將驅(qū)動(dòng)編譯到內(nèi)核中也是比較

    2023年04月09日
    瀏覽(51)
  • 嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)系列五:Linux系統(tǒng)和HelloWorld

    嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)系列五:Linux系統(tǒng)和HelloWorld

    三個(gè)問(wèn)題 了解Hello World程序的執(zhí)行過(guò)程有什么用? 編譯和執(zhí)行:Hello World程序的執(zhí)行分為兩個(gè)主要步驟:編譯和執(zhí)行。編譯器將源代碼轉(zhuǎn)換為可執(zhí)行文件,然后計(jì)算機(jī)執(zhí)行該文件并輸出相應(yīng)的結(jié)果。了解這個(gè)過(guò)程可以幫助我們理解如何將代碼轉(zhuǎn)化為可運(yùn)行的程序。 語(yǔ)法和語(yǔ)義

    2024年02月13日
    瀏覽(26)
  • 嵌入式linux驅(qū)動(dòng)開(kāi)發(fā)之移遠(yuǎn)4G模塊EC800驅(qū)動(dòng)移植指南

    嵌入式linux驅(qū)動(dòng)開(kāi)發(fā)之移遠(yuǎn)4G模塊EC800驅(qū)動(dòng)移植指南

    回顧下移遠(yuǎn)4G模塊移植過(guò)程, 還是蠻簡(jiǎn)單的。一通百通,無(wú)論是其他4G模塊都是一樣的。這里記錄下過(guò)程,分享給有需要的人。環(huán)境使用正點(diǎn)原子的imax6ul開(kāi)發(fā)板,板子默認(rèn)支持中興和移遠(yuǎn)EC20的驅(qū)動(dòng),這里要移植使用的是移遠(yuǎn)4G模塊EC800。 imax6ul開(kāi)發(fā)板 虛擬機(jī)(Ubuntu18.04) 交叉編譯

    2024年02月17日
    瀏覽(52)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包