我爱嵌入式系统

当前位置:首页 > 软件天地 > 企业新闻 > 详细内容
uClinux驱动编写心得(uClinux2.4+S3C44B0X)
发布时间:2009/10/28  阅读次数:1713  字体大小: 【】 【】【
uClinux驱动编写心得(uClinux2.4+S3C44B0X)
  下面的内容绝大部分不是我写的,我是根据网上前辈高手的教程一步一步来做的。但是,在编译的过程中发现资料还是有点错误和关键点的遗漏。昨晚加上今天一整天,回忆编译的过程,稍微有点理解编译的方法了。晚上改了半个小时,搞定,驱动能用了,虽然仅仅是点个led灯,但是修正编译时的错误就像侦探破案一样,成功后心情真爽啊!我把我修正后的文章重新发出来,让更多人能看到。ps今天又搜索了一整天,还是没找到更多驱动相关的资料,希望大家能够提供下。
  前期准备:
  既然要编写uClinux驱动,就要在操作系统和硬件之间打交道,我用的板子是经典的S3C44B0X,驱动教程基于uClinux2.4版本,2.6版本不太一样,还没有找到资料。
1)  需要掌握针对uClinux的打补丁、裁剪、编译全过程,自己可以编译一个完整的uClinux系统下载到开发板的flash中并正常工作。这方面的教程网上更多,我就下了数个版本。
2)  需要熟悉S3C44B0X的硬件资源,本例子很简单,要想驱动其他东西就复杂咯。

