当前位置:   article > 正文

Linux 蜂鸣器实验-基于正点原子IMX6ULL开发板_要用imx6ull开发板做门磁报警,首先需要连接门磁传感器和蜂鸣器到开发板上。

要用imx6ull开发板做门磁报警,首先需要连接门磁传感器和蜂鸣器到开发板上。

从软件的角度考虑,蜂鸣器驱动和 LED 灯驱动是一样的,都是控制 IO 输出高低电平。本实验来编写蜂鸣器的 Linux 驱动,也算是 pinctrl 和 gpio 子系统的巩固。


1 蜂鸣器驱动原理

I.MX6U-ALPHA 开发板上的蜂鸣器通过 SNVS_TAMPER1 引脚来控制,在 Linux 下编写蜂鸣器驱动需要做以下工作
①、在设备树中添加 SNVS_TAMPER1 引脚的 pinctrl 信息。
②、在设备树中创建蜂鸣器节点,在蜂鸣器节点中加入 GPIO 信息。
③、编写驱动程序和测试 APP,和上一篇《pinctrl 和 gpio 子系统实验-基于正点原子IMX6ULL开发板》LED 驱动程序和测试 APP 基本一样

2 硬件原理图分析



 

3 实验程序编写

3.1 修改设备树文件
1、添加 pinctrl 节点

I.MX6U-ALPHA开发板上的
BEEP使用了SNVS_TAMPER1这个PIN,打开imx6ull-alientek-emmc.dts,在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_beep”的子节点,节点 内容如下所示:

  1. pinctrl_beep: beepprp{
  2. fsl,pins = <
  3. MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0
  4. >;
  5. };
第 3 行,将 SNVS_TAMPER1 这 个 PIN 复用为 GPIO5_IO01。

 2、添加 BEEP 设备节点

在根节点“/”下创建 BEEP 节点,节点名为“ beep ”,节点内容如下:
  1. beep{
  2. compatible = "alientek,beep";
  3. pinctrl-names = "default";
  4. pinctrl-0 = <&pinctrl_beep>;
  5. beep-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
  6. status= "okay";
  7. };
4 行, pinctrl-0 属性设置蜂鸣器所使用的 PIN 对应的 pinctrl 节点。
第 5   行, beep-gpio 属性指定了蜂鸣器所使用的 GPIO
3 、检查 PIN 是否被其他外设使用
先检查 PIN SNVS_TAMPER1 这个 PIN 有没有被其他的 pinctrl 节点使用,如果有使用的话就要屏蔽掉。
再检查GPIO5_IO01 这个 GPIO 有没有被其他外设使用,如果有的话也要屏蔽掉。

编译设备树

然后使用新编译出来的 imx6ull-alientek-emmc.dtb 文件启动 Linux 系统,进入“/proc/device-tree”目录中查看“beep”节点是否存在



