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

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

嵌入式驅動開發兩大子系統的使用

FPGA之家 ? 來源:老吳嵌入式 ? 作者:吳偉東Jack ? 2022-03-15 13:41 ? 次閱讀

gpio 和 pinctrl 子系統在內核里的使用率非常高,和嵌入式產品的關聯非常大。從這兩個子系統開始學習驅動開發是個不錯的入門選擇。

本文目錄:

一、gpio與pinctrl
二、內核里如何引用gpio
三、gpio子系統框架
四、應用層如何訪問gpio

一、gpio 與 pinctrl

本文主要關注 gpio 子系統,但是老吳認為必要先說明一下 pinctrl 子系統和 gpio 子系統的之間關系。

pinctrl 的作用:

  • 引腳復用,例如某個引腳即可用作為普通的gpio,也可以作為UART的TX;
  • 引腳配置,一般包括上下拉、驅動能力等;

3b067044-9199-11ec-952b-dac502259ad0.png

點擊查看大圖

gpio 的作用:

  • 作為輸入功能時,支持讀引腳值;
  • 作為輸出功能時,支持輸出高低電平;
  • 部分 gpio 還負責接收中斷;

gpio 的使用依賴于 pinctrl:

3b1ae998-9199-11ec-952b-dac502259ad0.png

點擊查看大圖

本文的關注點是 gpio driver --> gpio subsystem core -> gpio consumer 這一路徑,讀者如果想更深入地了解 pinctrl 子系統.

gpio 子系統內核文檔:

Documentation/driver-api/gpio:

文檔 簡介
index.rst 文檔目錄和源碼清單
intro.rst gpio 簡介
driver.rst 描述如何編寫 gpio controller driver
consumer.rst 描述 gpio consumer 如何使用 gpio
board.rst 描述設備如何申請 gpio
drivers-on-gpio.rst 列舉一些使用了gpio子系統的常見驅動,例如 leds-gpio.c、gpio_keys.c 等
legacy.rst 描述 legacy gpio 接口

注:本文基于 Linux-4.19。

二、內核里如何引用 gpio

2 個步驟:

1) 設備樹里添加 gpio mappings

示例:

foo_device {
    compatible = "packt,gpio-descriptor-sample";
    led-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>, // red 
                <&gpio2 16 GPIO_ACTIVE_HIGH>, // green 

    btn1-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
    btn2-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
};

要點:

  • 屬性-gpios里的由使用者自行決定的, 例如上述例子中的為 led,在 gpio consumer driver 里可以通過 "led" 這個字符串,配合偏移值來獲取這一組 gpio 里的任一 gpio。

  • 至于如何標志是硬件上的哪一個引腳,是由平臺相關的 gpio controller driver 的設備樹節點里的#gpio-cells的值來決定,上述例子中需要 2個參數才能確定硬件引腳,所以#gpio-cells = 2

2) 在 gpio consumer driver 中引用

目前 gpio subsystem 提供了 2 套接口:

  • legacy API:integer-based GPIO interface,形式為 gpio_xxx(),例如void gpio_set_value(unsigned gpio, int value),不推薦使用該 API;

  • 推薦 API: descriptor-based GPIO interface,形式為 gpiod_xxx(),例如void gpiod_set_value(struct gpio_desc *desc, int value),新添加的驅動代碼一律采用這套 API。

示例:

staticstructgpio_desc*red,*green,*btn1,*btn2;staticintirq;