一共要编写2个C文件,一个是led.c,属于驱动文件,另外一个是ledtest.c属于用户程序,还有一个led.h头文件。
  /////////////////////led.h文件内容///////////////////////////
  /****************************************Copyright  (c)**************************************************
  **                            FREE
  **--------------File  Info-------------------------------
  **  File  Name:  led.h
  **  Last  modified  Date:    2008-6-3
  **  Last  Version:  1.0
  **  Descriptions:  User  Configurable  File
  **----------------------------------------------------
  **  Created  By:  
  **  Created  date:      2008-6-3
  **  Version:  1.0
  **  Descriptions:  First  version
  **-------------------------------------------------
  **  Modified  by:MAMAJINCO
  **  Modified  date:2006-9-9
  **  Version:1.0
  **  Descriptions:在此忠心感谢ZLG的模版  我的高质量编程意识起源于此
  *****************************************************/
  //防止重复包含此文件而设置的宏
  #ifndef  __CONFIG_H
  #define  __CONFIG_H 
  //包含必要的头文件
  #include  <linux/config.h>
  #include  <linux/module.h>  //模块必须包含的头文件
  #include  <linux/kernel.h>              /*  printk()函数,用于向内核输出信息  */
  #include  <linux/fs.h>                      /*  很重要  其中包含了如file_opration等结构  此结构用于文件层接口  */
  #include  <linux/errno.h>                /*  错误代码*/
  #include  <asm/uaccess.h>
  #include  <linux/types.h>
  #include  <linux/mm.h>
  #include  <asm/arch/s3c44b0x.h> 
  /********************************/
  /*          应用程序配置                          */
  /********************************/
  //以下根据需要改动
  //定义主设备号  设备名称   
  #define  LED_MAJOR_NR  231  //231~239  240~255都可以  
  #define  DEVICE_NAME  "led"                              /*  name  for  messaging  */  
  #define  SET_LED_OFF  0
  #define  SET_LED_ON    1 
  #endif
  /************************End  Of  File
  *********************************************************/


  
  ////////////////////led.c文件内容////////////////////////////////////
  /*************Copyright  (c)**************************
  **                            FREE
  **--------------File  Info-----------------------------------------
  **  File  Name:  led.c
  **  Last  modified  Date:    
  **  Last  Version:  1.0
  **  Descriptions:  User  Configurable  File
  **----------------------------------------------------
  **  Created  By:  ZLG  CHENMINGJI
  **  Created  date:      2006-9-9
  **  Version:  1.0
  **  Descriptions:  First  version
  **--------------------------------------------------------
  **  Modified  by:MAMAJINCO
  **  Modified  date:
  **  Version:1.0
  **  Descriptions:在此忠心感谢ZLG的模版  我的高质量编程意识起源于此
  ***********************************************************/
  #include  "led.h"//包含驱动头文件
 
  /************************************************************
                              function  announce
  ******************************************************/
  //以下是关键函数的声明
  static  int  led_open(struct  inode  *inode,  struct  file  *filp);    
  //打开设备时用的  linux把设备当作文件管理  设备最好在用的时候再打开  尽量不要提前
  static  int  led_release(struct  inode  *inode,  struct  file  *filp);  
  static  int  led_ioctl(struct  inode  *inode,  struct  file  *filp,  unsigned  int  cmd,
                                  unsigned  long  param);    
  //控制函数  这里用于控制LED亮与灭
  int    led_init(void);//注册时用的  注意  模块注册的越早越好
  void  led_cleanup(void);//卸载时用的
  
  /*************************************************************
  **                                    "全局和静态变量在这里定义"                  
  **                global  variables  and  static  variables  define  here 
  /****************************************************************/  
  static  struct  file_operations  LED_fops  =                /*  前面基础部分提到的重要结构体了*/
  {
          owner:            THIS_MODULE,  
  #if  0/*注意:#if  0-#endif里的代码是不编译的,但这里为了驱动模板讲解上的完整性仍然加上了*/
          llseek:          gpio_llseek,
          read:              gpio_read,
          write:            gpio_write,
  #endif
          ioctl:            led_ioctl,//控制函数
          open:              led_open,  //打开函数,打开文件时做初始化的
          release:        led_release,//释放函数,关闭时调用
  };
                                   
  /**************************************************************
  **  Function  name:  led_open
  **  Descriptions:    open  device
  **  Input:inode:      information  of  device
  **              filp:        pointer  of  file
  **  Output  0:            OK
  **                other:    not  OK
  **  Created  by:        Chenmingji
  **  Created  Date:    2006-9-9
  **-------------------------------------------------------------
  **  Modified  by:mamajinco
  **  Modified  Date:  2006-9-9
  **--------------------------------------------------------------
  **************************************************************/
  
  static  int  led_open(struct  inode  *inode,  struct  file  *filp)
  {
    /*初始化放在OPEN里*/ 
    (*(volatile  unsigned  *)S3C44B0X_PCONC)  &=  0xffffffc0;
    (*(volatile  unsigned  *)S3C44B0X_PCONC)  |=  0xffffffd5;  /*GPIO  C口0~2  设置为输出*/  
    (*(volatile  unsigned  *)S3C44B0X_PUPC)  &=  0xffffffc0;/*GPIO  C口0~2  设置为上拉*/  
            MOD_INC_USE_COUNT;
            return  0;                    
  }  
     
  /*********************************************************
  **  Function  name:  led_release
  **  Descriptions:    release  device
  **  Input:inode:      information  of  device
  **              filp:        pointer  of  file
  **  Output  0:            OK
  **                other:    not  OK
  **  Created  by:        Chenmingji
  **  Created  Date:    2006-9-9
  **-----------------------------------------------------
  **  Modified  by:  mamajinco
  **  Modified  Date:  2006-9-9
  **--------------------------------------------------------
  ****************************************************/ 
  static  int  led_release(struct  inode  *inode,  struct  file  *filp)  
  {
          MOD_DEC_USE_COUNT;
          return(0);  
  }  
  
  /****************************************************
  **  Function  name:  led_ioctl
  **  Descriptions:    IO  control  function
  **  Input:inode:      information  of  device
  **              filp:        pointer  of  file
  **              cmd:          command
  **              arg:          additive  parameter
  **  Output  0:            OK
  **                other:    not  OK
  **  Created  by:        Chenmingji
  **  Created  Date:    2006-9-9
  **-------------------------------------------------------
  **  Modified  by:  mamajinco
  **  Modified  Date:  2006-9-9
  **----------------------------------------------------------
  ***********************************************************/  
  static  int  led_ioctl(struct  inode  *inode,  struct  file  *filp,  
                                                unsigned  int  cmd,  unsigned  long  arg)
  {
          if(  arg  >  2  )//判断IO是否属于0-2
    return  -1;
  
          switch(cmd)
          {
                  case  0://把ARG传来的IO口编号转换成寄存器数据,把相应IO口置低
                    (*(volatile  unsigned  *)S3C44B0X_PDATC)  |=  0x1  <<  arg;
  
                            break;
  
                  case  1://把ARG传来的IO口编号转换成寄存器数据,把相应IO口置高
      (*(volatile  unsigned  *)S3C44B0X_PDATC)  &=  0x0  <<  arg;
                            break;
  
                  default:
      return  -1;
      break;
          }
          return  0;
  }
  
  /**************************************************
  **  Function  name:  led_init
  **  Descriptions:    init  driver
  **  Input:none
  **  Output  0:            OK
  **                other:    not  OK
  **  Created  by:        Chenmingji
  **  Created  Date:    2006-9-9
  **------------------------------------------------
  **  Modified  by:  mamajinco
  **  Modified  Date:  2006-9-9
  **-----------------------------------------------------
  *************************************************/  
  int  led_init(void)
  {
          int    result;  
          result  =  register_chrdev(231,"led",    &LED_fops);  
  /*关键语句  用于注册  
  **  注意!这是传统的注册方法  在2.4以上的linux版本中  加入了devfs设备文件系统  使注册更容易  但为了与大部分资料相**同  大家看的方便    这里仍然使用老方法*/
          if  (result  <  0)  //用于异常检测
          {
                  printk(KERN_ERR  DEVICE_NAME  ":  Unable  to  get  major  %d\n",  LED_MAJOR_NR  );  //printk用于向内核输出信息
                  return(result);  
          }  
          printk(KERN_INFO  DEVICE_NAME  ":  init  OK\n");      
    return(0);
  }
  
    
  /*************************************************************
  **  Function  name:  led_cleanup
  **  Descriptions:    exit  driver
  **  Input:none
  **  Output  none
  **  Created  by:        Chenmingji
  **  Created  Date:    2006-9-9
  **--------------------------------------------------------
  **  Modified  by:  mamajinco
  **  Modified  Date:  2006-9-9
  **-----------------------------------------------------
  **************************************************/  
  void  led_cleanup(void)
  {
          unregister_chrdev(231,  "led");  //与register_chrdev配对使用  用于清楚驱动
  }
  
  /***********************************************************
  **                                                        End  Of  File
  ****************************************************/





 
  ///////////////////最后是ledtest.c文件内容///////////////////////
  
  /*********************Copyright  (c)**************************
  **                            FREE
  **--------------File  Info----------------------------
  **  File  Name:  led.c
  **  Last  modified  Date:    2006-9-9
  **  Last  Version:  1.0
  **  Descriptions:  User  Configurable  File
  **-------------------------------------------------------
  **  Created  By:  ZLG  CHENMINGJI
  **  Created  date:      2006-9-9
  **  Version:  1.0
  **  Descriptions:  First  version
  **--------------------------------------------------------
  **  Modified  by:MAMAJINCO
  **  Modified  date:2006-9-9
  **  Version:1.0
  **  Descriptions:在此忠心感谢ZLG的模版  我的高质量编程意识起源于此
  ********************************************************/ 
  #include  <stdio.h>
  #include  <stdlib.h>
  #include  <unistd.h>
  #include  <fcntl.h>
  #include  <sys/types.h>
  #include  <sys/stat.h>
  
  void  delay(int  delay)//延时用函数
  {
    int  i;
    for(;delay>0;delay--)
    {
      for(i=0  ;  i  <  5000  ;  i  ++);    
    }
  }
  
  int  main()
  {
    int  fd1;
    int  j;
    fd1=  open("/dev/led"  ,  O_RDWR);/*打开设备,就象打开文件一样简单*/
    if(fd1  ==  -1)/*异常处理*/
    {
      printf  (  "file  can  not  be  open"  );
      return  -1;
    }
    for  (j  =0  ;  j<  10  ;  j  ++)/*重复10次*/
    {
      ioctl(fd1  ,  1  ,  0);/*GPC0上LED亮*/
      delay(1000);
      ioctl(fd1  ,  0  ,  0);/*GPC0上LED灭*/
      ioctl(fd1  ,  1  ,  1);/*GPC1上LED亮*/
      delay(1000);
      ioctl(fd1  ,  0  ,  1);/*GPC1上LED灭*/
      ioctl(fd1  ,  1  ,  2);/*GPC2上LED亮*/
      delay(1000);
      ioctl(fd1  ,  0  ,  2);/*GPC2上LED灭*/
      delay(1000);
    }   
    close  (fd1);/*关闭设备(文件)*/
    return  0;
      
  }
  /***********************************************************
  **                                                        End  Of  File
  ****************************************************/
  
  

