Linux驱动程序入门 三

LED驱动程序 第一步:看懂 PCB 原理图和 芯片datasheet 第二步:寻找对应 Pin 的寄存器地址 第三步:匹配有效的信息 下面以 iTOP4412 ARM9开发板为例 : 找出对应的 LED 引脚 通过 KP_COL0 和 VDD50_EN 匹配芯片上对应的 Pin : 从上图可知 : KP_COL0 对应在 chip 上的 Pin :GPL2_0 ; VDD50_EN 对应在 chip 上的 Pin :GPK1_1 然后通过 chip datasheet 去匹配对应的寄存器 : 从上图可知GPL2对应的个寄存器的功能。可知这些 datasheet 都是英文的,建议志同道合的伙伴们记得去提升一下自己的英语文化水平。 从匹配的信息来看,需要的是 GPL2_0 GPL_CON 寄存器 : 从上图可知 GPL2CON 的 Base Address :0x1100_0000 地址对应的偏移为:Base Address + 0x1000 重置值为 : 0x0000_0000 LED, 那么则须把 GPL2CON[0]设置成 : 0x1 = Output --->输出模式 GPL_DAT 寄存器 : Description 处要仔细读, 里面涉及了对应寄存器的用法。 GPK1_1 配信息的原理同上!!!! 综述 : GPL2_CON 地址为 : 0x11000100 GPL_DAT 地址为:0x11000104 GPK1_CON 地址为 : 0x11000060 GPK_DAT 地址为:0x11000064 驱动原理 :就是操作 open read write ioctl close 等函数,所以在 Linux驱动程序入门 二 时说过,学驱动很简单! 用户层 open read write ioctl file_operation || || || || 驱动层 led_open led_read led_write led_ioctl 用户层有一个 open 函数,则驱动层有对应的 led_open 函数,两者通过 file_operation结构关联起来!!! led 的驱动程序为 : 复制代码 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 int major; 11 12 volatile unsigned long *gpl2con = NULL; 13 volatile unsigned long *gpl2dat = NULL; 14 15 volatile unsigned long *gpk1con = NULL; 16 volatile unsigned long *gpk1dat = NULL; 17 18 static int led_open(struct inode *inode, struct file *file) 19 { 20 /*配置GPL2为输出,先清零,再配置*/ 21 *gpl2con &= ~0x03; 22 *gpl2con |= 0x01; 23 24 /*配置GPK1为输出,先清零,再配置*/ 25 *gpk1con &= ~(0x03<<4); 26 *gpk1con |= (0x01<<4); 27 return 0; 28 } 29 static int led_write(struct file *filp, 30 /const char __user *buf, size_t count, loff_t *ppos) 31 { 32 int val; 33 34 /*从用户拷贝到内核///copy_to_user()从内核拷贝到用户*/ 35 copy_from_user(&val, buf, count); 36 if(val == 1) 37 { 38 //点灯 39 *gpl2dat |= 1; 40 //点灯 41 *gpk1dat |= 0x02; 42 } 43 else 44 { 45 //灭灯 46 *gpl2dat &= ~1; 47 //点灯 48 *gpk1dat &= ~0x02; 49 } 50 return 0; 51 } 52 static struct file_operations led_fops = { 53 /*这是一个宏,推向编译环境时自动创建的__this_module*/ 54 .owner = THIS_MODULE, 55 .open = led_open, 56 .write = led_write, 57 }; 58 static int led_drv_init(void) 59 { 60 /*注册驱动程序,告诉内核这个函数来被谁调用*/ 61 register_chrdev(0, "first_drv", &first_drv_fops); 62 63 gpl2con = (volatile unsigned long *)ioremap(0x11000100, 4); 64 gpl2dat = gpl2con + 1; 65 66 gpk1con = (volatile unsigned long *)ioremap(0x11000060, 4); 67 gpk1dat = gpk1con + 1; 68 69 return 0; 70 } 71 static void led_drv_exit(void) 72 { 73 unregister_chrdev(major, "first_drv"); 74 device_unregister(firstdrv_class_dev); 75 class_destroy(firstdrv_class); 76 iounmap(gpl2con); 77 iounmap(gpk1con); 78 } 79 80 module_init(led_drv_init); 81 module_exit(led_drv_exit); 82 83 MODULE_LICENSE("Dual BSD/GPL"); 84 MODULE_AUTHOR("stormeli"); 85 MODULE_DESCRIPTION("LEDdriver"); 复制代码 对应的Makefile,即编译内核为 : 复制代码 #!/bin/bash obj-m += led_drv.o KDIR := /home/topeet/Android/Android4.0/iTop4412_Kernel_3.0 PWD ?= $(shell pwd) all: make -C $(KDIR) M=$(PWD) modules clean: rm -rf *.o 复制代码 用户层程序为 : 复制代码 #include #include #include #include #include /* *firstdrvtest on *firstdrvtest off */ int main(int argc, char **argv) { int fd; int val = 1; fd = open("/dev/led", O_RDWR); if(fd < 0) { printf("can't open!\n"); } if(argc != 2) { printf("Usage :\n"); printf("%s \n", argv[0]); return 0; } if(strcmp(argv[1], "on") == 0) { val = 1; } else { val = 0; } write(fd, &val, 4); return 0; } 复制代码 编译过程为: 一、编译驱动程序 : 使用 make 指令,得到 .ko 文件,即模块驱动文件 二、编译用户程序 : 使用 arm-none-linux-guneabi- gcc -o led_device led_device.c -static 指令编译 得到可执行文件 led_device 把编译得到的 可执行文件 led_device 和 led_drv.ko 文件拷贝进 iTOP4412 板子里(可使用的方法有 U盘拷贝, nfs协议传输,tftp协议传输) 板子上的操作: 加载内核模块的指令 : insmod xxx.ko 查看内核模块的指令:lsmod 卸载内核模块的指令:rmmod xxx 通过 insmod xxx.ko 加载内核模块, 然后 lsmod 查询,是否加载成功, 再使用 cat /proc/device 查看分配的 主设备号 跟 次设备号「此关于设备文件的创建」 「驱动匹配得有 设备文件『由用户层可知创建 /dev/led 文件』跟驱动文件」 创建设备文件的指令为 : mknod /dev/led c 主设备号 次设备号 c「代表是字符 character 设备驱动」 最后执行用户可执行文件 ./led_device 可知 led_drv 主设备号为 248, 次设备号为 0 板子 LED 点亮 标签: Linux 驱动编程https://www.cnblogs.com/dl04301201/p/10098864.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信