基于TINY4412的Andorid开发-------简单的LED灯控制

2019-07-13 01:51发布

阅读目录(Content) 参考资料: 《Andriod系统源代码情景分析》 《嵌入式Linux系统开发完全手册_基于4412_上册》     作者:彭东林 邮箱:pengdonglin137@163.com     平台介绍: 主机:Win7 32位 虚拟机:VMware10 + ubuntu-12.04.2-desktop-amd64 Android版本:  android-4.2.2_r1 Linux内核版本:linux-3.5.0 Bootloader:  友善之臂提供的Superboot4412.bin 目标平台:tiny4412ADK+S700 4GB Flash   目的: 在Tiny4412上运行的Android系统上,通过点击屏幕上的Button来控制Tiny4412的核心板上的四个LED灯的亮灭。一个有八个Button,每个灯的亮灭通过两个灯来控制,点击ON,相应的LED亮;点击OFF,相应的LED灯灭。   下面分几步完成: 1、编写驱动程序 2、测试驱动程序 3、编写HAL代码 4、编写framework代码 5、编写JNI代码 6、编写App 下面开始: 回到顶部(go to top)

一、编写驱动程序

分析tiny4412的原理图,看一下LED灯的位置: image 可以知道,LED是低电平亮,高电平灭。 看一下,接到了Exynos4412的哪些引脚上了: image 可以看到: LED1  --------- GPM4_0 LED2  --------- GPM4_1 LED3  --------- GPM4_2 LED4  --------- GPM4_3 看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器: image 图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000. 在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。 以GPM4_0引脚为例: image 为了控制灯,[3:0]应设置为0x01,即输出模式 image 向GPM4DAT的第0位写0,GPM4_0引脚输出低电平,LED1亮; 向GPM4DAT的第0位写1,GPM4_0引脚输出高电平,LED1灭; 接下来,开始写驱动程序,用友善之臂自带的Linux3.5.0内核 1: cd linux-3.5/ 2: cd drivers/ 3: mkdir android_led 4: cd android_led/ 在android_led/下创建led_demo.c和led_demo.h文件: touch led_demo.c led_demo.h 再在其中创建Makefile和Kconfig文件 touch Makefile Kconfig
  • 修改Kconfig:
1: config LED_DEMO 2: tristate "Android Led Demo" 3: default n 4: help 5: This is the led demo for Android system.
  • 修改Makefile:
obj-$(CONFIG_LED_DEMO) += led_demo.o
  • 修改drivers/Kconfig,添加 source “drivers/android_led/Kconfig”
1: menu "Device Drivers" 2:   3: source "drivers/android_led/Kconfig" 4:   5: ...... 6:   7: endmenu
  • 修改drivers/Makefile:
1: ...... 2:   3: obj-$(CONFIG_LED_DEMO) += android_led/
  • 在内核顶层目录下执行make  menuconfig,进入Device Drivers,将 Android Led Demo选择为*,然后保存配置退出。
image   注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了Android上用的Linux内核,并且在arch/arm/boot下生成了zImage等文件。 在前期开发的时候,时不时要编译,可以将drivers/android_led/Makefile修改为: 1: #obj-$(CONFIG_LED_DEMO) += led_demo.o 2: obj-m += led_demo.o 编译的时候,可以使用: make M=drivers/android_led modules 目的是提高编译速度,最后再将Makfile改回原样。临时测试,可以在Wind7的命令行下,使用adb push将led_demo.ko上传到/data/local下,然后用adb shell登陆板子,进行测试。
  • 修改led_demo.h和led_demo.c
