目的:编写userio端口驱动,控制其中的端口输出开关量。 硬件平台:OK6410-A,ARM11 操作系统:linux2.6.36 V1.05 端口:GPC0-GPC7 学习交流qq群:234945702 1. 查看可用硬件接口针脚从哪里找可用接口的信息呢?首先看硬件手册 OK6410-A 开发板硬件手册V2.1.pdf,P5 最后一段:…… 3个‘10×2’插针扩展口。其中,一个扩展口包括1路GND、1路DA、8路AD、10路IO、1路SPI;另一个扩展口用来扩展8×8矩阵键盘;第三个扩展口可连接3个TTL电平串口和6路IO(注:3个串口中,包括1个五线串口和2个三线串口) |
此章节说明了两个信息: 1、第三个扩展口还有6路io可用(本文暂时不涉及) 2、一个扩展口包括1路GND、1路DA、8路AD、10路IO、1路SPI; 我们就从这个扩展口下手,就是用户IO口,用的当然就是这10路IO了。 接着往下看:P28 J12就是用户IO了。 显然上面标注的很清楚了,哪个针脚是什么功能。 下面我们只需要找到对应的寄存器就可以编程操作了。 本次编程需要的信息中,硬件手册的有用信息已经找到了。可是SPIMOSI0等等是什么意思呢?图中GPCX是哪来的?当然需要另外一份文档了。 2. 查看接口对应资源寄存器接下来打开s3c6410英文手册_v1.2.pdf,搜索SPIMOSI0。 运气真好,在P1-17的表“Table 1-1. 424-Pin FBGA Pin Assignments −Pin Number Order”里找到了。可是只有针脚名,接着往下搜。P1-27的表更清楚一些。 这下知道哪个针脚对应哪个寄存器了吧。 为什么针脚会对应寄存器呢?我也不知道,自己找资料学习吧,现在只要这么记着就行了。 为什么只找到8个?还有两个呢?不管了。先用着吧。 可是怎么编驱动呢? 3. 开始学习驱动首先要找到led驱动做例子,为什么呢?因为大家都是这么说的。 那led驱动在哪啊? 打开:OK6410-A LINUX2.6.36用户手册,P92: 6-2-3 开发板驱动源码路径 …… (4)LED驱动 drivers/char/s3c6410_leds.c |
打开源码文件,找到s3c6410_leds.c,复制出来,要写驱动就靠它了。 #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include . #define DEVICE_NAME "leds" sta tic long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { unsigned tmp; case 0: case 1: if (arg > 4) { return -EINVAL; } tmp = readl(S3C64XX_GPMDAT);
if(cmd==0) //close light { tmp &= (~(1< } else //open light { tmp |= (1< } writel(tmp,S3C64XX_GPMDAT); printk (DEVICE_NAME": %d %dn", arg, cmd); return 0; default: return -EINVAL; } } static struct file_operations dev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; unsigned tmp; //gpm0-3 pull up tmp = readl(S3C64XX_GPMPUD); tmp &= (~0xFF); tmp |= 0xaa; writel(tmp,S3C64XX_GPMPUD); //gpm0-3 output mode tmp =readl(S3C64XX_GPMCON); tmp &= (~0xFFFF); tmp |= 0x1111; writel(tmp,S3C64XX_GPMCON); //gpm0-3 output 0 tmp = __raw_readl(S3C64XX_GPMDAT); tmp |= 0x10; writel(tmp,S3C64XX_GPMDAT); ret = misc_register(&misc); printk (DEVICE_NAME"tinitializedn"); return ret; } static void __exit dev_exit(void) { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FORLINX Inc."); |
显然代码还是比较简单的,那么就开始改吧!不过改之前还需要先了解一下基本知识吧?代码中哪些东西是陌生的? S3C64XX_GPMPUD、S3C64XX_GPMCON、S3C64XX_GPMDAT什么意思呢 好的,再次打开s3c6410英文手册_v1.2.pdf。搜索S3C64XX_GPMPUD试试,竟然找不到?? 那再试试GPMPUD,这次搜到了 原来,就是各个寄存器啊。既然如此,那就直接看我们需要的吧,试试搜索GPCPUD,找到了。可以和gpio-bank-c.h对照看一下 接着往下看看都是怎么定义和操作的。光有地址没用啊。 哦,原来每个端口con寄存器占4位(输出嘛,每次设置为0001就ok了),dat寄存器占1位(输入输出是啥结果就是啥了),pub占2位(当然是01了,就是允许)。 好了看完了,就开始编程吧 4. 开始编写驱动还是改别人的驱动方便啊,那就开始改吧。 #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //以上的头文件,不管了 //#include //我用不到这个GPE端口 #include //我用的是GPC端口 //飞凌还是比较厚道的,我竟然找到了gpio-bank-c.h文件,里面都定义好了相关的东西,这下省了自己很多工作. #define DEVICE_NAME "wyjgpc"//修改为我的驱动设备名称,不能与已有设备重复 ////////////////////////////////////////////// //名称:s3c6410_wyjgpc_ioctl //功能:控制端口 //参数:*filp:设备文件;cmd:输出高低电平【1/0】,arg:端口【0/7,对应GPC0/GPC7】 static long s3c6410_wyjgpc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { unsigned tmp; case 0: case 1: if (arg > 7) //端口号不能超过7 { return -EINVAL; } tmp = readl(S3C64XX_GPCDAT);//先读数据
if(cmd==0) //输出0 { tmp &= (~(1< } else //输出1 { tmp |= (1< } writel(tmp,S3C64XX_GPCDAT);//写回去 //printk (DEVICE_NAME": %d %dn", arg, cmd);//这行是调试用的 return 0; default: return -EINVAL; } } static struct file_operations dev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = s3c6410_wyjgpc_ioctl,//改为上面的函数名称 }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; unsigned tmp; //先将gpc0-7 pull up,数据长度:4*8=32bit tmp = readl(S3C64XX_GPCPUD);// tmp &= (~0xFFFFFFFF); //11111111 11111111 tmp |= 0xAAAAAAAA; //10101010 10101010 writel(tmp,S3C64XX_GPCPUD); //设置gpc0-7 为输出模式,数据长度:2*8=16bit tmp =readl(S3C64XX_GPCCON);//GPCCON 2bit*8port = 16 tmp &= (~0xFFFF); //11111111 11111111 tmp |= 0x1111; //00010001 00010001 writel(tmp,S3C64XX_GPCCON); //输出数据0到gpc0-7,开始置低电平,如果愿意高电平,就输出全1,数据长度:1*8=8bit tmp = __raw_readl(S3C64XX_GPCDAT); tmp |= 0x00; //00000000 writel(tmp,S3C64XX_GPCDAT); ret = misc_register(&misc); //printk (DEVICE_NAME"tinitializedn");//调试用的 return ret; } static void __exit dev_exit(void) { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("QHDZC Inc.");//好不容易编写了驱动,一定要加入自己公司名称 | 5. 开始编译安装驱动首先当然是建立一个Makefile,怎么建?当然还是找现成的。 运气真好,从度姐那里下到一个 obj-m := wyjgpcio.o CROSS_COMPILE=arm-linux- KERNELDIR ?= /abc/linux2.6.36.2V105/linux-2.6.36.2-v1.05 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean |
Wyjgpcio.o是要输出的文件名 /abc/linux2.6.36.2V105/linux-2.6.36.2-v1.05是我的linux核心代码路径 开始编译吧: make -C /abc/linux2.6.36.2V105/linux-2.6.36.2-v1.05 M=/abc/wyjgpio modules |
/abc/wyjgpio是我的驱动代码路径 好了编译成功了,提示 make:进入目录'/abc/linux2.6.36.2V105/linux-2.6.36.2-v1.05' CC [M] /abc/wyjgpio/wyjgpcio.o /abc/wyjgpio/wyjgpcio.c: In function 's3c6410_wyjgpc_ioctl': /abc/wyjgpio/wyjgpcio.c:62: warning: format '%d' expects type 'int', but argument 2 has type 'long unsigned int' Building modules, stage 2. MODPOST 1 modules CC /abc/wyjgpio/wyjgpcio.mod.o LD [M] /abc/wyjgpio/wyjgpcio.ko make:离开目录“/abc/linux2.6.36.2V105/linux-2.6.36.2-v1.05” |
然后生成了wyjgpcio.ko文件。就是驱动了。 那就安装吧,复制驱动arm板系统中。 运行 就安装成功了。 编一个测试程序吧,端口流水操作。不解释。 #include #include #include #include #include #define DEVFILE "/dev/wyjgpc" int main(void) { int m_fd; int i = 0; m_fd = open(DEVFILE,O_RDWR ); if(m_fd < 0 ) { printf("Error opening gpcio!n"); return -1; } printf("gpciodev Opened. Type Enter key to turn on the ledn"); getchar(); getchar(); for(i = 0;i < 7; i++) { ioctl(m_fd, 1, i); printf("opening LED %d!n", i+1); sleep(2); } for(i = 0;i < 7; i++) { ioctl(m_fd, 0, i); printf("Closeing LED %d!n", i+1); sleep(2); } close(m_fd); printf("gpcio dev closed!n"); //system("lsmod"); return 0; } |
/usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-gcc -o testpgcio testled.c Ok了,一个驱动就编完了,接下来就运行测试一下吧。 只需要一个LED,一个电阻,两个杜邦线就可以了。
-----------------------------------------------------
只有分享才能大家共同进步。
0
评分
-
查看全部评分
|
|
|
|
头像被屏蔽
· 2015-1-12 11:39:50
|
|
|
|
|