3.2 蜂鸣器驱动程序编写

 新建vscode工程,工程创建好以后新建 beep.c 文件,在 beep.c 里面输入如下内容:

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/fs.h>
  5. #include <linux/slab.h>
  6. #include <linux/uaccess.h>
  7. #include <linux/io.h>
  8. #include <linux/cdev.h>
  9. #include <linux/device.h>
  10. #include <linux/of.h>
  11. #include <linux/of_address.h>
  12. #include <linux/of_irq.h>
  13. #include <linux/gpio.h>
  14. #include <linux/of_gpio.h>
  15. #define BEEP_CNT 1
  16. #define BEEP_NAME "beep"
  17. #define BEEPOFF 0
  18. #define BEEPON 1
  19. /*beep 设备结构体*/
  20. struct beep_dev
  21. {
  22. dev_t devid;
  23. int major;
  24. int minor;
  25. struct cdev cdev;
  26. struct class *class;
  27. struct device *device;
  28. struct device_node *nd;
  29. int beep_gpio;
  30. };
  31. struct beep_dev beep; /*BEEP*/
  32. static int beep_open(struct inode *inode, struct file *filp)
  33. {
  34. filp->private_data = &beep;
  35. return 0;
  36. }
  37. static int beep_release(struct inode *inode, struct file *filp)
  38. {
  39. return 0;
  40. }
  41. static ssize_t beep_write(struct file *filp, const char __user *buf,
  42. size_t count, loff_t *ppos)
  43. {
  44. int ret;
  45. unsigned char databuf[1];
  46. struct beep_dev *dev = filp->private_data; //得到私有数据就是得到beep结构体
  47. ret = copy_from_user(databuf, buf, count);
  48. if (ret < 0)
  49. {
  50. return -EFAULT;
  51. }
  52. if (databuf[0] == BEEPON)
  53. {
  54. gpio_set_value(dev->beep_gpio, 0); //打开蜂鸣器,低电平
  55. }
  56. else if (databuf[0] == BEEPOFF)
  57. {
  58. gpio_set_value(dev->beep_gpio, 1); //关闭蜂鸣器,高电平
  59. }
  60. return 0;
  61. }
  62. /*操作集*/
  63. static const struct file_operations beep_fops = {
  64. .owner = THIS_MODULE,
  65. .write = beep_write,
  66. .open = beep_open,
  67. .release = beep_release,
  68. };
  69. /*驱动入口函数*/
  70. static int __init beep_init(void)
  71. {
  72. int ret = 0;
  73. /***********注册字符设备驱动 **************/
  74. /* 1、创建设备号 */
  75. beep.major = 0;
  76. if (beep.major)
  77. { /*给定主设备号*/
  78. beep.devid = MKDEV(beep.major, 0);
  79. ret = register_chrdev_region(beep.devid, BEEP_CNT, "BEEP_NAME");
  80. }
  81. else
  82. {
  83. ret = alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, "BEEP_NAME");
  84. beep.major = MAJOR(beep.devid);
  85. beep.minor = MINOR(beep.devid);
  86. }
  87. if (ret < 0)
  88. {
  89. goto fail_devid;
  90. }
  91. printk("beep major =%d, minor =%d \r\n", beep.major, beep.minor);
  92. /*2,初始化cdev*/
  93. beep.cdev.owner = THIS_MODULE;
  94. cdev_init(&beep.cdev, &beep_fops);
  95. /*3,添加cdev*/
  96. ret = cdev_add(&beep.cdev, beep.devid, BEEP_CNT);
  97. if (ret)
  98. goto fail_cdevadd;
  99. /*4,创建类*/
  100. beep.class = class_create(THIS_MODULE, BEEP_NAME);
  101. if (IS_ERR(beep.class))
  102. {
  103. ret = PTR_ERR(beep.class);
  104. goto fail_class;
  105. }
  106. /*5,创建设备*/
  107. beep.device = device_create(beep.class, NULL, beep.devid, NULL, BEEP_NAME);
  108. if (IS_ERR(beep.device))
  109. {
  110. ret = PTR_ERR(beep.device);
  111. goto fail_device;
  112. }
  113. /**************设置 BEEP 所使用的 GPIO ***************/
  114. /* 1、获取设备节点:beep */
  115. beep.nd = of_find_node_by_path("/beep");
  116. if (beep.nd == NULL)
  117. {
  118. ret = -EINVAL;
  119. goto fail_nd;
  120. }
  121. /* 2、 获取设备树中的 gpio 属性,得到 BEEP 所使用的 GPIO 编号 */
  122. beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpios", 0);
  123. if (beep.beep_gpio < 0)
  124. {
  125. ret = -EINVAL;
  126. goto fail_nd;
  127. }
  128. /*3,申请BEEP所使用的GPIO引脚*/
  129. ret = gpio_request(beep.beep_gpio, "beep-gpio");
  130. if (ret)
  131. {
  132. printk("Can't request beep gpio \r\n");
  133. goto fail_nd;
  134. }
  135. /* 4、设置 GPIO5_IO01 为输出,并且输出高电平,默认关闭 BEEP */
  136. ret = gpio_direction_output(beep.beep_gpio, 0);
  137. if (ret < 0)
  138. {
  139. goto fail_set;
  140. }
  141. /*5,输出低电平,关闭BEEP*/
  142. gpio_set_value(beep.beep_gpio, 0);
  143. return 0;
  144. fail_set:
  145. gpio_free(beep.beep_gpio);
  146. fail_nd:
  147. device_destroy(beep.class, beep.devid);
  148. fail_device:
  149. class_destroy(beep.class);
  150. fail_class:
  151. cdev_del(&beep.cdev);
  152. fail_cdevadd:
  153. unregister_chrdev_region(beep.devid, BEEP_CNT);
  154. fail_devid:
  155. return ret;
  156. }
  157. /*驱动出口函数*/
  158. static void __exit beep_exit(void)
  159. {
  160. /*关闭蜂鸣器*/
  161. gpio_set_value(beep.beep_gpio, 1);
  162. /*注销字符设备驱动*/
  163. cdev_del(&beep.cdev);
  164. unregister_chrdev_region(beep.devid, BEEP_CNT);
  165. device_destroy(beep.class, beep.devid);
  166. class_destroy(beep.class);
  167. gpio_free(beep.beep_gpio);
  168. }
  169. module_init(beep_init);
  170. module_exit(beep_exit);
  171. MODULE_LICENSE("GPL");
  172. MODULE_AUTHOR("supersmart");
