嵌入式linux與物聯網進階之路五:嵌入式驅動方式點亮LED
阿新 • • 發佈:2021-06-23
話說前面章節講到了如何利用嵌入式驅動開發的方式進行驅動開發。由於其學習路線相比於裸機開發來說,上手難度稍微大一些,而且程式碼量也相對來說較多,所以對剛上手的人來說是頗有難度的。本章節,我們將以一個類似於Hello World點燈的例子,來講解在linux下如何進行核心驅動的開發。
工欲善其事,必先利其器,開始之前,我們需要先將驅動開發用到的主體框架搭建一下,這裡由於上節講過,我這裡直接貼上來:
#include <linux/init.h> #include <linux/module.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/gpio.h> #include <linux/string.h> #define LED_MAJOR 200 #define LED_NAME "LED" static int led_open(struct inode *inode, struct file *filep){ printk("GPIO init \n"); return 0; } static int led_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos){ return count; } static int led_release(struct inode *inode, struct file *filep){ printk("Release !! \n"); return 0; } static const struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write, .release = led_release, }; static int __init led_init(void){ printk("led control device init success! \r\n"); return 0; } static void __exit led_exit(void){ printk(" led_exit \r\n"); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("CXSR");
可以看到,整個驅動開發框架無非是如下幾個東西,首先是module_init和module_exit函式,之後就是file_operations結構體,結構體中有對檔案的讀,寫,開啟,關閉等等,我們只需要把我們用到的操作去實現就行了。由於這部分整體比較固化,所以這裡我不再贅述了。
由於在荔枝派中,我選擇了A1口作為我的控制口,所以我先嚐試利用GPIO手動控制了一下,整體控制流程如下:
1、 進入sys/class/gpio目錄下 2、 執行echo 1 > export命令,可以看出來建立了gpio1的資料夾 3、 進入gpio1資料夾,cat direction檢視其值為in,通過vi direction,將其值改為out後, wq儲存。 4、 執行 echo 1 > value 命令,則可以設定A1口高電平,設定echo 0 > value 命令,則可以設定A1口低電平。
通過如上步驟,我們發現,我們可以控制板子上的LED燈的亮滅了。之所以能這麼控制,是因為我們編譯生成的根檔案中,包含了對GPIO的支援,所以使得我們很容易的進行控制。這裡的內容,之後我們會用到,先繼續。
接下來,我們就開始針對剛才的驅動框架模板,來慢慢的填寫我們的內容吧。
#include <linux/init.h> #include <linux/module.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/gpio.h> #include <linux/string.h> #define LED_MAJOR 200 #define LED_NAME "LED" /*led引腳,這裡是A1腳*/ #define LED_PIN 1 static int gpio_status; /*使用者態-核心態互動緩衝區*/ static char recv_msg[20]; /*class名稱, 會建立到/sys/class/目錄下 */ static const char *CLASS_NAME = "led_control_class"; /*led分類,由此分類可以創建出裝置*/ static struct class *led_control_class = NULL; /*led裝置,由此可以實現led控制*/ static struct device *led_control_device = NULL; /*gpio初始設定*/ static void gpio_config(void){ if(!gpio_is_valid(LED_PIN)){ printk("Error wrong gpio number !!\n"); return; } gpio_request(LED_PIN, "led_ctr"); /*設定引腳為輸出狀態*/ gpio_direction_output(LED_PIN,1); /*初始置為高電平*/ gpio_set_value(LED_PIN,1); gpio_status = 1; }
/*gpio關閉設定*/ static void gpio_deconfig(void){ gpio_free(LED_PIN); }
/*初始燈*/ static int led_open(struct inode *inode, struct file *filep){ printk("GPIO init \n"); gpio_config(); return 0; }
/*為燈的緩衝區進行資料交換*/ static int led_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos){ int cnt = _copy_from_user(recv_msg, buf, count); if(0 == cnt){
/*on命令, 則開燈*/ if(0 == memcmp(recv_msg, "on", 2)){ printk("LED on! \n"); gpio_set_value(LED_PIN, 1); gpio_status = 1; }
/*off命令,則關燈*/
else{ printk("LED off! \n"); gpio_set_value(LED_PIN, 0); gpio_status = 0; } }else{ printk("ERROR occur when writing!!\n"); return -EIO; } return count; }
/*燈裝置關閉*/ static int led_release(struct inode *inode, struct file *filep){ printk("Release !! \n"); gpio_deconfig(); return 0; } /*檔案操作結構體*/ static const struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write, .release = led_release, };
/*裝置初始化*/ static int __init led_init(void){ int ret = 0; /* 1. 註冊裝置 */ ret = register_chrdev(LED_MAJOR, LED_NAME,&led_fops); if(ret <0){ printk("register fail!\r\n"); return -EIO; } printk("register success, major number is %d \r\n",ret);
/* 2. 建立裝置分類 */ led_control_class = class_create(THIS_MODULE, CLASS_NAME); if(IS_ERR(led_control_class)){ unregister_chrdev(LED_MAJOR, LED_NAME); return -EIO; }
/* 3. 建立裝置 */ led_control_device = device_create(led_control_class, NULL, MKDEV(LED_MAJOR,0), NULL,LED_NAME); if(IS_ERR(led_control_device)){ class_destroy(led_control_class); unregister_chrdev(LED_MAJOR, LED_NAME); return -EIO; } printk("led control device init success! \r\n"); return 0; }
/*設備註銷*/ static void __exit led_exit(void){ printk(" led_exit \r\n"); device_destroy(led_control_class, MKDEV(LED_MAJOR,0)); class_unregister(led_control_class); class_destroy(led_control_class); unregister_chrdev(LED_MAJOR,LED_NAME); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("CXSR");