本文转载自:http://www.cnblogs.com/pengdonglin137/p/3857724.html

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

 

参考资料:

《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

下面开始:

一、编写驱动程序

分析tiny4412的原理图,看一下LED灯的位置:

可以知道,LED是低电平亮,高电平灭。

看一下,接到了Exynos4412的哪些引脚上了:

可以看到:

LED1  --------- GPM4_0

LED2  --------- GPM4_1

LED3  --------- GPM4_2

LED4  --------- GPM4_3

看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器:

图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000.

在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。

以GPM4_0引脚为例:

为了控制灯,[3:0]应设置为0x01,即输出模式

向GPM4DAT的第0位写0,GPM4_0引脚输出低电平,LED1亮;

向GPM4DAT的第0位写1,GPM4_0引脚输出高电平,LED1灭;

接下来,开始写驱动程序,用友善之臂自带的Linux3.5.0内核

  1. 1: cd linux-3.5/
  1. 2: cd drivers/
  1. 3: mkdir android_led
  1. 4: cd android_led/

在android_led/下创建led_demo.c和led_demo.h文件:

  1. touch led_demo.c led_demo.h

再在其中创建Makefile和Kconfig文件

  1. touch Makefile Kconfig
  • 修改Kconfig:
  1. 1: config LED_DEMO
  1. 2: tristate "Android Led Demo"
  1. 3: default n
  1. 4: help
  1. 5: This is the led demo for Android system.
  • 修改Makefile:
  1. obj-$(CONFIG_LED_DEMO) += led_demo.o
  • 修改drivers/Kconfig,添加 source “drivers/android_led/Kconfig”
  1. 1: menu "Device Drivers"
  1. 2:  
  1. 3: source "drivers/android_led/Kconfig"
  1. 4:  
  1. 5: ......
  1. 6:  
  1. 7: endmenu
  • 修改drivers/Makefile:
  1. 1: ......
  1. 2:  
  1. 3: obj-$(CONFIG_LED_DEMO) += android_led/
  • 在内核顶层目录下执行make  menuconfig,进入Device Drivers,将 Android Led Demo选择为*,然后保存配置退出。

注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了Android上用的Linux内核,并且在arch/arm/boot下生成了zImage等文件。

在前期开发的时候,时不时要编译,可以将drivers/android_led/Makefile修改为:

  1. 1: #obj-$(CONFIG_LED_DEMO) += led_demo.o
  1. 2: obj-m += led_demo.o

编译的时候,可以使用:

  1. 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. 1: #ifndef __LED_DEMO_H__
  1. 2: #define __LED_DEMO_H__
  1. 3:  
  1. 4: #include <linux/cdev.h>
  1. 5:  
  1. 6: #define LED_ON _IOW('L', 0, int)
  1. 7: #define LED_OFF _IOW('L', 1, int)
  1. 8:  
  1. 9: #define LED_DEMO_DEVICE_NODE_NAME "led_demo"
  1. 10: #define LED_DEMO_DEVICE_CLASS_NAME "led_demo"
  1. 11: #define LED_DEMO_DEVICE_FILE_NAME "led_demo"
  1. 12:  
  1. 13: #define EXYNOS4412_GPM4CON 0x110002E0
  1. 14: #define EXYNOS4412_GPM4DAT 0x110002E4
  1. 15:  
  1. 16:  
  1. 17: struct led_demo_dev
  1. 18: {
  1. 19: struct cdev dev;
  1. 20: };
  1. 21:  
  1. 22: #endif

