linux 核心模組程式設計之LED驅動程式(六)
阿新 • • 發佈:2018-11-03
我使用的是tiny6410的核心板,板子如下,淘寶可以買到
為了不與板子上的任何驅動發生IO衝突,我使用CON1那一排沒用到的IO口,引腳如下
LED1 |
LED2 |
LED3 |
LED4 |
|
對應GPIO |
GPM0 |
GPM1 |
GPM2 |
GPM3 |
在板子的手冊中,電路如下
這個是板子上的4個LED的電路圖,當然我不可能用這4個led來做實驗,但是除了IO口不一樣外,電路其實是可以作為參考的,於是我手動焊了個,如下:
由電路圖也是可以看出,他是低電平有效的
關於s3c6410的的IO說明如下
myled.c檔案如下
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> /*copy_to_user,copy_from_user*/ #include <linux/io.h> /*inl(),outl()*/ #include <linux/miscdevice.h> #include <linux/pci.h> #include <asm/io.h> #define GPBCON 0x7F008820 //實體地址 #define GPBDAT 0x7F008824 //實體地址 static long S3C64XX_GPMCON; static long S3C64XX_GPMDAT; #define LED_MAJOR 240 /*主裝置號*/ int led_open(struct inode *inode,struct file *file) { unsigned tmp; S3C64XX_GPMCON = ioremap(GPBCON, 4);//實體地址轉為虛擬地址 S3C64XX_GPMDAT = ioremap(GPBDAT, 4); tmp=inl(S3C64XX_GPMCON); printk("the pre GPMCON is %x",tmp); tmp=inl(S3C64XX_GPMDAT); printk("the pre GPMDAT is %x",tmp); //這裡為什麼是0x00111111 ?? outl(0x00111111,S3C64XX_GPMCON); /*向GPMCON命令埠寫命令字,設定GPM0-5為output口*/ printk("#############open#############"); return 0; } static ssize_t led_read(struct file *file,char __user *buf,size_t count,loff_t * f_pos) { unsigned tmp=inl(S3C64XX_GPMDAT); int num=copy_to_user(buf,&tmp,count); if(num==0) printk("copy successfully"); else printk("sorry copy failly"); printk("the GPMDAT is %x.",tmp); return count; } static ssize_t led_write(struct file * file,const char __user * buf,size_t count,loff_t * f_pos) //我是通過write()來控制LED燈的,也可以通過ioctl()來控制 { char kbuf[10]; printk("###########write###########"); int num=copy_from_user(kbuf,buf,count); if(num==0) printk("copy successfully"); else printk("sorry copy failly"); printk("##the kbuf is %c",kbuf[0]); switch(kbuf[0]) { case 0://off //這裡為什麼是 0xFF ? outl(0xff,S3C64XX_GPMDAT); /*拉高GPMDAT[0:5]的引腳,使LED燈滅,因為LED是低電平有電流通過*/ break; case 1://on //這裡為什麼是 0x00 ? outl(0x00,S3C64XX_GPMDAT); /*拉低GPMDAT[0:5]的引腳,使LED燈亮*/ break; default: break; } return count; } int led_release(struct inode *inode,struct file *file) { printk("#######release##########"); 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 led dev\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("module exit\n"); } module_init(led_init); module_exit(led_exit);
makefile檔案如下
ifneq ($(KERNELRELEASE),)
obj-m := myled.o
else
KERNELDIR ?= /home/grb/grb/arm/linux-2.6.38/
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *~ *.order
endif
測試用的應用程式程式碼如下
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { printf("hello led device .\n"); int buf[10]={0,1,0,1}; printf("1\n"); int fd=open("/dev/led",2,0777); printf("2\n"); if(fd<0){ printf("can't open led device\n"); return -1; } printf("open the led device successfully.\n"); while(1) { int num=write(fd,&buf[0],1); if(num<0) printf("we set the led failly.\n"); else printf("we set the led off\n"); sleep(1); write(fd,&buf[1],1); printf("we set the led on\n"); sleep(1); } close(fd); printf("bye led device .\n"); return 0; }
將上面的檔案分別編譯成驅動檔案:myled.ko和應用程式out檔案,然後拷貝到板子上。本人開發板上跑的是linux 2.6.38的核心,這個關係不大,只要你編譯時所用的核心和板子的核心版本一致就好。
然後按照下面步驟執行
此時我們的驅動就已經安裝好了,接下來執行我們的應用程式out就可以了,執行如下
然後就可以看到我們的led在一閃一閃的了。
程式碼還有很多我也不是很明白,希望大夥多指點指點
參考網址:
http://bbs.csdn.net/topics/391038318
http://blog.csdn.net/wq897387/article/details/7387615