基于ARM-contexA9蜂鸣器驱动开发
上次,我们写了一个LED的驱动程序,这一节,我们只需稍微改动一下就可以实现蜂鸣器的驱动,让我们来看看吧。
还是跟之前一样,先找电路图,找到电路板上对应的引脚和相关联的寄存器。
1、看电路图
(1)蜂鸣器接口位于电路板的底板,看电路图可知道是高电平有效。
(2)相对应的找到核心板的接口。由此可知,我们的蜂鸣器是GPD0_0
接下来找数据手册,找到对应的寄存器,然后配置它就可以了。
2、查数据手册,找到相关的寄存器,并配置
(1)找到GPD0CON,地址是0x114000A0,我们需要配置GPD0CON(0)为输出状态。也就是写0x1这个值到这个寄存器。
(2)找到GPD0DAT这个寄存器,用于配置蜂鸣器的高低电平,物理地址是0x114000A4,刚好与上一个差4个字节的偏移
我们只要对这个寄存器写1和写0,那么蜂鸣器就可以叫起来了,哈哈。是不是很简单?
3、开始写驱动程序。
<span style="font-size:18px;">#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#define DEV_NAME "test-dev"
//定义蜂鸣器配置IO的地址
#define GPD0CON 0x114000A0
volatile unsigned long *bell_config = NULL ;
volatile unsigned long *bell_dat = NULL ;
int bell_open(struct inode *inode, struct file *filp)
{
printk("bell_open\n");
//清寄存器
*bell_config &= ~(0xf);
//设置io为输出
*bell_config |= (0x1);
return 0;
}
int bell_close(struct inode *inode, struct file *filp)
{
printk("bell_close\n");
//关闭蜂鸣器
*bell_dat &= ~0x1 ;
return 0;
}
long bell_ioctl(struct file *filp, unsigned int request, unsigned long arg)
{
//控制蜂鸣器的状态
switch(request)
{
case 0:
printk(KERN_EMERG"bell on\n");
*bell_dat |= 0x1 ;
break;
case 1:
printk(KERN_EMERG"bell off\n");
*bell_dat &=~0x1 ;
break;
}
return 0 ;
}
struct file_operations fops = {
.owner = THIS_MODULE ,
.open = bell_open,
.release = bell_close,
.unlocked_ioctl = bell_ioctl,
};
int major ;
int test_init(void)
{
printk("bell_init\n");
//注册设备
major = register_chrdev(major, DEV_NAME, &fops);
//映射IO
bell_config = (volatile unsigned long *)ioremap(GPD0CON , 16);
//加4个字节偏移到GP0DAT顺便映射该物理地址
bell_dat = bell_config + 1 ;
return 0;
}
void test_exit(void)
{
printk("bell_exit\n");
//解除注册
unregister_chrdev(major, DEV_NAME);
//取消映射
iounmap(bell_config);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Y.X.YANG");
MODULE_VERSION("2016.1.16");</span>
4、写测试程序
<span style="font-size:18px;">#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd;
//打开设备
fd = open("/dev/test-dev",O_RDWR) ;
if(-1 == fd)
{
printf("open fair!\n");
return -1 ;
}
while(1){
//打开蜂鸣器
ioctl(fd,1);
sleep(1);
//关闭蜂鸣器
ioctl(fd,0);
sleep(1);
}
return 0;
}</span>
5、编写makefile
<span style="font-size:18px;">obj-m += bell.o ROOTFS = /disk/A9/filesystem KERNEL = /disk/A9/linux-3.5/ all: make -C $(KERNEL) M=`pwd` modules clean: make -C $(KERNEL) M=`pwd` clean rm -rf my_bell install: make -C $(KERNEL) M=`pwd` modules_install INSTALL_MOD_PATH=$(ROOTFS) my_bell: arm-linux-gcc my_bell.c -o my_bell </span>
6、编译
7、查看设备主设备号,这里就省略图了,我们得到主设备号是250 cat /proc/devices
8、创建设备节点 mknod /dev/test-dev c 250 0
9、开始执行
由于蜂鸣器的现象没有实质的效果展示,只能通过终端打印,如有兴趣,自己去尝试,用其它板子也可以,就照着我这个方法写驱动,一定成功的!
基于ARM-contexA9蜂鸣器驱动开发的更多相关文章
- 【转】基于V4L2的视频驱动开发
编写基于V4L2视频驱动主要涉及到以下几个知识点:1> 摄像头方面的知识 要了解选用的摄像头的特性,包括访问控制方法.各种参数的配置方法.信号输出类型等.2> Camera解码器.控制器 ...
- 基于V4L2的视频驱动开发【转】
转自:http://blog.chinaunix.net/uid-10747583-id-298573.html Tags:V4L2驱动框架.API.操作流程…… 原文地址:http://www.ee ...
- 【DSP开发】【Linux开发】基于ARM+DSP进行应用开发
针对当前应用的复杂性,SOC芯片更好能能满足应用和媒体的需求,集成众多接口,用ARM做为应用处理器进行多样化的应用开发和用户界面和接口,利用DSP进行算法加速,特别是媒体的编解码算法加速,既能够保持算 ...
- 基于MTD的NAND驱动开发、K9F1G08 2K page、Yaffs2 Files System
转载:http://hi.baidu.com/cui1206/item/1d4119e376132513585dd886 基于MTD的NAND驱动(linux-2.6.22.10内核),目前已可以在该 ...
- 基于arm的嵌入式QT开发(课程设计)
一. 项目要求 配置QT5.7基于x86及arm 等两种CPU架构的调试及开发环境: 移植arm编译后的QT5.7及屏幕校准工具tslib1.4至CORTEX ARM9实验平台: 开发基于QT5.7的 ...
- ARM&Linux 下驱动开发第二节
驱动文件:qudong.c,make生成qudong.ko文件,烧录到ARM板上 #include<linux/init.h> #include<linux/module.h> ...
- 基于ARM的RealView MDK开发环境
RealView MDK可以对各种嵌入式处理器的软件开发工具.这么高端,着实很吸引我,ADS12还不知道怎么搞,居然还有这么高端的,但是还是得了解一下唉.洗这个自动配 置启动代码,集成Flash烧写模 ...
- ARM&Linux 下驱动开发第三节
后台驱动代码如下:比较昨天的,添加了读写指针位置移动操作 #include<linux/init.h> #include<linux/module.h> #include< ...
- ARM&Linux 下驱动开发第一节(小试牛刀)
#include<linux/init.h> #include<linux/module.h> static int __init hello_init(void) { pri ...
随机推荐
- Writing Sentences [1]
1) try 'there will be' instead of 'then' In homogeneity MRF, if and , there will be even if . 2) in ...
- JVM内存区域划分(JDK6/7/8中的变化)
前言 Java程序的运行是通过Java虚拟机来实现的.通过类加载器将class字节码文件加载进JVM,然后根据预定的规则执行.Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同 ...
- 2.Cocos2dx 3.2中的重力系统Box2D
1 添加Box2D相关的库 步骤1:右击项目所在的解决方案à添加->现有项目àE:\Installed\cocos2d-x-3.2\cocos2d-x-3.2\external\Box2D ...
- Hibernate实体映射文件多对多等关系简单应用技巧
认真开完以后,就能很简单的写出各种关系了 第一步,写注释: <!--xx属性,本类与Yy(类)的多对一 --> <!--xx属性,本类与Yy(类)的一对多 --> <!- ...
- Freemarker 浅析
今天分享一下一个模板语言的使用,它就是Freemarker,有点类似与前些日子做Python的Django中的模板语言,其实原理上都是相似的.所以这里就不对那些基础性的语法类的直至进行讲解了,就拿几个 ...
- Android图片setBackgroundResource和setImageResource的区别
网上对于这2个的区别大都是如下所示: setImageResource與xml中的src的屬性才是相匹配的,而setBackgroundResource是與xml中的background屬性相匹配 的 ...
- shell的输入和输出
1.echo echo [option] string -e 解析转义字符 -n 回车不换行,linux系统默认回车换行 转移字符 \c \t \f \n #!/bin/bash #echo e ...
- UNIX网络编程——非阻塞connect: Web客户程序
非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...
- Nginx+PHP-FPM的域Socket配置方法
1什么是域Socket "Unix domain socket 或者 IPCsocket 是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信.与管道相比,Unix domain ...
- Linux Debugging(七): 使用反汇编理解动态库函数调用方式GOT/PLT
本文主要讲解动态库函数的地址是如何在运行时被定位的.首先介绍一下PIC和Relocatable的动态库的区别.然后讲解一下GOT和PLT的理论知识.GOT是Global Offset Table,是保 ...