//////////////////////////////////////////////////
现在有了led.h  led.c  ledtest.c三个文件了,正式开始吧
  
  PART  A  修改驱动
1)  把led.h和led.c  丢到目录uClinux-dist/linux-2.4.x/drivers/char中
2)  修改文件  
===============START==============
uClinux-dist/linux-2.4.x/drivers/char/Makefile
----------------------------------------------
obj-$(CONFIG_C5471_WDT)  +=  wdt_c5471.o之后加
obj-$(CONFIG_LED)  +=  led.o
================END============
3)  修改文件
=================START===========
uClinux-dist/linux-2.4.x/drivers/char/Config.in
-----------------------------------------
if  [  "$CONFIG_CPU_S3C44B0X"  =  "y"  ];  then
      bool  'Samsung  S3C44B0X  serial  ports  support'  CONFIG_SERIAL_S3C44B0X之后加
      bool  'Test  LED  Driver'  CONFIG_LED
================END=================
4)  修改文件
=================START=============
uClinux-dist/linux-2.4.x/drivers/char/mem.c
-----------------------------------------
开头的地方扎堆加
#ifdef  CONFIG_LED
extern  void  led_init(void);
#endif

int  __init  chr_dev_init(void)之后加
#ifdef  CONFIG_LED
  led_init();
