天天看點

Davinci DM6446開發攻略——LINUX GPIO驅動源碼移植

<b>一、             </b><b>DM6446 GPIO</b><b>的介紹</b>

     說到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的晶片DATASHEET,DM6446的GPIO分為3組BANK,BANK01組包括GPIO0~GPIO31,BANK23組包括GPIO32~GPIO63,BANK45組包括GPIO64~GPIO70,由于硬體資源的原因,DM6446并不是GPIO管腳就是純粹的GPIO腳,GPIO管腳和其他一些标準接口複用相同的引腳,比如SPI和GPIO複用,I2C和GPIO複用等,到底是使用GPIO還是其他接口,在初始化的時候,都需要對PINMUX0和PINMUX1兩個寄存器進行設定(見DM6446的晶片DATASHEET第3章),而軟體設定則在Montavista linux-2.6.18_pro500\arch\arm\mach-davinci目錄下mux_cfg.c和對應的mux.h裡。本人這裡使用GPIO10、GPIO12、GPIO28,分别對應控制BUZZER、LED1、LED0,是以不需要對mux_cfg.c和mux.h進行修改。我們把這些GPIO應用歸入linux字元裝置來移植。

<b>二、GPIO</b><b>源碼移植分析</b>

/* drivers/char/davinci_dm644x_gpios.c*/

#include &lt;linux/device.h&gt;

#include &lt;linux/fs.h&gt;

#include &lt;linux/module.h&gt;

#include &lt;linux/errno.h&gt;

#include &lt;linux/kernel.h&gt;

#include &lt;linux/init.h&gt;

#include &lt;linux/platform_device.h&gt;

#include &lt;linux/types.h&gt;

#include &lt;linux/cdev.h&gt;

#include &lt;asm/uaccess.h&gt;

#include &lt;asm/io.h&gt;

#include &lt;asm/arch/hardware.h&gt;

#include &lt;asm/arch/gpio.h&gt;

#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);

                     gpio_direction_output(DM644X_GPIO_LED1, 1);

                     gpio_direction_output(DM644X_GPIO_BUZZER, 1);

       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

       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, &amp;davinci_dm644x_gpio_fileops);

       if(ret &lt; 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 &lt;&gt;");

MODULE_DESCRIPTION("Davinci DM644x gpio driver");

MODULE_LICENSE("GPL");

這個驅動源碼是一種比較老的驅動移植,即register_chrdev(GPIO_MAJOR, DEVICE_NAME, &amp;davinci_dm644x_gpio_fileops),靜态配置設定裝置節點,适合linux-2.4.x和linux-2.6.10前的版本,當然也可以在2.6.18及以後的版本使用,現在新的版本char字元裝置的移植可以參考davinci_resizer.c、davinci_previewer.c等檔案。

上面的初始化函數調用udelay和msdelay,udelay一般适用于一個比較小的delay,如果你填的數大于2000,系統會認為你這個是一個錯誤的delay函數,是以如果需要2ms以上的delay需要使用mdelay函數。

由于這些delay函數本質上都是忙等待,對于長時間的忙等待意味這無謂的耗費着cpu的資源,是以對于毫秒級的延時,核心提供了msleep,ssleep等函數,這些函數将使得調用它的程序睡眠參數指定的時間。

寄存器級的驅動gpio_direction_output()函數是定義在linux-2.6.18_pro500/arch/arm/mach-davinci/下的gpio.c裡,裡邊還有gpio_direction_input()和GPIO中斷函數。

<b>三、修改核心配置檔案</b>

在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配置

<a target="_blank" href="http://blog.51cto.com/attachment/201007/103400464.jpg"></a>

選上“Character devices”裡的“Davinci DM644x GPIOs”,儲存修改後的配置,然後make uImage,對核心的編譯;

<b>四、GPIO</b><b>應用程式源碼</b>

    源碼添加:

/* dm644x_gpio_test.c*/

#include &lt;stdio.h&gt;

#include &lt;stdlib.h&gt;

#include &lt;unistd.h&gt;

#include &lt;sys/ioctl.h&gt;

/* ./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", &amp;gpio_number) != 1 || sscanf(argv[2],"%d", &amp;on) != 1 ||on &lt; 0 || on &gt; 1 || gpio _number &lt; 0 || gpio _number &gt; 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 &lt; 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 *~

<b>五、檔案系統節點添加</b>

        檔案系統裡,/etc/init.d/rcS檔案

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

         [ -x /etc/rc.d/rc.local ] &amp;&amp; /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

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

<b>六、總結</b>

      本人拿一個比較簡單的裝置驅動移植的例子來講解,目的讓大家了解davinci dm6446系統架構。由于時間倉促,以上可能會有不完善的地方,還請各位網友指點。Davinci dm6446 開發攻略到本章節,基本上一個完整的DM6446系統的架構基本介紹完了,感謝各位網友的支援,dm6446 開發攻略的文章也接近尾聲。由于很長一段時間忙着給購買我們産品的客戶搭建開發環境、codec環境,開發驅動,調試3G産品等等,是以更新部落格的速度放慢下來,畢竟客戶的要求才是最重要的。同時也趕在51CTO 5周年紀念日到來之前,結束DM6446開發攻略的主體文章,算是告一個段落,以便為51CTO 5周年紀念寫篇感想文章做好鋪墊,畢竟來這個圈子也快一年了,有些東西總是需要總結的。

本文轉自 zjb_integrated 51CTO部落格,原文連結:http://blog.51cto.com/zjbintsystem/359025,如需轉載請自行聯系原作者

繼續閱讀