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状态不断变化。