staticirqreturn_tbtn1_pushed_irq_handler(intirq,void*dev_id)
{
intstate;

/*readthebuttonvalueandchangetheledstate*/
state=gpiod_get_value(btn2);
gpiod_set_value(red,state);
gpiod_set_value(green,state);

pr_info("btn1interrupt:Interrupt!btn2stateis%d)
",state);
returnIRQ_HANDLED;
}

staticconststructof_device_idgpiod_dt_ids[]={
{.compatible="gpio-descriptor-sample",},
};


staticintmy_pdrv_probe(structplatform_device*pdev)
{
intretval;
structdevice*dev=&pdev->dev;

//獲得gpiodescriptor的同時也將其設置為output,并且輸出低電平
red=gpiod_get_index(dev,"led",0,GPIOD_OUT_LOW);
green=gpiod_get_index(dev,"led",1,GPIOD_OUT_LOW);

btn1=gpiod_get(dev,"btn1",GPIOD_IN);
btn2=gpiod_get(dev,"btn2",GPIOD_IN);

//獲得中斷號
irq=gpiod_to_irq(btn1);

//申請中斷
retval=request_threaded_irq(irq,NULL,
btn1_pushed_irq_handler,
IRQF_TRIGGER_LOW|IRQF_ONESHOT,
"gpio-descriptor-sample",NULL);
pr_info("Hello!deviceprobed!
");
return0;
}

staticintmy_pdrv_remove(structplatform_device*pdev)
{
free_irq(irq,NULL);

//釋放gpio
gpiod_put(red);
gpiod_put(green);
gpiod_put(btn1);
gpiod_put(btn2);
pr_info("goodbyereader!
");
return0;
}

staticstructplatform_drivermypdrv={
.probe=my_pdrv_probe,
.remove=my_pdrv_remove,
.driver={
.name="gpio_descriptor_sample",
.of_match_table=of_match_ptr(gpiod_dt_ids),
.owner=THIS_MODULE,
},
};
module_platform_driver(mypdrv);

gpiod_xxx() API

在 gpio 子系統中,用 struct gpio_desc 來描述一個 gpio 引腳,gpiod_xxx() 都是圍繞著 strcut gpio_desc 進行操作的。

完整的接口定義位于 linux/gpio/consumer.h,大約共有 70個 API。

常用 API:

  • 獲得/釋放 一個或者一組 gpio:

    • [devm]_gpiod_get*()
    • [devm]_gpiod_put*()
  • 設置/查詢 輸入或者輸出

    • gpiod_direction_input()
    • gpiod_direction_output()
    • gpiod_get_direction()
  • 讀寫一個 gpio

    • gpiod_get_value()
    • gpiod_set_value()
    • gpiod_get_value_cansleep()
    • gpiod_set_value_cansleep()
  • 讀寫一組 gpio

    • gpiod_get_array_value()
    • gpiod_set_array_value()
  • 獲得 gpio 對應的中斷號

    • gpiod_to_irq()

相關要點:

  • 以 _cansleep 為后綴的函數是可能會睡眠的 API,不可以在 hard (non-threaded) IRQ handlers 中使用;

  • gpiod_get_value() 返回的是硬件上的電平值;

  • gpiod_set_value() 設置的值是邏輯值而非電平值,1 表示使能,0 表示不使能,由設備樹里的 gpio mappings 里的 GPIO_ACTIVE_XXX 來決定哪個電平值是有效的,總結如下:

Function line property physical line
gpiod_set_raw_value(desc, 0); don't care low
gpiod_set_raw_value(desc, 1); don't care high
gpiod_set_value(desc, 0); default (active high) low
gpiod_set_value(desc, 1); default (active high) high
gpiod_set_value(desc, 0); active low high
gpiod_set_value(desc, 1); active low low
gpiod_set_value(desc, 0); default (active high) low
gpiod_set_value(desc, 1); default (active high) high
gpiod_set_value(desc, 0); open drain low
gpiod_set_value(desc, 1); open drain high impedance
gpiod_set_value(desc, 0); open source high impedance
gpiod_set_value(desc, 1); open source high

三、gpio 子系統框架

1. 整體框架

3b44b3f4-9199-11ec-952b-dac502259ad0.png

點擊查看大圖

正常情況下,驅動工程師不需要了解 gpio chip driver 和 gpiolib:

  • 驅動工程師負責編寫 gpio consumer drvier;

  • 芯片廠商的 bsp 工程師負責編寫 gpio chip driver;

  • 開源社區里的大牛負責 gpiolib 的核心實現;

但是當功能和預期的不一樣時,為了調試定位出問題,這時就有必要弄清楚 gpio chip driver 和 gpiolib 的工作流程。

2. gpiolib

作用:

  • 向下為 gpio chip driver 提供注冊 struct gpio_chip 的接口:gpiochip_xxx();

  • 向上為 gpio consumer 提供引用 gpio 的接口:gpiod_xxx();

  • 實現字符設備的功能;

  • 注冊 sysfs;

源碼:

$cdlinux-4_19/drivers/gpio$lsgpiolib*-1X
gpiolib-acpi.c//ACPIhelpersforGPIOAPI
gpiolib.c//GPIOsubsystemcore
gpiolib-devprop.c//DevicepropertyhelpersforGPIOchips.
gpiolib-legacy.c
gpiolib-of.c//OFhelpersfortheGPIOAPI
gpiolib-sysfs.c//sysfshelpers
gpiolib.h

int gpiochip_add(struct gpio_chip *chip)

這是 bsp 工程師比較關心的 api。

在 gpio 子系統中,SoC 上的每一個 gpio bank 都會被認為是一個 gpio controller,每一個 gpio controller 都由一個 struct gpio_chip 來描述,bsp 工程師的核心工作就是填充該結構體。

struct gpio_chip 比較龐大,但是我們只需要關注跟硬件聯系比較緊密的成員就好:

  • .set(),輸出電平
  • .get(),獲得電平
  • .get_direction(),獲得方向
  • .direction_input(),設置為輸入
  • .direction_output(),設置為輸出
  • .to_irq(),獲得中斷號

3. gpio chip driver

最簡單的 demo:

#defineGPIO_NUM16staticstructgpio_chipchip;staticintfake_get_value(structgpio_chip*gc,unsignedoffset)
{
return0;
}

staticvoidfake_set_value(structgpio_chip*gc,unsignedoffset,intval)
{
}

staticintfake_direction_output(structgpio_chip*gc,unsignedoffset,intval)
{
return0;
}

staticintfake_direction_input(structgpio_chip*gc,unsignedoffset)
{
return0;
}

staticconststructof_device_idfake_gpiochip_ids[]={
{.compatible="fake-gpio-chip",},
};

staticintmy_pdrv_probe(structplatform_device*pdev)
{
chip.label=pdev->name;
chip.base=-1;
chip.dev=&pdev->dev;
chip.owner=THIS_MODULE;
chip.ngpio=GPIO_NUM;
chip.can_sleep=1;
chip.get=fake_get_value;
chip.set=fake_set_value;
chip.direction_output=fake_direction_output;
chip.direction_input=fake_direction_input;

returngpiochip_add(&chip);
}

staticintmy_pdrv_remove(structplatform_device*pdev)
{
gpiochip_remove(&chip);
return0;
}

staticstructplatform_drivermypdrv={
.probe=my_pdrv_probe,
.remove=my_pdrv_remove,
.driver={
.name="fake-gpio-chip",
.of_match_table=of_match_ptr(fake_gpiochip_ids),
.owner=THIS_MODULE,
},
};
module_platform_driver(mypdrv);

RK3399 實例分析

1) 設備樹

gpio0: gpio0@ff720000 {
    compatible = "rockchip,gpio-bank";
    reg = <0x0 0xff720000 0x0 0x100>;
    clocks = <&pmucru PCLK_GPIO0_PMU>;
    interrupts = ;

    gpio-controller;
    #gpio-cells = <0x2>;

    interrupt-controller;
    #interrupt-cells = <0x2>;
};
...
gpio4: gpio4@ff790000 {
    ...
}

一共定義了 5 個 gpio-controller 節點,對應芯片上的 5 個 gpio bank。

里面用于表明寄存器地址 和 clock 等屬性會在 gpio chip driver 中被使用。

2) chip driver

這里只關心程序主干,不關心芯片廠商為了適應多款芯片而封裝的代碼。

gpio_chip 的注冊過程:

drivers/pinctrl/pinctrl-rockchip.c

rockchip_pinctrl_probe(){
//rockchip用于管理gpio/pinctrl大管家結構體
structrockchip_pinctrl*info=devm_kzalloc()

//rk3399gpiobank相關的硬件描述信息
structrockchip_pin_ctrl*ctrl=&rk3399_pin_ctrl;

info->ctrl=ctrl;

rockchip_gpiolib_register(pdev,info);{
structgpio_chip*gc;

for(i=0;inr_banks;++i,++bank){
//初始化gpio_chip
gc=&rockchip_gpiolib_chip;
gc->base=bank->pin_base;
gc->ngpio=bank->nr_pins;

//注冊gpio_chip
gpiochip_add_data(gc,bank);
}
}
}

struct gpio_chip 的定義:

staticconststructgpio_chiprockchip_gpiolib_chip={
.request=gpiochip_generic_request,
.free=gpiochip_generic_free,
.set=rockchip_gpio_set,
.get=rockchip_gpio_get,
.get_direction=rockchip_gpio_get_direction,
.direction_input=rockchip_gpio_direction_input,
.direction_output=rockchip_gpio_direction_output,
.set_config=rockchip_gpio_set_config,
.to_irq=rockchip_gpio_to_irq,
.owner=THIS_MODULE,
};

這些函數都是在操作 rk3399 gpio 相關的寄存器,實現一個 gpio chip driver 本質上就是實現上面一系列的硬件操作函數。

四、應用層如何訪問 gpio

1. /dev/gpiochipX

直接操作字符設備是比較低效率的,內核里提供了一些 demo:

$cdlinux-4_19/tools/gpio
$ls
Makefile
gpio-event-mon.c
gpio-hammer.c
gpio-utils.c
lsgpio.c
gpio-utils.h
$makeARCH=arm64CROSS_COMPILE=aarch64-linux-

具體的代碼請各位自行閱讀吧。

2. libgpiod

libgpiod 是一個用 C 語言編寫的用于訪問 gpio chardev 的庫,同時里面包含了一些訪問 gpio 的命令行工具,推薦優先采用這個庫來訪問 gpio。

編譯:

$gitclonehttps://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git-bv1.6.x
$./autogen.sh--enable-tools=yes
$make&&makeinstall
$ldconfig

附帶的幾個命令行工具:

  • gpiodetect – list all gpiochips present on the system, their names, labels and number of GPIO lines

  • gpioinfo – list all lines of specified gpiochips, their names, consumers, direction, active state and additional flags

  • gpioget – read values of specified GPIO lines

  • gpioset – set values of specified GPIO lines, potentially keep the lines exported and wait until timeout, user input or signal

  • gpiofind – find the gpiochip name and line offset given the line name

  • gpiomon – wait for events on GPIO lines, specify which events to watch, how many events to process before exiting or if the events should be reported to the console

$gpiodetect
gpiochip0[gpio0](32lines)
gpiochip1[gpio1](32lines)
gpiochip2[gpio2](32lines)
gpiochip3[gpio3](32lines)
gpiochip4[gpio4](32lines)
$gpioinfogpio0
gpiochip0-32lines:
line0:unnamedunusedinputactive-high
line1:unnamed"vcc_sd"outputactive-high[used]
line2:unnamedunusedinputactive-high
line3:unnamedunusedinputactive-high
line4:unnamed"bt_default_wake_host"inputactive-high[used]
line5:unnamed"GPIOKeyPower"inputactive-low[used]
...
line13:unnamed"status_led"outputactive-high[used]
...
line30:unnamedunusedinputactive-high
line31:unnamedunusedinputactive-high

3. sysfs

過時的接口,不推薦使用,用法如下:

$echo25>/sys/class/gpio/export
$echoout>/sys/class/gpio/gpio25/direction
$echo1>/sys/class/gpio/gpio25/valuesh

審核編輯:郭婷

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5082

    文章

    19106

    瀏覽量

    304829
  • uart
    +關注

    關注

    22

    文章

    1235

    瀏覽量

    101355

原文標題:五、相關參考

文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    嵌入式系統的應用范圍有哪些

    嵌入式系統的知識體系  嵌入式系統的應用范圍可以粗略分為兩大類:電子系統的智能化(工業 控制、現
    發表于 10-27 06:06

    嵌入式系統設計

    在我們的日常生活中,我們經常使用許多使用嵌入式系統技術設計的電氣和電子電路和套件。計算機,手機,平板,筆記本電腦,數字電子系統以及其他電子和電子設備都是使用嵌入式
    發表于 10-27 06:50

    嵌入式框架圖

    1.overview 圖1-1 嵌入式框架圖嵌入式系統分為硬件以及軟件兩大部分,大多數人參與的是嵌入式軟件設計,更多的是接觸的是上層軟件
    發表于 10-27 08:26

    嵌入式系統CPU怎么選

    1、什么是嵌入式技術(1)嵌入式軟件與非嵌入式軟件的區別?答:嵌入式軟件是結合操作系統之上做的開發
    發表于 11-03 07:23

    淺析input輸入子系統框架嵌入式Linux驅動

    )------USB鍵盤驅動程序嵌入式Linux驅動筆記(五)------學習platform設備驅動嵌入式Linux
    發表于 11-05 06:47

    嵌入式主板比較常見的兩大

    。標準的嵌入式系統架構有兩大體系,RISC處理器和CISC處理器體系。嵌入式主板分為比較常見的兩大類:1、基于X86的
    發表于 12-16 06:41

    嵌入式Linux系統開發基礎

    了解嵌入式Linux系統Ø 從Linux內核到文件系統ü嵌入式Linux開發流程v嵌入式
    發表于 09-10 11:11 ?68次下載
    <b class='flag-5'>嵌入式</b>Linux<b class='flag-5'>系統開發</b>基礎

    嵌入式Linux系統驅動開發

    ,文件系統構,bootloader等等底層的知識了。那么下面就跟著小編一起來聊一聊嵌入式Linux系統驅動開發方面的問題吧?! ∠胍钊?/div>
    發表于 10-11 11:11 ?798次閱讀

    媒體聚焦丨瑞薩電子兩大科技令嵌入式系統實現邊緣智能和擺脫電池束縛

    媒體聚焦丨瑞薩電子兩大科技令嵌入式系統實現邊緣智能和擺脫電池束縛
    的頭像 發表于 07-02 14:11 ?2048次閱讀

    嵌入式系統的入門學習教程合集

    1 嵌入式系統的知識體系嵌入式系統的應用范圍可以粗略分為兩大類: (1)電子系統的智能化(工業控
    發表于 12-14 12:23 ?22次下載

    嵌入式系統框架----軟件篇

    ,更多的是接觸的是上層軟件系統部分,可以分為兩大類型嵌入式軟件應用工程師以及嵌入式驅動工程師。前者主要負...
    發表于 10-20 19:21 ?5次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>系統</b>框架----軟件篇

    嵌入式系統

    在我們的日常生活中,我們經常使用許多使用嵌入式系統技術設計的電氣和電子電路和套件。計算機,手機,平板,筆記本電腦,數字電子系統以及其他電子和電子設備都是使用嵌入式
    發表于 10-21 10:51 ?1次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>系統</b>

    什么是嵌入式系統

    在我們的日常生活中,我們經常使用許多使用嵌入式系統技術設計的電氣和電子電路和套件。計算機,手機,平板,筆記本電腦,數字電子系統以及其他電子和電子設備都是使用嵌入式
    發表于 10-21 11:36 ?3次下載
    什么是<b class='flag-5'>嵌入式</b><b class='flag-5'>系統</b>

    視頻教程-嵌入式Linux驅動開發-嵌入式

    嵌入式Linux驅動開發 10年以上嵌入式軟件
    發表于 11-02 11:36 ?13次下載
    視頻教程-<b class='flag-5'>嵌入式</b>Linux<b class='flag-5'>驅動</b><b class='flag-5'>開發</b>-<b class='flag-5'>嵌入式</b>

    2020 年,嵌入式開發工程師的兩大必知必會!

    【CSDN 編者按】2020年,在嵌入式系統及硬件領域里有哪些新趨勢呢?本文作者從軟硬件兩大點出發,詳細介紹其中的新技術發展趨勢,對于嵌入式系統
    發表于 11-03 14:36 ?10次下載
    2020 年,<b class='flag-5'>嵌入式開發</b>工程師的<b class='flag-5'>兩大</b>必知必會!
    主站蜘蛛池模板: 久久婷婷五月综合色情| 亚洲国产综合久久精品| 97免费视频在线观看| 精品无码一区二区三区不卡| 玩弄放荡人妻一区二区三区| yin荡体育课羞耻play双性 | 粗大分开挺进内射| 免费毛片试看| 2021精品乱码多人收藏| 久久棋牌评测| 一级性生活毛片| 精品国产美女AV久久久久| 小黄文纯肉污到你湿| 女人会操出水图| 伊人久久综合成人亚洲| 娇妻中日久久持久久| 亚洲精品AV一区午夜福利| 国产乱码卡二卡三卡4W| 天天狠狠色噜噜| 国产精品久久久久精品A片软件| 日韩视频中文字幕精品偷拍| 成人免费观看在线视频| 欧洲-级毛片内射八十老太婆| BLACKED太粗太长| 女王黄金vk| jk制服喷水| 欧美一区二区三区激情视频| www.久久精品视频| 日产精品高潮呻吟AV久久| 大胸美女被cao哭| 神马电影院午夜神福利在线观看| 国产 日韩 欧美 高清 亚洲| 色欲久久99精品久久久久久AV| 国产Av影片麻豆精品传媒| 双性将军粗壮H灌满怀孕| 国产精品久久精品| 亚洲AV无码国产精品色在线看| 国产亚洲精品久久久久久禁果TV| 亚洲国产综合久久精品| 寂寞夜晚视频在线观看| 用快播看av的网站|