您当前的位置: 首页 >  嵌入式

正点原子

暂无认证

  • 2浏览

    0关注

    382博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【正点原子Linux连载】第四十六章 Linux蜂鸣器实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

正点原子 发布时间:2021-09-01 10:38:28 ,浏览量:2

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             
关注
打赏
1665308814
查看更多评论
0.1874s