led_demo.c

  1. 1: #include <linux/kernel.h>
  1. 2: #include <linux/module.h>
  1. 3: #include <linux/fs.h>
  1. 4: #include <linux/slab.h>
  1. 5: #include <linux/device.h>
  1. 6:  
  1. 7: #include <asm/io.h>
  1. 8: #include <asm/uaccess.h>
  1. 9:  
  1. 10:  
  1. 11: #include "led_demo.h"
  1. 12:  
  1. 13:  
  1. 14: MODULE_LICENSE("GPL");
  1. 15:  
  1. 16:  
  1. 17: static int led_demo_major;
  1. 18: static int led_demo_minor;
  1. 19: static int number_of_dev = 1;
  1. 20:  
  1. 21: static struct led_demo_dev *led_dev = NULL;
  1. 22:  
  1. 23: static unsigned int *GPM4CON = NULL;
  1. 24: static unsigned int *GPM4DAT = NULL;
  1. 25:  
  1. 26: static struct class *led_demo_class = NULL;
  1. 27:  
  1. 28:  
  1. 29: static int led_open (struct inode *node, struct file *fops)
  1. 30: {
  1. 31: struct led_demo_dev *dev;
  1. 32:  
  1. 33: dev = container_of(node->i_cdev, struct led_demo_dev, dev);
  1. 34:  
  1. 35: fops->private_data = dev;
  1. 36:  
  1. 37: return 0;
  1. 38: }
  1. 39: static int led_close (struct inode *node, struct file *fops)
  1. 40: {
  1. 41: return 0;
  1. 42: }
  1. 43:  
  1. 44: static long led_ioctl (struct file *fops, unsigned int cmd, unsigned long data)
  1. 45: {
  1. 46: //struct led_demo_dev * led_dev = (struct led_demo_dev *)fops->private_data;
  1. 47:  
  1. 48: if((data < 1) || (data > 4))
  1. 49: {
  1. 50: printk(KERN_ALERT"parameter is no valid.\n");
  1. 51: return -EINVAL;
  1. 52: }
  1. 53:
  1. 54: switch (cmd)
  1. 55: {
  1. 56: case LED_OFF:
  1. 57: writel(readl(GPM4DAT) | (0x1<<(data-1)), GPM4DAT);
  1. 58: break;
  1. 59: case LED_ON:
  1. 60: writel(readl(GPM4DAT) & ~(0x1<<(data-1)), GPM4DAT);
  1. 61: break;
  1. 62: default:
  1. 63: return -EINVAL;
  1. 64: break;
  1. 65: }
  1. 66:  
  1. 67:
  1. 68: return 0;
  1. 69: }
  1. 70:  
  1. 71: struct file_operations led_fops =
  1. 72: {
  1. 73: .owner = THIS_MODULE,
  1. 74: .open = led_open,
  1. 75: .unlocked_ioctl = led_ioctl,
  1. 76: .compat_ioctl = led_ioctl,
  1. 77: .release = led_close,
  1. 78: };
  1. 79:  
  1. 80: static int __led_setup_dev(struct led_demo_dev * dev)
  1. 81: {
  1. 82: int err = -1;
  1. 83:  
  1. 84: dev_t devno = MKDEV(led_demo_major, led_demo_minor);
  1. 85:  
  1. 86: memset(dev, 0, sizeof(struct led_demo_dev));
  1. 87:  
  1. 88: cdev_init(&(dev->dev), &led_fops);
  1. 89:  
  1. 90: dev->dev.owner = THIS_MODULE;
  1. 91:  
  1. 92: err = cdev_add(&(dev->dev), devno, number_of_dev);
  1. 93: if(err < 0)
  1. 94: {
  1. 95: return err;
  1. 96: }
  1. 97:
  1. 98: return 0;
  1. 99: }
  1. 100:  
  1. 101: static int led_demo_init(void)
  1. 102: {
  1. 103: int err = -1;
  1. 104: dev_t dev;
  1. 105: struct device *temp = NULL;
  1. 106:  
  1. 107: printk(KERN_ALERT"Initializing led demo device.\n");
  1. 108:  
  1. 109: err = alloc_chrdev_region(&dev, 0, number_of_dev, LED_DEMO_DEVICE_NODE_NAME);
  1. 110: if(err < 0)
  1. 111: {
  1. 112: printk(KERN_ALERT"fail to alloc char dev region.\n");
  1. 113: goto fail;
  1. 114: }
  1. 115:  
  1. 116: led_demo_major = MAJOR(dev);
  1. 117: led_demo_minor = MINOR(dev);
  1. 118:  
  1. 119: led_dev = kmalloc(sizeof(struct led_demo_dev), GFP_KERNEL);
  1. 120: if(!led_dev)
  1. 121: {
  1. 122: err = -ENOMEM;
  1. 123: printk(KERN_ALERT"Failed to alloc led device.\n");
  1. 124: goto unregister;
  1. 125: }
  1. 126:  
  1. 127: err = __led_setup_dev(led_dev);
  1. 128: if (err < 0)
  1. 129: {
  1. 130: printk(KERN_ALERT"Failed to setup led device.\n");
  1. 131: goto clean_up;
  1. 132: }
  1. 133:  
  1. 134: GPM4CON = (unsigned int *)ioremap(EXYNOS4412_GPM4CON, 4);
  1. 135: if(!GPM4CON)
  1. 136: {
  1. 137: err = -ENOMEM;
  1. 138: goto destroy_cdev;
  1. 139: }
  1. 140:
  1. 141: GPM4DAT = (unsigned int *)ioremap(EXYNOS4412_GPM4DAT, 4);
  1. 142: if(!GPM4DAT)
  1. 143: {
  1. 144: err = -ENOMEM;
  1. 145: goto unmap1;
  1. 146: }
  1. 147:  
  1. 148: writel((readl(GPM4CON) & ~0xffff) | 0x1111, GPM4CON);
  1. 149: writel(readl(GPM4DAT)| 0xf, GPM4DAT);
  1. 150:  
  1. 151: led_demo_class = class_create(THIS_MODULE, LED_DEMO_DEVICE_CLASS_NAME);
  1. 152: if(IS_ERR(led_demo_class))
  1. 153: {
  1. 154: err = PTR_ERR(led_demo_class);
  1. 155: printk(KERN_ALERT"Failed to create led demo class.\n");
  1. 156: goto unmap2;
  1. 157: }
  1. 158:  
  1. 159: temp = device_create(led_demo_class, NULL, dev, NULL, "%s", LED_DEMO_DEVICE_FILE_NAME);
  1. 160: if(IS_ERR(temp))
  1. 161: {
  1. 162: err = PTR_ERR(temp);
  1. 163: printk(KERN_ALERT"Failed to create led demo device.\n");
  1. 164: goto destroy_class;
  1. 165: }
  1. 166:  
  1. 167: dev_set_drvdata(temp, (void *)led_dev);
  1. 168:  
  1. 169: printk(KERN_ALERT"Succeed to initialize led demo device.\n");
  1. 170:
  1. 171: return 0;
  1. 172:  
  1. 173: destroy_class:
  1. 174: class_destroy(led_demo_class);
  1. 175:
  1. 176: unmap2:
  1. 177: iounmap(GPM4DAT);
  1. 178:
  1. 179: unmap1:
  1. 180: iounmap(GPM4CON);
  1. 181:
  1. 182: destroy_cdev:
  1. 183: cdev_del(&(led_dev->dev));
  1. 184:  
  1. 185: clean_up:
  1. 186: kfree(led_dev);
  1. 187:
  1. 188: unregister:
  1. 189: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev);
  1. 190:
  1. 191: fail:
  1. 192:  
  1. 193: return err;
  1. 194: }
  1. 195:  
  1. 196: static void led_demo_exit(void)
  1. 197: {
  1. 198: if(led_demo_class)
  1. 199: {
  1. 200: device_destroy(led_demo_class, MKDEV(led_demo_major, led_demo_minor));
  1. 201: class_destroy(led_demo_class);
  1. 202: }
  1. 203:
  1. 204: iounmap(GPM4DAT);
  1. 205: iounmap(GPM4CON);
  1. 206:  
  1. 207: if(led_dev)
  1. 208: {
  1. 209: cdev_del(&(led_dev->dev));
  1. 210: kfree(led_dev);
  1. 211: }
  1. 212:  
  1. 213: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev);
  1. 214: }
  1. 215:  
  1. 216:  
  1. 217:  
  1. 218: module_init(led_demo_init);
  1. 219: module_exit(led_demo_exit);
  1. 220:  

