STM32MP157驱动开发——蜂鸣器设备驱动

news/2024/12/2 20:43:59/

STM32MP157驱动开发——蜂鸣器设备驱动

  • 0.相关知识
  • 一、驱动程序开发
    • 1.设备树修改
    • 2.启动程序编写
    • 3.测试程序编写
  • 二、编译及运行测试


0.相关知识

  蜂鸣器常用于计算机、打印机、报警器、电子玩具等电子产品中,常用的蜂鸣器有两种:有源蜂鸣器和无源蜂鸣器,“源”指的是震荡源,有源蜂鸣器内部带有震荡源,所以只要通电就会鸣叫。无源蜂鸣器内部没有震荡源,直接用直流电无法驱动,需要 2K-5K 的方波去驱动。
  正点原子的STM32MP157开发板上使用的是有源蜂鸣器,所以只要设置相关引脚的高低电平即可控制是否鸣叫。但蜂鸣器并不直接连在芯片的GPIO上,而是通过一个三极管去驱动,这是因为蜂鸣器工作的电流比 LED 灯大,直接将蜂鸣器接到开发板的 GPIO 上有可能会烧毁 IO。
  以下就是正电原子开发板上的蜂鸣器原理图,可以通过控制PC7引脚来控制蜂鸣器。当PC7为高电平时,三极管基极截止,蜂鸣器关闭;当PC7低电平时,基极导通,蜂鸣器鸣叫。
  所以原理上驱动蜂鸣器也是只针对GPIO进行开发,与之前的LED驱动差别不大。本节内容主要是加深对GPIO驱动开发流程的理解和记忆。
在这里插入图片描述

一、驱动程序开发

  由于与LED驱动原理相似,所以话不多说,直接进入驱动开发流程,包括设备树修改、使用gpio子系统开发驱动、实验程序编写,以及编译测试等部分。

1.设备树修改

在stm32mp157d-atk.dts文件中,仿照之前的LED节点,在根目录下添加beep节点:

beep {compatible = "amonter,beep";status = "okay";beep-gpio = <&gpioc 7 GPIO_ACTIVE_HIGH>;};

然后使用make dtbs命令编译出设备树文件,放入tftp目录启动开发板,查看/proc/device-tree目录下是否添加成功。
在这里插入图片描述

2.启动程序编写

