Linux 內核探秘:從零構建 GPIO 設備驅動程序實戰指南

在嵌入式系統開發領域,GPIO(通用輸入 / 輸出)作為硬件與軟件交互的橋梁,是實現設備控制與數據采集的基礎。編寫高效、穩定的 GPIO 設備驅動程序,對于發揮硬件性能至關重要。本文將深入剖析 Linux 內核中 GPIO 驅動開發的全流程,從原理到代碼實現,帶你一步步掌握 GPIO 設備驅動的核心技術。

一、GPIO 驅動基礎理論

1.1 GPIO 工作原理

GPIO 引腳可以通過軟件配置為輸入或輸出模式。作為輸出時,可設置引腳的高低電平,控制外部設備,如 LED 燈的亮滅、繼電器的開合;作為輸入時,可讀取引腳的電平狀態,獲取外部設備的信號,例如按鈕的按下與釋放。在 Linux 系統中,GPIO 的操作需要通過驅動程序來實現對硬件寄存器的讀寫控制。

1.2 Linux 驅動模型與 GPIO 子系統

Linux 采用統一的設備驅動模型,將設備分為字符設備、塊設備和網絡設備等類型。GPIO 設備通常作為字符設備進行驅動開發。Linux 內核提供了 GPIO 子系統,它封裝了底層硬件操作,為驅動開發者提供了一套通用的 API,使得開發者無需直接操作硬件寄存器,降低了開發難度,提高了驅動的可移植性和通用性。

二、搭建開發環境

2.1 硬件準備

首先需要準備一塊支持 GPIO 功能的開發板,如樹莓派、STM32MP1 系列開發板等。確保開發板與主機能夠正常通信,一般通過串口或 SSH 進行連接。

2.2 軟件準備

在主機上安裝交叉編譯工具鏈,用于將驅動程序代碼編譯為目標開發板的可執行文件。例如,對于 ARM 架構的開發板,可能需要安裝arm-linux-gnueabihf-gcc等工具鏈。同時,安裝 Linux 內核源代碼,可從官方網站下載對應開發板的內核版本,解壓后作為驅動開發的基礎。

三、編寫 GPIO 驅動程序

3.1 驅動框架搭建

基于 Linux 字符設備驅動框架,編寫 GPIO 驅動的基本結構。首先定義設備號、設備類和設備節點:

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/uaccess.h>

#include <linux/gpio.h>

#include <linux/of_gpio.h>

#define DEVICE_NAME "my_gpio_device"

static dev_t dev_num;

static struct cdev my_cdev;

static struct class *my_class;

然后實現驅動的初始化和退出函數:

 

static int __init my_gpio_driver_init(void)

{

// 申請設備號

int ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);

if (ret < 0) {

printk(KERN_ERR "Failed to allocate device number\n");

return ret;

}

// 初始化cdev結構

cdev_init(&my_cdev, &my_fops);

my_cdev.owner = THIS_MODULE;

// 添加cdev到系統

ret = cdev_add(&my_cdev, dev_num, 1);

if (ret < 0) {

printk(KERN_ERR "Failed to add cdev\n");

unregister_chrdev_region(dev_num, 1);

return ret;

}

// 創建設備類

my_class = class_create(THIS_MODULE, DEVICE_NAME);

if (IS_ERR(my_class)) {

printk(KERN_ERR "Failed to create class\n");

cdev_del(&my_cdev);

unregister_chrdev_region(dev_num, 1);

return PTR_ERR(my_class);

}

// 創建設備節點

device_create(my_class, NULL, dev_num, NULL, DEVICE_NAME);

return 0;

}

static void __exit my_gpio_driver_exit(void)

{

device_destroy(my_class, dev_num);

class_destroy(my_class);

cdev_del(&my_cdev);

unregister_chrdev_region(dev_num, 1);

}

module_init(my_gpio_driver_init);

module_exit(my_gpio_driver_exit);

3.2 GPIO 操作實現

從設備樹獲取 GPIO 引腳編號,并實現 GPIO 的輸入輸出操作。假設設備樹中已定義好 GPIO 節點:

 

static int gpio_num;

static int __init get_gpio_num(void)

