目錄
- Petalinux驅動開發以及代碼框架解讀
- 一、引言
- 二、步驟
- 2.1 創建PetaLinux工程
- 2.2 配置硬件描述文件
- 2.3 設備樹配置
- 2.4 建立驅動框架
- 2.5 編輯 `.bb` 文件
- 2.6 編寫驅動文件
- 2.7 編寫 `Makefile`
- 2.8 驗證配方配置
- 2.9 集成驅動到 RootFS
- 2.10 全系統編譯與部署
- 2.11 啟動驗證
- 三、框架解讀
- 3.1 模塊基本信息
- 3.2 模塊參數
- 3.3 數據結構:customGpioExport_local
- 3.4 中斷處理函數
- 3.5 Probe函數:設備初始化
- **功能**:
- **流程**:
- 3.5 Remove函數:資源釋放
- 3.7 設備樹匹配
- 3.8 平臺驅動結構體
- 3.9 模塊初始化和退出
- 3.10 代碼執行流程
- 3.11 潛在改進點
- 四、結語
Petalinux驅動開發以及代碼框架解讀
一、引言
Petalinux是Xilinx提供的Linux開發工具鏈。通過Petalinux,可以很輕松的完成Xilinx SOC的Linux系統定制,驅動和應用開發。本文主要從驅動開發角度,基于petalinux2022.2版本,介紹如何同通過Petalinux開發自己的驅動。
二、步驟
安裝Petalinux以及使用Vivado創建SOC工程,這些基礎步驟,網上由太多教程,這里就不累述了。這里假設大家已經安裝好了Vivado,Petalinux,并已經通過Vivado工程導出了硬件描述文件(.xsa文件)。
2.1 創建PetaLinux工程
petalinux-create -t project --name zynq_gpio_demo --template zynq
cd zynq_gpio_demo
2.2 配置硬件描述文件
- 將Vivado生成的
system.xsa
文件復制到工程目錄。 - 導入硬件配置:
petalinux-config --get-hw-description=.
2.3 設備樹配置
在project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
中添加GPIO節點:
/ {custom_gpios {compatible = "customGpioExport";status = "okay";gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>, // EMIO GPIO0<&gpio0 55 GPIO_ACTIVE_HIGH>; // EMIO GPIO1};
};
- 關鍵屬性:
compatible
:驅動匹配標識符。gpios
:指定GPIO控制器、引腳號和激活電平。
2.4 建立驅動框架
petalinux為用戶開發自己的驅動建立了完整易用的驅動框架,可以通過petalinux-create -t modules
命令創建,如下所示:
petalinux-create -t modules --name customGpioExport --enable
通過上述指令,就會在{petalinux project}/project-spec/meta-user/recipes-modules/
目錄下生成custom_gpio_export
目錄,在該目錄下,自動生成了custom_gpio_export .bb
文件以及files
文件加,在files
文件夾下,成了驅動框架文件customGpioExport .c
以及Makefile
,以下是目錄結構圖:
{petalinux project}/
└── project-spec/└── meta-user/└── recipes-modules/└── customGpioExport/├── customGpioExport.bb└── files/├── customGpioExport.c└── Makefile
2.5 編輯 .bb
文件
打開{petalinux project}/project-spec/meta-user/recipes-modules/customGpioExport
下的customGpioExport.bb
文件并修改內容如下:
# 配方基礎配置
SUMMARY = "Custom GPIO Export Driver"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6"# 定義模塊名稱和源碼路徑
MODULE_NAME = "customGpioExport"
SRC_URI = " \file://${MODULE_NAME}.c \file://Makefile \
"# 指定源碼目錄(默認為當前目錄)
S = "${WORKDIR}"# 繼承內核模塊構建類
inherit module# 定義模塊編譯參數
EXTRA_OEMAKE:append = " \KERNEL_SRC=${STAGING_KERNEL_DIR} \KERNEL_VERSION=${KERNEL_VERSION} \
"# 安裝目標(將模塊復制到 rootfs 的 /lib/modules/ 目錄)
do_install() {install -d ${D}/lib/modules/${KERNEL_VERSION}/extrainstall -m 0644 ${B}/${MODULE_NAME}.ko ${D}/lib/modules/${KERNEL_VERSION}/extra/
}# 定義模塊依賴(可選)
# DEPENDS = "virtual/kernel"
關鍵配置解釋
-
SRC_URI
指定驅動源碼路徑。此處假設源碼文件為customGpioExport.c
和Makefile
,位于files
子目錄。
若源碼文件名為customGpioExport.c
,需同步修改:SRC_URI = " \file://customGpioExport.c \file://Makefile \ "
-
inherit module
繼承內核模塊構建類,自動處理模塊編譯和簽名(如需 Secure Boot)。 -
EXTRA_OEMAKE
向make
命令傳遞額外參數:KERNEL_SRC
:指向內核源碼目錄。KERNEL_VERSION
:內核版本號(自動填充)。
-
do_install
定義模塊安裝邏輯,將生成的.ko
文件復制到 rootfs 的/lib/modules/$(uname -r)/extra/
目錄。
2.6 編寫驅動文件
根據自己需要以customGpioExport.c
為基礎框架,增加自己模塊需要的功能實現即可,不在這里累述。
2.7 編寫 Makefile
確保 files/Makefile
內容如下(適配內核模塊編譯):
obj-m := custom_gpio_export.oKERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)all:$(MAKE) -C $(KERNEL_SRC) M=$(PWD) modulesclean:$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
- 注意:
obj-m
后的目標名必須與.c
文件名一致(例如customGpioExport.c
→customGpioExport.o
)。- 若源碼文件名為
customGpioExport.c
,需修改為:obj-m := customGpioExport.o customGpioExport-objs := customGpioExport.o
2.8 驗證配方配置
執行以下命令檢查語法和路徑:
# 進入 PetaLinux 工程根目錄
cd zynq_gpio_demo# 運行 BitBake 解析配方
petalinux-build -c customGpioExport --force
-
預期輸出:
若配置正確,將輸出編譯日志并在build/tmp/work/.../customGpioExport/
下生成.ko
文件。 -
常見錯誤:
- 文件未找到:檢查
SRC_URI
和files/
目錄中的文件名是否一致。 - 編譯錯誤:查看
build/tmp/work/.../temp/log.do_compile
中的詳細日志。
- 文件未找到:檢查
2.9 集成驅動到 RootFS
在 petalinux-config
中啟用模塊自動加載:
petalinux-config -c rootfs
進入菜單:
Filesystem Packages --->module --->customGpioExport --->[*] customGpioExport
2.10 全系統編譯與部署
petalinux-build
petalinux-package --boot --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/system.bit --u-boot
2.11 啟動驗證
系統啟動后檢查模塊加載:
# 查看模塊是否加載
lsmod | grep customGpioExport# 手動加載(若未自動加載)
modprobe customGpioExport# 檢查 GPIO 導出狀態
ls /sys/class/gpio/
三、框架解讀
3.1 模塊基本信息
代碼開頭通過宏定義了模塊的基本信息:
- MODULE_LICENSE(“GPL”):聲明模塊遵循GPL協議。
- MODULE_AUTHOR和MODULE_DESCRIPTION:提供作者和模塊描述。
- MODULE_DEVICE_TABLE(of, …):用于與設備樹中的節點匹配(后文詳述)。
3.2 模塊參數
通過module_param
定義了兩個模塊參數:
unsigned myint = 0xdeadbeef;
char *mystr = "default";
module_param(myint, int, S_IRUGO); // 整型參數
module_param(mystr, charp, S_IRUGO); // 字符串參數
- 這些參數可在加載模塊時通過命令行指定,例如:
insmod customGpioExport.ko myint=1234 mystr="hello"
- 參數權限為
S_IRUGO
,表示用戶空間可讀但不可寫。
3.3 數據結構:customGpioExport_local
struct customGpioExport_local {int irq; // 中斷號unsigned long mem_start; // 內存起始地址unsigned long mem_end; // 內存結束地址void __iomem *base_addr; // 映射后的虛擬地址
};
- 該結構體保存設備的硬件資源信息,如中斷號、寄存器物理地址及其映射后的虛擬地址。
3.4 中斷處理函數
static irqreturn_t customGpioExport_irq(int irq, void *lp) {printk("customGpioExport interrupt\n");return IRQ_HANDLED;
}
- 當設備觸發中斷時,此函數被調用。
- 當前僅打印一條日志,實際應用中需添加具體的中斷處理邏輯(如讀取狀態寄存器、處理數據等)。
- 注意:
request_irq
的第三個參數(標志位)為0
,未指定觸發方式(如上升沿或電平觸發),可能需要根據硬件需求調整。
3.5 Probe函數:設備初始化
static int customGpioExport_probe(struct platform_device *pdev)
功能:
- 在設備樹匹配到驅動時調用,負責初始化設備資源(內存、中斷等)。
流程:
-
獲取內存資源:
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- 從設備樹中獲取寄存器內存范圍(
mem_start
和mem_end
)。
- 從設備樹中獲取寄存器內存范圍(
-
分配結構體內存:
lp = kmalloc(sizeof(struct customGpioExport_local), GFP_KERNEL);
- 為
customGpioExport_local
分配內存,保存設備信息。
- 為
-
請求內存區域:
request_mem_region(lp->mem_start, ...);
- 鎖定物理內存區域,防止其他驅動占用。
-
內存映射:
lp->base_addr = ioremap(lp->mem_start, ...);
- 將物理地址映射為內核虛擬地址,后續可通過
iowrite32
/ioread32
等函數訪問寄存器。
- 將物理地址映射為內核虛擬地址,后續可通過
-
獲取中斷資源:
r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- 若設備樹中定義了中斷,注冊中斷處理函數:
request_irq(lp->irq, &customGpioExport_irq, 0, ...);
- 若設備樹中定義了中斷,注冊中斷處理函數:
-
錯誤處理:
- 若某步驟失敗,依次釋放已申請的資源(如
release_mem_region
、iounmap
、kfree
等)。
- 若某步驟失敗,依次釋放已申請的資源(如
3.5 Remove函數:資源釋放
static int customGpioExport_remove(struct platform_device *pdev)
- 在模塊卸載或設備移除時調用。
- 釋放所有資源:中斷、虛擬地址映射、內存區域及結構體內存。
3.7 設備樹匹配
static struct of_device_id customGpioExport_of_match[] = {{ .compatible = "vendor,customGpioExport", },{ /* end of list */ },
};
- 通過
compatible
屬性與設備樹中的節點匹配。例如,設備樹中需包含:customGpioExport@0x12340000 {compatible = "vendor,customGpioExport";reg = <0x12340000 0x1000>;interrupts = <0 29 4>; };
3.8 平臺驅動結構體
static struct platform_driver customGpioExport_driver = {.driver = {.name = DRIVER_NAME,.of_match_table = customGpioExport_of_match,},.probe = customGpioExport_probe,.remove = customGpioExport_remove,
};
- 定義平臺驅動的名稱、設備樹匹配表、Probe和Remove函數。
3.9 模塊初始化和退出
-
初始化:
static int __init customGpioExport_init(void) {platform_driver_register(&customGpioExport_driver);printk("Hello module world.\n"); }
- 注冊平臺驅動,并打印初始化信息。
-
退出:
static void __exit customGpioExport_exit(void) {platform_driver_unregister(&customGpioExport_driver);printk("Goodbye module world.\n"); }
- 注銷驅動并清理資源。
3.10 代碼執行流程
-
模塊加載:
- 執行
customGpioExport_init
,注冊平臺驅動。 - 內核掃描設備樹,若找到匹配的
compatible
節點,調用customGpioExport_probe
初始化設備。
- 執行
-
設備初始化:
- 申請內存、映射地址、注冊中斷(如有)。
-
模塊卸載:
- 執行
customGpioExport_exit
,注銷驅動并調用customGpioExport_remove
釋放資源。
- 執行
3.11 潛在改進點
- 中斷標志位:
request_irq
未指定觸發方式(如IRQF_TRIGGER_RISING
),需根據硬件配置。 - GPIO功能:當前代碼未實現GPIO的導出或操作邏輯,需補充
gpio_request
、gpio_direction_output
等函數。 - 模塊參數應用:
myint
和mystr
未被使用,可擴展為配置參數(如設置GPIO初始狀態)。
總結
此代碼是一個典型的內核模塊框架,實現了設備樹匹配、資源管理、中斷處理等基礎功能,但具體功能(如GPIO操作)需進一步擴展。開發者可根據實際需求,在Probe函數中添加硬件初始化代碼,并在中斷處理函數中實現業務邏輯。
四、結語
在petalinux框架下,完成linux驅動開發門檻大大降低,效率提高不少,希望這篇文章能夠拋磚引玉,對大家有所幫助。
研究學習不易,點贊易。
工作生活不易,收藏易,點收藏不迷茫 :)