仿照LED的gpio子系统驱动进行开发:
gpio_beep.c:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>#define BEEP_ON 1
#define BEEP_OFF 0#define BEEP_CNT 1      /*设备号个数*/
#define BEEP_NAME "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;
};struct beep_dev beepdev;/*设备操作函数:open、read、write、release*//*
* @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 = &beepdev;      /* 设置私有数据 */return 0;
}/*
* @description : 从设备读取数据
* @param - filp : 要打开的设备文件(文件描述符)
* @param - buf : 返回给用户空间的数据缓冲区
* @param - cnt : 要读取的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 读取的字节数,如果为负值,表示读取失败
*/
static ssize_t beep_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{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 == BEEP_ON){gpio_set_value(dev->beep_gpio, 0);} else if(beepstat == BEEP_OFF){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,.read           = beep_read,.write          = beep_write,.release        = beep_release,
};/*驱动入口函数*/
static int __init beep_init(void)
{int retvalue = 0;const char *str;/*获取设备树中的属性*//*1.获取设备节点*/beepdev.nd = of_find_node_by_path("/beep");if(beepdev.nd == NULL){printk("beep node not find!\r\n");return -EINVAL;} else {printk("beep node find!\r\n");}/*获取status属性值*/retvalue = of_property_read_string(beepdev.nd, "status", &str);if(retvalue < 0){printk("status read failed!\r\n");return -EINVAL;}if(strcmp(str, "okay")) {printk("beep not okay!\r\n");return -EINVAL;}/*获取compatible属性内容并匹配*/retvalue = of_property_read_string(beepdev.nd, "compatible", &str);if(retvalue < 0){printk("beep:Failed to cpmpatible property!\r\n");return -EINVAL;}if(strcmp(str, "amonter,beep")){printk("beep:compatible match faled!\r\n");return -EINVAL;}/*获取设备树中的gpio属性,得到beep的引脚编号*/beepdev.beep_gpio = of_get_named_gpio(beepdev.nd, "beep-gpio", 0);if(beepdev.beep_gpio < 0){printk("can't get beep-gpio!\r\n");return -EINVAL;}printk("beep-gpio num = %d\r\n", beepdev.beep_gpio);/*向gpio子系统申请使用GPIO*/retvalue = gpio_request(beepdev.beep_gpio, "BEEP_GPIO");if(retvalue){printk(KERN_ERR "beep_gpio:Failed to request beep gpio!\r\n");return retvalue;}/*设置GPIO为输出,默认输出高电平,关闭蜂鸣器*/retvalue = gpio_direction_output(beepdev.beep_gpio, 1);if(retvalue < 0){printk("can't set GPIO!\r\n");}/*注册字符设备驱动*//*创建设备号*/retvalue = alloc_chrdev_region(&beepdev.devid, 0, BEEP_CNT, BEEP_NAME);    /*直接使用动态分配设备号*/if(retvalue < 0){pr_err("%s couldn't alloc_chrdev_region, retvalue = %d\r\n", BEEP_NAME, retvalue);goto free_gpio;}beepdev.major = MAJOR(beepdev.devid);beepdev.minor = MINOR(beepdev.devid);printk("beepdev major = %d, minor = %d\r\n", beepdev.major, beepdev.minor);/*初始化cdev*/beepdev.cdev.owner = THIS_MODULE;cdev_init(&beepdev.cdev, &beep_fops);/*添加一个cdev*/retvalue = cdev_add(&beepdev.cdev, beepdev.devid, BEEP_CNT);if(retvalue < 0){goto del_unregister;}/*创建类*/beepdev.class = class_create(THIS_MODULE, BEEP_NAME);if(IS_ERR(beepdev.class)){goto del_cdev;}/*创建设备*/beepdev.device = device_create(beepdev.class, NULL, beepdev.devid, NULL, BEEP_NAME);if(IS_ERR(beepdev.device)){goto destroy_class;}return 0;destroy_class:class_destroy(beepdev.class);
del_cdev:cdev_del(&beepdev.cdev);
del_unregister:unregister_chrdev_region(beepdev.devid, BEEP_CNT);
free_gpio:gpio_free(beepdev.beep_gpio);return -EIO;
}/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit beep_exit(void)
{/*注销字符设备驱动*/cdev_del(&beepdev.cdev);/* 删除 cdev */unregister_chrdev_region(beepdev.devid, BEEP_CNT);device_destroy(beepdev.class, beepdev.devid);class_destroy(beepdev.class);gpio_free(beepdev.beep_gpio);        /*释放GPIO*/
}module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Amonter");
MODULE_INFO(intree, "Y");

与之前的LED驱动很相似,在这里取消了设备号申请阶段的判断,直接让系统分配设备号。

3.测试程序编写

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>#define BEEP_ON 1
#define BEEP_OFF 0int 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];/*打开LED驱动*/fd = open(filename, O_RDWR);if(fd < 0){printf("file %s open failed!\r\n");return -1;}databuf[0] = atoi(argv[2]);/*向/dev/beep文件写入数据*/retvalue = write(fd, databuf, sizeof(databuf));if(retvalue < 0){printf("beep control failed!\r\n");return -1;}retvalue = close(fd);if(retvalue < 0){printf("file %s close failed!\r\n", filename);return -1;}return 0;
}

与之前的LED测试程序也差不多,主要是对beep节点进行操作。

二、编译及运行测试

