Linux misc设备(二)蜂鸣器驱动
Linux misc设备驱动
Linux misc设备(一)misc驱动框架
Linux misc设备(二)蜂鸣器驱动
Linux misc设备(二)蜂鸣器驱动
文章目录
- Linux misc设备(二)蜂鸣器驱动
- 一、注册misc设备
- 二、硬件操作
- 2.1 GPIO设置
- 2.2 PWM定时器的时钟设置
- 2.3 PWM定时器设置
- 三、源码
- 四、测试
本文将介绍如何基于misc框架写一个蜂鸣器驱动程序
一、注册misc设备
首先先基于misc驱动框架注册一个misc设备
static int buzzer_open(struct inode *inode, struct file *file)
{return 0;
}static int buzzer_close(struct inode *inode, struct file *file)
{return 0;
}static int buzzer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{return 0;
}static struct file_operations buzzer_fops = {.owner = THIS_MODULE,.open = buzzer_open,.release = buzzer_close, .ioctl = buzzer_ioctl,
};static struct miscdevice buzzer_dev = {.minor = MISC_DYNAMIC_MINOR, //动态分配次设备号.name = "buzzer",.fops = &buzzer_fops, //文件操作集
};static int __init buzzer_init(void)
{/* 注册杂项设备 */misc_register(&buzzer_dev);return 0;
}static void __exit buzzer_exit(void)
{/* 注销杂项设备 */misc_deregister(&buzzer_dev);
}module_init(buzzer_init);
module_exit(buzzer_exit);
MODULE_LICENSE("GPL");
编译该驱动程序后,加载模块,就会生成/dev/buzzer
设备节点
我们要实现这个驱动程序的功能是可以通过ioctl来控制蜂鸣器的频率
那么就需要在buzzer_ioctl
里去操作硬件,下面来讲一讲如何去操控蜂鸣器
二、硬件操作
此驱动程序的芯片是三星S5PV210
,硬件平台是X210
首先打开原理图,找到蜂鸣器
从原理图中可以看到蜂鸣器接在PWMTOUT2
引脚处,表明该引脚可以用于PWM输出
只要该引脚为高电平,蜂鸣器就会响,那么通过PWM就可以控制蜂鸣器的频率
再看一看PWMTOUT2
接到芯片的哪一个引脚
该GPIO为GPD0_2
要使该GPIO输出PWM,第一步就是设置该GPIO的功能,第二步就是设置PWM相关的寄存器
我们先看第一部分,打开datasheet,查找该GPIO相关的寄存器
2.1 GPIO设置
GPD0CON
为GPD0组的GPIO的功能配置寄存器,其地址为0xE020_00A0
,其中GPD0CON[2]表示GPD0_2的配置
配置中的TOUT_2
表示PWM输出功能,那么要配置GPD0_2为PWM输出功能,可以这样做
GPD0CON |= 0x2<<4;
下面继续来介绍PWM相关的设置
从datasheet中可以得知,S5PV210有5个PWM定时器,其中定时器0、1、2、3有PWM输出引脚,定时器4没有PWM输出引脚
从我们上述的原理图可以看出,我们使用的是PWM定时器2,其对应输出引脚为GPD0_2
2.2 PWM定时器的时钟设置
这些定时器的时钟源为APB-PCLK,定时器0和1共享一个8位分频器,定时器2、3、4共享一个8位分频器,每个定时器还有二级的时钟分频器,如下图所示
也就是说,PWM的定时器的时钟源是APB-PCLK
经过1级8位分频器分频,再经过2级复用器分频得来
查看相应的寄存器
其中TCFG0
用于设置1级分频器倍数,TCFG1
用于设置2级复用器
PWM定时器的频率可以这样计算
Frequency = PCLK / (一级分频 + 1) / (二级分频)
如果要设置PWM定时器2的频率,可以这样做
TCFG0 |= prescaler<<8;
TCFG1 |= mux<<8;
2.3 PWM定时器设置
每个PWM定时器都有一个32位的向下计数器
需要设置计数周期,PWM电平触发时间,然后手动更新计数周期(使其加载到定时器的计数器中)
需要设置自动装载,在每次定时器减到0后,会自动装载计数周期
图中所示,计数周期为159(50+109),PWM电平触发时间时间为109,表示每次加载到定时器的计数器的起始值为159,当计数器减到109时,触发电平装换
查看datasheet中描述寄存器
TCNTBn为计数周期的缓存寄存器
TCMPBn为比较寄存器,描述PWM电平转换时刻
TCON控制PWM定时器,设置自动重装载,手动更新计数周期,启动定时器
设置PWM定时器的步骤
- 设置计数周期缓存寄存器TCNTBn
- 设置比较器TCMPBn
- 通过置位TCON中的手动更新TCMPBn的位,来加载TCNBn的值到PWM定时器的计数器中
- 通过置位TCON中相应的位来开启自动重装载
- 复位TCON中的手动更新TCMPBn的位
- 通过设置TCON寄存器打开定时器
总结一下:pwm的设置总共三部分,第一设置GPIO功能,第二设置PWM定时器的时钟源,第三设置PWM定时器
三、源码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <plat/gpio-cfg.h>#define TCFG0 0xE2500000
#define TCFG1 0xE2500004
#define TCON 0xE2500008
#define TCNTB2 0xE2500024
#define TCMPB2 0xE2500028#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 0static volatile unsigned int *tcfg0;
static volatile unsigned int *tcfg1;
static volatile unsigned int *tcon;
static volatile unsigned int *tcntb2;
static volatile unsigned int *tcmpb2;static void pwm_set_freq( unsigned long freq)
{unsigned long cfg;struct clk *clk_p;unsigned long pclk;/* 设置GPD0_2为PWM输出 */s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(2));clk_p = clk_get(NULL, "pclk");pclk = clk_get_rate(clk_p);/* 计算周期 */cfg = (pclk/16/16)/freq;writel(cfg, tcntb2);writel(cfg/2, tcmpb2); //占空比50%/* 设置并启动定时器 */cfg = readl(tcon);cfg &= ~(0xf<<12);cfg |= (0xb<<12); //取消死区,使能自动装载,置位手动更新,开启定时器writel(cfg, tcon);/* 复位手动更新位 */cfg &= ~(2<<12);writel(cfg, tcon);
}void pwm_stop( void )
{s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_INPUT);
}static int buzzer_open(struct inode *inode, struct file *file)
{return 0;
}static int buzzer_close(struct inode *inode, struct file *file)
{return 0;
}static int buzzer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{switch (cmd) {case PWM_IOCTL_SET_FREQ:pwm_set_freq(arg);break;case PWM_IOCTL_STOP:default:pwm_stop();break;}return 0;
}static struct file_operations buzzer_fops = {.owner = THIS_MODULE,.open = buzzer_open,.release = buzzer_close, .ioctl = buzzer_ioctl,
};static struct miscdevice buzzer_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "buzzer",.fops = &buzzer_fops,
};static int __init buzzer_init(void)
{int ret;unsigned long cfg;/* 注册杂项设备 */ret = misc_register(&buzzer_dev);/* 申请GPIO */ret = gpio_request(S5PV210_GPD0(2), "GPD0");/* 设置GPIO为输入,不让蜂鸣器响 */s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_INPUT);/* 映射地址 */tcfg0 = ioremap(TCFG0, 4);tcfg1 = ioremap(TCFG1, 4);tcon = ioremap(TCON, 4);tcntb2 = ioremap(TCNTB2, 4);tcmpb2 = ioremap(TCMPB2, 4);/* 配置定时器时钟 *//* prescaler1+1 */cfg = readl(tcfg0);cfg &= ~(0xFF<<8);cfg |= (0x0F<<8);writel(cfg, tcfg0);/* MUX1 */cfg = readl(tcfg1);cfg &= ~(0xF<<8);cfg |= (0x4<<8);writel(cfg, tcfg1);return ret;
}static void __exit buzzer_exit(void)
{/* 注销杂项设备 */misc_deregister(&buzzer_dev);/* 取消地址映射 */iounmap(tcfg0);iounmap(tcfg1);iounmap(tcon);iounmap(tcntb2);iounmap(tcmpb2);
}module_init(buzzer_init);
module_exit(buzzer_exit);
MODULE_LICENSE("GPL");
四、测试
编译驱动程序,加载模块,会生成/dev/buzzer
设备节点
测试应用程序
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>#define DEVNAME "/dev/buzzer"#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 0int main(void)
{int fd = -1;fd = open(DEVNAME, O_RDWR);if (fd < 0){perror("open");return -1;}ioctl(fd, PWM_IOCTL_SET_FREQ, 10000);sleep(1);ioctl(fd, PWM_IOCTL_STOP);sleep(1);ioctl(fd, PWM_IOCTL_SET_FREQ, 3000);sleep(1);ioctl(fd, PWM_IOCTL_STOP);sleep(1);close(fd);return 0;
}
运行测试程序,可以听到不同频率的蜂鸣器响声
Linux misc设备(二)蜂鸣器驱动相关推荐
- misc类设备与蜂鸣器驱动
以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 一.板载蜂鸣器驱动测试 1.驱动部分 (1)九鼎移植内核已经提供了蜂鸣器驱动源码,但如何查找是否已经有驱动文件? 法一 ...
- linux MISC设备驱动
系列文章 I.MX6ULL 手册查找使用方法 实战点亮LED(寄存器版) I.MX6ULL 手册查找使用方法 实战点亮LED(固件库版本) linux 字符设备驱动实战 linux LED设备驱动文件 ...
- 嵌入式linux MISC设备驱动
misc 的意思是混合.杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某 些外设无法进行分类的时候就可以使用 MISC 驱动.MISC 驱动其实就是最简单的字符设备驱 动,通常嵌套在 ...
- [转]linux 块设备驱动
转自 linux块设备IO栈 http://www.sysnote.org/2015/08/06/linux-io-stack/ linux块设备IO流程 驱动 https://www.cnblogs ...
- linux 深入理解I2C内核驱动
系列文章 I.MX6ULL 手册查找使用方法 实战点亮LED(寄存器版) I.MX6ULL 手册查找使用方法 实战点亮LED(固件库版本) linux 字符设备驱动实战 linux LED设备驱动文件 ...
- linux 块设备驱动(二)——块设备数据结构
linux 块设备驱动(二)--块设备数据结构 本文来源于: 1. http://www.cnblogs.com/dyllove98/archive/2013/07/01/3165567.html 块 ...
- linux misc device字符杂项设备驱动
杂项设备也是在嵌入式系统中用得比较多的一种设备驱动.miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同.misc设备其实就是特殊的字符设备,主设备编号采用10,并且可自 ...
- 【linux驱动分析】misc设备驱动
misc设备驱动.又称混杂设备驱动. misc设备驱动共享一个设备驱动号MISC_MAJOR.它在include\linux\major.h中定义: #define MISC_ ...
- platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架
platform框架 input. pinctrl. gpio 子系统都是 Linux 内核针对某一类设备而创建的框架, input子系统是管理输入的子系统 pinctrl 子系统重点是设置 PIN( ...
- 浅谈Linux PCI设备驱动(二)
我们在浅谈Linux PCI设备驱动(一)中(以下简称浅谈(一) )介绍了PCI的配置寄存器组,而Linux PCI初始化就是使用了这些寄存器来进行的.后面我们会举个例子来说明Linux PCI设备驱 ...
最新文章
- Linux修改/etc/profile配置错误command is not found自救方法
- call,apply,bind,new实现原理
- 深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-03-基于Python的LeNet之LR
- jmeter 取json值_JMeter中JSON数据处理
- tensorflow量化感知训练_tensorflow模型量化实例
- c++虚函数和虚函数表
- 亡命逃窜(nyoj523广搜)
- [UE4]OnComponentBeginOverlap.AddDynamic 的编译错误
- mongodb有关的研究
- DotNetNuke 7.0 发布
- 关于 数据库 my_slq的 安装及其卸载
- hbuildx微信开发者工具-微信小程序测试
- Linux期末复习总结
- D - Daydreaming Stockbroker Gym - 101550D
- Pull request 团队合作开发使用详解
- 微信语音能保存多久服务器,微信语音播放失败?可能是这几个原因导致的,看完你就懂了...
- UE4 Slate四 SlateUI如何做动画
- 下载和安装MySQL(傻瓜)教程
- 美国国土安全部仍然使用 COBOL 语言
- 手机号验证 199号码等
热门文章
- el-amap的使用
- latex 显示黑色的点命令 black dot.
- webpack-theme-color-replacer 路由跳转之后,样式丢失
- PHP+MYSQL【学生信息管理系统】(极简版)
- signature=de4fefc549f99f0b0c76a2cec8e340bf,Diagnostics based on faulty signature
- Spring @Validate 报 :No validator could be found for type 异常解決
- gitter 卸载_最佳Gitter频道:Rust
- Python列表解析式-生成器
- R语言数学表达式、特殊符号等
- 修改手机屏幕刷新率_手机屏幕刷新率真的越高越好吗?