9、LED驱动

avatar
作者
猴君
阅读量:0

编写步骤:

1、确定LED是哪个GPIO,通过看原理图确认

2、配置GPIO的寄存器(复用关系、方向、数据寄存器)

        找到相关寄存器的地址 例如设置复用功能的寄存器设置:       

Linux系统 可以使用 io 命令查看寄存器的值 :

io -r -4 0xfdc2000c

3、驱动代码里使用ioremap 获取寄存器的虚拟地址

例程

#include <linux/module.h> #include <linux/init.h>  #include <linux/fs.h> #include <linux/modulepram.h> #include <linux/kdev_t.h>  #include <linux/cdev.h> #include <linux/device.h> #include <linux/gpio.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h>      #define LED_GPIO_DIR_REG   0xfd000000  #define LED_GPIO_DATA_REG  0xfd00000C     struct led_device={       dev_t dev_num;      int major;     int minor;         struct cdev cdev_test;      struct class *class;     struct device *device;     char kbuf[32]; 	unsigened int  *vir_gpio_dir;     }     struct led_device  led1;         static  int led_open(struct inode *node, struct file *file) {     file->private_data=&led1;        printk("cdev_test_open \n");      return 0; }   static int cdev_test_release(struct inode *node, struct file *file) {        printk("cdev_test_release \n");      return 0;   }   static ssize_t cdev_test_read (struct file *file, char __user *buf, size_t size, loff_t *off) {     struct led_device *test_dev=(struct led_device *) file->private_data;       char kbuf[64]="123456hello";          copy_to_user(buf,test_dev ->kbuf,strlen(test_dev ->kbuf));        printk("cdev_test_read \n");     }     static ssize_t cdev_test_write (struct file *file, const char __user *buf, size_t size, loff_t *off) {      struct led_device *test_dev=(struct led_device *) file->private_data;      char kbuf[64];      copy_from_user(test_dev -> kbuf,buf,size);      printk("write buf[%s]\n",test_dev ->kbuf);      printk("cdev_test_write\n");   }     struct file_operations cdev_test_ops={       .owner=THIS_MODULE,     .open=cdev_test_open,     .release=cdev_test_release,     .read=cdev_test_read,     .write=cdev_test_write,     .ioctl=cdev_test_ioctl };     static int cdv_init(void) {     int ret;    	//动态申请 	ret=alloc_chrdev_region(&led1.dev_num,0,1,"led_num"); 	if( ret <0 ) 	{ 		printk("alloc_chrdev_regionerr %d\n",ret); 		goto err_alloc_chrdev_region; 	} 	printk("dev_num=%d \n",led1.dev_num); 	led1.major = MAJOR(led1.dev_num); 	led1.minor = MINOR(led1.dev_num); 	printk("input major=%d minor=%d \n",led1.major,led1.minor);           led1.cdev_test.owner= THIS_MODULE;     cdev_init(&led1.cdev_test,&cdev_test_ops);       ret = cdev_add(&led1.cdev_test,led1.dev_num,1);  	if( ret <0 ) 	{ 		printk("alloc_chrdev_regionerr %d\n",ret); 		goto err_cdev_add; 	}     led1.class = class_create(THIS_MODULE,"led1");	     if(IS_ERR(led1.class  ))     {         ret=PTR_ERR( led1.class );         goto err_device_create ;     }  	     led1.device = device_create(led1.class,NULL,led1.dev_num,NULL,"/dev/led1");          if(IS_ERR(led1.device ))     {         ret=PTR_ERR( led1.device );         goto err_device_create ;     } 	 	 	 	//内核中不能直接操作虚拟地址,需要将物理地址转换成虚拟地址 	led1.vir_gpio_dir= ioremap(LED_GPIO_DIR_REG,4);        	 	     printk("cdv init\n");     return 0; 	 	 err_device_create:     device_destroy(led1.class,led1.dev_num); err_class_create:     classs_destroy(led1.class); err_cdev_add:     cdev_del(&led1.cdev_test);	 err_alloc_chrdev_region :     unregister_chrdev_region(led1.dev_num,1);  	 }   static void cdv_exit(void) { 	iounmap(led1.vir_gpio_dir); 	     device_destroy(led1.class,led1.dev_num);     classs_destroy(led1.class);         cdev_del(&led1.cdev_test);	     //释放设备号     unregister_chrdev_region(led1.dev_num,1); 	     printk("cdv exit\n");     return 0; }     module_init(cdv_init); module_exit(cdv_exit);   MODULE_LICENSE("GPL"); MODULE_AUTHOR("SONG"); MODULE_VERSION("v1.0");

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!