【IMX6ULL驅動開發學習】08.馬達驅動實戰:驅動編寫、手動注冊平臺設備和設備樹添加節點信息

目錄

一、使用設備樹

1.1 修改設備樹流程

二、手動創建平臺設備?

三、總結(附驅動程序)


前情提要:???????【IMX6ULL驅動開發學習】07.驅動程序分離的思想之平臺總線設備驅動模型和設備樹_阿龍還在寫代碼的博客-CSDN博客

手動注冊平臺設備和設備樹的目的都是為了構造platform_device結構體

一、使用設備樹

之前的驅動編寫方式,引腳信息在驅動程序里寫死了,移植性差。而使用設備樹,這樣的程序編寫方式便于在換了板子或引腳之后,只要修改設備樹的節點信息即可,不需要看復雜的驅動程序,前提是有完備的驅動程序。

在驅動程序的入口函數里注冊了gpio_platform_driver,

module_init(gpio_drv_init);
static int __init gpio_drv_init(void)
{/* 注冊platform_driver */return platform_driver_register(&gpio_platform_driver);
}

gpio_platform_driver結構體中probe函數被調用,需要在設備樹中找到與之匹配的設備節點信息,即設備節點信息也要含有這個語句.compatible = "100ask,gpiodemo"

static const struct of_device_id gpio_dt_ids[] = {{ .compatible = "100ask,gpiodemo", },{ /* sentinel */ }
};static struct platform_driver gpio_platform_driver = {.driver		= {.name	= "100ask_gpio_plat_drv",.of_match_table = gpio_dt_ids,},.probe		= gpio_drv_probe,.remove		= gpio_drv_remove,
};

1.1 修改設備樹流程

在內核目錄下找到設備樹文件,以我的路徑為例,這里給出絕對路徑

  • 修改設備樹:vi /home/book/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/dts/100ask_imx6ull-14x14.dts
  • 增加節點信息如下:
motor {compatible = "100ask,gpiodemo";gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>, <&gpio4 20 GPIO_ACTIVE_HIGH>,<&gpio4 21 GPIO_ACTIVE_HIGH>,<&gpio4 22 GPIO_ACTIVE_HIGH>;
};
  • 一定要在/home/book/100ask_imx6ull-sdk/Linux-4.9.88目錄下編譯設備樹:make dtbs
  • 復制到單板上,如下:
PC:
cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/開發板:
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
cp /mnt/100ask_imx6ull-14x14.dtb  /boot
reboot
  • 查看設備樹節點信息:ls /sys/firmware/devicetree/base/?

  • ?查看馬達節點有沒有被轉換成平臺設備(platform_device):ls /sys/bus/platform/devices/

?

?有這個motor文件表示有了對應的平臺設備。

  • 進入motor文件查看,因為還沒裝驅動,所以沒有顯示驅動程序

?

  • 裝載驅動后,查看motor文件:?說明驅動和設備都匹配上了

?

  • 最后就編寫測試程序進行測試即可:?
./button_test /dev/motor ...

二、手動創建平臺設備?

  • 編寫dev.c文件
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>static struct resource my_drv_resource[] = {{.start          = 115,.end            = 115,.flags          = IORESOURCE_IRQ,},{.start          = 116,.end            = 116,.flags          = IORESOURCE_IRQ,},{.start          = 117,.end            = 117,.flags          = IORESOURCE_IRQ,},{.start          = 118,.end            = 118,.flags          = IORESOURCE_IRQ,},
};static struct platform_device gpio_platform_device = {.name           = "100ask_gpio_plat_drv",.id             = 0,.num_resources  = ARRAY_SIZE(my_drv_resource),// =4 宏來計算數組大小.resource       = my_drv_resource,
};static int __init gpio_dev_init(void)
{/* 注冊platform_driver */return platform_device_register(&gpio_platform_device);
}static void __exit gpio_dev_exit(void)
{/* 反注冊platform_driver */platform_device_unregister(&gpio_platform_device);
}/* 7. 其他完善:提供設備信息,自動創建設備節點                                     */module_init(gpio_dev_init);
module_exit(gpio_dev_exit);MODULE_LICENSE("GPL");

