Linux设备驱动程序学习(基于2440的GPIO字符设备驱动)
2015-07-01 13:40
831 查看
基于2440的GPIO字符设备驱动及应用程序是针对2440型号的底板的驱动及测试应用程序,详细情况请见底板的PCB图。
S3C2440提供130 路复用的IO口线,分为如下端口进行管理:
— Port A (GPA): 23路输出口线
— Port B (GPB): 11路输入/输出口线
— Port C (GPC): 16路输入/输出口线
— Port D (GPD): 16路输入/输出口线
— Port E (GPE): 16路输入/输出口线
— Port F (GPF): 8路输入/输出口线
— Port G (GPG): 16路输入/输出口线
Port H (GPH): 11路输入/输出口线
Port J (GPJ): 13路输入/输出口线
每个端口可以通过软件来进行配置,从而定义每个管脚的功能。如果管脚没有用在复用功能,可以作为通用IO口进行操作。要对端口进行配置,要了解各个寄存器的作用,每个寄存器的作用可以参考2440的手册。
本实验主要关注的寄存器有如下三个:
端口配置寄存器(GPACON-GPJCON)
主要功能:配置IO端口的功能,如输入、输出和其他复用功能
端口数据寄存器(GPADAT-GPJDAT)
主要功能:保存IO端口的数据
端口上拉寄存器(GPAUP-GPJUP)
主要功能:控制IO端口的上拉使能,1-禁止,0-使能(本实验中禁用就可以了)
本实验的硬件连接示意图:
蜂鸣器的实验:GPE-14-----------------------蜂鸣器的控制管脚:0蜂鸣器开;1蜂鸣器关
GPIO驱动程序如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#define RING_MAJOR 224 //mknod /dev/ring c 224 0
#define rGPECON (*(volatile unsigned *)(vaddr+0x40))
#define rGPEDAT (*(volatile unsigned *)(vaddr
edc9
+0x44))
#define rGPEUP (*(volatile unsigned *)(vaddr+0x48))
#define GPECON_MASK ~(3<<28)
#define GPECON_OUTPUT (1<<28)
#define GPEUP_MASK ~(1<<14)
#define GPEUP_OUTPUT (1<<14)
#define GPEDAT_MASK ~(1<<14)
#define GPEDAT_OUTPUT (1<<14)
#define ring_on() rGPEDAT = rGPEDAT & GPEDAT_MASK
char *vaddr;
static int ring_open(struct inode *,struct file *);
static int ring_release(struct inode *,struct file *);
static int ring_ioctl(struct inode *,struct file *,unsigned int ,unsigned long);
static struct file_operations ring_ctl_fops = {
owner : THIS_MODULE,
open : ring_open,
ioctl : ring_ioctl,
release : ring_release,
};
static int ring_open(struct inode *inode,struct file *file)
{
printk("open ring device...\n");
return 0;
}
static int ring_ioctl(struct inode *inode,struct file *fiel,unsigned int command,unsigned long arg)
{
printk("ring_ioctl called,with command=%d\n",command);
if(command ==0)
{
while(arg--)
{
printk("...");
ring_on();
}
printk("\n");
}
return 0;
}
static int ring_release(struct inode *inode,struct file *file)
{
rGPEDAT = (rGPEDAT & GPEDAT_MASK) | GPEDAT_OUTPUT;
printk("device close!!!\n");
return 0;
}
static int __init ring_init(void)
{
int err = 0;
vaddr = ioremap(0x56000000,0x100);
rGPECON = (rGPECON & GPECON_MASK) | GPECON_OUTPUT;
rGPEUP = (rGPEUP & GPEUP_MASK) | GPEUP_OUTPUT;
printk("ring_init\n");
err = register_chrdev(RING_MAJOR,"ring",&ring_ctl_fops);
if(err<0)
{
printk("fail to register\n");
return -1;
}
printk("success to register\n");
return 0;
}
static int __exit ring_exit(void)
{
printk("release this device!!!\n");
unregister_chrdev(RING_MAJOR,"ring");
return 0;
}
module_init(ring_init);
module_exit(ring_exit);
MODULE_LICENSE("GPL");
Makefile文件:
#ring module example Makefile
ifneq ($(KERNELRELEASE),)
obj-m :=ring_driver.o
else
KERNELDIR ?= /home/czd/mike/linux-2.6.28.7
#KERNELDIR=/lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
endif
ring的测试程序test.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_RINGTEST "/dev/ring"
int main(int argc ,char * argv[])
{
int fd;
int val = -1;
fd = open(DEVICE_RINGTEST,O_RDONLY);
printf("fd:%x\n",fd);
if(fd<0)
{
perror("can not open device!");
exit(1);
}
while(1)
{
printf("please Select number to run program\n");
printf("1 : ring on\n");
printf("2 : ring off\n");
scanf("%d",&val);
if (val == 1)
{
ioctl(fd,0,3);
}else if(val == 2)
{
close(fd);
break;
}
}
return 0;
}
测试程序的Makefile文件:
CC = /opt/virt.arm/bin/armv4tl-caozhudong-linux-gnueabi-gcc
test:test.o
$(CC) -o $@ $^
test.o:test.c
$(CC) -c -o $@ $<
.PHONY : clean
clean:
rm -rf *.o
编译、测试驱动程序:
打开超级终端,命令:minicom
启动系统
以NFS加载网络文件系统:
vivi-->param set linux_cmd_line "noinitrd root=/dev/nfs nfsroot=192.168.0.25:/home/czd/nfs/,proto=tcp,nolock,nfsvers=3 ip=192.168.0.125:192.168.0.25:192.168.0.1:255.255.255.0:bamboo:eth0:off
console=ttySAC0"
vivi>boot
编译驱动模块
切换目录,命令:cd ../ring /ring_driver 回车
编译驱动模块,命令:make clean; make 回车(生成驱动模块ring_driver.ko)
编译测试程序
切换目录,命令:cd ../ring /test_ring 回车
编译测试程序,命令:make clean; make 回车(生成测试文件test_ring)
加载驱动模块并执行测试程序
建立节点:mknod /dev/ring c 224 0
切换目录,命令,cd ../ring /ring_driver 回车
加载驱动模块,命令,insmod ring_driver.ko回车
查看模块, 命令: lsmod 回车
切换目录,命令:cd ../ring /test_ring 回车
执行测试文件,命令:./test_ring回车
S3C2440提供130 路复用的IO口线,分为如下端口进行管理:
— Port A (GPA): 23路输出口线
— Port B (GPB): 11路输入/输出口线
— Port C (GPC): 16路输入/输出口线
— Port D (GPD): 16路输入/输出口线
— Port E (GPE): 16路输入/输出口线
— Port F (GPF): 8路输入/输出口线
— Port G (GPG): 16路输入/输出口线
Port H (GPH): 11路输入/输出口线
Port J (GPJ): 13路输入/输出口线
每个端口可以通过软件来进行配置,从而定义每个管脚的功能。如果管脚没有用在复用功能,可以作为通用IO口进行操作。要对端口进行配置,要了解各个寄存器的作用,每个寄存器的作用可以参考2440的手册。
本实验主要关注的寄存器有如下三个:
端口配置寄存器(GPACON-GPJCON)
主要功能:配置IO端口的功能,如输入、输出和其他复用功能
端口数据寄存器(GPADAT-GPJDAT)
主要功能:保存IO端口的数据
端口上拉寄存器(GPAUP-GPJUP)
主要功能:控制IO端口的上拉使能,1-禁止,0-使能(本实验中禁用就可以了)
本实验的硬件连接示意图:
蜂鸣器的实验:GPE-14-----------------------蜂鸣器的控制管脚:0蜂鸣器开;1蜂鸣器关
GPIO驱动程序如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#define RING_MAJOR 224 //mknod /dev/ring c 224 0
#define rGPECON (*(volatile unsigned *)(vaddr+0x40))
#define rGPEDAT (*(volatile unsigned *)(vaddr
edc9
+0x44))
#define rGPEUP (*(volatile unsigned *)(vaddr+0x48))
#define GPECON_MASK ~(3<<28)
#define GPECON_OUTPUT (1<<28)
#define GPEUP_MASK ~(1<<14)
#define GPEUP_OUTPUT (1<<14)
#define GPEDAT_MASK ~(1<<14)
#define GPEDAT_OUTPUT (1<<14)
#define ring_on() rGPEDAT = rGPEDAT & GPEDAT_MASK
char *vaddr;
static int ring_open(struct inode *,struct file *);
static int ring_release(struct inode *,struct file *);
static int ring_ioctl(struct inode *,struct file *,unsigned int ,unsigned long);
static struct file_operations ring_ctl_fops = {
owner : THIS_MODULE,
open : ring_open,
ioctl : ring_ioctl,
release : ring_release,
};
static int ring_open(struct inode *inode,struct file *file)
{
printk("open ring device...\n");
return 0;
}
static int ring_ioctl(struct inode *inode,struct file *fiel,unsigned int command,unsigned long arg)
{
printk("ring_ioctl called,with command=%d\n",command);
if(command ==0)
{
while(arg--)
{
printk("...");
ring_on();
}
printk("\n");
}
return 0;
}
static int ring_release(struct inode *inode,struct file *file)
{
rGPEDAT = (rGPEDAT & GPEDAT_MASK) | GPEDAT_OUTPUT;
printk("device close!!!\n");
return 0;
}
static int __init ring_init(void)
{
int err = 0;
vaddr = ioremap(0x56000000,0x100);
rGPECON = (rGPECON & GPECON_MASK) | GPECON_OUTPUT;
rGPEUP = (rGPEUP & GPEUP_MASK) | GPEUP_OUTPUT;
printk("ring_init\n");
err = register_chrdev(RING_MAJOR,"ring",&ring_ctl_fops);
if(err<0)
{
printk("fail to register\n");
return -1;
}
printk("success to register\n");
return 0;
}
static int __exit ring_exit(void)
{
printk("release this device!!!\n");
unregister_chrdev(RING_MAJOR,"ring");
return 0;
}
module_init(ring_init);
module_exit(ring_exit);
MODULE_LICENSE("GPL");
Makefile文件:
#ring module example Makefile
ifneq ($(KERNELRELEASE),)
obj-m :=ring_driver.o
else
KERNELDIR ?= /home/czd/mike/linux-2.6.28.7
#KERNELDIR=/lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
endif
ring的测试程序test.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_RINGTEST "/dev/ring"
int main(int argc ,char * argv[])
{
int fd;
int val = -1;
fd = open(DEVICE_RINGTEST,O_RDONLY);
printf("fd:%x\n",fd);
if(fd<0)
{
perror("can not open device!");
exit(1);
}
while(1)
{
printf("please Select number to run program\n");
printf("1 : ring on\n");
printf("2 : ring off\n");
scanf("%d",&val);
if (val == 1)
{
ioctl(fd,0,3);
}else if(val == 2)
{
close(fd);
break;
}
}
return 0;
}
测试程序的Makefile文件:
CC = /opt/virt.arm/bin/armv4tl-caozhudong-linux-gnueabi-gcc
test:test.o
$(CC) -o $@ $^
test.o:test.c
$(CC) -c -o $@ $<
.PHONY : clean
clean:
rm -rf *.o
编译、测试驱动程序:
打开超级终端,命令:minicom
启动系统
以NFS加载网络文件系统:
vivi-->param set linux_cmd_line "noinitrd root=/dev/nfs nfsroot=192.168.0.25:/home/czd/nfs/,proto=tcp,nolock,nfsvers=3 ip=192.168.0.125:192.168.0.25:192.168.0.1:255.255.255.0:bamboo:eth0:off
console=ttySAC0"
vivi>boot
编译驱动模块
切换目录,命令:cd ../ring /ring_driver 回车
编译驱动模块,命令:make clean; make 回车(生成驱动模块ring_driver.ko)
编译测试程序
切换目录,命令:cd ../ring /test_ring 回车
编译测试程序,命令:make clean; make 回车(生成测试文件test_ring)
加载驱动模块并执行测试程序
建立节点:mknod /dev/ring c 224 0
切换目录,命令,cd ../ring /ring_driver 回车
加载驱动模块,命令,insmod ring_driver.ko回车
查看模块, 命令: lsmod 回车
切换目录,命令:cd ../ring /test_ring 回车
执行测试文件,命令:./test_ring回车
相关文章推荐
- 解决centos安装 sda必须有一个GPT磁盘标签
- centos 修改最大打开文件数量。
- centos下安装nodejs及websocket
- linux VIM基本命令
- 嵌入式linux入门之c语言学习注意事项总结(二)
- CentOS修改默认运行级别
- ctrl+alt+l:linux 锁屏 win+l:windows锁屏
- ctrl+alt+l:linux 锁屏 win+l:windows锁屏
- linux下VMware安装出现的问题解决
- Linux LVM学习总结——创建卷组VG
- linux集群时间同步
- centos 7 使用KVM建虚拟机,但只能使用ROOT目录下的空间。
- Linux更改时间
- Linux中exec命令相关
- Linux 核心阅读工具vim+ctags+cscope+taglist
- Linux学习笔记(七)——Linux目录与档案管理
- Linux服务器维护统计连接数查看外部IP
- arm-none-linux-gnueabi交叉工具链安装 ,介绍,区别总结
- linux wget用法详解
- linux升级相关