Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1301213
  • 博文数量: 548
  • 博客积分: 7597
  • 博客等级: 少将
  • 技术积分: 4224
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-15 13:21
个人简介

嵌入式软件工程师&&太极拳

文章分类

全部博文(548)

文章存档

2014年(10)

2013年(76)

2012年(175)

2011年(287)

分类: 嵌入式

2012-02-29 17:45:24

一、             DM6446 GPIO的介绍

     说到LINUX 驱动移植,没有移植过的朋友,或刚刚进入LINUX领域的朋友,最好去看看《LINUX 设备驱动程序》第三版,有个理论或感性的认识。该版本是基于2.6.10的基础上描述的,经典读物,网上有电子版,但是建议花几十元买本书是值得的。

       GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在Montavista linux-2.6.18中,有关GPIO的最底层的寄存器驱动,是在linux-2.6.18_pro500\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋友应该比较熟悉寄存器级的驱动。根据DM6446的芯片DATASHEETDM6446GPIO分为3BANKBANK01组包括GPIO0~GPIO31BANK23组包括GPIO32~GPIO63BANK45组包括GPIO64~GPIO70,由于硬件资源的原因,DM6446并不是GPIO管脚就是纯粹的GPIO脚,GPIO管脚和其他一些标准接口复用相同的引脚,比如SPIGPIO复用,I2CGPIO复用等,到底是使用GPIO还是其他接口,在初始化的时候,都需要对PINMUX0PINMUX1两个寄存器进行设置(见DM6446的芯片DATASHEET3章),而软件设置则在Montavista linux-2.6.18_pro500\arch\arm\mach-davinci目录下mux_cfg.c和对应的mux.h里。本人这里使用GPIO10GPIO12GPIO28,分别对应控制BUZZERLED1LED0,所以不需要对mux_cfg.cmux.h进行修改。我们把这些GPIO应用归入linux字符设备来移植。

 

二、GPIO源码移植分析

 

/* drivers/char/davinci_dm644x_gpios.c*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#include

#include

#include

#include

 

#define DEVICE_NAME "dm644x_gpios"   /*定义设备驱动的名字,或设备节点名称*/

#define GPIO_MAJOR 199 /*使用 cat /proc/devices查看不要和存在的char节点重复*/

 

/*my app gpio define*/

#define DM644X_GPIO_BUZZER             10    /*GPIO10*/

#define DM644X_GPIO_LED1           12    /*GPIO10*/

#define DM644X_GPIO_LED0           28    /*GPIO10*/

 

static int davinci_dm644x_gpio_open(struct inode *inode, struct file *file)

{

    return 0;/*该函数可以什么都不做,也可以加入类似初始化的设置*/

}

 

static int davinci_dm644x_gpio_ioctl(

       struct inode *inode,

       struct file *file,

       unsigned int cmd,

       unsigned long arg)

{

       switch(cmd) /*cmd 表示应用程序传入的led动作,是on 还是off*/

       {

       case 0:     //gpio = 0

              if(0==arg) /*arg由自己硬件电路决定使用那些GPIO*/

              {

                     gpio_direction_output(DM644X_GPIO_LED0, 0);/*调用TI linux-2.6.18寄存器驱动*/

              }

              else if(1==arg)

              {

                     gpio_direction_output(DM644X_GPIO_LED1, 0);

              }

              else if(2==arg)

              {

                     gpio_direction_output(DM644X_GPIO_BUZZER, 0);

              }

              else

              {

                     return -EINVAL;

              }

              break;

       case 1:            //gpio = 1

              if(0==arg)

              {

                     gpio_direction_output(DM644X_GPIO_LED0, 1);

              }

              else if(1==arg)

              {

                     gpio_direction_output(DM644X_GPIO_LED1, 1);

              }

              else if(2==arg)

              {

                     gpio_direction_output(DM644X_GPIO_BUZZER, 1);

              }

              else

              {

                     return -EINVAL;

              }

              break;

       default:

              return -EINVAL;

       }

}

 

/*定义驱动设备文件API,在linux系统当中,任何设备都可以当做文件的方式操作,这一点和单片机和MCU有很大差别*/

static const struct file_operations davinci_dm644x_gpio_fileops = {

       .owner   = THIS_MODULE,

       .open    = davinci_dm644x_gpio_open,

       .ioctl       = davinci_dm644x_gpio_ioctl,

};

 

static int __init davinci_dm644x_gpio_init(void) /*内核初始化会调用该函数*/

{

       int ret;

 

       gpio_direction_output(DM644X_GPIO_LED0, 1);     //led0 is on

udelay(1);

       gpio_direction_output(DM644X_GPIO_LED1, 1);     //led1 is on

udelay(1);

       gpio_direction_output(DM644X_GPIO_BUZZER, 1);       //BUZZER is on

mdelay(500); /*初始化时,buzzer 发出声音500ms*/

       gpio_direction_output(DM644X_GPIO_BUZZER, 1);       //BUZZER is off

 

       ret = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &davinci_dm644x_gpio_fileops);

       if(ret < 0)

       {

              printk(DEVICE_NAME " register falid!\n");

              return ret;

       }

 

       printk (DEVICE_NAME" initialized\n");

 

       return ret;

}

 

static void __exit davinci_dm644x_gpio_exit(void)

{

       unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);

}

 

module_init(davinci_dm644x_gpio_init);

module_exit(davinci_dm644x_gpio_exit);

 

MODULE_AUTHOR("xxx <>");

MODULE_DESCRIPTION("Davinci DM644x gpio driver");

MODULE_LICENSE("GPL");

 