编写完成后,在内核源码的顶层目录执行make zImage –jN,然后就会在arch/arm/boot/生成zImage文件,利用友善之臂提供的Minitools将zImage烧写到板子上。具体步骤,参考友善之臂提供的PDF文档:《Tiny4412用户手册》

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

在android-4.2.2_r1源码顶层目录下

  1. 1: external/led_demo/
  1. 2: ├── Android.mk
  1. 3: ├── led_demo.c
  1. 4: └── led_demo.h

即,在external/下创建led_demo目录,并在其中创建Android.mk、led_demo.c以及led_demo.h文件.

Android.mk:

  1. 1: LOCAL_PATH:= $(call my-dir)
  1. 2: include $(CLEAR_VARS)
  1. 3: LOCAL_MODULE_TAGS := optional
  1. 4: LOCAL_SRC_FILES := $(call all-subdir-c-files)
  1. 5: LOCAL_MODULE := led_demo_test
  1. 6: include $(BUILD_EXECUTABLE)
  1. 7:  

led_demo.h:

  1. 1: #ifndef __LED_DEMO_H__
  1. 2: #define __LED_DEMO_H__
  1. 3:  
  1. 4: #define LED_ON _IOW('L', 0, int)
  1. 5: #define LED_OFF _IOW('L', 1, int)
  1. 6:  
  1. 7: #endif

led_demo.c:

  1. 1: #include <stdio.h>
  1. 2: #include <sys/types.h>
  1. 3: #include <sys/stat.h>
  1. 4: #include <fcntl.h>
  1. 5: #include <stdlib.h>
  1. 6: #include <sys/ioctl.h>
  1. 7:  
  1. 8: #include "led_demo.h"
  1. 9:  
  1. 10: int main(int argc, const char *argv[])
  1. 11: {
  1. 12: int fd;
  1. 13: int i;
  1. 14:  
  1. 15: fd = open("/dev/led_demo", O_RDWR);
  1. 16: if (fd < 0)
  1. 17: {
  1. 18: perror("failed to open.\n");
  1. 19: exit(-1);
  1. 20: }
  1. 21:  
  1. 22: while(1)
  1. 23: {
  1. 24: for(i=0; i<4; i++)
  1. 25: {
  1. 26: ioctl(fd, LED_OFF, i+1);
  1. 27: sleep(1);
  1. 28: ioctl(fd, LED_ON, i+1);
  1. 29: sleep(1);
  1. 30: ioctl(fd, LED_OFF, i+1);
  1. 31: sleep(1);
  1. 32: }
  1. 33: }
  1. 34:  
  1. 35: close(fd);
  1. 36:  
  1. 37: return 0;
  1. 38: }

编写完成后,在android-4.2.2_r1源码顶层目录下执行:

  1. 1: mmm ./external/led_demo/
  1. 2:  
  1. 3: ./gen-img.sh

