您的位置:首页 > 运维架构 > Linux

①tiny4412 Linux驱动开发之蜂鸣器

2017-11-14 21:51 411 查看
本次主要是通过讲解蜂鸣器的开发来讲述驱动开发的流程,平台是三星猎户座4412.

本次使用的是板载蜂鸣器为有源蜂鸣器,在这里我们先看电路图:



从电路图中我们可以看出我们的电平信号会控制NPN型三极管的方式驱动蜂鸣器,可以看出当PWM0为高电平时,蜂鸣器可以发出声音,低电平不发声音,接下来我们找PWM0是哪个引脚,如下图:



从图中可知,PWM0是GPD0_0,下面我们去找datasheet,以确定GPD0_0的地址,如下图:



从图中可以看出,GPD0_0的地址为0x1140000 + 0x00A0 = 0x114000A0,好的,我们现在已经掌握了我们所需要的数据:蜂鸣器高电平响,低电平不响,控制它的引脚为GPD0_0,它的地址为0x114000A0.接下来,我们写驱动程序,如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>

#include <asm/io.h>
#include <asm/uaccess.h>

#define BEEP_Switch _IOW('L', 0x1234, int)

struct exynos4412_beep{
unsigned int dev_major;
struct class *cls;
struct device *dev;
int value;
};

struct exynos4412_beep *beep_dev;

volatile unsigned long *gpd0_conf;
volatile unsigned long *gpd0_data;

int beep_open(struct inode *inode, struct file *filp){
printk("-------%s--------\n", __func__);
// 硬件初始化,设置成输出模式
*gpd0_conf &= ~0xf;
*gpd0_conf |= 0x01;

return 0;
}

ssize_t beep_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos){
printk("-------%s--------\n", __func__);

return count;
}

ssize_t beep_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos){
int ret = -1;
printk("-------%s--------\n", __func__);

ret = copy_from_user(&beep_dev->value, buf, count);
if(ret > 0){
printk("copy from user failed!\n");
return -EFAULT;
}

if(beep_dev->value){
*gpd0_data |= 0x01;
}
else{
*gpd0_data &= ~0x01;
}

return count;
}

long beep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
printk("-------%s--------\n", __func__);

switch(cmd)
{
case BEEP_Switch:
if(arg){
*gpd0_data |= 0x01;
}
else{
*gpd0_data &= ~0x01;
}
break;

default:
break;
}

return 0;
}

int beep_close(struct inode *inode, struct file *filp){
printk("-------%s--------\n", __func__);

// 设置成关闭蜂鸣器
*gpd0_data &= ~0x01;

return 0;
}

struct file_operations beep_fops = {
//.owner = THIS_MODULE,
.open = beep_open,
.read = beep_read,
.write = beep_write,
.unlocked_ioctl = beep_ioctl,
.release = beep_close,
};

static __exit void beep_exit(void)
{
printk("--------%s---------\n", __func__);
device_destroy(beep_dev->cls, MKDEV(beep_dev->dev_major, 0));
class_destroy(beep_dev->cls);
unregister_chrdev(beep_dev->dev_major, "beep_drv");
kfree(beep_dev);
}

static __init int beep_init(void)
{
int ret = -1;
printk("--------%s---------\n", __func__);
// 1,实例化一个设备对象
beep_dev = kzalloc(sizeof(struct exynos4412_beep), GFP_KERNEL);
if(NULL == beep_dev){
printk("kzalloc failed!\n");
return -ENOMEM;
}

// 2,申请设备号
beep_dev->dev_major = register_chrdev(0, "beep_drv", &beep_fops);
if(beep_dev->dev_major < 0){
printk("register failed\n");
return -EINVAL;
}

// 3,创建设备类
beep_dev->cls = class_create(THIS_MODULE, "led_cls");
if(IS_ERR(beep_dev->cls)){
printk("class_register failed!\n");
ret = PTR_ERR(beep_dev);
goto err1;
}

// 4,创建设备节点
beep_dev->dev = device_create(beep_dev->cls, NULL, MKDEV(beep_dev->dev_major, 0), NULL, "beep1");
if(IS_ERR(beep_dev->dev)){
printk("device create failed!\n");
ret = PTR_ERR(beep_dev->dev);
goto err2;
}

// 5,硬件映射
gpd0_conf = ioremap(0x114000a0, 8);
gpd0_data = gpd0_conf + 1;

return 0;

err2:
class_destroy(beep_dev->cls);
err1:
unregister_chrdev(beep_dev->dev_major, "beep_drv");
return ret;
}

module_init(beep_init);
module_exit(beep_exit);

MODULE_LICENSE("GPL");


写好了驱动,接下来我们来写上层测试程序,如下:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>

#define BEEP_Switch _IOW('L', 0x1234, int)

int main(void)
{
int fd = -1,
val = -1;

fd = open("/dev/beep1", O_RDWR);
if(fd < 0){
perror("open");
exit(1);
}

while(1)
{
ioctl(fd, BEEP_Switch, 1);
sleep(1);

ioctl(fd, BEEP_Switch, 0);
sleep(1);

val = 1;
write(fd, &val, 4);
sleep(1);

val = 0;
write(fd, &val, sizeof(int));
sleep(1);
}

return 0;
}

好的,以上是测试程序,接下来还有makefile,如下:
ifeq ($(KERNELRELEASE),)
KERNELDIR = /home/george/1702/exynos/linux-3.5
PWD =$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
943f

arm-none-linux-gnueabi-gcc beep_test.c -o beep_test

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *_test *.so *.o *.ko .tmp_versions *.mod.c *.order *.symvers
else
obj-m :=beep.o
endif
其中驱动的文件名为beep.c,测试程序的文件名为beep_test.c.
编译之后,运行tiny4412之后,insmod加载beep.ko,然后运行./beep_test,你就可以听到蜂鸣器隔一秒响一秒了.哈哈.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: