Chinaunix首页 | 论坛 | 博客
  • 博客访问: 799700
  • 博文数量: 135
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1664
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-09 16:16
个人简介

围城

文章分类

全部博文(135)

文章存档

2019年(3)

2018年(7)

2017年(14)

2016年(15)

2015年(34)

2014年(9)

2013年(53)

我的朋友

分类: 嵌入式

2013-08-09 14:07:51

原文地址:Nios2 linux环境LED驱动开发 作者:FBI888XH

1.编写Linux设备驱动驱动程序,将该文件复制到(linux 源码目录)/drivers/(目标文件夹)中

LED驱动(nios2-linux/linux-2.6/drivers/myleds/myleds.c)

点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/types.h>
  7. #include <linux/fcntl.h>
  8. #include <asm/io.h>
  9. #include <linux/string.h>
  10. #include <asm/uaccess.h>
  11. #include <linux/cdev.h>
  12. #include <linux/slab.h>
  13. #define DEV_NAME "myleds"
  14. //#define DEV_MAJOR 242
  15. #define na_pio_LED (0x08000080)
  16. dev_t        leds_devno;
  17. struct cdev leds_cdev;
  18. static int leds_open(struct inode *inode,struct file *filp)
  19. {
  20.     return 0;
  21. }
  22. static size_t leds_write(struct file* filp,char __user *buff,size_t count,loff_t *offp)
  23. {
  24.     char led_string[7];
  25.     unsigned int led_dat;
  26.     int len=count;
  27.     if(len>6)
  28.     {
  29.         printk(KERN_ALERT "write:only use 3 bytes lower data\n");
  30.         buff+=len-6;
  31.         len=6;
  32.     }
  33.     if(copy_from_user(led_string,buff,len)!=0)
  34.     {
  35.         printk(KERN_ALERT "write:user pointer is not valid\n");
  36.         return -EFAULT;
  37.     }
  38.     led_string[len]=0;
  39.     if(sscanf(led_string,"%x",&led_dat)==0)
  40.     {
  41.         printk(KERN_ALERT "write:sscanf error\n");
  42.         return -EFAULT;
  43.     }
  44.     void *led_base;
  45.     led_base=ioremap(na_pio_LED,4);
  46.     //led_base=phys_to_virt(na_pio_LED);
  47.     printk("led_base=%x\n",led_base);
  48.     iowrite32(led_dat,led_base);
  49.     return count;
  50. }
  51. static size_t leds_read(struct file* filp,char __user *buff,size_t count,loff_t *offp)
  52. {
  53.     unsigned int led_dat;
  54.     char led_string[9];
  55.     if(*offp)
  56.         return 0;
  57.     void *led_base;
  58.     led_base=ioremap(na_pio_LED,4);
  59.     led_dat=ioread32(led_base);
  60.     if(sprintf(led_string,"%x",led_dat)==0)
  61.     {
  62.         printk(KERN_ALERT "read:sprintf error\n");
  63.         return -EFAULT;
  64.     }
  65.     if(copy_to_user(buff,led_string,strlen(led_string))!=0)
  66.     {
  67.         printk(KERN_ALERT "read:copy_to_user error\n");
  68.         return -EFAULT;
  69.     }
  70.     *offp=1;
  71.     return strlen(led_string);
  72. }
  73. static struct file_operations leds_fops=
  74. {
  75.     .owner    =THIS_MODULE,
  76.     .read    =leds_read,
  77.     .write    =leds_write,
  78.     .open    =leds_open,
  79. };
  80. static int leds_init(void)
  81. {
  82.     int ret;
  83.     printk(KERN_ALERT "call leds_init\n");
  84.     if((ret=alloc_chrdev_region(&leds_devno,0,1,DEV_NAME))!=0)
  85.     {
  86.      printk(KERN_ALERT "alloc device no error!\n");
  87.         return ret;
  88.     }
  89.     cdev_init(&leds_cdev,&leds_fops);
  90.     leds_cdev.owner=THIS_MODULE;
  91.     leds_cdev.ops=&leds_fops;    
  92.     if((ret=cdev_add(&leds_cdev,leds_devno,1))!=0)
  93.     {
  94.      printk(KERN_ALERT "cannot register leds device!\n");
  95.         return ret;
  96.     }
  97.     return 0;
  98. }
  99. static void leds_exit(void)
  100. {
  101.     printk(KERN_ALERT "call leds_exit\n");
  102.     cdev_del(&leds_cdev);
  103. }
  104. module_init(leds_init);
  105. module_exit(leds_exit);
  106. MODULE_LICENSE("GPL");
  107. MODULE_AUTHOR("xh");

