[S5PV210 Linux字符驱动之PWM蜂鸣器驱动
在SMDK210.C中添加如下beeper_device 结构体
static struct platform_device beeper_device = {
.name = "pwm_buzzer",
.id = 1,
.dev = {
.parent
= &s3c_device_timer[1].dev, //PWM1是定时器1
.platform_data
= 0,
},
};
然后在smdkv210_devices中添加该结构体
static struct platform_device *smdkv210_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_adc,
&s3c_device_cfcon,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
&s3c_device_i2c0,
&s3c_device_i2c1,
&s3c_device_i2c2,
&s3c_device_timer[1], //add
&beeper_device, //add
}
一、硬件分析
对蜂鸣器的操作,主要是通过S5PV210的PWM来实现的,因为在OK210上,连接的是一个无源蜂鸣器,必须通过外部的驱动信号,才能控制其的“鸣叫”。
首先从OK210的底板原理图中可知,OK210开发板上的蜂鸣器连接通过一个三极管组成的放大电路连接到了核心板的XpwmTOUT[1]引脚上,如下图所示:
而XpwmTOUT[1]引脚由S5PV210用户手册,可知,该引脚位于GPD0[1]引脚上,默认为GPI,即当作通用输入端口使用,如下图所示:

但的第一功能名为TOUT_0,继续查阅,可知,该功能可作为PWM输出使用,如下所示,

所以,我们要对蜂鸣器进行操作,就是通过对XpwmTOUT[1]引脚的设置,即将其设置为TOUT_0功能,通过配置PWM的波形来实现蜂鸣器的鸣叫。
二、软件基础
如上所述,无源蜂鸣器没有自带震荡电路,必须外部提供2-5Khz左右的方波,才能驱动其发声,而要想产生方波,就会用到S5PV210的PWM模块。
S5PV210共有5个32bit的PWM定时器,其中定时器0、1、2、3有PWM功能,定时器4没有输出引脚。这些定时器都可产生中断。每个定时器可选择输入时钟为PCLK或SCLK_PWM。对PWM的操作,主要通过几个寄存器来完成,操作步骤如下:
1、设置TCFG0寄存器:配置定时器的一级分频值
2、设置TCFG1寄存器:配置定时器的二级分频值
3、设置TCNTBn寄存器:递减计数器缓冲寄存器
4、设置TCMPBn寄存器:比较缓冲寄存器
5、设置TCON寄存器:
(1)手动更新on(执行后,CPU会把TCNTBn的值加载到递减计数器中)
(2)手动更新off、自动重载、启动定时器
不过在Linux内核中,三星公司和飞凌公司已经为我们配置好了对这些PWM模块的使用,具体参见源码目录下 arch/arm/plat-s3c/的pwm.c文件,在驱动编程中,主要使用pwm_config()、pwm_enable()、pwm_disable(pwm4buzzer)这三个函数。另外,也可参见另一篇博文【S5PV210
PWM】。
三
驱动编程
有图有真相,按照如下运行后,即可听到“鸣叫”。

