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设备(二)蜂鸣器驱动相关推荐

  1. misc类设备与蜂鸣器驱动

    以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 一.板载蜂鸣器驱动测试 1.驱动部分 (1)九鼎移植内核已经提供了蜂鸣器驱动源码,但如何查找是否已经有驱动文件? 法一 ...

  2. linux MISC设备驱动

    系列文章 I.MX6ULL 手册查找使用方法 实战点亮LED(寄存器版) I.MX6ULL 手册查找使用方法 实战点亮LED(固件库版本) linux 字符设备驱动实战 linux LED设备驱动文件 ...

  3. 嵌入式linux MISC设备驱动

    misc 的意思是混合.杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某 些外设无法进行分类的时候就可以使用 MISC 驱动.MISC 驱动其实就是最简单的字符设备驱 动,通常嵌套在 ...

  4. [转]linux 块设备驱动

    转自 linux块设备IO栈 http://www.sysnote.org/2015/08/06/linux-io-stack/ linux块设备IO流程 驱动 https://www.cnblogs ...

  5. linux 深入理解I2C内核驱动

    系列文章 I.MX6ULL 手册查找使用方法 实战点亮LED(寄存器版) I.MX6ULL 手册查找使用方法 实战点亮LED(固件库版本) linux 字符设备驱动实战 linux LED设备驱动文件 ...

  6. linux 块设备驱动(二)——块设备数据结构

    linux 块设备驱动(二)--块设备数据结构 本文来源于: 1. http://www.cnblogs.com/dyllove98/archive/2013/07/01/3165567.html 块 ...

  7. linux misc device字符杂项设备驱动

    杂项设备也是在嵌入式系统中用得比较多的一种设备驱动.miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同.misc设备其实就是特殊的字符设备,主设备编号采用10,并且可自 ...

  8. 【linux驱动分析】misc设备驱动

        misc设备驱动.又称混杂设备驱动. misc设备驱动共享一个设备驱动号MISC_MAJOR.它在include\linux\major.h中定义:         #define MISC_ ...

  9. platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架

    platform框架 input. pinctrl. gpio 子系统都是 Linux 内核针对某一类设备而创建的框架, input子系统是管理输入的子系统 pinctrl 子系统重点是设置 PIN( ...

  10. 浅谈Linux PCI设备驱动(二)

    我们在浅谈Linux PCI设备驱动(一)中(以下简称浅谈(一) )介绍了PCI的配置寄存器组,而Linux PCI初始化就是使用了这些寄存器来进行的.后面我们会举个例子来说明Linux PCI设备驱 ...

最新文章

  1. Linux修改/etc/profile配置错误command is not found自救方法
  2. call,apply,bind,new实现原理
  3. 深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-03-基于Python的LeNet之LR
  4. jmeter 取json值_JMeter中JSON数据处理
  5. tensorflow量化感知训练_tensorflow模型量化实例
  6. c++虚函数和虚函数表
  7. 亡命逃窜(nyoj523广搜)
  8. [UE4]OnComponentBeginOverlap.AddDynamic 的编译错误
  9. mongodb有关的研究
  10. DotNetNuke 7.0 发布
  11. 关于 数据库 my_slq的 安装及其卸载
  12. hbuildx微信开发者工具-微信小程序测试
  13. Linux期末复习总结
  14. D - Daydreaming Stockbroker Gym - 101550D
  15. Pull request 团队合作开发使用详解
  16. 微信语音能保存多久服务器,微信语音播放失败?可能是这几个原因导致的,看完你就懂了...
  17. UE4 Slate四 SlateUI如何做动画
  18. 下载和安装MySQL(傻瓜)教程
  19. 美国国土安全部仍然使用 COBOL 语言
  20. 手机号验证 199号码等

热门文章

  1. el-amap的使用
  2. latex 显示黑色的点命令 black dot.
  3. webpack-theme-color-replacer 路由跳转之后,样式丢失
  4. PHP+MYSQL【学生信息管理系统】(极简版)
  5. signature=de4fefc549f99f0b0c76a2cec8e340bf,Diagnostics based on faulty signature
  6. Spring @Validate 报 :No validator could be found for type 异常解決
  7. gitter 卸载_最佳Gitter频道:Rust
  8. Python列表解析式-生成器
  9. R语言数学表达式、特殊符号等
  10. 修改手机屏幕刷新率_手机屏幕刷新率真的越高越好吗?