然后将顶层目录下新生成的system.img利用友善之臂提供的Minitools烧写到板子上。

烧写完成后,重启板子。

使用串口终端登陆板子,使用su命令进入root用户模式,然后进入/system/bin目录下,执行./led_demo_test,观察现象,可以看到,TINY4412的核心板上的四个LED灯循环亮灭。也可以使用wind7下的控制终端,用adb shell登陆板子,进行测试。

三、编写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. 1: #ifndef ANDROID_LED_DEMO_HAL_H
  1. 2: #define ANDROID_LED_DEMO_HAL_H
  1. 3:  
  1. 4: #include <hardware/hardware.h>
  1. 5:  
  1. 6: __BEGIN_DECLS
  1. 7:  
  1. 8: #define LED_DEMO_HARDWARE_MODULE_ID "led_demo_hal" //模块ID 需要与下面的Android.mk中的LOCAL_MODULE 匹配,否则无法加载该HAL模块
  1. 9: #define LED_DEMO_HARDWARE_DEVICE_ID "led_demo" // 设备ID
  1. 10:  
  1. 11:  
  1. 12: struct led_demo_module_t
  1. 13: {
  1. 14: struct hw_module_t common;
  1. 15: };
  1. 16:  
  1. 17: struct led_demo_device_t
  1. 18: {
  1. 19: struct hw_device_t common;
  1. 20: int fd;
  1. 21: int (*set_on)(struct led_demo_device_t *dev, int val); //用于控制LED,点亮第val个LED灯
  1. 22: int (*set_off)(struct led_demo_device_t *dev, int val); //熄灭第val个LED灯
  1. 23: };
  1. 24:  
  1. 25: __END_DECLS
  1. 26:  
  1. 27:  
  1. 28: #endif

hardware/libhardware/modules/led_demo_hal/led_demo_hal.cpp

  1. 1: #define LOG_TAG "LED_DEMO_HALSTUB" //将来可以用DDMS的LogCat工具进行调试,便于查看打印信息
  1. 2:  
  1. 3: #include <hardware/hardware.h>
  1. 4: #include <hardware/led_demo_hal.h>
  1. 5:  
  1. 6: #include <fcntl.h>
  1. 7: #include <errno.h>
  1. 8:  
  1. 9: #include <utils/Log.h>
  1. 10: #include <cutils/atomic.h>
  1. 11:  
  1. 12:  
  1. 13: #define DEVICE_NAME "/dev/led_demo" //设备结点,有Linux驱动程序自动创建
  1. 14: #define MODULE_NAME "led_demo"
  1. 15: #define MODULE_AUTHOR "pengdonglin137@163.com"
  1. 16:  
  1. 17: #define LED_ON 0x40044c00 //点灯的命令,其实就是_IOW('L', 0, int)的值,_IOW在编译时无法识别,待以后解决
  1. 18: #define LED_OFF 0x40044c01 //灭灯命令,其实就是_IOW('L', 1, int)的值,可以在上面的led_demo.c中加打印,看一下这个值是多少
  1. 19:  
  1. 20:  
  1. 21: static int led_demo_open(const struct hw_module_t* module, const char* id,
  1. 22: struct hw_device_t** device);
  1. 23:  
  1. 24: static int led_demo_close(struct hw_device_t* device);
  1. 25:  
  1. 26: static int led_demo_set_on(struct led_demo_device_t *dev, int val);
  1. 27:  
  1. 28: static int led_demo_set_off(struct led_demo_device_t *dev, int val);
  1. 29:  
  1. 30:  
  1. 31: static hw_module_methods_t led_demo_module_methods =
  1. 32: {
  1. 33: open:led_demo_open,
  1. 34: };
  1. 35:  
  1. 36: struct led_demo_module_t HAL_MODULE_INFO_SYM =
  1. 37: {
  1. 38: common:{
  1. 39: tag:HARDWARE_MODULE_TAG,
  1. 40: version_major:1,
  1. 41: version_minor:0,
  1. 42: id:LED_DEMO_HARDWARE_MODULE_ID,
  1. 43: name:MODULE_NAME,
  1. 44: author:MODULE_AUTHOR,
  1. 45: methods:&led_demo_module_methods,
  1. 46: }
  1. 47: };
  1. 48:  
  1. 49: static int led_demo_open(const struct hw_module_t* module, const char* id,
  1. 50: struct hw_device_t** device)
  1. 51: {
  1. 52: if(!strcmp(id, LED_DEMO_HARDWARE_DEVICE_ID))
  1. 53: {
  1. 54: struct led_demo_device_t *dev;
  1. 55:  
  1. 56: dev = (struct led_demo_device_t *)malloc(sizeof(struct led_demo_device_t));
  1. 57: if(!dev)
  1. 58: {
  1. 59: ALOGE("Failed to alloc space for struct led_demo_device_t.");
  1. 60: return -EFAULT;
  1. 61: }
  1. 62:  
  1. 63: memset(dev, 0, sizeof(struct led_demo_device_t));
  1. 64:  
  1. 65: dev->common.tag =

HARDWARE_DEVICE_TAG

  1. ;
  1. 66: dev->common.version = 0;
  1. 67: dev->common.module = (struct hw_module_t *)module;
  1. 68: dev->common.close = led_demo_close;
  1. 69: dev->set_on = led_demo_set_on;
  1. 70: dev->set_off = led_demo_set_off;
  1. 71:  
  1. 72: if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1)
  1. 73: {
  1. 74: ALOGE("Failed to open device %s ---- %s\n.", DEVICE_NAME, strerror(errno));
  1. 75: free(dev);
  1. 76: return -EFAULT;
  1. 77: }
  1. 78:  
  1. 79: *device = &(dev->common);
  1. 80:  
  1. 81: ALOGE("Open device file %s successfully.", DEVICE_NAME);
  1. 82:  
  1. 83: }
  1. 84:  
  1. 85: return -EFAULT;
  1. 86: }
  1. 87:  
  1. 88: static int led_demo_close(struct hw_device_t* device)
  1. 89: {
  1. 90: struct led_demo_device_t *led_device = (struct led_demo_device_t *)device;
  1. 91: if(led_device)
  1. 92: {
  1. 93: close(led_device->fd);
  1. 94: free(led_device);
  1. 95: }
  1. 96:  
  1. 97: return 0;
  1. 98: }
  1. 99:  
  1. 100: static int led_demo_set_on(struct led_demo_device_t *dev, int val)
  1. 101: {
  1. 102: if(!dev)
  1. 103: {
  1. 104: ALOGE("Null dev pointer.");
  1. 105: return -EFAULT;
  1. 106: }
  1. 107:
  1. 108: if(ioctl(dev->fd, LED_ON, val) < 0)
  1. 109: {
  1. 110: ALOGE("ioctl error --- %s.", strerror(errno));
  1. 111: return -EFAULT;
  1. 112: }
  1. 113:  
  1. 114: return 0;
  1. 115:
  1. 116: }
  1. 117:  
  1. 118: static int led_demo_set_off(struct led_demo_device_t *dev, int val)
  1. 119: {
  1. 120: if(!dev)
  1. 121: {
  1. 122: ALOGE("Null dev pointer.");
  1. 123: return -EFAULT;
  1. 124: }
  1. 125:
  1. 126: if(ioctl(dev->fd, LED_OFF, val) < 0)
  1. 127: {
  1. 128: ALOGE("ioctl error --- %s.", strerror(errno));
  1. 129: return -EFAULT;
  1. 130: }
  1. 131:
  1. 132: return 0;
  1. 133:
  1. 134: }
  1. 135:  

