<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 <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/gpio.h>
#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, &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.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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* ./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 *~
<b>五、檔案系統節點添加</b>
檔案系統裡,/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
等等,有平台的朋友可以試試。
<b>六、總結</b>
本人拿一個比較簡單的裝置驅動移植的例子來講解,目的讓大家了解davinci dm6446系統架構。由于時間倉促,以上可能會有不完善的地方,還請各位網友指點。Davinci dm6446 開發攻略到本章節,基本上一個完整的DM6446系統的架構基本介紹完了,感謝各位網友的支援,dm6446 開發攻略的文章也接近尾聲。由于很長一段時間忙着給購買我們産品的客戶搭建開發環境、codec環境,開發驅動,調試3G産品等等,是以更新部落格的速度放慢下來,畢竟客戶的要求才是最重要的。同時也趕在51CTO 5周年紀念日到來之前,結束DM6446開發攻略的主體文章,算是告一個段落,以便為51CTO 5周年紀念寫篇感想文章做好鋪墊,畢竟來這個圈子也快一年了,有些東西總是需要總結的。
本文轉自 zjb_integrated 51CTO部落格,原文連結:http://blog.51cto.com/zjbintsystem/359025,如需轉載請自行聯系原作者