led_demo.h 1: #ifndef __LED_DEMO_H__ 2: #define __LED_DEMO_H__ 3:   4: #include 5:   6: #define LED_ON _IOW('L', 0, int) 7: #define LED_OFF _IOW('L', 1, int) 8:   9: #define LED_DEMO_DEVICE_NODE_NAME "led_demo" 10: #define LED_DEMO_DEVICE_CLASS_NAME "led_demo" 11: #define LED_DEMO_DEVICE_FILE_NAME "led_demo" 12:   13: #define EXYNOS4412_GPM4CON 0x110002E0 14: #define EXYNOS4412_GPM4DAT 0x110002E4 15:   16:   17: struct led_demo_dev 18: { 19: struct cdev dev; 20: }; 21:   22: #endif   led_demo.c 1: #include 2: #include 3: #include 4: #include 5: #include 6:   7: #include 8: #include 9:   10:   11: #include "led_demo.h" 12:   13:   14: MODULE_LICENSE("GPL"); 15:   16:   17: static int led_demo_major; 18: static int led_demo_minor; 19: static int number_of_dev = 1; 20:   21: static struct led_demo_dev *led_dev = NULL; 22:   23: static unsigned int *GPM4CON = NULL; 24: static unsigned int *GPM4DAT = NULL; 25:   26: static struct class *led_demo_class = NULL; 27:   28:   29: static int led_open (struct inode *node, struct file *fops) 30: { 31: struct led_demo_dev *dev; 32:   33: dev = container_of(node->i_cdev, struct led_demo_dev, dev); 34:   35: fops->private_data = dev; 36:   37: return 0; 38: } 39: static int led_close (struct inode *node, struct file *fops) 40: { 41: return 0; 42: } 43:   44: static long led_ioctl (struct file *fops, unsigned int cmd, unsigned long data) 45: { 46: //struct led_demo_dev * led_dev = (struct led_demo_dev *)fops->private_data; 47:   48: if((data < 1) || (data > 4)) 49: { 50: printk(KERN_ALERT"parameter is no valid. "); 51: return -EINVAL; 52: } 53: 54: switch (cmd) 55: { 56: case LED_OFF: 57: writel(readl(GPM4DAT) | (0x1<<(data-1)), GPM4DAT); 58: break; 59: case LED_ON: 60: writel(readl(GPM4DAT) & ~(0x1<<(data-1)), GPM4DAT); 61: break; 62: default: 63: return -EINVAL; 64: break; 65: } 66:   67: 68: return 0; 69: } 70:   71: struct file_operations led_fops = 72: { 73: .owner = THIS_MODULE, 74: .open = led_open, 75: .unlocked_ioctl = led_ioctl, 76: .compat_ioctl = led_ioctl, 77: .release = led_close, 78: }; 79:   80: static int __led_setup_dev(struct led_demo_dev * dev) 81: { 82: int err = -1; 83:   84: dev_t devno = MKDEV(led_demo_major, led_demo_minor); 85:   86: memset(dev, 0, sizeof(struct led_demo_dev)); 87:   88: cdev_init(&(dev->dev), &led_fops); 89:   90: dev->dev.owner = THIS_MODULE; 91:   92: err = cdev_add(&(dev->dev), devno, number_of_dev); 93: if(err < 0) 94: { 95: return err; 96: } 97: 98: return 0; 99: } 100:   101: static int led_demo_init(void) 102: { 103: int err = -1; 104: dev_t dev; 105: struct device *temp = NULL; 106:   107: printk(KERN_ALERT"Initializing led demo device. "); 108:   109: err = alloc_chrdev_region(&dev, 0, number_of_dev, LED_DEMO_DEVICE_NODE_NAME); 110: if(err < 0) 111: { 112: printk(KERN_ALERT"fail to alloc char dev region. "); 113: goto fail; 114: } 115:   116: led_demo_major = MAJOR(dev); 117: led_demo_minor = MINOR(dev); 118:   119: led_dev = kmalloc(sizeof(struct led_demo_dev), GFP_KERNEL); 120: if(!led_dev) 121: { 122: err = -ENOMEM; 123: printk(KERN_ALERT"Failed to alloc led device. "); 124: goto unregister; 125: } 126:   127: err = __led_setup_dev(led_dev); 128: if (err < 0) 129: { 130: printk(KERN_ALERT"Failed to setup led device. "); 131: goto clean_up; 132: } 133:   134: GPM4CON = (unsigned int *)ioremap(EXYNOS4412_GPM4CON, 4); 135: if(!GPM4CON) 136: { 137: err = -ENOMEM; 138: goto destroy_cdev; 139: } 140: 141: GPM4DAT = (unsigned int *)ioremap(EXYNOS4412_GPM4DAT, 4); 142: if(!GPM4DAT) 143: { 144: err = -ENOMEM; 145: goto unmap1; 146: } 147:   148: writel((readl(GPM4CON) & ~0xffff) | 0x1111, GPM4CON); 149: writel(readl(GPM4DAT)| 0xf, GPM4DAT); 150:   151: led_demo_class = class_create(THIS_MODULE, LED_DEMO_DEVICE_CLASS_NAME); 152: if(IS_ERR(led_demo_class)) 153: { 154: err = PTR_ERR(led_demo_class); 155: printk(KERN_ALERT"Failed to create led demo class. "); 156: goto unmap2; 157: } 158:   159: temp = device_create(led_demo_class, NULL, dev, NULL, "%s", LED_DEMO_DEVICE_FILE_NAME); 160: if(IS_ERR(temp)) 161: { 162: err = PTR_ERR(temp); 163: printk(KERN_ALERT"Failed to create led demo device. "); 164: goto destroy_class; 165: } 166:   167: dev_set_drvdata(temp, (void *)led_dev); 168:   169: printk(KERN_ALERT"Succeed to initialize led demo device. "); 170: 171: return 0; 172:   173: destroy_class: 174: class_destroy(led_demo_class); 175: 176: unmap2: 177: iounmap(GPM4DAT); 178: 179: unmap1: 180: iounmap(GPM4CON); 181: 182: destroy_cdev: 183: cdev_del(&(led_dev->dev)); 184:   185: clean_up: 186: kfree(led_dev); 187: 188: unregister: 189: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev); 190: 191: fail: 192:   193: return err; 194: } 195:   196: static void led_demo_exit(void) 197: { 198: if(led_demo_class) 199: { 200: device_destroy(led_demo_class, MKDEV(led_demo_major, led_demo_minor)); 201: class_destroy(led_demo_class); 202: } 203: 204: iounmap(GPM4DAT); 205: iounmap(GPM4CON); 206:   207: if(led_dev) 208: { 209: cdev_del(&(led_dev->dev)); 210: kfree(led_dev); 211: } 212:   213: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev); 214: } 215:   216:   217:   218: module_init(led_demo_init); 219: module_exit(led_demo_exit); 220:     编写完成后,在内核源码的顶层目录执行make zImage –jN,然后就会在arch/arm/boot/生成zImage文件,利用友善之臂提供的Minitools将zImage烧写到板子上。具体步骤,参考友善之臂提供的PDF文档:《Tiny4412用户手册》 回到顶部(go to top)