这个驱动源码是一种比较老的驱动移植,即register_chrdev(GPIO_MAJOR, DEVICE_NAME, &davinci_dm644x_gpio_fileops),静态分配设备节点,适合linux-2.4.xlinux-2.6.10前的版本,当然也可以在2.6.18及以后的版本使用,现在新的版本char字符设备的移植可以参考davinci_resizer.cdavinci_previewer.c等文件。

上面的初始化函数调用udelaymsdelayudelay一般适用于一个比较小的delay,如果你填的数大于2000,系统会认为你这个是一个错误的delay函数,因此如果需要2ms以上的delay需要使用mdelay函数。

由于这些delay函数本质上都是忙等待,对于长时间的忙等待意味这无谓的耗费着cpu的资源,因此对于毫秒级的延时,内核提供了msleepssleep等函数,这些函数将使得调用它的进程睡眠参数指定的时间。

寄存器级的驱动gpio_direction_output()函数是定义在linux-2.6.18_pro500/arch/arm/mach-davinci/下的gpio.c里,里边还有gpio_direction_input()和GPIO中断函数。

 

三、修改内核配置文件

 

linux-2.6.18_pro500/drivers/char目录下,

修改Kconfig文件,在menu "Character devices"下面,加入

 

config DAVINCI_DM644X_GPIOS

       tristate "Davinci DM644x GPIO GPIOs"

       depends on ARCH_DAVINCI

       help

        This option enables support for LEDs and Buzzer connected to GPIO lines

        on Ti Davinci DM644x CPUs, such as the DM6446

修改Makefile文件,在128

obj-$(CONFIG_DAVINCI_DM646X_TSIF)       += tsif_control.o tsif_data.o下面,加入:

obj-$( DAVINCI_DM644X_GPIOS) += davinci_dm644x_gpios.o

 

修改linux-2.6.18 内核menu配置

选上“Character devices”里的“Davinci DM644x GPIOs”,保存修改后的配置,然后make uImage,对内核的编译;

 

四、GPIO应用程序源码

 

    源码添加:

/* dm644x_gpio_test.c*/

#include

#include

#include

#include

 

/* ./dm644x_gpio_test 0 1 */ //led0 on

/* ./dm644x_gpio_test 0 0 */ //led0 off

/* ./dm644x_gpio_test 1 1 */ //led1 on

/* ./dm644x_gpio_test 1 0 */ //led1 off

/* ./dm644x_gpio_test 2 1 */ // buzzer on

/* ./dm644x_gpio_test 2 0 */ // buzzer off

 

int main(int argc, char **argv)

{

       int on;

       int gpio_number;

       int fd;

       // argv[0]== dm644x_gpio_test

    // argv[1]== gpio_number

    // argv[1]== on

       if (argc != 3 || sscanf(argv[1], "%d", &gpio_number) != 1 || sscanf(argv[2],"%d", &on) != 1 ||on < 0 || on > 1 || gpio _number < 0 || gpio _number > 3)

       {

              fprintf(stderr, "Usage:\n");

              fprintf(stderr, "\t dm644x_gpio_test  gpio_number on|off\n");

              fprintf(stderr, "Options:\n");

              fprintf(stderr, "\t gpio_number from 0 to 2\n");

              fprintf(stderr, "\t on 1   off 0\n");

              exit(1);

       }

       fd = open("/dev/dm644x_gpios", 0);

       if (fd < 0)

       {

      

             perror("open device /dev/dm644x_gpios");

             exit(1);

      

       }

       ioctl(fd, on, gpio_number);

       close(fd);

       return 0;

}

 

Makefile添加:

#application makefile for dm644x gpio test

CROSSCOMPILE = arm_v5t_le-

CC=$(CROSSCOMPILE)gcc

LD=$(CROSSCOMPILE)ld

OBJCOPY=$(CROSSCOMPILE)objcopy

OBJDUMP=$(CROSSCOMPILE)objdump

INCLUDE = /home/user/linux-2.6.18_pro500/include/*指向你的内核include*/

 

all: dm644x_gpio_test

 

dm644x_gpio_test: dm644x_gpio_test.c

       $(CROSSCOMPILE)gcc -Wall -O2 dm644x_gpio_test.c -I $(INCLUDE) -o dm644x_gpio_test

       $(CROSSCOMPILE)strip dm644x_gpio_test

       cp -f dm644x_gpio_test /home/user/nfs/target/opt/app/

clean:

       @rm -vf dm644x_gpio_test *.o *~

 

五、文件系统节点添加

        文件系统里,/etc/init.d/rcS文件

         # Run /etc/rc.d/rc.local if it exists

         [ -x /etc/rc.d/rc.local ] && /etc/rc.d/rc.local

        前面加mknod /dev/dm644x_gpios c 199 0或在shell命令行下执行mknod /dev/dm644x_gpios c 199 0;这就是静态分配设备节点的做法。

       运行系统,进入shell命令下,

     #cd / opt/app/

     #./ dm644x_gpio_test 0 1可以控制点亮LED0

     等等,有平台的朋友可以试试。

 

六、总结

      本人拿一个比较简单的设备驱动移植的例子来讲解,目的让大家理解davinci dm6446系统架构。由于时间仓促,以上可能会有不完善的地方,还请各位网友指点。Davinci dm6446 开发攻略到本章节,基本上一个完整的DM6446系统的框架基本介绍完了,感谢各位网友的支持,dm6446 开发攻略的文章也接近尾声。由于很长一段时间忙着给购买我们产品的客户搭建开发环境、codec环境,开发驱动,调试3G产品等等,所以更新博客的速度放慢下来,毕竟客户的要求才是最重要的。同时也赶在51CTO 5周年纪念日到来之前,结束DM6446开发攻略的主体文章,算是告一个段落,以便为51CTO 5周年纪念写篇感想文章做好铺垫,毕竟来这个圈子也快一年了,有些东西总是需要总结的。

 

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