{

struct device_node *np = of_find_compatible_node(NULL, NULL, "my,gpio-device");

if (!np) {

printk(KERN_ERR "Failed to find device node\n");

return -ENODEV;

}

gpio_num = of_get_named_gpio(np, "gpio", 0);

if (gpio_num < 0) {

printk(KERN_ERR "Failed to get gpio number\n");

return gpio_num;

}

if (gpio_request(gpio_num, "my_gpio")) {

printk(KERN_ERR "Failed to request gpio\n");

return -EBUSY;

}

return 0;

}

實現文件操作接口函數,如open、read、write等:

 

static int my_gpio_open(struct inode *inode, struct file *filp)

{

if (get_gpio_num() < 0) {

return -EIO;

}

// 設置為輸出模式

gpio_direction_output(gpio_num, 0);

return 0;

}

static ssize_t my_gpio_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)

{

int value;

if (count != sizeof(int)) {

return -EINVAL;

}

if (copy_from_user(&value, buf, sizeof(int))) {

return -EFAULT;

}

gpio_set_value(gpio_num, value);

return count;

}

static ssize_t my_gpio_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)

{

int value = gpio_get_value(gpio_num);

if (copy_to_user(buf, &value, sizeof(int))) {

return -EFAULT;

}

return count;

}

static int my_gpio_release(struct inode *inode, struct file *filp)

{

gpio_free(gpio_num);

return 0;

}

static const struct file_operations my_fops = {

.owner = THIS_MODULE,

.open = my_gpio_open,

.write = my_gpio_write,

.read = my_gpio_read,

.release = my_gpio_release,

};

四、編譯與測試

4.1 編譯驅動程序

編寫 Makefile 文件,指定內核源代碼路徑和交叉編譯工具鏈:

 

obj-m += my_gpio_driver.o

all:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

執行make命令編譯驅動程序,生成.ko文件。

4.2 加載與測試

將編譯好的驅動模塊拷貝到開發板上,使用insmod命令加載驅動:

 

insmod my_gpio_driver.ko

加載成功后,會在/dev目錄下生成設備節點my_gpio_device。編寫測試程序,通過設備節點對 GPIO 進行讀寫操作:

 

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

int main()

{

int fd = open("/dev/my_gpio_device", O_RDWR);

if (fd < 0) {

perror("open");

return -1;

}

int value = 1;

write(fd, &value, sizeof(int)); // 點亮LED

sleep(2);

value = 0;

write(fd, &value, sizeof(int)); // 熄滅LED

close(fd);

return 0;

}

編譯并運行測試程序,觀察 GPIO 控制的設備狀態變化。

五、總結與進階

通過以上步驟,我們完成了一個簡單的 GPIO 設備驅動程序的編寫、編譯、加載與測試。但實際應用中,還需考慮更多問題,如中斷處理、電源管理、錯誤處理優化等。后續可以深入研究 Linux 內核文檔和優秀的開源驅動代碼,進一步提升驅動開發能力,為更復雜的嵌入式系統開發打下堅實基礎。

上述文章涵蓋了 GPIO 驅動開發全流程,若你覺得某些部分需要更詳細講解,或想增加調試技巧等內容,隨時告訴我。

  • 摩爾獅云計算每日課堂Top1-課程大綱:
    Linux系統管理-數據庫與監控平臺-網絡安全與控制技術課程大綱:
  • 本課程聚焦 Linux 系統管理、數據庫、監控平臺、網絡安全與控制四大核心板塊。Linux 系統管理模塊,涵蓋系統安裝配置、用戶權限管理、進程服務維護、文件系統存儲及網絡管理等內容;數據庫板塊從基礎理論切入,深入講解關系數據庫與 SQL 語言、數據庫設計及主流數據庫(如 MySQL、Oracle)的應用;監控平臺部分,介紹開源工具(Zabbix、Prometheus 等)的使用,以及系統性能監控、數據可視化;網絡安全與控制技術,剖析網絡安全基礎、常見攻擊防范、防火墻配置、網絡加密與 VPN 技術。教學采用理論講授、實踐操作、小組項目、案例分析及在線學習相結合的方式,考核通過平時成績、期中期末筆試、小組項目綜合評定,旨在培養學生系統運維、數據庫管理、性能監控及網絡安全防護等多方面能力。