1
驱动程序
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/platform_device.h>
- #include <linux/fb.h>
- #include <linux/backlight.h>
- #include <linux/err.h>
- #include <linux/pwm.h>
- #include <linux/slab.h>
- #include <linux/miscdevice.h>
- #include <linux/delay.h>
- #include <mach/gpio.h>
- #include <mach/regs-gpio.h>
- #include <plat/gpio-cfg.h>
- #define DEVICE_NAME "pwm_buzzer"
- #define PWM_IOCTL_SET_FREQ 1
- #define PWM_IOCTL_STOP 0
- #define NS_IN_1HZ (1000000000UL)
- #define BUZZER_PWM_ID 0
- #define BUZZER_PMW_GPIO S5PV210_GPD0(0)
- static struct pwm_device *pwm4buzzer;
- static struct semaphore lock;
- static void pwm_set_freq(unsigned long freq) {
- int period_ns = NS_IN_1HZ / freq;
- pwm_config(pwm4buzzer, period_ns / 2, period_ns);
- pwm_enable(pwm4buzzer);
- }
- static void pwm_stop(void) {
- pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
- pwm_disable(pwm4buzzer);
- }
- static int my_pwm_open(struct inode *inode, struct file *file) {
- if (!down_trylock(&lock))
- return 0;
- else
- return -EBUSY;
- }
- static int my_pwm_close(struct inode *inode, struct file *file) {
- up(&lock);
- return 0;
- }
- static long my_pwm_ioctl(struct file *filep, unsigned int cmd,unsigned long arg)
- {
- switch (cmd) {
- case PWM_IOCTL_SET_FREQ:
- if (arg == 0)
- return -EINVAL;
- pwm_set_freq(arg);
- break;
- case PWM_IOCTL_STOP:
- default:
- pwm_stop();
- break;
- }
- return 0;
- }
- static struct file_operations my_pwm_ops = {
- .owner = THIS_MODULE,
- .open = my_pwm_open,
- .release = my_pwm_close,
- .unlocked_ioctl = my_pwm_ioctl,
- };
- static struct miscdevice my_misc_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DEVICE_NAME,
- .fops = &my_pwm_ops,
- };
- static int __init my_pwm_dev_init(void) {
- int ret;
- printk(DEVICE_NAME " my_pwm_dev_init\n");
- ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME);
- if (ret) {
- printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO);
- return ret;
- }
- gpio_set_value(BUZZER_PMW_GPIO, 0);
- s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT);
- pwm4buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME);
- if (IS_ERR(pwm4buzzer)) {
- printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME);
- return -ENODEV;
- }
- pwm_stop();
- s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_SFN(2));
- gpio_free(BUZZER_PMW_GPIO);
- init_MUTEX(&lock);
- ret = misc_register(&my_misc_dev);
- return ret;
- }
- static void __exit my_pwm_dev_exit(void) {
- printk(DEVICE_NAME " my_pwm_dev_exit\n");
- pwm_stop();
- misc_deregister(&my_misc_dev);
- }
- module_init(my_pwm_dev_init);
- module_exit(my_pwm_dev_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("gjianw217@163.com");
- MODULE_DESCRIPTION("PWM Driver");
复制代码
2 应用程序
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #define PWM_IOCTL_SET_FREQ 1
- #define PWM_IOCTL_STOP 0
- int main(int argc ,char* argv[])
- {
- int m_fd=0;//
- m_fd = open("/dev/pwm", O_RDONLY);
- int freq=1000;
- if(argc>1)
- freq=atoi(argv[1]);
- printf("%d \t\t",freq);
- ioctl(m_fd, PWM_IOCTL_STOP);
- ioctl(m_fd, PWM_IOCTL_SET_FREQ,freq);
- getchar();
- ioctl(m_fd, PWM_IOCTL_STOP);
- close(m_fd);
- return 0;
- }
复制代码
3 Makefile文件
- #pwm Makefile
- ARCH=arm
- CROSS_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
- APP_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
- #obj-m := app-drv.o
- obj-m := pwm-drv.o
- #KDIR := /path/to/kernel/linux/
- KDIR := /home/ok210/android-kernel-samsung-dev/
- PWD := $(shell pwd)
- default:
- make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
- app:pwm-app.c
- $(APP_COMPILE)gcc -o app pwm-app.c
- clean:
- $(MAKE) -C $(KDIR) M=$(PWD) clean
复制代码
[S5PV210 Linux字符驱动之PWM蜂鸣器驱动的更多相关文章
- linux驱动开发之九鼎板载蜂鸣器驱动测试【转】
本文转载自:http://whylinux.blog.51cto.com/10900429/1932491 字符设备驱动用的fileopretion结构体. 1.板载蜂鸣器的驱动测试 我手里有一个BS ...
- at91sam9x5 linux 4.1.0下使能蜂鸣器驱动
测试环境: CPU: AT91SAM9X35 Linux: Atmel提供的linux-at91-linux4sam_5.3 (Linux-4.1.0) 转载请注明: 凌云物网智科嵌入式实 ...
- Linux字符设备驱动框架
字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标.键盘.显示器.串口等等,当我们执行ls -l ...
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】
本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
- Linux 字符设备驱动及一些简单的Linux知识
一.linux系统将设备分为3类:字符设备.块设备.网络设备 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见 ...
- 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl 0. 导语 在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后 ...
- Linux字符设备驱动实现
Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...
随机推荐
- Zookeeper 入门第一篇
转载原文地址: ZooKeeper学习总结 第一篇:ZooKeeper快速入门 ZooKeeper学习总结 第二篇:ZooKeeper深入探讨 ZooKeeper学习第一期---Zookeeper简单 ...
- redis之(三)redis的数据类型
[一]字符串类型(基本数据类型) --->字符串类型是redis的最基本的数据类型 --->能存储任何形式的字符串,(用户邮箱,json化的对象,一张图片) --->一个字符串类型的 ...
- 安装jdk8-linux版
下载jdk http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装 rpm -iv ...
- PHP 扩展安装
PHP版本 >= 5.6.4 PHP扩展:OpenSSL --- 已经有啦 PHP扩展:PDO PHP扩展:Mbstring PHP扩展:Tokenizer PHP扩展:XML .安装php ...
- NHibernate框架与BLL+DAL+Model+Controller+UI 多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)
原文://http://blog.csdn.net/wb09100310/article/details/47271555 1. 概述 搭建了Spring.NET+NHibernate的一个数据查询系 ...
- ST表算法笔记
[模板]洛谷P3865 #include<cstdio> #include<string> #include<cstdlib> #include<cmath& ...
- 洛谷P1919 A*B problem 快速傅里叶变换模板 [FFT]
题目传送门 A*B problem 题目描述 给出两个n位10进制整数x和y,你需要计算x*y. 输入输出格式 输入格式: 第一行一个正整数n. 第二行描述一个位数为n的正整数x. 第三行描述一个位数 ...
- hibernate对象关系映射的配置
一对一主键关联单双向 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-m ...
- CSU - 1337 (搞笑版费马大定理 )
费马大定理:当n>2时,不定方程an+bn=cn没有正整数解.比如a3+b3=c3没有正整数解.为了活跃气氛,我们不妨来个搞笑版:把方程改成a3+b3=c3,这样就有解了,比如a=4, b=9, ...
- [ARC062F]Painting Graphs with AtCoDeer
题意:一个无向图,用$k$种不同的颜色给每条边染色,问能染出多少种不同的图,如果两张图能通过循环移位环边使得颜色相同,那么这两张图被认为是相同的 数学太差伤不起啊...补了一下Burnside定理的证 ...