2.在目标文件夹(myleds文件夹)中创建Makefile和Kconfig(菜单配置文件),内容分别如下:

#Makefile

obj-$(CONFIG_MYLEDS) += myleds.o

 

#Kconfig
menu  USER_DEVICE_DRIVERS
config MYLEDS
    tristate "myleds"
    ---help---
      This is a sample driver programme.
endmenu

Kconfig中的MYLEDS与Makefile中CONFIG_MYLEDS中的MYLEDS对应。

注意,如果Kconfig文件中的"tristate"写成"bool",则该模块只能选为Y(编译进内核)或N(不选择),不能选为M(编译为模块,可动态加载)

 

3.修改上层目录( linux内核源码目录/drivers/)中的Makefile和Kconfig文件,Makefile中加入如下语句

#makefile
obj-y += myleds/

Kconfig中加入如下语句:

#Kconfig
source "drivers/myleds/Kconfig"

 

4.编译内核

make menuconfig

进入Kernel Setting-> Device Drivers->USER_DEVICE_DRIVERS->myleds。

找到我们自己的菜单名,然后按回车或空格进入,用M键使选项前的尖括号里显示M表示该模块要动态加载,也可以按y键选择直接编辑进内核,选择完后exit退出,选择yes或no的对话框通一选yes。

可以在nios2-linux/uClinux-dist/romfs/lib/modules/ 中的若干层子目录中看到myleds/myleds.ko


5.加载测试:将生成的zImage文件下载到开发板,开发板上的嵌入式Linux启动后到上面/lib/modules

中myleds目录中使用

insmod myleds.ko

modprobe myleds

加载驱动模块

则完成对驱动程序的加载。
查看/proc/devices中myleds对应的设备号,若为254。则使用mknod命令建立对应字符设备文件:
mknod myleds c 254 0
其中myleds为设备文件名,c表示设备为字符设备,254为主设备号,0为次设备号。
生成设备文件之后,就可以直接在shell中使用命令控制led:
echo –n ff00ff > myleds
将led都设为绿色。8组3种颜色的led,控制led的24bits数据,低8位控制8个led的蓝色,低电平有效。中8位控制绿色,高8位控制红色。

但可能会出现错误:

module myleds: relocation overflow
modprobe: failed to load module myleds: invalid module format

这很有可能是因为FPGA使用的的存储器太大,导致编译时myleds模块的存储位置超出nios指令jmp的跳跃范围。因此在sopc中将使用的存储器设小即可。


二、将驱动静态编译进uClinux内核

要将一个写好的驱动加入uClinux,需要对配置文件和Makefile作一些修改,由于我们的这个驱动程序是作为一个字符型驱动程序,我们把 mydevice.c拷到(uClinux目录)/(linux 内核目录)/drivers/char目录下。并对这个目录下的Config.in和Makefile以及mem.c作一些修改。

1、 修改Config.in:

在comment 'Character devices' 这行底下加上以下一行:

bool 'support for mydevice' CONFIG_MYDEVICE y

2、 修改Makefile

#

# uClinux drivers

#

下加上以下内容:

obj-$(CONFIG_MYDEVICE) += mydevice.o

3、 修改mem.c

mem.c主要是初始化一些以虚拟设备,这些设备通常是以内存作为基础“设备”的,我们把mydevice的初始化代码加入其中:

在mem.c文件的起始位置加上以下代码:

#ifdef CONFIG_MYDEVICE

extern int mydevice_init(void);

#endif

修改mem.c的chr_dev_init函数

if (devfs_register_chrdev(MEM_MAJOR,"mem",&memory_fops))

printk("unable to get major %d for memory devs\n", MEM_MAJOR);

memory_devfs_register();

rand_initialize();

#ifdef CONFIG_MYDEVICE

mydevice_init();

#endif

#ifdef CONFIG_I2C

i2c_init_all();

#endif

4、 编译mydevice驱动

所有要作的修改就是这么简单,接下来的问题就是怎样将我们的驱动编译进内核了

(1) 配置内核

运行make menuconfig

进入Kernel/Library/Defaults Selection菜单

选上Customize Kernel Settings

退出并保存设置

在新出现的菜单中进入Character devices子菜单

选上support for mydevice

退出并保存设置

用make dep和make命令生成内核镜像和内存文件系统镜像

阅读(1088) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~