撰寫自己的 GPIO Driver
自己在工作上會利用到 FPGA 的腳位來當做 GPIO 的功能,雖然搭著 character device 也能辦到操控的功能,不過感覺用標準的框架會更帥一些,所以就研究了一下用法。
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
PWD := $(shell pwd) KERNEL=/lib/modules/`uname -r`/build obj-m := vgpio.o SRC=gpiochip.o vgpio-objs = $(SRC) all: $(MAKE) -C $(KERNEL) M=$(PWD) modules clean: $(MAKE) -C $(KERNEL) M=$(PWD) clean |
主程式(gpiochip.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include <linux/err.h> #include <linux/gpio.h> #define GPIO_PINS 128 unsigned int v[GPIO_PINS] = { 0 }; struct gpio_chip vgpio_gpio_chip = { 0 }; static int vgpio_gpio_get(struct gpio_chip *chip, unsigned offset) { printk("%s(): get GPIO bit %d.\n", __func__, offset); return v[offset]; } static void vgpio_gpio_set(struct gpio_chip *chip, unsigned offset, int val) { printk("%s(): set GPIO bit %d as %d\n", __func__, offset, val); v[offset] = val; return ; } static int vgpio_gpio_probe(void) { int ret; vgpio_gpio_chip.ngpio = GPIO_PINS; vgpio_gpio_chip.label = "vgpio"; /* base will take effect of /sys/class/gpio256 */ vgpio_gpio_chip.base = 0x100; vgpio_gpio_chip.get = vgpio_gpio_get; vgpio_gpio_chip.set = vgpio_gpio_set; ret = gpiochip_add(&vgpio_gpio_chip); if (ret < 0) { printk("gpiochip_add failed with error %d\n", ret); return -1; } printk("%s(): registerred.\n", __func__); return 0; } static void __exit vgpio_gpio_remove(void) { gpiochip_remove(&vgpio_gpio_chip); printk("%s(): unregisterred.\n", __func__); } module_init(vgpio_gpio_probe); module_exit(vgpio_gpio_remove); MODULE_LICENSE("GPL"); |
行 4: 這邊假設有支援到 128 個 GPIO Pins ,這個其實要設多少都可以,就看自己實際上要用到多少
行 5: 由於這邊是一個模擬範例,就將輸出的值存在一個 array
行 9: vgpio_gpio_get() 當讀取 GPIO value 時所使用的 function. 其中的 offset 也就是代表要讀取哪1根 GPIO 的值,以本例來說,範圍就是 0 ~127.
行14: vgpio_gpio_set() 設定 GPIO value 時所使的 function. 其中 offset 指定哪1個 GPIO,而 value 是其值。
行22: 此 module 的 probe function,在裡面做 GPIO driver 的註冊動作。
行25: 設定一共有幾根 GPIO PIN 可以用
行28: 設定此 driver 所用到的 memory base,由於這邊是虛擬的,所以可以隨便設。如果我們設定 0x100,就會產生 /sys/class/gpio/gpiochip256這樣一個名稱的目錄。
行29~30: 就是指定 get/set 時要呼叫的function, 也就是剛提到的 vgpio_gpio_get() / vgpio_gpio_set() 。
編譯與載入
將2個檔案放在一起後,執行 make 就可以編出 vgpio.ko 的 module 了。文末會附上檔案,方便直接使用。本文是在 Ubuntu 20.04 上測試的,舊一點的版本應該也可以用。
載入後就可以看到 gpiochip256 了,並下達 “echo 261 > /sys/class/gpio/export” 來指定要存取其 PIN5。
與實體裝置連結
本範例只是一個框架,若要與實體裝置互動,可以在 probe 裡對硬體做設定,而在 vgpio_gpio_get() / vgpio_gpio_set() 對值做讀寫。另外這邊沒有提到的是設定 GPIO 的方向,因為實際上我沒用到,有需要的人可能需要自行查詢。