日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux蜂鸣器实验(使用上一节子系统思想,摈弃了自己配置寄存器的繁琐操作)

發布時間:2023/12/10 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux蜂鸣器实验(使用上一节子系统思想,摈弃了自己配置寄存器的繁琐操作) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 子系統思想的蜂鳴器驅動流程
  • 硬件原理圖分析
  • 實驗程序編寫
    • 修改設備樹文件
    • 蜂鳴器驅動程序編寫
    • 編寫測試APP
  • 運行測試
    • 編譯驅動程序和測試APP
    • 運行測試

上一章實驗中我們借助pinctrl 和gpio 子系統編寫了LED 燈驅動,I.MX6U-ALPHA 開發板上還有一個蜂鳴器,從軟件的角度考慮,蜂鳴器驅動和LED 燈驅動其實是一摸一樣的,都是控制IO 輸出高低電平。本章我們就來學習編寫蜂鳴器的Linux 驅動,也算是對上一章講解的pinctrl和gpio 子系統的鞏固。

子系統思想的蜂鳴器驅動流程

蜂鳴器驅動原理已經在第十四章有了詳細的講解,I.MX6U-ALPHA 開發板上的蜂鳴器通過SNVS_TAMPER1 引腳來控制,本節我們來看一下如果在Linux 下編寫蜂鳴器驅動需要做哪些工作:

  • ①、在設備樹中添加SNVS_TAMPER1 引腳的pinctrl信息。
  • ②、在設備樹中創建蜂鳴器節點,在蜂鳴器節點中加入GPIO 信息。
  • ③、編寫驅動程序和測試APP,和第四十五章的LED 驅動程序和測試APP 基本一樣。

硬件原理圖分析

本章實驗硬件原理圖參考14.3 小節即可。

實驗程序編寫

本實驗對應的例程路徑為:開發板光盤-> 2、Linux 驅動例程-> 6_beep。
本章實驗在四十二章實驗的基礎上完成,重點是將驅動改為基于設備樹的.

修改設備樹文件

1、添加pinctrl 節點

I.MX6U-ALPHA 開發板上的BEEP 使用了SNVS_TAMPER1 這個PIN,打開imx6ull-alientek-emmc.dts,在iomuxc 節點的imx6ul-evk 子節點下創建一個名為“pinctrl_beep”的子節點,節點內容如下所示:

1 pinctrl_beep: beepgrp { 2 fsl,pins = < 3 MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0 /* beep */ 4 >; 5 };

第3 行,將SNVS_TAMPER1 這個PIN 復用為GPIO5_IO01,電氣屬性0x10B0 ,宏
MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 定義在arch/arm/boot/dts/imx6ull-pinfunc-snvs.h文件中。

2、添加BEEP設備節點

在根節點“/”下創建BEEP 節點,節點名為“beep”,節點內容如下:

