日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

嵌入式Linux设备驱动程序:用户空间中的设备驱动程序

發(fā)布時間:2023/11/28 生活经验 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嵌入式Linux设备驱动程序:用户空间中的设备驱动程序 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

嵌入式Linux設(shè)備驅(qū)動程序:用戶空間中的設(shè)備驅(qū)動程序

Embedded Linux
device drivers: Device drivers in user space

Interfacing with Device Drivers

Device drivers in user space

用戶空間中的設(shè)備驅(qū)動程序

在開始編寫設(shè)備驅(qū)動程序之前,請暫停片刻,考慮是否確實有必要。對于許多常見類型的設(shè)備,有通用的設(shè)備驅(qū)動程序,允許您直接從用戶空間與硬件交互,而不必編寫一行內(nèi)核代碼。用戶空間代碼當然更容易編寫和調(diào)試。它也不包括在GPL中,盡管我覺得這本身并不是一個很好的理由來這樣做。

這些驅(qū)動程序分為兩大類:通過sysfs中的文件(包括GPIO和led)進行控制的驅(qū)動程序,以及通過設(shè)備節(jié)點(如I2C)公開通用接口的串行總線。

GPIO

通用輸入/輸出(GPIO)是最簡單的數(shù)字接口形式,因為它可以直接訪問各個硬件引腳,每個引腳可以處于兩種狀態(tài)之一:高或低。在大多數(shù)情況下,您可以將GPIO管腳配置為輸入或輸出。你甚至可以使用一組GPIO管腳,通過操作軟件中的每個位來創(chuàng)建更高級的接口,比如I2C或SPI,這種技術(shù)被稱為位碰撞。主要的限制是軟件循環(huán)的速度和精度,以及您希望專用于它們的CPU周期數(shù)。一般來說,除非配置一個實時內(nèi)核,否則很難達到比毫秒更好的計時器精度。GPIO更常見的用例是讀取按鈕和數(shù)字傳感器以及控制led、電機和繼電器。

大多數(shù)soc有很多GPIO位,這些位被組合在GPIO寄存器中,通常每個寄存器32位。片上GPIO位通過多路復用器(稱為pinmux)路由到芯片封裝上的GPIO管腳。在電源管理芯片和專用的GPIO擴展器中,可能有額外的GPIO引腳,通過I2C或SPI總線連接。所有這些多樣性都由一個名為gpiolib的內(nèi)核子系統(tǒng)來處理,它實際上不是一個庫,而是GPIO驅(qū)動程序用來以一致的方式公開I/O的基礎(chǔ)設(shè)施。在Documentation/gpio的內(nèi)核源代碼中有關(guān)于gpiolib實現(xiàn)的詳細信息,驅(qū)動程序本身的代碼在drivers/gpio中。

應(yīng)用程序可以通過/sys/class/gpio目錄中的文件與gpiolib交互。下面是一個典型的嵌入式板(BeagleBone Black)的示例:

ls /sys/class/gpio

export
gpiochip0 gpiochip32 gpiochip64 gpiochip96
unexport

名為gpiochip0到gpiochip96的目錄代表四個GPIO寄存器,每個寄存器有32個GPIO位。如果您查看其中一個gpiochip目錄,您將看到以下內(nèi)容:

ls

/sys/class/gpio/gpiochip96

base
label ngpio power subsystem uevent

名為base的文件包含寄存器中第一個GPIO引腳的編號,ngpio包含寄存器中的位數(shù)。在本例中,gpiochip96/base是96,gpiochip96/ngpio是32,這說明它包含GPIO位96到127。在一個寄存器中的最后一個GPIO和下一個寄存器中的第一個GPIO之間可能存在間隙。 要從用戶空間控制GPIO位,首先必須從內(nèi)核空間導出它,這是通過將GPIO編號寫入/sys/class/GPIO/export來完成的。此示例顯示GPIO 53的處理過程,它連接到BeagleBone Black上的用戶LED 0:

echo 53 >

/sys/class/gpio/export

ls

/sys/class/gpio

export gpio53 gpiochip0
gpiochip32 gpiochip64 gpiochip96 unexport

現(xiàn)在,有一個新的目錄gpio53,其中包含控制pin所需的文件。

如果GPIO位已經(jīng)被內(nèi)核聲明,您將無法以這種方式導出它。

目錄gpio53包含以下文件:

ls

/sys/class/gpio/gpio53

active_low direction
power uevent

device
edge subsystem value

