ARM技术william hill官网
直播中

aiku

12年用户 212经验值
擅长:嵌入式技术
私信 关注
[资料]

【创科之龙】aiku系列教程之Ok6410A(用户IO插座GPC端口)过程

目的:编写userio端口驱动,控制其中的端口输出开关量。
硬件平台:OK6410-AARM11
操作系统:linux2.6.36 V1.05
端口:GPC0-GPC7
学习交流qq群:234945702
1. 查看可用硬件接口针脚
从哪里找可用接口的信息呢?首先看硬件手册
OK6410-A开发板硬件手册V2.1.pdf,P5最后一段:
……
3个‘10×2’插针扩展口。其中,一个扩展口包括1GND1DA8AD10IO1SPI;另一个扩展口用来扩展8×8矩阵键盘;第三个扩展口可连接3TTL电平串口和6IO(注:3个串口中,包括1个五线串口和2个三线串口)
此章节说明了两个信息:
1、第三个扩展口还有6io可用(本文暂时不涉及)
2、一个扩展口包括1GND1DA8AD10IO1SPI
我们就从这个扩展口下手,就是用户IO口,用的当然就是这10IO了。
接着往下看: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
#include
#include
#include
#include
#include .
#define DEVICE_NAME "leds"
static 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_GPMPUDS3C64XX_GPMCONS3C64XX_GPMDAT什么意思呢
好的,再次打开s3c6410英文手册_v1.2.pdf。搜索S3C64XX_GPMPUD试试,竟然找不到??
那再试试GPMPUD,这次搜到了
原来,就是各个寄存器啊。既然如此,那就直接看我们需要的吧,试试搜索GPCPUD,找到了。可以和gpio-bank-c.h对照看一下
接着往下看看都是怎么定义和操作的。光有地址没用啊。
哦,原来每个端口con寄存器占4位(输出嘛,每次设置为0001ok了),dat寄存器占1位(输入输出是啥结果就是啥了),pub2位(当然是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
#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板系统中。
运行
Insmod wyjgpcio.ko
就安装成功了。
编一个测试程序吧,端口流水操作。不解释。
#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,一个电阻,两个杜邦线就可以了。
-----------------------------------------------------
只有分享才能大家共同进步。



回帖(4)

sandy888

2015-1-12 11:39:50
提示: 作者被禁止或删除 内容自动屏蔽
举报

a1231231234

2015-8-23 10:23:24
实验好,分析也不错,谢谢了。
举报

sundy868

2015-9-8 20:11:43
分析好很好的··不错·
举报

JUSTDOIT12

2016-6-8 12:05:03
楼主图片看不了,求图片,呜呜~~
举报

更多回帖

发帖
×
20
完善资料,
赚取积分