主题:基于ARM-contexA9蜂鸣器驱动开发
上次,我们写了一个LED的驱动程序,这一节,我们只需稍微改动一下就可以实现蜂鸣器的驱动,让我们来看看吧。
还是跟之前一样,先找电路图,找到电路板上对应的引脚和相关联的寄存器。
1、看电路图
(1)蜂鸣器接口位于电路板的底板,看电路图可知道是高电平有效。
(2)相对应的找到核心板的接口。由此可知,我们的蜂鸣器是GPD0_0
接下来找数据手册,嵌入式物联网等系统学习企鹅意义气呜呜吧久零就易,找到对应的寄存器,然后配置它就可以了。
2、查数据手册,找到相关的寄存器,并配置
(1)找到GPD0CON,地址是0x114000A0,我们需要配置GPD0CON(0)为输出状态。也就是写0x1这个值到这个寄存器。
(2)找到GPD0DAT这个寄存器,用于配置蜂鸣器的高低电平,物理地址是0x114000A4,刚好与上一个差4个字节的偏移
我们只要对这个寄存器写1和写0,那么蜂鸣器就可以叫起来了,哈哈。是不是很简单?
3、开始写驱动程序。
[plain] view plain copy print?
1.
#include <linux/init.h>
2.
3.
#include <linux/module.h>
4.
5.
#include <linux/kernel.h>
6.
7.
#include <linux/fs.h>
8.
9.
#include <linux/io.h>
10.
11.
#include <asm/uaccess.h>
12.
13.
#include <asm/irq.h>
14.
15.
#include <asm/io.h>
16.
17.
#define DEV_NAME "test-dev"
18.
19.
//定义蜂鸣器配置IO的地址
20.
21.
#define GPD0CON 0x114000A0
22.
23.
volatile unsigned long *bell_config = NULL ;
24.
25.
volatile unsigned long *bell_dat = NULL ;
26.
27.
int bell_open(struct inode *inode, struct file *filp)
28.
29.
{
30.
31.
printk("bell_open\n");
32.
33.
//清寄存器
34.
35.
*bell_config &= ~(0xf);
36.
37.
//设置io为输出
38.
39.
*bell_config |= (0x1);
40.
41.
return 0;
42.
43.
}
44.
45.
46.
47.
int bell_close(struct inode *inode, struct file *filp)
48.
49.
{
50.
51.
printk("bell_close\n");
52.
53.
//关闭蜂鸣器
54.
55.
*bell_dat &= ~0x1 ;
56.
57.
return 0;
58.
59.
}
60.
61.
62.
63.
long bell_ioctl(struct file *filp, unsigned int request, unsigned long arg)
64.
65.
{
66.
67.
//控制蜂鸣器的状态
68.
69.
switch(request)
70.
71.
{
72.
73.
case 0:
74.
75.
printk(KERN_EMERG"bell on\n");
76.
77.
*bell_dat |= 0x1 ;
78.
79.
break;
80.
81.
82.
83.
case 1:
84.
85.
printk(KERN_EMERG"bell off\n");
86.
87.
*bell_dat &=~0x1 ;
88.
89.
break;
90.
91.
}
92.
93.
return 0 ;
94.
95.
}
96.
97.
98.
99.
struct file_operations fops = {
100.
101.
.owner = THIS_MODULE ,
102.
103.
.open = bell_open,
104.
105.
.release = bell_close,
106.
107.
.unlocked_ioctl = bell_ioctl,
108.
109.
};
110.
111.
112.
113.
int major ;
114.
115.
int test_init(void)
116.
117.
{
118.
119.
printk("bell_init\n");
120.
121.
//注册设备
122.
123.
major = register_chrdev(major, DEV_NAME, &fops);
124.
125.
//映射IO
126.
127.
bell_config = (volatile unsigned long *)ioremap(GPD0CON , 16);
128.
129.
//加4个字节偏移到GP0DAT顺便映射该物理地址
130.
131.
bell_dat = bell_config + 1 ;
132.
133.
return 0;
134.
135.
}
136.
137.
138.
139.
void test_exit(void)
140.
141.
{
142.
143.
printk("bell_exit\n");
144.
145.
//解除注册
146.
147.
unregister_chrdev(major, DEV_NAME);
148.
149.
//取消映射
150.
151.
iounmap(bell_config);
152.
153.
}
154.
155.
156.
157.
module_init(test_init);
158.
159.
module_exit(test_exit);
160.
161.
162.
163.
MODULE_LICENSE("GPL");
164.
165.
MODULE_AUTHOR("Y.X.YANG");
166.
167.
MODULE_VERSION("2016.1.16");</span>
168.
4、写测试程序
[plain] view plain copy print?
1.
#include <stdio.h>
2.
3.
#include <sys/types.h>
4.
5.
#include <sys/stat.h>
6.
7.
#include <fcntl.h>
8.
9.
10.
11.
int main(int argc, char **argv)
12.
13.
{
14.
15.
int fd;
16.
17.
//打开设备
18.
19.
fd = open("/dev/test-dev",O_RDWR) ;
20.
21.
if(-1 == fd)
22.
23.
{
24.
25.
printf("open fair!\n");
26.
27.
return -1 ;
28.
29.
}
30.
31.
while(1){
32.
33.
//打开蜂鸣器
34.
35.
ioctl(fd,1);
36.
37.
sleep(1);
38.
39.
//关闭蜂鸣器
40.
41.
ioctl(fd,0);
42.
43.
sleep(1);
44.
45.
}
46.
47.
return 0;
48.
49.
}</span>
50.
5、编写makefile
[plain] view plain copy print?
1.
obj-m += bell.o
2.
3.
4.
5.
ROOTFS = /disk/A9/filesystem
6.
7.
KERNEL = /disk/A9/linux-3.5/
8.
9.
all:
10.
11.
make -C $(KERNEL) M=`pwd` modules
12.
13.
14.
15.
clean:
16.
17.
make -C $(KERNEL) M=`pwd` clean
18.
19.
rm -rf my_bell
20.
21.
22.
23.
install:
24.
25.
make -C $(KERNEL) M=`pwd` modules_install INSTALL_MOD_PATH=$(ROOTFS)
26.
27.
28.
29.
my_bell:
30.
31.
arm-linux-gcc my_bell.c -o my_bell
32.
33.
</span>
34.