Ok6410开发板LED连接:
4个LED分别连接到核心板上的GPM端:
目前4个LED对应的端口:
GPM0->LED1 GPM1->LED2 GPM2->LED3 GPM3->LED4
查看s3c6410芯片手册,端口M对应的三个寄存器地址:
对应控制寄存器GPMCON设置相应的位,将端口设置为输出:
再对寄存器GPMDAT对应的位写入0/1即可控制LED的点亮与熄灭:
以上是原理部分,下面开工写代码,。
驱动代码可以在linux的源代码树里添加编写也可以另外在单独的目录里编写,第一种方法比较直观,并可以用内核的图形配置界面进行配置,但是需要修改相应的Mkaefile和Kconfig文件,这里为了尽量不破坏源代码的结构,也为了更好的移植采用第二种办法,另起炉灶,但是仍需要借助内核的源代码。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include<mach/gpio-bank-m.h> //此文件是GPM对应的寄存器地址等的定义
#include <plat/gpio-cfg.h>
#define LED_MAJOR 240
int led_open (struct inode *inode,struct file *filp)
{
unsigned tmp;
tmp =readl(S3C64XX_GPMCON);
tmp = (tmp &~(0x7U<<1))|(0x1U);
writel(tmp,S3C64XX_GPMCON);
printk("#########open######\n");
return 0;
}
ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t*f_pos)
{
printk("#########read######\n");
return count;
}
ssize_t led_write (struct file *filp, const char __user *buf, size_tcount,loff_t *f_pos)
{
char wbuf[10];
unsigned tmp;
printk("#########write######\n");
copy_from_user(wbuf,buf,count);
switch(wbuf[0])
{
case 0: //off
tmp =readl(S3C64XX_GPMDAT);
tmp |= (0x1U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 1: //on
tmp =readl(S3C64XX_GPMDAT);
tmp &= ~(0x1U);
writel(tmp, S3C64XX_GPMDAT);
break;
default :
break;
}
return count;
}
int led_release (struct inode *inode, struct file *filp)
{
printk("#########release######\n");
return 0;
}
struct file_operations led_fops ={
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
int __init led_init (void)
{ int rc;
printk ("Test leddev\n");
rc =register_chrdev(LED_MAJOR,"led",&led_fops);
if (rc <0)
{
printk ("register%s char dev error\n","led");
return -1;
}
printk("ok!\n");
return 0;
}
void __exit led_exit (void)
{
unregister_chrdev(LED_MAJOR,"led");
printk ("moduleexit\n");
return ;
}
module_init(led_init);
module_exit(led_exit);
gpio-bank-m.h文件代码树中没有该文件,众里寻他千百度啊,终于在WRT的一个补丁文件中找到了该文件:
在\home\linux-2.6\arch\arm\mach-s3c64xx\include\mach可以自己新建一个gpio-bank-m.h
编写Makefile文件 KDIR为linux内核所在目录
obj-m := driver_led.o
KDIR :=/home/linux-2.6/
all:
make -C $(KDIR) M=$(shellpwd) modules
install:
cp driver_led.ko/nfsroot/
clean:
make -C $(KDIR) M=$(shellpwd) clean
编写测试程序:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (void)
{
int fd;
char buf[10]={0,1};
fd = open("/dev/my_led",O_RDWR);
if (fd < 0)
{
printf("Open /dev/my_led file error\n");
return -1;
}
while(1)
{
write(fd,&buf[0],1);
sleep(1);
write(fd,&buf[1],1);
sleep(1);
}
close (fd);
return 0;
}
Make生成.ko文件:
arm-linux-gcc test.c -o test
将以上生成的两个文件拷贝到NFS目录,连接开发板,进行实验
模块儿文件拷贝到/lib/modules/3.2.0-rc7-00022-gd0c9386/目录下,3.2.0-是对应的版本号:
程序可以拷贝到任意目录:
创建设备文件:
mknod /dev/my_led c 240 0
加载模块
运行测试程序:
可以看到开发板上第一个LED状态不断变化。