最近在看一本书,受益匪浅,作者是李宁,下边是编写本次蜂鸣器的全程实录:
1. 了解开发板中的蜂鸣器
1) 查看蜂鸣器buzzer在底板中的管脚信息
2) 查看蜂鸣器在总线中的信息
3) 翻看S3C6410芯片手册,查看GPF15相关信息
2. 在了解了开发板中蜂鸣器之后,编写代码对它进行控制。
由于蜂鸣器是通过PWM(脉冲宽度调制)进行开关控制的,故也称为PWM。
1) 编写pwm.c(包含Linux驱动模块的主要模型代码)
#include "pwm_fun.h"
static struct semaphore lock; /*创建信号量*/
//文件打开时,自动操作此函数,使用信号量控制其访问
static int s3c6410_pwm_open(struct inode *inode, struct file *file){if (!down_trylock(&lock)) /*使用信号量控制只能由一个进程打开*/{return 0;
}else{return -EBUSY;
}
}//文件关闭时,自动操作此函数,使用信号量控制其访问
static int s3c6410_pwm_close(struct inode *inode, struct file *file){
up(&lock); /*释放信号量*/
return 0;
}//文件中关于ioctl的操作
static long s3c6410_pwm_ioctl(struct file *filep, unsigned int cmd, unsigned longarg){switch( cmd ) {casePWM_IOCTL_START:
pwm_start();break;casePWM_IOCTL_STOP:
pwm_stop();break;default:break;
}/*----- end switch -----*/
return 0;
}//文件操作的指针
static struct file_operations dev_fops ={
.owner=THIS_MODULE,
.open=s3c6410_pwm_open,
.release=s3c6410_pwm_close,
.unlocked_ioctl=s3c6410_pwm_ioctl,
};//设备的属性
static struct miscdevice misc ={
.minor=MISC_DYNAMIC_MINOR,
.name=DEVICE_NAME,
.fops= &dev_fops,
};//驱动的入口函数
static int __init dev_init(void){intret;
init_MUTEX(&lock); /*初始化信号量*/ret= misc_register(&misc);
printk(DEVICE_NAME"initialized");returnret;
}//驱动的退出函数
static void __exit dev_exit(void){
misc_deregister(&misc);
printk(DEVICE_NAME"exited");
}
module_init(dev_init);
module_exit(dev_exit);
2) 编写pwm_fun.c(包含对蜂鸣器控制的主要代码)
#include "pwm_fun.h"
void pwm_start(void){
unsignedinttmp;
tmp=ioread32(S3C64XX_GPFCON);
tmp&= ~(0x3U<<30); /*最高两位清零,保留其他位*/tmp|= (0x2U<<30); /*最高两位设置为10,蜂鸣器发出尖叫声*/iowrite32(tmp, S3C64XX_GPFCON);
}void pwm_stop(void){
unsigned tmp;
tmp=ioread32(S3C64XX_GPFCON);
tmp&= ~(0x3U<<30); /*最高两位清零,蜂鸣器停止尖叫*/iowrite32(tmp, S3C64XX_GPFCON);
}
3) 编写pwm_fun.h(包含一些必须的头文件及宏定义信息)
#include #include#include#include#include#include#include#include#include#include#include#include#include#include
#define DEVICE_NAME "pwm_dev"
#define PWM_IOCTL_START 1
#define PWM_IOCTL_STOP 0
extern void pwm_start(void);extern void pwm_stop(void);
4) 编写Makefile文件(使编译过程自动完成)
obj-m :=pwm_driver.o
pwm_driver-objs :=pwm.o pwm_fun.o
PWD := $(shell pwd)
CROSS_COMPILE?= arm-none-linux-gnueabi-CC := $(CROSS_COMPILE)gccCFLAGS+= -static
KPATH := /media/Source/Forlinx/android2.3_kernel_v1.01all: ioctlmake -C $(KPATH) M=$(PWD) modules
ioctl: ioctl.c
$(CC) $(CFLAGS) $^ -o $@
clean:rm -rf *.o *.ko *.mod.c Module.* modules.* ioctl
5) 编写测试程序ioctl(用于对驱动程序的测试)
#include #include#include#include#include
/** === FUNCTION ======================================================================
* Name: main
* Description: 对驱动程序进行测试
* =====================================================================================*/
int main ( int argc, char *argv[] )
{int file_handler = 0;int cmd = 0;int arg = 0;if (argc < 4)
{
printf("Usage: ioctl ");returnEXIT_FAILURE;
}
cmd= atoi(argv[2]);
arg= atoi(argv[3]);
printf("dev:%s", argv[1]);
printf("cmd:%d", cmd);
printf("arg:%d", arg);
file_handler= open(argv[1], 0);if (file_handler<0)
{
printf("open %s failure.", argv[1]);
}
ioctl(file_handler, cmd, arg);
close(file_handler);return EXIT_SUCCESS;
3. 编写好源代码程序之后,交叉编译,上传至OK6410A开发板,进行测试
1) 配置好交叉编译工具链arm-none-linux-gnueabi-gcc之后,在终端输入make即可自动完成编译
2) OK6410A(Android2.3.4操作系统)通过USB线连接至PC端,通过adb上传至开发板:
adb push pwm_driver.ko /tmp/pwm_driver.ko
adb push ioctl /tmp/ioctl
3) 通过adb shell打开并控制OK6410A开发板,输入命令安装驱动模块:
adb shell
insmod /tmp/pwm_driver.ko
4) 测试蜂鸣器驱动程序
/tmp/ioctl /dev/pwm_dev 1 0 #打开蜂鸣器
/tmp/ioctl /dev/pwm_dev 0 0 #关闭蜂鸣器