云計算培訓摩爾獅的獨特優勢助力解決問題 摩爾獅的課程不僅有理論知識和實踐方法,還有強大的師資團隊和教學服務。當遇到運維相關問題時,不要慌張。借助在摩爾獅學到的知識和技能,從理論分析到實踐排查,多維度入手,就能精準定位并解決問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80829.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80829.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80829.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

嵌入式單片機中STM32F1演示寄存器控制方法

該文以STM32F103C8T6為示例,演示如何使用操作寄存器的方法點亮(關閉LED燈),并講解了如何調試,以及使用宏定義。 第一:操作寄存器點亮LED燈。 (1)首先我們的目的是操作板子上的LED2燈,對其實現點亮和關閉操作。打開STM32F103C8T6的原理圖,找到LED2的位置。 可以看到…

牛客網 NC16407 題解:托米航空公司的座位安排問題

牛客網 NC16407 題解&#xff1a;托米航空公司的座位安排問題 題目分析 解題思路 本題可以采用深度優先搜索(DFS)來解決&#xff1a; 從左上角開始&#xff0c;按行優先順序遍歷每個座位對于每個座位&#xff0c;有兩種選擇&#xff1a; 選擇該座位&#xff08;如果滿足條件…

智慧展館數字孿生平臺

2022年進博會上&#xff0c;國家會展中心憑借“數字孿生機器人調度平臺”驚艷全球&#xff0c;實現人機協同、虛實聯動的智慧運營&#xff1b;2023年天府農博園通過“BIMIoT”技術&#xff0c;貫穿展館全生命周期管理&#xff0c;成為農業會展的數字化標桿。這些案例背后&#…

胡說八道1---豆包問答總結

用戶提問 1 指令&#xff1a;25 - - [21/May/2025:01:35:45 0000] “POST /prod-api/system/base/getList HTTP/1.1” 405 559 “http://192.168.1.109:16380/login” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 …

C# AOP編程