使用Makefile编译beepgpio.c驱动文件,内容可以使用之前的LED驱动的Makefile,修改一下目标文件即可。
beep_test.c测试程序使用交叉编译工具编译,将得到的gpiobeep.ko和beep_test可执行文件放到nfs的/lib/modules/5.4.31目录下,启动开发板。
在这里插入图片描述
在这里插入图片描述


http://www.ppmy.cn/news/905125.html

相关文章

STM32MP157驱动开发——Linux IIO驱动(下)

STM32MP157驱动开发——Linux IIO驱动&#xff08;下&#xff09; 0.前言一、IIO 触发缓冲区1.IIO 触发器2.申请触发器3.释放触发器4.注册触发器5.注销触发器6. IIO 缓冲区7.向驱动程序添加触发缓冲功能8.驱动编写9.触发缓冲测试10.缓冲区读取 二、测试App三、测试结果 0.前言 …

STM32MP157驱动开发——USB设备驱动

STM32MP157驱动开发——USB设备驱动 一、简介1.电气属性2.USB OTG3.STM32MP1 USB 接口简介4.Type-C 电气属性 二、USB HOST 驱动开发1.USB HOST 驱动编写2.配置 PHY 控制器3.配置usbh_ehci 三、USB HOST 测试1.鼠标键盘驱动使能2.U盘驱动 四、USB OTG驱动开发1.USB OTG 控制器节…

STM32MP157驱动开发——Linux块设备驱动

STM32MP157驱动开发——Linux块设备驱动 一、简介二、驱动开发1.使用请求队列的方式2.测试①3.不使用请求队列的方式4.测试② 参考文章&#xff1a;【正点原子】I.MX6U嵌入式Linux驱动开发——Linux 块设备驱动 一、简介 之前学习的都是关于字符设备的驱动&#xff0c;包括 pl…

Shiro反序列化漏洞(CVE-2016-4437)+docker靶场+工具利用

一、Shiro反序列化漏洞-CVE-2016-4437原理 将java对象转换为字节序列&#xff08;json/xml&#xff09;的过程叫序列化&#xff0c;将字节序列&#xff08;json/xml&#xff09;恢复为java对象的过程称为反序列化。 Shiro框架提供了“记住我”的功能&#xff0c;用户登陆成功…

习题1.25

对吗?实践出真知,运行看看。代码如下。 (defn square [x] (* x x))(defn fast-expt[b n](println "call iter" n)(cond (= 1 n) b(= 2 n) (square b)(even? n) (square (fast-expt b (/ n 2))):else (* b (fast-expt b (- n 1)))))(defn expmod [base exp m](mod…

python贴吧顶贴_贴吧回复app-贴吧回复(贴吧顶贴神器手机版)v3.2.5-西西软件下载...

贴吧回复(贴吧顶贴神器手机版)&#xff0c;贴吧回复app是一款手机贴吧自动回复软件&#xff0c;可以设置自动回复内容以及间隔时间&#xff0c;可以设置想要回复的贴吧&#xff0c;让你成为贴吧第一回复达人。贴吧回复app推荐使用专用回帖文字诸如顶帖&#xff0c;DD&#xff0…

贴一张标签让你的手机支持NFC

NFC技术很不错&#xff0c;熟悉的人也不少&#xff0c;市场上具备NFC功能的手机却只有寥寥数款。巴克莱银行最近引进了一种名为PayTag的标签&#xff0c;贴着这个标签的任何设备都能实现NFC付款。 在此之前&#xff0c;巴克莱银行推出的借记卡和信用卡已经支持近距离无线支付。…

自制贴纸图案大全图片_贴纸的制作方法

本发明涉及装饰贴纸领域&#xff0c;尤其涉及一种贴纸。 背景技术&#xff1a; 贴纸作为包装用品中的一种&#xff0c;以其方便的印刷方式和粘贴方式受到商家的喜爱。但是在粘贴过程中&#xff0c;需要将贴纸从撕离部上分离出来。为了放置贴纸和底层单独的剥离&#xff0c;现在…