您的位置:首页 > 移动开发 > Android开发

Android 从硬件到应用:一步一步向上爬 1 -- 从零编写底层硬件驱动程序

2014-12-12 20:26 423 查看
硬件平台:TI AM335X Starter Kit

开发源码:TI-Android-ICS-4.0.3-DevKit-EVM-SK-3.0.1.bin

主机系统:Ubuntu 10.04

这次写《Android 从硬件到应用》是想尝试从底层的最简单的GPIO硬件驱动开始,一步一步的向上走,经过硬件抽象层HAL、JNI方法等,最终编写出APP,达到硬件调用的目的,期间会增加一些Android下C程序测试底层驱动的细节。既然是从零编写驱动,那就要脱离源码包里已有的一些api函数,从硬件电路开始。找到EVM板GPIO处原理图:



我要控制LED D1的状态,如上图所示,D1接了Q4,也就是BSS138,N沟道的MOS器件,AM335X_GPIO_LED4为高电平时,Q4的栅极漏极导通,D1为亮,反之,灭。首先设置GPIO时钟:



一、CM_PER_GPIO1_CLKCTRL:地址0x44E000AC 要装载的值为 0x00040002
接着设置GPIO1输出使能:



二、GPIO_OE:地址0x4804C134 要装载的值为 0x0
然后设置输出GPIO1的输出:



三、GPIO_DATAOUT:地址0x4804C13C 要装载的值为 0x00000010或者是0x00000000,让AM335X_GPIO_LED4引脚为高或低,这样D1就可以亮灭
编写驱动程序 android_gpio.c:移到drivers/char目录下

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <asm/io.h>

static struct class  *gpio_class;

volatile unsigned long *DIR;
volatile unsigned long *DAT;
volatile unsigned long *CLK;

int gpio_open (struct inode *inode,struct file *filp)

{
*CLK = 0x00040002; //Enable
*DIR = (*DIR)&0xffffffef;  //output
return 0;
}

ssize_t gpio_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
return 0;
}

ssize_t gpio_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
char val_buf[2];
int ret;
ret = copy_from_user(val_buf,buf,count);

switch(val_buf[0])
{
case 0x31 :
*DAT = (*DAT)|0x00000010;
break;
case 0x30 :
*DAT = (*DAT)&0xffffffef;
break;
default :
break;
}
return count;
}

struct file_operations gpio_fops =
{
.owner   = THIS_MODULE,
.open    = gpio_open,
.read    = gpio_read,
.write   = gpio_write,
} ;

int major;
int gpio_init (void)
{

major = register_chrdev(0,"Android_gpio",&gpio_fops);
gpio_class = class_create(THIS_MODULE, "Android_gpio");
device_create(gpio_class,NULL,MKDEV(major,0),NULL,"AdrIO");

DIR = (volatile unsigned long *)ioremap(0x4804C134,4);
DAT = (volatile unsigned long *)ioremap(0x4804C13C,4);
CLK = (volatile unsigned long *)ioremap(0x44E000AC,4);

printk ("gpio is ready\n");
return 0;
}

void gpio_exit (void)
{
unregister_chrdev(major,"Android_gpio");
device_destroy(gpio_class,MKDEV(major,0));
class_destroy(gpio_class);

iounmap(DIR);
iounmap(DAT);
iounmap(CLK);

printk ("module exit\n");
return ;
}

MODULE_LICENSE("GPL");
module_init(gpio_init);
module_exit(gpio_exit);
打开drivers/char目录下的Makefile,增加:

obj-$(CONFIG_ANDROID_GPIO)	+= android_gpio.o
打开drivers/char目录下的Kconfig,增加:

config ANDROID_GPIO
tristate "android gpio enable"
default y
源码目录下执行:

make ARCH=arm CROSS_COMPILE=arm-eabi- uImage
生成uImage,重新启动新系统,ls /dev 查看设备:

# ls /dev
AdrIO
alarm
android_adb
ashmem
binder
block
bus

发现AdrIO设备,第一步完成,注意在操作物理地址时一定要对位进行操作,不然

GPIO1会影响到AM335X Starter Kit的LCD显示,下一步就要执行C程序测试该驱动。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