hardware/libhardware/modules/led_demo_hal/Android.mk

  1. 1: LOCAL_PATH := $(call my-dir)
  1. 2: include $(CLEAR_VARS)
  1. 3: LOCAL_MODULE_TAGS := optional
  1. 4: LOCAL_PRELINK_MODULE := false
  1. 5: LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
  1. 6: LOCAL_SHARED_LIBRARIES := liblog
  1. 7: LOCAL_SRC_FILES := led_demo_hal.cpp
  1. 8: LOCAL_MODULE := led_demo_hal.default
  1. 9: include $(BUILD_SHARED_LIBRARY)

编写完成后,在Android源码的顶层目录执行:

  1. mmm ./hardware/libhardware/modules/led_demo_hal/

最终out/target/product/tiny4412/system/lib/hw/目录下得到一个led_demo_hal.default.so文件。

下面处理一下硬件设备访问权限问题

在硬件抽象层模块中,我们是调用open函数来打开对应的设备文件的,在默认情况下,只有root用户才有权限访问系统的设备文件。但是一般的应用程序是没有root用户权限的。

解决办法,赋予root之外的其他用户访问设别文件/dev/led_demo的权限。做法如下:

在Android源码顶层目录下,修改system/core/rootdir/ueventd.rc,添加如下内容:

  1. /dev/led_demo 0666 root root

修改了ueventd.rc文件后,需要重新编译Android源代码工程,编译时,文件system/core/rootdir/ueventd.rc会拷贝到out/target/product/tiny4412/root/下,并且最终打包在ramdisk.img中。对于友善之臂,执行完make -jN后,还需要执行./gen-img.sh脚本,然后在Android源码顶层目录中会生成ramdisk-u.img文件,利用MiniTools将其烧写到板子上。

四、编写Framework代码

  • 定义硬件访问服务接口

在frameworks/base/core/java/android/os/创建文件ILed_demo_service.aidl,内容如下:

  1. 1: package android.os;
  1. 2:  
  1. 3: interface ILed_demo_service
  1. 4: {
  1. 5: void led_set_ON(int val);
  1. 6: void led_set_OFF(int val);
  1. 7: }

然后,修改frameworks/base/Android.mk

  1. 1: LOCAL_SRC_FILES += \
  1. 2: ......
  1. 3: core/java/android/os/IVibratorService.aidl \
  1. 4: core/java/android/os/ILed_demo_service.aidl \

