Android i2c

Android industrial multi touch panelThe main topic I want to present is how to use Android i2c, with exam­ples and source code.

Android multi touch pan­els are very com­mon in home and indus­trial appli­ca­tions. Many of them let you inter­face for instance with RS485 and mod­bus in order to con­nect slave devices through long dis­tance twisted cables, but what hap­pens if you already have a device that sup­port only i2c? I had the pos­si­bil­ity of test­ing android i2c on one of the lat­est indus­trial multi touch pan­els, the Ltouch F.

In this first part, I show you how to send data from an Android touch panel to an Arduino through i2c. The Arduino will then dis­play the data received in its ser­ial monitor.

What you need to do is the following:

  1. Set up the Arduino sketch
  2. Con­nect SCL and SDA pins
  3. Cre­ate an Android project
  4. Cre­ate an Android native library
  5. Link it in your Android project
  6. Call the native method from Java code

Let’s go through every points listed above.

Set up the Arduino sketch

The first point is straight­for­ward because one of the Arduino exam­ples (Wire slave receiver) already has all you need. The Arduino library involved is Wire. The sketch I’ll use is the following:

#include <Wire.h>

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

Con­nect SCL and SDA pins

The pins involved in I2C com­mu­ni­ca­tion are SCL and SDA. They are located in the con­nec­tor J7 (pin 16–17) for the Ltouch panel and pins A4 and A5 in the Arduino. (Arduino i2c)

Cre­ate an Android project

The cre­ation of an Android project is quite easy and for those of you that are not famil­iar take a look at this Android brief tuto­r­ial.

Cre­ate an Android native library

The cre­at­ing of a native library could be a daunt­ing process for basic users. If you don’t feel con­fi­dent with that, I would sug­gest look­ing at these tuto­ri­als on youtube.

The steps involved are the following:

  1. Make a jni folder inside your project’s root folder
  2. This folder will con­tains ini­tially three files. The .c and .h file names will depend from your pack­age name. Sup­pose that your pack­age is named com.biemme.i2c, then your files will be named like com_biemme_i2c_I2cLib.c and com_biemme_i2c_I2cLib.h. I2cLib will cor­re­spond to the name of the library (see below). The third file, named Android.mk, will be a sup­port file that helps the Android NDK to com­pile the native library. It can be
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := com_biemme_i2c_I2cLib.c
LOCAL_MODULE := com_biemme_i2c_I2cLib
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY

Now let’s delve into the details of the native library for Android i2c writ­ing. The source code of the com_biemme_i2c_I2cLib.c file is the following:

#include "com_biemme_i2c_I2cLib.h"	//should be modified according your package name
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include <unistd.h>
#include <stdio.h>

#include <linux/i2c.h>
#include <memory.h>
#include <malloc.h>

//library for log
#include <android/log.h>
#define APPNAME "BiemmeI2c"

static const char *TAG="com_biemme";

#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

//should be modified according your package name
JNIEXPORT jint JNICALL Java_com_biemme_i2c_I2cLib_writeI2C(JNIEnv * env, jclass clazz)
{

    char *bufByte;

    int slaveAddr = 0x4;	//i2c slave device address
    int res = 0, i = 0, j = 0;
    int mode = 0;
    int len = 10;

    //open the file that corresponds to the i2c on the Ltouch board
    int fd = open("/dev/i2c-1", O_RDWR);

    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "OPEN i2c, file handler: %d", fd);

    //allocate memory for the array that will contains the data to be written
    bufByte = (char*) malloc((len + 1)*sizeof(char));

    if (bufByte == 0) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "i2c no memory available");
        return -1;
    }

    bufByte[0] = mode;
    for (i = 1; i < len+1; i++){
    	//store into the array 10 values starting from 65.
    	//Why 65? Because the Arduino sketch will interpret them as character values
    	//so will be displayed in the monitor as A,B,C, ... etc
        bufByte[i] = i+64;
     }

    //specify the Address of the slave device (in my project the Arduino)
    res = ioctl(fd, I2C_SLAVE, slaveAddr);
    if (res != 0) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Can't set slave address");
        return -2;
    }

    //write data
    if ((j = write(fd, bufByte, len)) != len) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "write fail i2c (%d)", j);
	return -3;
    }
    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "I2C: %d byte(s) written", j);

    //free memory and close file handler
    free(bufByte);
    close(fd);

    //return 0 when no errors occur, negative value otherwise
    return 0;

}

The header file is the following:

#include <jni.h>

//should be modified according your package name

#ifndef _Included_com_biemme_i2c_I2cLib
#define _Included_com_biemme_i2c_I2cLib
#ifdef __cplusplus
extern "C" {
#endif

//should be modified according your package name
JNIEXPORT jint JNICALL Java_com_biemme_i2c_I2cLib_writeI2C(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

Once the C and its header files are cre­ated, just build the library by typ­ing the com­mand “ndk-build” from the jni folder. Check whether the path of your NDK instal­la­tion is in the PATH envi­ron­ment vari­able, oth­er­wise you have to spec­ify the absolute path of the com­mand too.
The NDK will cre­ate the com­piled library for you SoC archi­tec­ture (ARM in my case) and you’ll find it in the libs folder. It has a .so file extension.

Link it in your Android project

Once the native library is ready, let go back to the Android project and cre­ate a new java class, named I2cLib.java with the fol­low­ing code:

package com.biemme.ic2; //should be modified according your package name

public class I2cLib {
    public native static int writeI2C();
    static{
	    //should be modified according your package name
            System.loadLibrary("com_biemme_i2c_I2cLib");
    }
}

This class stands as a wrap­per to the native library. Once you call the writeI2C() method from your Android app, the call is for­warded to the native method Java_com_biemme_i2c_I2cLib_writeI2C that is then exe­cuted.
In an enhanced ver­sion of the writeI2C method, it might man­age some para­me­ters like for instance the data to send and the slave address of devices.

As a final remark, check whether the per­mis­sion of the /dev/ic2-1 are set to 666, oth­er­wise it might not work.

That’s it!

The list of I2C devices is infi­nite. Being able to inter­face with them is a must have for new multi-touch pan­els Android-based. I’ve demon­strated how you can use Android i2c with the Ltouch indus­trial panel and in par­tic­u­lar, how to cre­ate native Android library that will man­age the low-level i2c communication.

This is only a demon­stra­tive exam­ple, how­ever I hope to shed new light on how to use Android i2c with new devices.

Ref­er­ences:
[1] http://www.biemmeitalia.net
[2] http://www.biemmeitalia.net/wiki
[3] Arduino sketch pro­vided by Nicholas Zam­betti www.zambetti.com
[4] Tuto­r­ial NDK Videos.
[5] http://sourceforge.net/projects/mini6410-i2c/