一、基本介紹
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
微信掃一掃
支付寶掃一掃