管腳從輸入開始。若要將其更改為輸出,請寫入方向文件。文件值包含管腳的當前狀態(tài),0表示低,1表示高。如果是輸出,則可以通過將0或1寫入值來更改狀態(tài)。有時,在硬件中,低和高的含義是相反的(硬件工程師喜歡做這種事情),所以寫1到active_low會顛倒值的含義,這樣低電壓報告為1,高電壓報告為0。

通過將GPIO編號寫入到/sys/class/gpio/unexport,可以從用戶空間控件中刪除GPIO。

處理來自GPIO的中斷

在許多情況下,可以將GPIO輸入配置為在狀態(tài)改變時生成中斷,這允許您等待中斷,而不是在效率低下的軟件循環(huán)中輪詢。如果GPIO位可以生成中斷,則存在名為edge的文件。最初,它的值稱為none,這意味著它不會生成中斷。要啟用中斷,可以將其設(shè)置為以下值之一:

上升:上升沿中斷

下降:下降沿中斷

兩個:在上升和下降邊緣都中斷

無:無中斷(默認)

可以使用poll()函數(shù)和POLLPRI作為事件等待中斷。如果要等待GPIO 48上的上升沿,請首先啟用中斷:

echo 48 >

/sys/class/gpio/export

echo falling

/sys/class/gpio/gpio48/edge

然后,使用poll(2)等待更改,如下面的代碼示例所示,您可以在 MELP/chapter_09/gpio-int/gpio-int.c中的代碼存檔一書中看到

#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <poll.h> int main(int argc, char *argv[]) { int f; struct pollfd poll_fds[1]; int ret; char value[4]; int n; f = open("/sys/class/gpio/gpio48/value", O_RDONLY); if (f == -1) { perror(“Can’t open gpio48”); return 1; } n = read(f, &value, sizeof(value)); if (n > 0) { printf(“Initial value=%cn”, value[0]); lseek(f, 0, SEEK_SET); } poll_fds[0].fd = f; poll_fds[0].events = POLLPRI | POLLERR; while (1) { printf(“Waitingn”); ret = poll(poll_fds, 1, -1); if (ret > 0) { n = read(f, &value, sizeof(value)); printf(“Button pressed: value=%cn”, value[0]); lseek(f, 0, SEEK_SET); } } return 0; }

發(fā)光二極管

led通常通過GPIO管腳進行控制,但是還有另一個內(nèi)核子系統(tǒng)提供了更專門的控制。LED內(nèi)核子系統(tǒng)增加了設(shè)置亮度的功能,如果LED有這種能力,它可以處理以其他方式連接的LED,而不是簡單的GPIO管腳。它可以配置為觸發(fā)事件,如阻止設(shè)備訪問或只是一個心跳信號,以顯示設(shè)備正在工作。您必須使用選項CONFIG_LEDS_CLASS和適合您的LED觸發(fā)器操作來配置內(nèi)核。有關(guān)文檔/led/的詳細信息,驅(qū)動程序位于drivers/led/中。

與GPIOs一樣,led是通過sysfs中目錄為/sys/class/led的接口控制的。在BeagleBone Black的情況下,led的名稱以d的形式編碼在設(shè)備樹中設(shè)備名稱:顏色:函數(shù)devicename:colour:function,如下所示:

ls /sys/class/leds

beaglebone:green:heartbeat beaglebone:green:usr2

beaglebone:green:mmc0
beaglebone:green:usr3

現(xiàn)在,我們可以查看其中一個指示燈的屬性,注意shell要求路徑名中的冒號字符“:”前面必須有一個反斜杠轉(zhuǎn)義符“”:

cd

/sys/class/leds/beaglebone:green:usr2

ls

brightness max_brightness
subsystem uevent

device power trigger

亮度文件控制LED的亮度,可以是0(關(guān)閉)和最大亮度(完全打開)之間的數(shù)字。如果LED不支持中等亮度,任何非零值都會將其打開。名為trigger的文件列出了觸發(fā)LED亮起的事件。觸發(fā)器列表取決于實現(xiàn)。下面是一個例子:

cat trigger

none mmc0 mmc1 timer oneshot
heartbeat backlight gpio [cpu0]

default-on

當前選定的觸發(fā)器顯示在方括號中。您可以通過將其他觸發(fā)器之一寫入文件來更改它。如果要完全通過亮度控制LED,請選擇“無”。如果將觸發(fā)器設(shè)置為計時器,則會出現(xiàn)兩個額外文件,允許您以毫秒為單位設(shè)置開關(guān)時間:

echo timer > trigger

ls

brightness delay_on max_brightness
subsystem uevent

delay_off device power trigger

cat delay_on