最后,在Android源码顶层目录下执行

  1. mmm ./frameworks/base/

编译后得到的framework.jar文件就包含了ILed_demo_service接口。

  • 实现硬件访问服务

在frameworks/base/services/java/com/android/server/创建文件Led_demo_Service.java,内容如下:

  1. 1: package com.android.server;
  1. 2: import android.content.Context;
  1. 3: import android.os.ILed_demo_service;
  1. 4: import android.util.Slog;
  1. 5:  
  1. 6:  
  1. 7: public class Led_demo_Service extends ILed_demo_service.Stub
  1. 8: {
  1. 9: private static final String TAG = "Led_demo_Service"; //方便DDMS提供的LogCat工具看打印信息
  1. 10:  
  1. 11: private int mPtr = 0;
  1. 12:  
  1. 13: Led_demo_Service()
  1. 14: {
  1. 15: mPtr = init_native(); //硬件访问服务Led_demo_Service在启动时,会通过JNI方法init_native
  1. 16:  
  1. 17: if(mPtr == 0)
  1. 18: {
  1. 19: Slog.e(TAG, "Failed to initialize Led demo Service.");
  1. 20: }
  1. 21: }
  1. 22:  
  1. 23: public void led_set_ON(int val)
  1. 24: {
  1. 25: if(mPtr == 0)
  1. 26: {
  1. 27: Slog.e(TAG, "Led demo Service is not initialized.");
  1. 28: return;
  1. 29: }
  1. 30:  
  1. 31: set_ON_native(mPtr, val);
  1. 32: }
  1. 33:  
  1. 34: public void led_set_OFF(int val)
  1. 35: {
  1. 36: if(mPtr == 0)
  1. 37: {
  1. 38: Slog.e(TAG, "Led demo Service is not initialized.");
  1. 39: return;
  1. 40: }
  1. 41:  
  1. 42: set_OFF_native(mPtr, val);
  1. 43: }
  1. 44:  
  1. 45:  
  1. 46: private static native int init_native();
  1. 47: private static native void set_OFF_native(int mPtr, int val);
  1. 48: private static native void set_ON_native(int mPtr, int val);
  1. 49:  
  1. 50:  
  1. 51: };

编写完成后,在Android源码顶层目录下执行:

  1. mmm ./frameworks/base/services/java/

编译后得到的services.jar文件就包含有Led_demo_Service类。

五、编写JNI代码

在frameworks/base/services/jni/下创建文件com_android_server_led_demo_service.cpp,内容如下:

  1. 1: #define LOG_TAG "LED_DEMO_Service_JNI" //方便LogCat调试工具查看打印信息
  1. 2:  
  1. 3: #include "jni.h"
  1. 4: #include "JNIHelp.h"
  1. 5: #include "android_runtime/AndroidRuntime.h"
  1. 6:  
  1. 7: #include <utils/misc.h>
  1. 8: #include <utils/Log.h>
  1. 9: #include <hardware/hardware.h>
  1. 10: #include <hardware/led_demo_hal.h>
  1. 11:  
  1. 12: #include <stdio.h>
  1. 13:  
  1. 14:  
  1. 15: namespace android
  1. 16: {
  1. 17:  
  1. 18: static void led_demo_setOFF(JNIEnv *env, jobject clazz, jint ptr, jint value)
  1. 19: {
  1. 20: led_demo_device_t *device = (led_demo_device_t *)ptr;
  1. 21: if(!device)
  1. 22: {
  1. 23: ALOGE("Device led demo is not open.");
  1. 24: return ;
  1. 25: }
  1. 26:  
  1. 27: int val = value;
  1. 28:  
  1. 29: ALOGI("Set value %d to device led demo.", val);
  1. 30:  
  1. 31: device->set_off(device, value);
  1. 32: }
  1. 33:  
  1. 34: static void led_demo_setON(JNIEnv *env, jobject clazz, jint ptr, jint value)
  1. 35: {
  1. 36: led_demo_device_t *device = (led_demo_device_t *)ptr;
  1. 37: if(!device)
  1. 38: {
  1. 39: ALOGE("Device led demo is not open.");
  1. 40: return ;
  1. 41: }
  1. 42:  
  1. 43: int val = value;
  1. 44:  
  1. 45: ALOGI("Set value %d to device led demo.", val);
  1. 46:  
  1. 47: device->set_on(device, value);
  1. 48: }
  1. 49:
  1. 50:  
  1. 51: static inline int led_demo_device_open(const hw_module_t *module, struct led_demo_device_t **device)
  1. 52: {
  1. 53: return module->methods->open(module, LED_DEMO_HARDWARE_DEVICE_ID, (struct hw_device_t **)device);
  1. 54: }
  1. 55:  
  1. 56:  
  1. 57:  
  1. 58: static jint led_demo_init(JNIEnv *env, jclass clazz)
  1. 59: {
  1. 60: struct led_demo_module_t *module;
  1. 61: struct led_demo_device_t *device;
  1. 62:  
  1. 63:  
  1. 64: ALOGI("Initializing HAL stub led ......");
  1. 65:  
  1. 66: if(hw_get_module(

LED_DEMO_HARDWARE_MODULE_ID

  1. , (const struct hw_module_t **)&module) == 0)
  1. 67: {
  1. 68: ALOGE("Device led demo found.");
  1. 69:  
  1. 70: if(led_demo_device_open(&(module->common), &device))
  1. 71: {
  1. 72: ALOGI("Device led demo is open.");
  1. 73: return (jint)device;
  1. 74: }
  1. 75:  
  1. 76: ALOGE("Failed to open device led.");
  1. 77:  
  1. 78: return 0;
  1. 79: }
  1. 80:  
  1. 81: ALOGE("Failed to get HAL stub led demo.");
  1. 82: return 0;
  1. 83: }
  1. 84:  
  1. 85: static const JNINativeMethod method_table[] =
  1. 86: {
  1. 87: {"init_native", "()I", (void *)led_demo_init},
  1. 88: {"set_OFF_native", "(II)V", (void *)led_demo_setOFF},
  1. 89: {"set_ON_native", "(II)V", (void *)led_demo_setON},
  1. 90: };
  1. 91:  
  1. 92: int register_android_server_led_demo_service(JNIEnv *env)
  1. 93: {
  1. 94: return jniRegisterNativeMethods(env, "com/android/server/Led_demo_Service",
  1. 95: method_table, NELEM(method_table));
  1. 96: }
  1. 97:  
  1. 98: };
  1. 99:  
  1. 100:  