?其中,由這個名字"100ask_gpio_plat_drv"找到與之匹配的平臺驅動(platform_driver)

static struct platform_device gpio_platform_device = {.name           = "100ask_gpio_plat_drv",.id             = 0,.num_resources  = ARRAY_SIZE(my_drv_resource),// =4 宏來計算數組大小.resource       = my_drv_resource,
};
  • ?修改Makefile文件
KERN_DIR =  /home/book/100ask_imx6ull-sdk/Linux-4.9.88 # 板子所用內核源碼的目錄all:make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o button_test button_test.c
clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.order  button_test# 參考內核源碼drivers/char/ipmi/Makefile
# 要想把a.c, b.c編譯成ab.ko, 可以這樣指定:
# ab-y := a.o b.o
# obj-m += ab.oobj-m += gpio_drv.o
obj-m += gpio_dev.o
  • ?編譯:make
  • 設備樹節點信息取消:因為內核里有了設備樹節點信息,需要改回去或者添加disabled狀態
motor {compatible = "100ask,gpiodemo";gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>, <&gpio4 20 GPIO_ACTIVE_HIGH>,<&gpio4 21 GPIO_ACTIVE_HIGH>,<&gpio4 22 GPIO_ACTIVE_HIGH>;status = "disabled";
};
  • 編譯:make dtbs
  • 更新設備樹:
PC:
cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/開發板:
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
cp /mnt/100ask_imx6ull-14x14.dtb  /boot
reboot
  • 查看設備樹節點信息:ls /sys/firmware/devicetree/base/

????????狀態為禁止狀態,設備樹節點信息被我們禁用了?

?

  • 查看馬達節點有沒有被轉換成平臺設備(platform_device):ls /sys/bus/platform/devices/,這里肯定也是沒有的

?

  • ?裝載驅動程序、查看是否匹配上、查看設備節點

?這個平臺驅動支持名為"100ask_gpio_plat_drv"的設備,設備節點也出來了

?

三、總結(附驅動程序)

這個驅動程序,在入口函數里注冊了平臺驅動,這個平臺驅動可以支持來自設備樹的平臺設備.compatible = "100ask,gpiodemo",和來自自己手動創建的平臺設備.name = "100ask_gpio_plat_drv"。匹配規則有4種,這里用的是最簡單的。當平臺driver匹配到平臺device時,驅動程序里的probe函數就被調用,probe函數里可以從設備樹里得到引腳信息,也可以從手動注冊的平臺device里得到所謂的資源。

