一、基本介紹
gpio_get_value函數是Linux內核中一個非常基本的函數,用於獲取GPIO的當前電平值(0或1)。GPIO代表通用輸入輸出,可用於諸如控制LED燈,讀取傳感器等應用。在嵌入式系統中,GPIO通常由SoC內部的GPIO控制器所管理,而gpio_get_value函數就是用於從GPIO控制器中獲取GPIO電平信息的函數。
二、GPIO獲取方法
在使用gpio_get_value函數之前,我們需要確定目標GPIO管腳的編號。在Linux內核中,GPIO可以使用兩種方式進行編號:物理編號和內核編號。在SoC芯片數據手冊中,一般會給出GPIO管腳的物理編號,如圖所示:
GPIO0_IO03 | HDR1 Pin20 |
可以看到,該GPIO管腳的物理編號為GPIO0_IO03,這個編號將作為參數傳遞到gpio_get_value函數中。
另一種GPIO編號方式是內核編號,內核編號通常是在系統啟動時自動映射的,不同的平台可能內核編號不同。在這種情況下,我們可以使用對應的設備樹節點,獲取GPIO的內核編號。具體獲取方法可以參考相關文獻。
三、GPIO獲取過程
具體來說,gpio_get_value函數的實現方式與具體SoC芯片和所使用的GPIO控制器相關,下面以i.MX6ULL芯片為例進行分析。
在i.MX6ULL芯片中,GPIO使用一個叫做GPIO1~7的控制器進行管理。每個GPIO控制器都有一個GDIR寄存器,用於控制具體GPIO管腳是輸入還是輸出,並有一個DR寄存器,用於讀取和設置具體GPIO管腳的電平值。因此,gpio_get_value函數的實際實現就是從DR寄存器中讀取指定GPIO管腳的電平值。
int gpio_get_value(unsigned gpio) { struct gpio_chip *chip = gpio_to_chip(gpio); unsigned off = gpio_to_offset(gpio); unsigned long flags; int ret; raw_spin_lock_irqsave(&gpio_lock, flags); ret = !!(*chip->read_reg)(chip, off); raw_spin_unlock_irqrestore(&gpio_lock, flags); return ret; }
具體來說,gpio_get_value函數首先通過gpio_to_chip和gpio_to_offset函數將GPIO物理編號轉換為所對應的GPIO控制器和管腳編號。然後,它獲取全局變量gpio_lock上的自旋鎖,以確保訪問DR寄存器的互斥性。最後,它通過執行控制器的read_reg函數,從DR寄存器中讀取與指定管腳相關的電平值,並將其轉換為一個布爾值返回。
四、其他注意事項
除了上述過程外,我們還需注意以下事項。
1. 對DR寄存器的操作必須在內核上下文中進行
GPIO控制器通常位於SoC的內存映射空間中,因此對其進行的訪問必須在內核上下文中進行。GPIO框架為讀取和設置GPIO的函數提供了合適的上下文,因此我們必須使用這些函數進行GPIO的讀寫操作。
2. 驅動中使用GPIO時需要先請求該GPIO控制器
在驅動程序中使用GPIO時,需要先使用gpio_request函數請求所使用的GPIO控制器。如果該GPIO已經被其他驅動程序或應用程序使用,請求操作將會失敗。我們還需在程序結束時使用gpio_free函數釋放請求過的GPIO。
五、示例代碼
以下是一個示例驅動程序,其目的是讀取i.MX6ULL芯片GPIO0_IO03管腳的電平值:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/gpio.h> #define GPIO_PIN 3 static int __init gpio_test_init(void) { int ret; /* Request GPIO */ ret = gpio_request(GPIO_PIN, "GPIO Test"); if (ret) { pr_err("Failed to request GPIO\n"); return ret; } /* Set GPIO direction to input */ ret = gpio_direction_input(GPIO_PIN); if (ret) { pr_err("Failed to set GPIO direction\n"); gpio_free(GPIO_PIN); return ret; } /* Read GPIO value */ ret = gpio_get_value(GPIO_PIN); if (ret) { pr_info("GPIO is HIGH\n"); } else { pr_info("GPIO is LOW\n"); } /* Free GPIO */ gpio_free(GPIO_PIN); return 0; } static void __exit gpio_test_exit(void) { pr_info("gpio_test module exit\n"); } module_init(gpio_test_init); module_exit(gpio_test_exit); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("GPIO Test Driver"); MODULE_LICENSE("GPL");
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/154832.html