修改frameworks/base/services/jni/onload.cpp文件:

  1. 1: namespace android {
  1. 2: ......
  1. 3: int register_android_server_led_demo_service(JNIEnv *env);
  1. 4: };
  1. 5:  
  1. 6: extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
  1. 7: {
  1. 8: ......
  1. 9: register_android_server_led_demo_service(env);
  1. 10:  
  1. 11: return JNI_VERSION_1_4;
  1. 12: }

修改frameworks/base/services/jni/Android.mk文件,内容如下:

  1. 1: LOCAL_SRC_FILES:= \
  1. 2: ......
  1. 3: com_android_server_led_demo_service.cpp \
  1. 4: onload.cpp

最后,在Android源码顶层目录下执行:

  1. mmm ./frameworks/base/services/jni/
  • 启动硬件服务

修改frameworks/base/services/java/com/android/server/SystemServer.java文件

  1. 1: // Bring up services needed for UI.
  1. 2: if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
  1. 3: ......
  1. 4: try{
  1. 5: Slog.i(TAG, "Led demo Service");
  1. 6: ServiceManager.addService("led_demo", new Led_demo_Service()); //这里的名字要跟App中getService时传入的参数相同
  1. 7: } catch (Throwable e) {
  1. 8: Slog.e(TAG, "Failed to start Led demo Service", e);
  1. 9: }
  1. 10:  
  1. 11: }

编写完成后,在Android源码顶层目录下执行:

  1. mmm ./frameworks/base/services/java/

六、编写App

这个app是在Win7下用eclipse开发的,如下图:

上面的错误是因为Win7下的SDK开发包中并没有我们编写的ILed_demo_service,这个不要紧。导出方法:在工程Tiny4412_led_demo上右键单击,点击Export,选择General----> File System ,选择导出路径,最后点击Finish。将导出的工程Tiny4412_led_demo拷贝到packages/experimental/目录下,然后进入packages/experimental/Tiny4412_led_demo,在其中创建一个Android.mk文件:

  1. 1: LOCAL_PATH:= $(call my-dir)
  1. 2: include $(CLEAR_VARS)
  1. 3:  
  1. 4: LOCAL_MODULE_TAGS := optional
  1. 5:  
  1. 6: # Only compile source java files in this apk.
  1. 7: LOCAL_SRC_FILES := $(call all-java-files-under, src)
  1. 8:  
  1. 9: LOCAL_PACKAGE_NAME := Led_demo
  1. 10:  
  1. 11: include $(BUILD_PACKAGE)

下面是最终的效果图:

完成操作后,在Android源码顶层目录下执行

  1. mmm ./packages/experimental/Tiny4412_led_demo/

然后再执行

  1. ./gen-img.sh

将生成的system.img利用MiniTools提供的烧写工具烧写到板子上。

最后,附上源代码:

http://pan.baidu.com/s/1ntwTz1B

完!!