500

cat

/sys/class/leds/beaglebone:green:heartbeat/delay_off

500

如果LED具有片上定時器硬件,則閃爍不會中斷CPU。

I2C

I2C是一種簡單的低速2線總線,在嵌入式板上很常見,通常用于訪問不在SoC上的外圍設(shè)備,如顯示控制器、攝像頭傳感器、GPIO擴展器等。在PCs上有一個稱為系統(tǒng)管理總線(SMBus)的相關(guān)標準,用于訪問溫度和電壓傳感器。SMBus是I2C的一個子集。

I2C是一種主從協(xié)議,主機是SoC上的一個或多個主機控制器。從機有一個由制造商分配的7位地址(請閱讀數(shù)據(jù)表),每個總線最多允許128個節(jié)點,但保留了16個節(jié)點,因此實際上只允許112個節(jié)點。主機可以與其中一個從機啟動讀或?qū)懯聞?wù)。通常,第一個字節(jié)用于指定從機上的寄存器,其余字節(jié)是從該寄存器讀取或?qū)懭氲臄?shù)據(jù)。

每個主機控制器有一個設(shè)備節(jié)點,例如,該SoC有四個:

ls -l /dev/i2c*

crw-rw—- 1 root
i2c 89, 0 Jan 1 00:18 /dev/i2c-0

crw-rw—- 1 root i2c 89, 1 Jan 1 00:18 /dev/i2c-1

crw-rw—- 1 root i2c 89, 2 Jan 1 00:18 /dev/i2c-2

crw-rw—- 1 root i2c 89, 3 Jan 1 00:18 /dev/i2c-3

設(shè)備接口提供一系列ioctl命令,用于查詢主機控制器并將讀寫命令發(fā)送到I2C從機。有一個名為i2c-tools的包,它使用這個接口提供與i2c設(shè)備交互的基本命令行工具。工具如下:

· i2cdetect : This lists the I2C adapters, and probes the bus

· i2cdump : This dumps data from all the registers of an I2C
peripheral

· i2cget : This reads data from an I2C slave

· i2cset : This writes data to an I2C slave

i2c工具包可以在Buildroot和Yocto項目以及大多數(shù)主流發(fā)行版中獲得。所以,只要你知道從機的地址和協(xié)議,編寫一個用戶空間程序來與設(shè)備對話是很簡單的。下面的示例顯示如何從安裝在I2C總線0上BeagleBone Black上的從機地址0x50上的AT24C512B EEPROM讀取前四個字節(jié)(代碼在MELP/章節(jié)U 09/I2C示例中):

#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #define I2C_ADDRESS 0x50 int main(void) { int f; int n; char buf[10]; f = open("/dev/i2c-0", O_RDWR); /* Set the address of the i2c slave device / ioctl(f, I2C_SLAVE, I2C_ADDRESS); / Set the 16-bit address to read from to 0 / buf[0] = 0; / address byte 1 / buf[1] = 0; / address byte 2 / n = write(f, buf, 2); / Now read 4 bytes from that address */ n = read(f, buf, 4); printf(“0x%x 0x%x0 0x%x 0x%xn”, buf[0], buf[1], buf[2], buf[3]); close(f); return 0; }

在Documentation/I2C/dev interface中有關(guān)于I2C的Linux實現(xiàn)的更多信息。主控制器驅(qū)動程序位于drivers/i2c/總線中。

串行外設(shè)接口(SPI)

SPI總線類似于I2C,但速度更快,最高可達數(shù)十兆赫。在雙工線路中使用四條獨立的雙工線路進行操作。總線上的每個芯片都通過專用芯片選擇線進行選擇。它通常用于連接觸摸屏傳感器、顯示控制器和串行或閃存設(shè)備。

與I2C一樣,它是主從協(xié)議,大多數(shù)SOC實現(xiàn)一個或多個主主機控制器。有一個通用的SPI設(shè)備驅(qū)動程序,您可以通過內(nèi)核配置CONFIG_SPI峎SPIDEV來啟用它。它為每個SPI控制器創(chuàng)建一個設(shè)備節(jié)點,允許您從用戶空間訪問SPI芯片。設(shè)備節(jié)點被命名為spidev[bus].[chip select]:

ls -l /dev/spi*

crw-rw—- 1 root root 153, 0 Jan 1 00:29 /dev/spidev1.0

有關(guān)使用spidev接口的示例,請參閱Documentation/spi中的示例代碼。

總結(jié)

以上是生活随笔為你收集整理的嵌入式Linux设备驱动程序:用户空间中的设备驱动程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。