文章目录
实验环境准备
实验材料:GEC6818实验箱、电脑、
实验环境:VMware下Linux系统、arm-linux-交叉编译环境,windows系统、secureCRT平台
第一步:测试三个系统是否连通
-
使用串口线、以太网线连接pc机与实验箱
-
禁用pc机的防火墙,并禁用无线网卡
-
设置pc机上以太网网卡的ip地址、子网掩码、网关(注意,不可设为主动获取,需要手动设置,因为目前只连接pc机与实验箱)
-
在secureCRT下设置实验箱Linux系统的ip地址,使其与pc机处于同一网段下(此处注意,开启实验箱时,直接等待其进入Linux系统,而不是u-boot模式,接着按CTRL+c即可进入Linux系统命令行)
-
在pc机上的vmware虚拟机的Linux系统下设置ip地址(此处注意要先设置好与pc机的网络连接模式,这里选择桥接模式桥接到外部机的一张网卡(该网卡可能是虚拟出来的)
-
前面三个ip地址一定要保证在同一网段下,例如pc机设ip为192.168.1.160、子网掩码为255.255.255.0、网关为192.168.1.1
实验箱ip地址设为192.168.1.180,虚拟机上Linux系统ip地址设为192.168.1.170 -
然后确保两两相互能ping得通
第二步:编写并编译驱动与测试程序
编写蜂鸣器驱动程序pwm.c
/*---------------------------------------
*功能描述: 蜂鸣器驱动
*创建者: 粤嵌技术部
*创建时间: 2015,01,01
---------------------------------------
*修改日志:
*修改内容:
*修改人:
*修改时间:
----------------------------------------*/
/*************************************************
*头文件
*************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <cfg_type.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <mach/platform.h>
#include <mach/devices.h>
#include <mach/soc.h>
#define DEVICE_NAME "pwm"
#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 0
#define NS_IN_1HZ (1000000000UL)
#define NS_IN_HZ (1000000000UL)
#define TO_PERCENT(duty, period) (((duty)*100)/(period))
#define TO_HZ(period) (NS_IN_HZ/(period))
#define BUZZER_PWM_ID 2
#define BUZZER_PMW_GPIO (PAD_GPIO_C + 14)
static struct pwm_device *pwm2buzzer;
static struct semaphore lock;
static void pwm_set_freq(unsigned long freq) {
int period_ns = NS_IN_1HZ / freq;
pwm_config(pwm2buzzer, period_ns / 4, period_ns);
pwm_enable(pwm2buzzer);
}
static void pwm_stop(void) {
pwm_config(pwm2buzzer, 0, NS_IN_1HZ / 100);
pwm_disable(pwm2buzzer);
}
static int gec6818_pwm_open(struct inode *inode, struct file *file) {
if (!down_trylock(&lock))
return 0;
else
return -EBUSY;
}
static int gec6818_pwm_close(struct inode *inode, struct file *file) {
up(&lock);
return 0;
}
static long gec6818_pwm_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case PWM_IOCTL_SET_FREQ:
if (arg == 0)
return -EINVAL;
pwm_set_freq(arg);
break;
case PWM_IOCTL_STOP:
pwm_stop();
default:
break;
}
return 0;
}
static struct file_operations gec6818_pwm_ops = {
.owner = THIS_MODULE,
.open = gec6818_pwm_open,
.release = gec6818_pwm_close,
.unlocked_ioctl = gec6818_pwm_ioctl,
};
static struct miscdevice gec6818_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &gec6818_pwm_ops,
};
static int __init gec6818_pwm_dev_init(void) {
int ret;
ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME);
if (ret) {
printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO);
return ret;
}
gpio_direction_output(BUZZER_PMW_GPIO, 0);
pwm2buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME);
if (IS_ERR(pwm2buzzer)) {
printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME);
return -ENODEV;
}
pwm_stop();
gpio_free(BUZZER_PMW_GPIO);
//init_MUTEX(&lock);
sema_init(&lock,1);
ret = misc_register(&gec6818_misc_dev);
printk(DEVICE_NAME "\tinitialized\n");
return ret;
}
static void __exit gec6818_pwm_dev_exit(void) {
pwm_stop();
misc_deregister(&gec6818_misc_dev);
}
module_init(gec6818_pwm_dev_init);
module_exit(gec6818_pwm_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kaoyangou");
MODULE_DESCRIPTION("S5PV6818 PWM Driver");
编写驱动程序的Makefile文件
INSTALLDIR = /home/Hello
ifneq ($(KERNELRELEASE),)
obj-m:=pwm.o
else
KERNELDIR:=/home/Hello/demo/6818GEC/kernel
CROSS_COMPILE:=/home/Hello/demo/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
PWD:=$(shell pwd)
default:
$(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.order .*.cmd *.mod.c *.symvers
endif
编写蜂鸣器测试程序buzzer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <limits.h>
#define BUZZER_IOCTL_SET_FREQ 1
#define BUZZER_IOCTL_STOP 0
void Usage(char *args)
{
printf("Usage: %s <on/off> <freq>\n",args);
return ;
}
int main(int argc , char **argv)
{
int buzzer_fd;
unsigned long freq = 0;
char *endstr, *str;
if(argc==3){
buzzer_fd = open("/dev/pwm",O_RDWR);
if(buzzer_fd<0){
perror("open device:");
exit(1);
}
str = argv[2];
errno = 0;
freq = strtol(str , &endstr, 0);
if((errno == ERANGE &&(freq == LONG_MAX ||freq ==LONG_MIN))||(errno !=0 && freq ==0)){
perror("freq :");
exit(EXIT_FAILURE);
}
if(endstr ==str){
fprintf(stderr , "Please input a digits for freq\n");
exit(EXIT_FAILURE);
}
if(!strncmp(argv[1], "on" ,2)){
ioctl(buzzer_fd, BUZZER_IOCTL_SET_FREQ , freq );
}
else if(!strncmp(argv[1], "off", 3)){
ioctl(buzzer_fd , BUZZER_IOCTL_STOP , freq);
}
else{
close(buzzer_fd);
exit(EXIT_FAILURE);
}
}
else if(argc ==2){
buzzer_fd = open("/dev/pwm",O_RDWR);
if(buzzer_fd<0){
perror("open device:");
exit(1);
}
if(!strncmp(argv[1], "off", 3)){
ioctl(buzzer_fd , BUZZER_IOCTL_STOP , freq);
}
else{
close(buzzer_fd);
exit(EXIT_FAILURE);
}
}
else {
Usage(argv[0]);
exit(EXIT_FAILURE);
}
close(buzzer_fd);
return 0;
}
编写测试程序的Makefile文件
#
# Makefile for Linux application test example.
#
#---------------------------------------------------------------
# Linux application Makefile sample
# make -- the optical output without debug info
# make clean -- clean the object file(s)
# make install -- install the execute file(s) to INSTALLDIR
#---------------------------------------------------------------
# History:
#
INSTALLDIR = /home/Hello/
#--------------------------------- /* execute file(s) */
TESTFILE = buzzer
#--------------------------------- /* object file(s) */
SRCFILE = buzzer.c
#--------------------------------- /* header file(s) */
TESTFILE_H =
CROSS = arm-none-linux-gnueabi-
CC = $(CROSS)gcc
AS = $(CROSS)as
LD = $(CROSS)ld
CFLAGS += -O2 -Wall
all: $(TESTFILE)
$(TESTFILE): $(SRCFILE) $(TESTFILE_H) Makefile
mkdir -p $(INSTALLDIR)
$(CC) $(CFLAGS) -o $@ $@.c
cp --target-dir=$(INSTALLDIR) $(TESTFILE)
clean:
rm -f $(TESTFILE)
第三步:编译生成pwm.ko与buzzer二进制执行文件
- 将驱动程序pwm.c与其对应Makefile文件放在同一目录下,然后在该目录下执行命令make,生成目标文件pwm.ko
注意:Makefile中可能制定了生成的二进制执行文件安装路径:INSTALLDIR = 某某某- 将驱动程序buzzer.c与其对应Makefile文件放在同一目录下,然后在该目录下执行命令make,生成目标文件buzzer
注意:Makefile中可能制定了生成的二进制执行文件安装路径:INSTALLDIR = 某某某
需要知道的是,以上的编译属于交叉编译,Makefile文件中已指定相应的交叉编译器
第四步:将pwm.ko文件与buzzer文件挂载到实验箱板子
- 将pwm.ko文件与buzzer文件统一放在虚拟机的nfs_share目录上
- 在secureCRT命令框使用mount命令进行挂载,命令中的ip地址是虚拟机的ip地址
mount -o nolock,tcp 192.168.0.190:/home/Hello/nfs_share /mnt
第五步:在实验箱装载驱动并使用程序进行测试
- 在secureCRT中输入命令lsmod,然后回车,在返回的消息中如果找到有led字眼的一行,则使用rmmod pwm进行卸载原有驱动,确保实验箱系统不存在蜂鸣器的驱动程序
lsmod //查看已存在驱动
rmmod pwm //卸载buzzer的驱动,注意,可能不是pwm,看系统中原有pwm驱动具体的名字
- 进入到目录 /mnt,然后插入驱动pwm.ko,因为刚才把自己制作的驱动挂载到了/mnt目录下
insmod pwm.ko
- 测试,输入命令打开蜂鸣器
./buzzer on 1000
如果没声音试试把1000改大一点
- 测试,输入命令关闭蜂鸣器
./buzzer off
如果蜂鸣器能正常打开与关闭,则蜂鸣器的驱动程序开发实验完成