static const struct of_device_id gpio_dt_ids[] = {{ .compatible = "100ask,gpiodemo", },{ /* sentinel */ }
};static struct platform_driver gpio_platform_driver = {.driver		= {.name	= "100ask_gpio_plat_drv",.of_match_table = gpio_dt_ids,//設備樹信息},.probe		= gpio_drv_probe,.remove		= gpio_drv_remove,
};

?驅動程序:

#include <linux/module.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>struct gpio_desc{int gpio;int irq;char name[128];int key;struct timer_list key_timer;
} ;static struct gpio_desc *gpios;
static int count;/* 主設備號                                                                 */
static int major = 0;
static struct class *gpio_class;/* 馬達引腳設置數字 */
static int g_motor_pin_ctrl[8]= {0x2,0x3,0x1,0x9,0x8,0xc,0x4,0x6};
static int g_motor_index = 0;void set_pins_for_motor(int index)
{int i;for (i = 0; i < 4; i++){gpio_set_value(gpios[i].gpio, g_motor_pin_ctrl[index] & (1<<i) ? 1 : 0);}
}void disable_motor(void)
{int i;for (i = 0; i < 4; i++){gpio_set_value(gpios[i].gpio, 0);}
}/* int buf[2];* buf[0] = 步進的次數, > 0 : 逆時針步進; < 0 : 順時針步進* buf[1] = mdelay的時間*/
static ssize_t motor_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int ker_buf[2];int err;int step;if (size != 8)return -EINVAL;err = copy_from_user(ker_buf, buf, size);if (ker_buf[0] > 0){/* 逆時針旋轉 */for (step = 0; step < ker_buf[0]; step++)
{set_pins_for_motor(g_motor_index);mdelay(ker_buf[1]);g_motor_index--;if (g_motor_index == -1)g_motor_index = 7;}}else{/* 順時針旋轉 */ker_buf[0] = 0 - ker_buf[0];for (step = 0; step < ker_buf[0]; step++)
{set_pins_for_motor(g_motor_index);mdelay(ker_buf[1]);g_motor_index++;if (g_motor_index == 8)g_motor_index = 0;}
}/* 改進:旋轉到位后讓馬達不再消耗電源 */disable_motor();return 8;    
}/* 定義自己的file_operations結構體                                              */
static struct file_operations gpio_key_drv = {.owner	 = THIS_MODULE,.write   = motor_write,
};/* 在入口函數 */
static int gpio_drv_probe(struct platform_device *pdev)
{int err = 0;int i;struct device_node *np = pdev->dev.of_node;struct resource *res;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 從platfrom_device獲得引腳信息 * 1. pdev來自c文件* 2. pdev來自設備樹*/if (np){/* pdev來自設備樹 : 示例reg_usb_ltemodule: regulator@1 {compatible = "100ask,gpiodemo";gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>, <&gpio5 3 GPIO_ACTIVE_HIGH>;};*/count = of_gpio_count(np);if (!count)return -EINVAL;gpios = kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL);for (i = 0; i < count; i++){gpios[i].gpio = of_get_gpio(np, i);sprintf(gpios[i].name, "%s_pin_%d", np->name, i);}}else{/* pdev來自c文件 static struct resource omap16xx_gpio3_resources[] = {{.start  = 115,.end    = 115,.flags  = IORESOURCE_IRQ,},{.start  = 118,.end    = 118,.flags  = IORESOURCE_IRQ,},		};		*/count = 0;while (1){res = platform_get_resource(pdev, IORESOURCE_IRQ, count);if (res){count++;}else{break;}}if (!count)return -EINVAL;gpios = kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL);for (i = 0; i < count; i++){res = platform_get_resource(pdev, IORESOURCE_IRQ, i);gpios[i].gpio = res->start;sprintf(gpios[i].name, "%s_pin_%d", pdev->name, i);}}for (i = 0; i < count; i++){err = gpio_request(gpios[i].gpio, gpios[i].name);gpio_direction_output(gpios[i].gpio, 0);}/* 注冊file_operations 	*/major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/gpio_desc */gpio_class = class_create(THIS_MODULE, "100ask_gpio_key_class");if (IS_ERR(gpio_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "100ask_gpio_key");return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "motor"); /* /dev/motor */return err;
}/* 有入口函數就應該有出口函數:卸載驅動程序時,就會去調用這個出口函數*/
static int gpio_drv_remove(struct platform_device *pdev)
{int i;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, "100ask_gpio_key");for (i = 0; i < count; i++){gpio_free(gpios[i].gpio);}return 0;
}static const struct of_device_id gpio_dt_ids[] = {{ .compatible = "100ask,gpiodemo", },{ /* sentinel */ }
};static struct platform_driver gpio_platform_driver = {.driver		= {.name	= "100ask_gpio_plat_drv",.of_match_table = gpio_dt_ids,//設備樹信息},.probe		= gpio_drv_probe,.remove		= gpio_drv_remove,
};static int __init gpio_drv_init(void)
{/* 注冊platform_driver */return platform_driver_register(&gpio_platform_driver);
}static void __exit gpio_drv_exit(void)
{/* 反注冊platform_driver */platform_driver_unregister(&gpio_platform_driver);
}/* 7. 其他完善:提供設備信息,自動創建設備節點                                     */module_init(gpio_drv_init);
module_exit(gpio_drv_exit);MODULE_LICENSE("GPL");

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42143.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42143.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42143.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android中如何不編譯源生模塊

如果想讓自己的app 替換系統的app 比如使用閃電瀏覽器替換系統的Browser 首先把閃電瀏覽器放到 vendor/rockchip/common/apps Android.mk LOCAL_PATH : $(call my-dir) include $(CLEAR_VARS)LOCAL_MODULE : Lightning LOCAL_SRC_FILES : $(LOCAL_MODULE).apk LOCAL_MODULE_C…

英語詞法——冠詞

冠詞是一種虛詞,與名詞連用,放在名詞的前面,說明或限制該名詞所表示的人或物是泛指的還是特指的。冠詞是最主要、最典型的限定詞。冠詞可以分為不定冠詞a,an,定冠詞the和零冠詞(即不用任何冠詞的場合)三種。 第一節 定冠詞 定冠詞the用于各類名詞(單數可數名詞、復數可…

linux 命令- systemctl

systemctl 參數說明 1、使用語法 用法&#xff1a;systemctl [OPTIONS…] {COMMAND} … 2 、參數說明 參數參數說明start立刻啟動后面接的unitstop立刻關閉后面接的unitrestart立刻關閉后啟動后面接的unit&#xff0c;亦即執行stop再start的意思reload不關閉后面接的unit的…

Elasticsearch查詢之Disjunction Max Query

前言 Disjunction Max Query 又稱最佳 best_fields 匹配策略&#xff0c;用來優化當查詢關鍵詞出現在多個字段中&#xff0c;以單個字段的最大評分作為文檔的最終評分&#xff0c;從而使得匹配結果更加合理 寫入數據 如下的兩條例子數據&#xff1a; docId: 1 title: java …

基于 Redis 實現分布式限流

基于 Redis 實現分布式限流 一、 簡介二、分布式限流1 數據結構1.1 Redis List1.2 Redis Set1.3 Redis Sorted Set 2 實現分布式限流3 實現原理分析 三、分布式限流算法1. 計數器算法2. 漏斗算法3. 令牌桶算法 四、分布式限流實戰1. 單機限流實現2. 基于Redis Clusters的分布式…

常見程序搜索關鍵字轉碼

個別搜索類的網站因為用戶惡意搜索出現誤攔截情況&#xff0c;這類網站本身沒有非法信息&#xff0c;只是因為把搜索關鍵字顯示在網頁中&#xff08;如下圖&#xff09;&#xff0c;可以參考下面方法對輸出的關鍵字進行轉碼 DEDECMS程序 本文針對Dedecms程序進行搜索轉碼&…

優先級隊列【C++】

文章目錄 priority_queuepriority_queue 使用priority_queue的模擬實現向上調整算法向下調整算法pushpoptopsizeempty 仿函數完整代碼 priority_queue 優先隊列&#xff08;priority_queue&#xff09;也是隊列的一種&#xff0c;priority_queue的接口是和queue的接口是相同的…

快速上手Vue開發:在項目中如何配置 tsconfig.json 文件?

文章目錄 一、簡介二、配置1、示例2、編譯器選項列表 一、簡介 tsconfig.json文件中指定了用來編譯這個項目的根文件和編譯選項。 二、配置 1、示例 {"compilerOptions": {"baseUrl": ".","paths": {"/*": ["src/*&…

C#__基本特性和使用

// 特性&#xff08;attribute&#xff09;: // 一種允許我們向程序集添加元數據的語言結構 // 用于保存程序結構信息的某種特殊類型的類 // 類似“批注”&#xff0c;用于解釋說明 #define IsShowMessage // 宏定義&#xff0c;在開頭定義&#xff0…

uni-app彈窗列表滾動, 彈框下面的內容也跟隨滾動解決方案

滑動彈窗里的列表&#xff0c;彈框下面的內容也會跟著滑動&#xff0c;導致彈窗中的列表不能正常滾動 1.彈窗組件代碼&#xff0c;需要在最外層的view中加入touchmove.stop.prevent"moveHandle"&#xff0c;且彈窗中需要滾動的列表要使用scroll-view標簽包裹起來&…

Python爬蟲——requests_post請求

import requests import jsonurl https://fanyi.baidu.com/sugheaders {User-Agent: ,Cookie: }data {kw: hello }response requests.post(url, data, headersheaders)content response.textobj json.loads(content.encode(utf-8)) print(obj)總結&#xff1a; post請求…

五分鐘搭建生鮮蔬果小程序

如今&#xff0c;隨著移動互聯網的快速發展&#xff0c;小程序已經成為眾多企業和商家推廣產品和服務的重要工具。而生鮮蔬果行業作為一個常見的消費領域&#xff0c;也開始逐漸轉向小程序商城來進行銷售和服務。那么&#xff0c;如何從零開始搭建一個生鮮蔬果小程序商城呢&…

Hlang--用Python寫個解釋器

文章目錄 前言流程數學解釋器結果封裝數的操作運行時異常運行解釋實現總結前言 沒錯今天提前來做這個東西,昨天晚上干這個玩意差不多干了兩個多小時才搞定,導致凌晨2點才睡覺,最要命的是,寫著寫著突然想到有一道線代理解錯了,一個晚上,做夢全是這兩個東西。尤其是晚上效…

LeetCode150道面試經典題-- 快樂數(簡單)

1.題目 編寫一個算法來判斷一個數 n 是不是快樂數。 「快樂數」 定義為&#xff1a; 對于一個正整數&#xff0c;每一次將該數替換為它每個位置上的數字的平方和。然后重復這個過程直到這個數變為 1&#xff0c;也可能是 無限循環 但始終變不到 1。如果這個過程 結果為 1&am…

JVM——JVM參數指南

文章目錄 1.概述2.堆內存相關2.1.顯式指定堆內存–Xms和-Xmx2.2.顯式新生代內存(Young Ceneration)2.3.顯示指定永久代/元空間的大小 3.垃圾收集相關3.1.垃圾回收器3.2.GC記錄 1.概述 在本篇文章中&#xff0c;你將掌握最常用的 JVM 參數配置。如果對于下面提到了一些概念比如…

Linux系統之安裝my-mind思維導圖工具

Linux系統之安裝my-mind思維導圖工具 一、my-mind介紹二、本地環境介紹2.1 本地環境規劃2.2 本次實踐介紹 三、檢查本地環境3.1 檢查本地操作系統版本3.2 檢查系統內核版本3.3 檢查端口占用情況 四、安裝httpd4.1 檢查本地yum倉庫4.2 安裝httpd4.3 關閉防火墻和selinux4.4 創建…

arcgis數據采集與拓撲檢查

1、已準備好一張配準好的浙江省行政區劃圖&#xff0c;如下&#xff1a; 2、現在需要繪制湖州市縣級行政區劃。需要右擊文件夾新建文件地理數據庫&#xff0c;如下&#xff1a; 其余步驟均默認即可。 創建好縣級要素數據集后&#xff0c;再新建要素類&#xff0c;命名為縣。 為…

【Java 動態數據統計圖】動態數據統計思路案例(動態,排序,containsKey)五(117)

需求&#xff1a;前端根據后端的返回數據&#xff1a;畫統計圖&#xff1b; 1.動態獲取地域數據以及數據中的平均值&#xff0c;按照平均值降序排序&#xff1b; 說明&#xff1a; X軸是動態的&#xff0c;有對應區域數據則展示&#xff1b; X軸 區域數據降序排序&#xff1b;…

03-第一個Spark程序WordCount

Scala版 1&#xff09;創建項目 增加 Scala 插件 Spark 由 Scala 語言開發的&#xff0c;咱們當前使用的 Spark 版本為 3.2.0&#xff0c;默認采用的 Scala 編譯版本為 2.13&#xff0c;所以后續開發時。我們依然采用這個版本。開發前請保證 IDEA 開發工具中含有 Scala 開發…

ebay燈串UL報告 UL588檢測標準

季節性和裝飾性照明用品即燈串以及配件都是便攜式插頭連接的臨時性商品&#xff0c;最大額定輸入電壓為 120 伏。 由 ILAC ISO 17025 認證的實驗室出具的檢測報告&#xff0c;確認每件商品均已經過檢測&#xff0c;符合下列要求&#xff1a; 季節性和裝飾性照明用品(燈串&…