1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子Linux感兴趣的同学可以加群讨论:935446741 4)关注正点原子公众号,获取最新资料更新
第四十六章 Linux蜂鸣器实验
上一章实验中我们借助pinctrl和gpio子系统编写了LED灯驱动,I.MX6U-ALPHA开发板上还有一个蜂鸣器,从软件的角度考虑,蜂鸣器驱动和LED灯驱动其实是一摸一样的,都是控制IO输出高低电平。本章我们就来学习编写蜂鸣器的Linux驱动,也算是对上一章讲解的pinctrl和gpio子系统的巩固。
46.1 蜂鸣器驱动原理 蜂鸣器驱动原理已经在第十四章有了详细的讲解,I.MX6U-ALPHA开发板上的蜂鸣器通过SNVS_TAMPER1引脚来控制,本节我们来看一下如果在Linux下编写蜂鸣器驱动需要做哪些工作: ①、在设备树中添加SNVS_TAMPER1引脚的pinctrl信息。 ②、在设备树中创建蜂鸣器节点,在蜂鸣器节点中加入GPIO信息。 ③、编写驱动程序和测试APP,和第四十五章的LED驱动程序和测试APP基本一样。 接下来我们就根据上面这三步来编写蜂鸣器Linux驱动。 46.2 硬件原理图分析 本章实验硬件原理图参考14.3小节即可。 46.3 实验程序编写 本实验对应的例程路径为:开发板光盘-> 2、Linux驱动例程-> 6_beep。 本章实验在四十二章实验的基础上完成,重点是将驱动改为基于设备树的. 46.3.1 修改设备树文件 1、添加pinctrl节点 I.MX6U-ALPHA开发板上的BEEP使用了SNVS_TAMPER1这个PIN,打开imx6ull-alientek-emmc.dts,在iomuxc节点的imx6ul-evk子节点下创建一个名为“pinctrl_beep”的子节点,节点内容如下所示: 示例代码46.3.1.1 SNVS_TAMPER1 pinctrl节点
1 pinctrl_beep: beepgrp {
2 fsl,pins = ;
5 };
第3行,将SNVS_TAMPER1这个PIN复用为GPIO5_IO01,宏MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01定义在arch/arm/boot/dts/imx6ull-pinfunc-snvs.h文件中。
2、添加BEEP设备节点
在根节点“/”下创建BEEP节点,节点名为“beep”,节点内容如下:
示例代码46.3.1.2 创建BEEP蜂鸣器节点
1 beep {
2 #address-cells = ;
3 #size-cells = ;
4 compatible = "atkalpha-beep";
5 pinctrl-names = "default";
6 pinctrl-0 = ;
7 beep-gpio = ;
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所示:
图46.3.1.1 beep子节点 46.3.2 蜂鸣器驱动程序编写 设备树准备好以后就可以编写驱动程序了,本章实验在第四十五章实验驱动文件gpioled.c的基础上修改而来。新建名为“6_beep”的文件夹,然后在6_beep文件夹里面创建vscode工程,工作区命名为“beep”。工程创建好以后新建beep.c文件,在beep.c里面输入如下内容: 示例代码46.3.2.1 beep.c文件代码段
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 /***************************************************************
18 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
19 文件名 : beep.c
20 作者 : 左忠凯
21 版本 : V1.0
22 描述 : 蜂鸣器驱动程序。
23 其他 : 无
24 论坛 : www.openedv.com
25 日志 : 初版V1.0 2019/7/15 左忠凯创建
26 ***************************************************************/
27 #define BEEP_CNT 1 /* 设备号个数 */
28 #define BEEP_NAME "beep" /* 名字 */
29 #define BEEPOFF 0 /* 关蜂鸣器 */
30 #define BEEPON 1 /* 开蜂鸣器 */
31
32
33 /* beep设备结构体 */
34 struct beep_dev{
35 dev_t devid; /* 设备号 */
36 struct cdev cdev; /* cdev */
37 struct class *class; /* 类 */
38 struct device *device; /* 设备 */
39 int major; /* 主设备号 */
40 int minor; /* 次设备号 */
41 struct device_node *nd; /* 设备节点 */
42 int beep_gpio; /* beep所使用的GPIO编号 */
43 };
44
45 struct beep_dev beep; /* beep设备 */
46
47 /*
48 * @description : 打开设备
49 * @param – inode : 传递给驱动的inode
50 * @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
51 * 一般在open的时候将private_data指向设备结构体。
52 * @return : 0 成功;其他 失败
53 */
54 static int beep_open(struct inode *inode, struct file *filp)
55 {
56 filp->private_data = &beep; /* 设置私有数据 */
57 return 0;
58 }
59
60 /*
61 * @description : 向设备写数据
62 * @param - filp : 设备文件,表示打开的文件描述符
63 * @param - buf : 要写给设备写入的数据
64 * @param - cnt : 要写入的数据长度
65 * @param - offt : 相对于文件首地址的偏移
66 * @return : 写入的字节数,如果为负值,表示写入失败
67 */
68 static ssize_t beep_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt)
69 {
70 int retvalue;
71 unsigned char databuf[1];
72 unsigned char beepstat;
73 struct beep_dev *dev = filp->private_data;
74
75 retvalue = copy_from_user(databuf, buf, cnt);
76 if(retvalue beep_gpio, 0); /* 打开蜂鸣器 */
85 } else if(beepstat == BEEPOFF) {
86 gpio_set_value(dev->beep_gpio, 1); /* 关闭蜂鸣器 */
87 }
88 return 0;
89 }
90
91 /*
92 * @description : 关闭/释放设备
93 * @param - filp : 要关闭的设备文件(文件描述符)
94 * @return : 0 成功;其他 失败
95 */
96 static int beep_release(struct inode *inode, struct file *filp)
97 {
98 return 0;
99 }
100
101 /* 设备操作函数 */
102 static struct file_operations beep_fops = {
103 .owner = THIS_MODULE,
104 .open = beep_open,
105 .write = beep_write,
106 .release = beep_release,
107 };
108
109 /*
110 * @description : 驱动入口函数
111 * @param : 无
112 * @return : 无
113 */
114 static int __init beep_init(void)
115 {
116 int ret = 0;
117
118 /* 设置BEEP所使用的GPIO */
119 /* 1、获取设备节点:beep */
120 beep.nd = of_find_node_by_path("/beep");
121 if(beep.nd == NULL) {
122 printk("beep node not find!\r\n");
123 return -EINVAL;
124 } else {
125 printk("beep node find!\r\n");
126 }
127
128 /* 2、 获取设备树中的gpio属性,得到BEEP所使用的GPIO编号 */
129 beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpio", 0);
130 if(beep.beep_gpio
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?