1 beep { 2 #address-cells = <1>; 3 #size-cells = <1>; 4 compatible = "atkalpha-beep"; 5 pinctrl-names = "default"; 6 pinctrl-0 = <&pinctrl_beep>; 7 beep-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>; 8 status = "okay"; 9 };

第6 行,pinctrl-0 屬性設置蜂鳴器所使用的PIN 對應的pinctrl 節點。
第7 行,beep-gpio 屬性指定了蜂鳴器所使用的GPIO。

3、檢查PIN 是否被其他外設使用

在本章實驗中蜂鳴器使用的PIN 為SNVS_TAMPER1,因此先檢查PIN 為SNVS_TAMPER1這個PIN 有沒有被其他的pinctrl 節點使用,如果有使用的話就要屏蔽掉,然后再檢查GPIO5_IO01 這個GPIO 有沒有被其他外設使用,如果有的話也要屏蔽掉。

設備樹編寫完成以后使用“make dtbs”命令重新編譯設備樹,然后使用新編譯出來的imx6ull-alientek-emmc.dtb 文件啟動Linux 系統。啟動成功以后進入“/proc/device-tree”目錄中查看“beep”節點是否存在,如果存在的話就說明設備樹基本修改成功(具體還要驅動驗證),結果如圖46.3.1.1 所示:

蜂鳴器驅動程序編寫

設備樹準備好以后就可以編寫驅動程序了,本章實驗在第四十五章實驗驅動文件gpioled.c的基礎上修改而來。新建名為“6_beep”的文件夾,然后在6_beep 文件夾里面創建vscode 工程,工作區命名為“beep”。工程創建好以后新建beep.c 文件,在beep.c 里面輸入如下內容:

#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> /*************************************************************** Copyright ? ALIENTEK Co., Ltd. 1998-2029. All rights reserved. 文件名 : beep.c 作者 : 左忠凱 版本 : V1.0 描述 : 蜂鳴器驅動程序。 其他 : 無 論壇 : www.openedv.com 日志 : 初版V1.0 2019/7/15 左忠凱創建 ***************************************************************/ #define BEEP_CNT 1 /* 設備號個數 */ #define BEEP_NAME "beep" /* 名字 */ #define BEEPOFF 0 /* 關蜂鳴器 */ #define BEEPON 1 /* 開蜂鳴器 *//* beep設備結構體 */ struct beep_dev{dev_t devid; /* 設備號 */struct cdev cdev; /* cdev */struct class *class; /* 類 */struct device *device; /* 設備 */int major; /* 主設備號 */int minor; /* 次設備號 */struct device_node *nd; /* 設備節點 */int beep_gpio; /* beep所使用的GPIO編號 */ };struct beep_dev beep; /* beep設備 *//** @description : 打開設備* @param - inode : 傳遞給驅動的inode* @param - filp : 設備文件,file結構體有個叫做private_data的成員變量* 一般在open的時候將private_data指向設備結構體。* @return : 0 成功;其他 失敗*/ static int beep_open(struct inode *inode, struct file *filp) {filp->private_data = &beep; /* 設置私有數據 */return 0; }/** @description : 向設備寫數據 * @param - filp : 設備文件,表示打開的文件描述符* @param - buf : 要寫給設備寫入的數據* @param - cnt : 要寫入的數據長度* @param - offt : 相對于文件首地址的偏移* @return : 寫入的字節數,如果為負值,表示寫入失敗*/ static ssize_t beep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) {int retvalue;unsigned char databuf[1];unsigned char beepstat;struct beep_dev *dev = filp->private_data;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}beepstat = databuf[0]; /* 獲取狀態值 */if(beepstat == BEEPON) { gpio_set_value(dev->beep_gpio, 0); /* 打開蜂鳴器 */} else if(beepstat == BEEPOFF) {gpio_set_value(dev->beep_gpio, 1); /* 關閉蜂鳴器 */}return 0; }/** @description : 關閉/釋放設備* @param - filp : 要關閉的設備文件(文件描述符)* @return : 0 成功;其他 失敗*/ static int beep_release(struct inode *inode, struct file *filp) {return 0; }/* 設備操作函數 */ static struct file_operations beep_fops = {.owner = THIS_MODULE,.open = beep_open,.write = beep_write,.release = beep_release, };/** @description : 驅動出口函數* @param : 無* @return : 無*/ static int __init beep_init(void) {int ret = 0;/* 設置BEEP所使用的GPIO *//* 1、獲取設備節點:beep */beep.nd = of_find_node_by_path("/beep");if(beep.nd == NULL) {printk("beep node not find!\r\n");return -EINVAL;} else {printk("beep node find!\r\n");}/* 2、 獲取設備樹中的gpio屬性,得到BEEP所使用的BEEP編號 */beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpio", 0);if(beep.beep_gpio < 0) {printk("can't get beep-gpio");return -EINVAL;}printk("led-gpio num = %d\r\n", beep.beep_gpio);//視頻里此處要gpio_request 后面要free /* 3、設置GPIO5_IO01為輸出,并且輸出高電平,默認關閉BEEP */ret = gpio_direction_output(beep.beep_gpio, 1);if(ret < 0) {printk("can't set gpio!\r\n");}/* 注冊字符設備驅動 *//* 1、創建設備號 */if (beep.major) { /* 定義了設備號 */beep.devid = MKDEV(beep.major, 0);register_chrdev_region(beep.devid, BEEP_CNT, BEEP_NAME);} else { /* 沒有定義設備號 */alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, BEEP_NAME); /* 申請設備號 */beep.major = MAJOR(beep.devid); /* 獲取分配號的主設備號 */beep.minor = MINOR(beep.devid); /* 獲取分配號的次設備號 */}printk("beep major=%d,minor=%d\r\n",beep.major, beep.minor); /* 2、初始化cdev */beep.cdev.owner = THIS_MODULE;cdev_init(&beep.cdev, &beep_fops);/* 3、添加一個cdev */cdev_add(&beep.cdev, beep.devid, BEEP_CNT);/* 4、創建類 */beep.class = class_create(THIS_MODULE, BEEP_NAME);if (IS_ERR(beep.class)) {return PTR_ERR(beep.class);}/* 5、創建設備 */beep.device = device_create(beep.class, NULL, beep.devid, NULL, BEEP_NAME);if (IS_ERR(beep.device)) {return PTR_ERR(beep.device);}return 0; }/** @description : 驅動出口函數* @param : 無* @return : 無*/ static void __exit beep_exit(void) {/* 注銷字符設備驅動 */cdev_del(&beep.cdev);/* 刪除cdev */unregister_chrdev_region(beep.devid, BEEP_CNT); /* 注銷設備號 */device_destroy(beep.class, beep.devid);class_destroy(beep.class); }module_init(beep_init); module_exit(beep_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("zuozhongkai");

beep.c 中的內容和上一章的gpioled.c 中的內容基本一樣,只是換為了初始化
SNVS_TAMPER1 這個PIN,這里就不詳細的講解了。

編寫測試APP

測試APP 在上一章實驗的ledApp.c 文件的基礎上完成,新建名為beepApp.c 的文件,然后輸入如下所示內容:

#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" /*************************************************************** Copyright ? ALIENTEK Co., Ltd. 1998-2029. All rights reserved. 文件名 : beepApp.c 作者 : 左忠凱 版本 : V1.0 描述 : beep測試APP。 其他 : 無 使用方法 :./beepApp /dev/beep 0 關閉蜂鳴器./beepApp /dev/beep 1 打開蜂鳴器 論壇 : www.openedv.com 日志 : 初版V1.0 2019/1/30 左忠凱創建 ***************************************************************/#define BEEPOFF 0 #define BEEPON 1/** @description : main主程序* @param - argc : argv數組元素個數* @param - argv : 具體參數* @return : 0 成功;其他 失敗*/ int main(int argc, char *argv[]) {int fd, retvalue;char *filename;unsigned char databuf[1];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打開beep驅動 */fd = open(filename, O_RDWR);if(fd < 0){printf("file %s open failed!\r\n", argv[1]);return -1;}databuf[0] = atoi(argv[2]); /* 要執行的操作:打開或關閉 *//* 向/dev/beep文件寫入數據 */retvalue = write(fd, databuf, sizeof(databuf));if(retvalue < 0){printf("BEEP Control Failed!\r\n");close(fd);return -1;}retvalue = close(fd); /* 關閉文件 */if(retvalue < 0){printf("file %s close failed!\r\n", argv[1]);return -1;}return 0; }

beepApp.c 的文件內容和ledApp.c 文件內容基本一樣,要是對文件進行打開、寫、關閉等操作。

運行測試

編譯驅動程序和測試APP

1、編譯驅動程序
編寫Makefile 文件,本章實驗的Makefile 文件和第四十章實驗基本一樣,只是將obj-m 變量的值改為beep.o,Makefile 內容如下所示:

KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek CURRENT_PATH := $(shell pwd)obj-m := beep.obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modulesclean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

第4 行,設置obj-m 變量的值為beep.o。
輸入如下命令編譯出驅動模塊文件:

make -j32

編譯成功以后就會生成一個名為“beep.ko”的驅動模塊文件。

2、編譯測試APP
輸入如下命令編譯測試beepApp.c 這個測試程序:

arm-linux-gnueabihf-gcc beepApp.c -o beepApp

編譯成功以后就會生成beepApp 這個應用程序。

運行測試

將上一小節編譯出來的beep.ko 和beepApp 這兩個文件拷貝到rootfs/lib/modules/4.1.15 目錄中,重啟開發板,進入到目錄lib/modules/4.1.15 中,輸入如下命令加載beep.ko 驅動模塊:

depmod //第一次加載驅動的時候需要運行此命令 modprobe beep.ko //加載驅動

驅動加載成功以后會在終端中輸出一些信息,如圖46.4.2.1 所示:

從圖46.4.2.1 可以看出,beep 這個節點找到了,并且GPIO5_IO01 這個GPIO 的編號為129。
使用beepApp 軟件來測試驅動是否工作正常,輸入如下命令打開蜂鳴器:

./beepApp /dev/beep 1 //打開蜂鳴器

輸入上述命令,查看I.MX6U-ALPHA 開發板上的蜂鳴器是否有鳴叫,如果鳴叫的話說明驅
動工作正常。在輸入如下命令關閉蜂鳴器:

./beepApp /dev/beep 0 //關閉蜂鳴器

輸入上述命令以后觀察I.MX6U-ALPHA 開發板上的蜂鳴器是否停止鳴叫。如果要卸載驅動的話輸入如下命令即可:

rmmod beep.ko

總結

以上是生活随笔為你收集整理的Linux蜂鸣器实验(使用上一节子系统思想,摈弃了自己配置寄存器的繁琐操作)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。