#endif
================END==============
5)  继续修改文件
=================START============
uClinux-dist/vendors/Samakmsung/44B0/Makefile
-----------------------------------------
ttypc,c,3,12  ttypd,c,3,13  ttype,c,3,14  ttypf,c,3,15\之后加
\
led,c,231,0  \
================END==============



PART  B  修改用户程序
1)  把ledtest.c丢入自己建立的目录uClinux-dist/user/ledtest
2)  修改文件
================START============
uClinux-dist/user/Makefile
-----------------------------------------
扎堆加个下面
dir_$(CONFIG_USER_LEDTEST)      +=  ledtest
=================END===============
3)  修改文件
================START============
uClinux-dist/config/Configure.help
-----------------------------------------
扎堆加个下面
CONFIG_USER_LEDTEST
    Test  the  LED  driver
=================END=============
4)  修改文件,就是在最后加上一段
================START================
uClinux-dist/config/Configure.in
-----------------------------------------
##############################
mainmenu_option  next_comment
comment  'LED  driver  test  '

bool  'LEDtest'  CONFIG_USER_LEDTEST
endmenu

###############################
=================END=============


PART  C  编译
1)  make  menuconfig  
要选中Kernel和User那两个选项,在kernel中的能找到“Test  LED  Driver”选项,勾上,在user中能找到“LEDtest”,也要勾上,保存退出。
2)  make  clean
3)  make  lib_only
4)  make  user_only
5)  make  romfs
6)  make  image
7)  make
我的led.c刚开始有不少问题,make会提示是多少行有问题,然后再回去改,还蛮不错的

好了,生成bin文件了

PART  D  烧录
只是我的板子的地址,但基本上差不多,在uboot中操作
1)  loadb  0x0c008000
2)  发送bin文件
3)  erase  0x50000  0x1fffff
4)  cp  0x0c008000  0x50000  3370d    
  //3370d根据自己载入文件的大小除以4再加2,我是cdc2e/4+2的
5)  save
6)  reset

如果没问题,应该能看到uClinux的界面了,下面在板子中运行
1)  cd  /dev
2)ls
看见里面有个LED了吧?
3)  cd  /proc
4)cat  devices
看见驱动列表吧?
led  231也应该在里面
5)ledtest
在任何地方执行这个语句  就可以看到板子上的灯亮了。
上一篇:没有了! 下一篇:真正的嵌入式精英是如何修炼成的?
我要评论
  • 匿名发表
  • [添加到收藏夹]
  • 发表评论:(匿名发表无需登录,已登录用户可直接发表。) 登录状态:未登录
最新评论
所有评论[0]
    暂无已审核评论!

51RTOS.com 版权所有  

Copyright 20006-2009 我爱嵌入式 ( 51RTOS.com ) All rights reserved 沪ICP备09080633号