AOP(面向切片編程的概念我這里就不介紹了&#xff0c;這里先介紹一下C#中的AOP編程框架。 1.AOP的分類 .net下支持AOP的框架很多&#xff0c;搜了一下有&#xff1a;PostSharp、AspectInjector、Fody 、Castle Windsor、Spring.NET、Ninject、Unity等&#xff0c;實現的方式主要…

linux編譯安裝srs

下載編譯運行 git clone https://github.com/ossrs/srs.git cd srs/trunk ./configure --h265on make需要安裝 yum install -y patch yum install -y unzip yum install -y tcl編譯完成后即可啟動SRS # 啟動 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/s…

EtherNet/IP機柜內解決方案在醫療控制中心智能化的應用潛能和方向分析

引言 在數智化轉型浪潮席卷各行各業的今天,醫療領域同樣面臨著提升運營效率、改善患者體驗和加強系統可靠性的多重挑戰。Rockwell Automation于2025年5月20日推出的EtherNet/IP機柜內解決方案,為醫療中心的自動化升級提供了一種創新路徑。本報告將深入分析這一解決方案的核心…

大模型下載到本地

一、huggingface 方式一 from huggingface_hub import snapshot_downloadlocal_dir "./origin" model_name "Qwen/Qwen2.5-1.5B"# snapshot_download(repo_idmodel_name, cache_dirlocal_dir) model_dir snapshot_download(model_name,cache_dirlocal…

【C++】vector容器實現

目錄 一、vector的成員變量 二、vector手動實現 &#xff08;1&#xff09;構造 &#xff08;2&#xff09;析構 &#xff08;3&#xff09;尾插 &#xff08;4&#xff09;擴容 &#xff08;5&#xff09;[ ]運算符重載 5.1 迭代器的實現&#xff1a; &#xff08;6&…

PostgreSQL日常維護

目錄 一、PostgreSQL 概述 二、基本使用 &#xff08;一&#xff09;登錄數據庫 &#xff08;二&#xff09;數據庫操作 1. 列出數據庫 2. 創建數據庫 3. 刪除數據庫 4. 切換數據庫 5. 查看數據庫大小 &#xff08;三&#xff09;數據表操作 1. 列出表 2. 創建表 …

廣東省省考備考(第十六天5.21)—言語:語句排序題(聽課后強化)

錯題 解析 對比選項&#xff0c;確定首句。①句介紹目前人類可以利用一些技術手段進入元宇宙&#xff0c;憑借網絡重新定義自己&#xff0c;體驗一種全新的生活&#xff0c;②句介紹對于多數人來說&#xff0c;首先要弄清楚什么是元宇宙&#xff0c;③句介紹元宇宙是指超越現實…

高并發架構設計之限流

一、引言 再強大的系統&#xff0c;也怕流量短事件內集中爆發&#xff0c;就像銀行怕擠兌一樣&#xff0c;所以&#xff0c;高并發另一個必不可少的模塊就是限流。限流是一種通過控制請求的速率或數量來保護系統免受過載的技術。流控的精髓是限制單位時間內的請求量&#xff0…

視頻監控聯網系統GB28181協議中設備控制流程詳解

文章目錄 9.3 設備控制9.3.1 基本要求9.3.2 命令流程9.3.2.1 無應答命令流程 9.3.3 協議接口9.3.3.1 請求命令9.3.3.2 應答命令 智聯視頻超融合平臺介紹 9.3 設備控制 9.3.1 基本要求 控制滿足以下基本要求&#xff1a; a) 源設備向目標設備發送控制命令&#xff0c;控制命令…

深入剖析原型模式:原理、實現與應用實踐

在軟件開發的世界里,設計模式如同建筑師手中的藍圖,為復雜系統的構建提供了行之有效的解決方案。其中,原型模式(Prototype Pattern)作為創建型設計模式的重要一員,以其獨特的對象創建方式,在提高代碼復用性、增強系統靈活性等方面發揮著關鍵作用。本文將深入剖析原型模式…

圖繪Linux:基礎指令脈絡閣

目錄 Linux命令行介紹 目錄操作 ls 目錄所含文件信息 ls 常用選項 pwd 在那個目錄下 cd 進入目錄 mkdir 創建目錄 文件操作 touch 創建普通文件 echo向文件寫入 cat 輸出文件內容 cp 拷貝文件/目錄 mv剪切重命名 rm 刪除文件/目錄 查找 * 匹配符 man 查找指令 …

數據分析 —— 數據預處理

一、什么是數據預處理 數據預處理&#xff08;Data Preprocessing&#xff09;是數據分析和機器學習中至關重要的步驟&#xff0c;旨在將原始數據轉換為更高質量、更適合分析或建模的形式。由于真實世界的數據通常存在不完整、不一致、噪聲或冗余等問題&#xff0c;預處理可以…

【Redis】哨兵(Sentinel)機制

文章目錄 1. Redis Sentinel的概念1.1 基本概念1.2 引出高可用 2. Redis Sentinel的部署&#xff08;基于docker&#xff09;2.1 部署2.2 驗證2.3 選舉流程 Redis 的主從復制模式下&#xff0c;?旦主節點由于故障不能提供服務&#xff0c;需要人工進行主從切換&#xff0c;同時…

初識Linux · 五種IO模型和非阻塞IO

目錄 前言&#xff1a; 五種IO模型 什么是IO IO模型 非阻塞IO 前言&#xff1a; 前文我們已經將網絡的基本原理介紹完了&#xff0c;都是通過圍繞TCP/IP四層協議&#xff0c;將應用層&#xff0c;傳輸層&#xff0c;網絡層&#xff0c;數據鏈路層全部介紹完畢&#xff0c…

Node.js 24發布:性能與安全雙提升

在科技的迅速發展中&#xff0c;Node.js作為一個備受青睞的開源跨平臺Java運行環境&#xff0c;近日迎來了其24.0版本的正式發布。此次更新不僅承諾提升性能和安全性&#xff0c;還為開發者提供了更為順暢的開發體驗&#xff0c;值得我們深入探討。 Node.js 24.0的最大亮點之一…

SLAM文獻之-SuperOdometry: Lightweight LiDAR-inertial Odometry and Mapping

《Super Odometry: IMU-centric LiDAR-Visual-Inertial Estimator for Challenging Environments》是一篇旨在增強 SLAM 系統在惡劣環境下魯棒性的工作&#xff0c;尤其關注塵霧、煙霧等遮擋條件下的魯棒估計。下面從算法原理、公式推導、創新點和應用場景四個方面進行詳細解析…