基于TINY4412的Andorid开发-------简单的LED灯控制【转】的更多相关文章

  1. [转] 基于TINY4412的Andorid开发-------简单的LED灯控制

    阅读目录 一.编写驱动程序 二.编写代码测试驱动程序 三.编写HAL代码 四.编写Framework代码 五.编写JNI代码 六.编写App 参考资料: <Andriod系统源代码情景分析> ...

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

    参考资料: <Andriod系统源代码情景分析> <嵌入式Linux系统开发完全手册_基于4412_上册> 作者:彭东林 邮箱:pengdonglin137@163.com 平 ...

  3. 【转载】基于TINY4412的Andorid开发-------简单的LED灯控制

    阅读目录(Content) 一.编写驱动程序 二.编写代码测试驱动程序 三.编写HAL代码 四.编写Framework代码 五.编写JNI代码 六.编写App 参考资料: <Andriod系统源 ...

  4. CC2530 LED灯控制

      有三个寄存器 分别是功能寄存器.方向寄存器.配置寄存器 功能寄存器 通用 I/O口 说的就是一般的I/O口,可以输出高低电平 为外设IO 例如摄像头或者打印机他们具体实现某些功能(拍照或打印文档) ...

  5. android驱动例子(LED灯控制)

    本例子,讲述在android2.1上完全自已开发一个驱动去控制硬件口并写应用测试该驱动,通过这样一个例子,解析android下的驱动开发流程的应用调用流程,可以说是很好的入门引导 要达到的效果:通过a ...

  6. RK3399 友善NanoPC-T4开发板使用sysfs方法控制status LED状态灯-【申嵌视频-RK3399篇】

    实验1:sysfs 操作方法控制NanoPC-T4开发板上LED灯 (status LED状态灯:GPIO0_B5/LED1_OUT)root@NanoPC-T4: cd /sys/class/led ...

  7. 《RT-Thread Studio开发STM32》第一章~第一节《配置STM32H743XIH6点亮LED灯》

    安装RT-Thread Studio后添加相关芯片库文件,打开软件 打开SDK管理界面,安装相关的库文件,本次采用STM32H743XIH6芯片,野火开发板. 新建工程并设置相关的参数 先编译下下载到 ...

  8. 单片机学习(二)开发板LED灯的控制

    目录 开发板上LED灯相关的电路图 点灯 LED闪烁 LED流水灯 其他效果 灯光二进制计数器 进阶版流水灯 开发板上LED灯相关的电路图 这是P2相关7个引脚的电路图,在默认情况下它是直接接着VCC ...

  9. Visual Studio 2022 开发 STM32 单片机 - 环境搭建点亮LED灯

    安装VS2022社区版软件 选择基础的功能就好 安装VisualGDB软件(CSDN资源) 按照提示一步一步安装就好 VisualGDB激活软件(CSDN资源) 将如下软件放在VisualGDB的安装 ...

随机推荐

  1. [转]Selenium-Webdriver系列Python版教程(1)————快速开始

    elenium的历史,selenium2与WebDriver的关系本文就不讲了,想了解的同学们百度一下就可以Ok.     本系列教程是以Selenium-WebDriver的Python版本,首先从 ...

  2. Python+selenium鼠标、键盘事件

    鼠标操作 现在的Web产品提供了丰富的鼠标交互方式,例如鼠标右击.双击.悬停.甚至是鼠标拖动等功能,在Webdriver中,将这些关于鼠标操作的方法封装在ActionChains类提供. 1.鼠标右击 ...

  3. 图的最小生成树——Kruskal算法

    Kruskal算法 图的最小生成树的算法之一,运用并查集思想来求出最小生成树. 基本思路就是把所有边从小到大排序,依次遍历这些边.如果这条边所连接的两个点在一个连通块里,遍历下一条边,如果不在,就把这 ...

  4. SHELL脚本运行的几种方法以及区别

    #1 给脚本加上执行权限chmod u+x a.sh, 而后就可以直接用全路径来执行脚本了,比如当前文件夹下用./a.sh,如果如果脚本所在目录在PATH环境变量之中, 则直接用a.sh即可(这和运行 ...

  5. 使用Navicat进行数据库对比同步

    使用Navicat进行数据库对比同步 当有多个数据库时,有时会出现结构或者数据不同步的问题,这时候可以使用navivat工具对比同步( 我的Navicat版本是11.0.17). 参考博客: 岁伏的博 ...

  6. HDU3549 最大流 裸题

    EK算法 时间复杂度o(n*m*m)  因为有反向边每次bfs时间为 n*m 每次删一条边 最多m次 代码 #include<iostream> #include<string.h& ...

  7. Python的描述符

    1.描述符的定义 描述符是与特定属性互相绑定的一种协议,通过方法被触发修改属性,这些方法包括__get__(),__set__(),__delete__().将这些方法定义在类中,即可实现描述符 2. ...

  8. Javascript标准事件模型

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p http://www.cnblogs.com/zt-blog/p/6676913.html 1. 分类 IE -- 冒泡型 现代 ...

  9. Eclipse中git插件导入远程库和上传项目源代码到远程库

    陆陆续续,从github,csdn的code.之前实习的小公司也是用git管理.发如今版本号控制方面确实比較方便.代码一敲完 . 自己由于完毕了新功能.加入一个新分支.然后提交上去,这就是程序猿一天干 ...

  10. jquery全局变量---同步请求设置

    1.同步 $.ajaxSetup({ async: false }); 2.异步 $.ajaxSetup({   async: true   }); 3.说明:我们一般使用同步完要恢复异步.由于js默 ...