標籤:android 硬體 驅動 hal
硬體平台: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程式測試該驅動。
Android 從硬體到應用:一步一步向上爬 1 -- 從零編寫底層硬體驅動程式