3.3 编写测试 APP
 
新建名为 beepAPP.c 的文件,同以前实验ledAPP.c 内容基本一样,然后输入如下所示内容:
 
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. /*
  9. *argc:应用程序参数个数
  10. * argv[]:具体的参数内容,字符串形式
  11. * ./beepAPP <filename> <0:1> 0 关蜂鸣器,1 开蜂鸣器
  12. * ./beepAPP /dev/beep 0 关蜂鸣器
  13. * ./beepAPP /dev/beep 1 开蜂鸣器
  14. */
  15. #define BEEPOFF 0
  16. #define BEEPON 1
  17. int main(int argc, char *argv[])
  18. {
  19. int fd, retvalue;
  20. char *filename;
  21. unsigned char databuf[1];
  22. if (argc != 3)
  23. {
  24. printf("Error Usage!\r\n");
  25. return -1;
  26. }
  27. filename = argv[1];
  28. fd = open(filename, O_RDWR);
  29. if (fd < 0)
  30. {
  31. printf("file %s open failed!\r\n", filename);
  32. return -1;
  33. }
  34. databuf[0] = atoi(argv[2]); /*将字符转化为数字*/
  35. retvalue = write(fd, databuf, sizeof(databuf));
  36. if (retvalue < 0)
  37. {
  38. printf("BEEP Control Failed ! \r\n");
  39. close(fd);
  40. return -1;
  41. }
  42. close(fd);
  43. return 0;
  44. }
4 运行测试
4.1 编译驱动程序和测试 APP
        1、编译驱动程序
        
编写
Makefile 文件
  1. KERNELDIR := /home/znn/linux/IMX6ULL/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga
  2. CURRENT_PAHT := $(shell pwd)
  3. obj-m := beep.o
  4. build :kernel_modules
  5. kernel_modules:
  6.     $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PAHT) modules
  7. clean:
  8.     $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PAHT) clean

        编译驱动模块

        2、编译测试 APP

  
      使用以下命令编译生成beepAPP这个应用程序。
        
arm-linux-gnueabihf-gcc beepAPP.c -o beepAPP

4.2 运行测试

将beep.ko beepApp 这两个文件拷贝到 rootfs/lib/modules/4.1.15 目录中。
重启开发板,进入到目录 lib/modules/4.1.15 中,输入如下命令加载 beep.ko 驱动模块:
 

 

打开蜂鸣器,蜂鸣器鸣叫

关闭蜂鸣器,蜂鸣器停止鸣叫

卸载驱动

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/385594
推荐阅读
相关标签
  

闽ICP备14008679号