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 的驱动程序为 :
- #include <Linux/module.h>
- #include <Linux/kernel.h>
- #include <Linux/fs.h>
- #include <Linux/init.h>
- #include <Linux/delay.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <Linux/device.h>
- int major;
- volatile unsigned long *gpl2con = NULL;
- volatile unsigned long *gpl2dat = NULL;
- volatile unsigned long *gpk1con = NULL;
- volatile unsigned long *gpk1dat = NULL;
- static int led_open(struct inode *inode, struct file *file)
- {
- /* 配置 GPL2 为输出, 先清零, 再配置 */
- *gpl2con &= ~0x03;
- *gpl2con |= 0x01;
- /* 配置 GPK1 为输出, 先清零, 再配置 */
- *gpk1con &= ~(0x03<<4);
- *gpk1con |= (0x01<<4);
- return 0;
- }
- static int led_write(struct file *filp,
- /const char __user *buf, size_t count, loff_t *ppos)
- {
- int val;
- /* 从用户拷贝到内核 ///copy_to_user() 从内核拷贝到用户 */
- copy_from_user(&val, buf, count);
- if(val == 1)
- {
- // 点灯
- *gpl2dat |= 1;
- // 点灯
- *gpk1dat |= 0x02;
- }
- else
- {
- // 灭灯
- *gpl2dat &= ~1;
- // 点灯
- *gpk1dat &= ~0x02;
- }
- return 0;
- }
- static struct file_operations led_fops = {
- /* 这是一个宏, 推向编译环境时自动创建的__this_module*/
- .owner = THIS_MODULE,
- .open = led_open,
- .write = led_write,
- };
- static int led_drv_init(void)
- {
- /* 注册驱动程序, 告诉内核这个函数来被谁调用 */
- register_chrdev(0, "first_drv", &first_drv_fops);
- gpl2con = (volatile unsigned long *)ioremap(0x11000100, 4);
- gpl2dat = gpl2con + 1;
- gpk1con = (volatile unsigned long *)ioremap(0x11000060, 4);
- gpk1dat = gpk1con + 1;
- return 0;
- }
- static void led_drv_exit(void)
- {
- unregister_chrdev(major, "first_drv");
- device_unregister(firstdrv_class_dev);
- class_destroy(firstdrv_class);
- iounmap(gpl2con);
- iounmap(gpk1con);
- }
- module_init(led_drv_init);
- module_exit(led_drv_exit);
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("stormeli");
- 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 <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <string.h>
- /*
- *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 <on|off>\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 点亮
来源: https://www.cnblogs.com/dl04301201/p/10098864.html