嵌入式Linux驱动学习笔记(一)------第一个LED驱动程序

2019-07-12 15:25发布

1、查看原理图,得到控制led的管脚GPF4/GPF5/GPF6

 

2、查看datasheet,找到LED对应的寄存器(GPFCON, GPFDAT)

目的是得到控制寄存器和数据寄存器的地址以及控制寄存器的控制模式选择 该寄存器占用16个字节,其中4个字节是保留字节    

3、开始编写LED驱动程序

1/*my01leds_driver.c*/2#include 3#include 4#include 5#include 6#include 7#include 8#include 9#include 10#include 11#include 1213static struct class *my01drv_leds_class;  14static struct class_device *my01drv_leds_dev;1516volatile unsigned long *gpfcon = NULL; 17volatile unsigned long *gpfdat = NULL;1819static int my01drv_leds_open(struct inode *inode, struct file *file)20{21 /* 配置GPF4,5,6为输入引脚 */22 *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));23 *gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));24 return 0;25}2627static ssize_t my01drv_leds_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)28{29 int val;30 int num=0;31 copy_from_user(&val,buf,count);/*从用户空间得到的参数val */32 if(val == 1) //点灯33 *gpfdat &= ~((1<<4) | (1<<5) | (1<<6));34 else //关灯35 *gpfcon |= ((1<<4)|(1<<5)|(1<<6));3637 return 0;38}3940static struct file_operations my01drv_leds_fops = {41   .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */42   .open   =   my01drv_leds_open,       43 .write = my01drv_leds_write,   44};4546int my01drv_leds_major;47static int my01_leds_init(void)48{49 /*向内核注册设备,设备名称为 my01drv_leds ,可以在内核目录下的/proc/device下看到设备名称 */50 my01drv_leds_major = register_chrdev(0, "my01drv_leds", &my01drv_leds_fops);51 52 /*注册一个设备类   */53 54 my01drv_leds_class = class_create(THIS_MODULE,"my01drvleds");55 56 /*注册一个设备号,使mdev可以在/dev/目录下自动建立设备号 /dev/JIJIJI*/57 58 my01drv_leds_dev = class_device_create(my01drv_leds_class,NULL,MKDEV(my01drv_leds_major,0),NULL,"JIJIJI");5960 /*物理地址映射*/61 62 gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);63 64 /*确定gpfdat 寄存器的地址*/65 gpfdat = gpfcon + 1;66 67 return 0;68}69static int my01_leds_exit(void)70{71 /*卸载设备*/72 unregister_chrdev(my01drv_leds_major, "my01drv_leds");73 /*卸载设备号,先卸载设备号后卸载设备类,否则在卸载模块会出现段错误*/74 class_device_create(my01drv_leds_dev);75 /*卸载设备类*/76 class_destroy(my01drv_leds_class);77 /*解除地址映射*/78 iounmap(gpfcon);79}8081/* 这两行指定驱动程序的初始化函数和卸载函数 */82module_init(my01_leds_init);83module_exit(my01_leds_exit);8485/* 描述驱动程序的一些信息,不是必须的 */86MODULE_AUTHOR("jishubao");87MODULE_VERSION("0.1.0");88MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");89MODULE_LICENSE("GPL");90

4、编写测试程序

1 #include 2 #include 3 #include 4 #include 5 int main(int argc, char **argv) 6 { 7 int val = 1; 8 int fd = open("/dev/JIJIJI",O_RDWR); 9 if(fd < 0) 10 printf("can't open "); 11 if(argc != 2) 12 { 13 printf("Usage : "); 14 printf("%s ", argv[0]); 15 return 0; 16 } 17 if (strcmp(argv[1], "on") == 0) 18 { 19 val  = 1; 20 printf("LED ON OK "); 21 } 22 else 23 { 24 val = 0; 25 printf("LED OFF OK "); 26 } 27 28 write(fd, &val, 4); 29 return 0; 30 }

5、编写Makefile

1KERN_DIR = /home/fs/linux/linux-2.6.22.623all:4 make -C $(KERN_DIR) M=`pwd` modules 56clean:7 make -C $(KERN_DIR) M=`pwd` modules clean8 rm -rf modules.order910obj-m += my01leds_driver.o

6、编译驱动文件和测试文件,拷贝到单板运行


1 fs@ubuntu:~/linux/mydrvtest/my01leds_driver$ make
1fs@ubuntu:~/linux/mydrvtest/my01leds_driver$ arm-linux-gcc -o my01leds_test my01leds_test.c
1 fs@ubuntu:~/linux/mydrvtest/my01leds_driver$ sudo cp my01leds_test my01leds_driver.ko /source/rootfs/fs_2440/
1# insmod my01leds_driver.ko
1 # ./my01leds_test on 若是卸载出现段错误,请注意是否是驱动程序中的卸载设备类与设备顺序是否有误,正确的是先注册类后注册设备,先卸载设备后卸载设备类
7、基本完成工作目的

后期实时更新链接: LED驱动练习