二、编写代码测试驱动程序

在android-4.2.2_r1源码顶层目录下 1: external/led_demo/ 2: ├── Android.mk 3: ├── led_demo.c 4: └── led_demo.h 即,在external/下创建led_demo目录,并在其中创建Android.mk、led_demo.c以及led_demo.h文件. Android.mk: 1: LOCAL_PATH:= $(call my-dir) 2: include $(CLEAR_VARS) 3: LOCAL_MODULE_TAGS := optional 4: LOCAL_SRC_FILES := $(call all-subdir-c-files) 5: LOCAL_MODULE := led_demo_test 6: include $(BUILD_EXECUTABLE) 7:   led_demo.h: 1: #ifndef __LED_DEMO_H__ 2: #define __LED_DEMO_H__ 3:   4: #define LED_ON _IOW('L', 0, int) 5: #define LED_OFF _IOW('L', 1, int) 6:   7: #endif led_demo.c: 1: #include 2: #include 3: #include 4: #include 5: #include 6: #include 7:   8: #include "led_demo.h" 9:   10: int main(int argc, const char *argv[]) 11: { 12: int fd; 13: int i; 14:   15: fd = open("/dev/led_demo", O_RDWR); 16: if (fd < 0) 17: { 18: perror("failed to open. "); 19: exit(-1); 20: } 21:   22: while(1) 23: { 24: for(i=0; i<4; i++) 25: { 26: ioctl(fd, LED_OFF, i+1); 27: sleep(1); 28: ioctl(fd, LED_ON, i+1); 29: sleep(1); 30: ioctl(fd, LED_OFF, i+1); 31: sleep(1); 32: } 33: } 34:   35: close(fd); 36:   37: return 0; 38: } 编写完成后,在android-4.2.2_r1源码顶层目录下执行: 1: mmm ./external/led_demo/ 2:   3: ./gen-img.sh 然后将顶层目录下新生成的system.img利用友善之臂提供的Minitools烧写到板子上。 烧写完成后,重启板子。 使用串口终端登陆板子,使用su命令进入root用户模式,然后进入/system/bin目录下,执行./led_demo_test,观察现象,可以看到,TINY4412的核心板上的四个LED灯循环亮灭。也可以使用wind7下的控制终端,用adb shell登陆板子,进行测试。 回到顶部(go to top)

三、编写HAL代码

在hardware/libhardware/include/hardware/下创建文件led_demo_hal.h 在hardware/libhardware/modules/下创建目录led_demo_hal,然后进入led_demo_hal,创建两个文件,分别是Android.mk和 led_demo_hal.cpp。 下面是文件内容: hardware/libhardware/include/hardware/led_demo_hal.h 1: #ifndef ANDROID_LED_DEMO_HAL_H 2: #define ANDROID_LED_DEMO_HAL_H 3:   4: #include 5:   6: __BEGIN_DECLS 7:   8: #define LED_DEMO_HARDWARE_MODULE_ID "led_demo_hal" //模块ID 需要与下面的Android.mk中的LOCAL_MODULE 匹配,否则无法加载该HAL模块 9: