X
  • July 29, 2013

Emulating I2C Devices with Java ME Embedded 3.3

Tom McGinn
Sr. Manager, Training and User Assistance

In this post, I will show you how to create an
emulated inter-integrated circuit (I2C) device using the Oracle Java ME SDK 3.3 Custom
Device Editor and the Embedded Support API.



Oracle's Java ME SDK 3.3 is a fantastic tool to learn how to create applications for embedded devices.
The focus of ME Embedded is the Information Module Profile - Next Generation
(IMP-NG) headless devices - simple micro controllers with 160KB of memory (or
more) designed to read sensor input or control small mechanical devices. The
embedded market is growing rapidly as more devices become connected to the
"internet of things."

New in the 3.3 version of the SDK is support for a host of peripheral
devices, including GPIO, ADC/DAC, UART, I2C, SPI, MMIO and more. The SDK includes an emulator (for
Windows) and you can choose between one of two default devices that support IMP-NG.

While the default emulator is useful to start learning Java
ME Embedded, at some point you will want an emulator that resembles the target embedded device. This is where the Java ME SDK really shines, by
allowing you to design your own emulator. Through the Custom Device Editor, provided with the Java ME SDK 3.3, you select the peripheral devices your
physical embedded device supports, including all of relevant information to
access the peripherals: hardware port number, pin number, trigger mode, etc. Designing an emulator that matches your physical embedded device can greatly shorten the
development cycle of an embedded application.

Start the Custom Device Editor from the command line C:\Java_ME_platform_SDK_3.3\bin\device-editor.exe
or through NetBeans and Eclipse. Using the editor, you specify GPIO pins
and ports, ADC and DAC devices, and pulse counters as needed. To add serial communication
devices (I2C, SPI and MMIO), the editor provides two options: add a simple
loopback that echoes back bytes as they are written to the device, or add an
implementation of the device using the embedded support API.

Of the three serial bus specifications, I2C is the simplest. It is a two-wire protocol, thus requiring only
four lines. For more detailed information on the specification, click here.

The installation directory of the Java ME SDK 3.3, C:\Java_ME_platform_SDK_3.3,
contains the documentation and a JAR for the Embedded Support API. Expand the
embedded-support-api.zip file located under \docs\api and look at the com.oracle.jme.toolkit.deviceaccess.i2c
package.

To emulate an I2C device, you create a class that
implements the I2CSlaveBus interface. In NetBeans (or Eclipse) create a Java ME
Embedded Application project. Add the \lib\embedded-support-api.jar to the project, then add a Java class that implements the interface:

public class TMP102Device implements I2CSlaveBus { ... }

There are just four methods to implement:

  • int read(byte[] data, int
    len, I2CSlaveBus.I2CSlaveIdentifier id)
  • void write(byte[] data,
    I2CSlaveBus.I2CSlaveIdentifier id)
  • void initialize(I2CSlaveBus.I2CSlaveIdentifier
    id)
  • void close(I2CSlaveBus.I2CSlaveIdentifier
    id)

The read method writes bytes into the byte array passed to
the method as an argument and returns a count of the bytes written to the
array. The write method can be used to signal the device for some action. The
initialize method is called every time the device is accessed through a
PeripheralManager.open call - this method can be used to reset the internal
state of your emulated device. Finally, the close method should release any
resources the emulated device is using.

I choose to emulate a simple I2C temperature device, the
Texas Instruments TMP102, a digital
temperature sensor with I2C communication capability. After power-on, this
device returns two bytes from an internal buffer every time it is read. The
first byte contains the left-most 8 bits of a 12-bit word, and the second byte
contains the 4 least significant bytes.

This 12-bit value represents a count of 0.0625 degree (Celsius)
increments, using the first high order bit to indicate values below 0. Positive
temperature values are converted directly to an integer and multiplied by the
increment to get the temperature value. For example, if the 12-bit word is
0x320 (0011 0010 000), the temperature is calculated as 0x320 = 800 * 0.0625 =
50 degrees Celsius.

Negative temperature values have a 1 in the high-order bit,
and the temperature value is calculated by the 2's complement of the count minus
1. For example, if the 12-bit word is 0xE70 (1110 0111 0000), the temperature
is calculated as 0xE70 - 1 = 0xE6F (1110 0110 1111), 2's complement = 0001 1001
000 = 400 * (-0.0625) = -25 degrees C.

Rather than just create a static TMP102 device (returning the same temperature over and over), the class I wrote simulates temperature fluctuations with a thread that randomly changes the "temperature"
value by a maximum of +/- .5 degree C every 5 seconds. I start this thread in the initialize method and kill it through the close method. The timing and range of temperature fluctuations is adjustable. To see the complete code, click
here to download the NetBeans project for the TMP102 emulator.

 To add the TMP102 device to a custom emulator, start
by creating a jar file of the project. In
NetBeans, you can right-click the project and select Build. A jar file will
be created in the dist folder of your NetBeans project.

Next create or modify an existing custom IMP-NG
emulator. Start the Custom Device Editor from the command line or through your
IDE. Select IMP-NG in the Custom Device Editor Dialog and click New to create a
new IMP-NG emulator device, or select one you already have and click Edit.

In the IMP-NG Device editor window, select the I2C tab.
Click Custom, then click the Browse button to navigate to the directory where
the jar file is located. The implementation class name is the fully qualified name of
the I2CSlaveBus class. Enter oracle.example.TMP102Device
in the Implementation Class Name field. Click the Add button in the lower right
to create a Slave entry.

At this point, you can choose to modify the ID,
Name, Bus Number, Address Size and Address of the slave device by clicking in each field and typing. Since my design goal is
to emulate a TMP102 device connected to a Raspberry Pi, Model B, I changed the
bus number to 1 and the address to 48 (this is a hex number). I2C devices on
the Pi use bus 1, and the default address and address size of the TMP102 is 0x48 (72) and 7-bit.

Finally, click OK, and in a few minutes you will see a
message that the new/updated emulator is registered with the Device manager. Next, write some code to test the emulated I2C device. You could
open the device using the String name of the emulated device like this:

I2CDevice tmp102 =
(I2CDevice) PeripheralManager.open("Slave0", I2CDevice.class, null);

However, to emulate opening the device the way it would be opened
when attached to a Raspberry Pi, you need to create an I2CConfig object first
and pass that to PeripheralManager to open the device:

I2CDeviceConfig
config = new I2CDeviceConfig(1, 0x48, 7, 10000);
// Bus 1, address 0x48, 7-bit addressing, 10KHz clock

I2CDevice tmp102 =
(I2CDevice) PeripheralManager.open(config);

If you prefer, you can run this small NetBeans embedded
application project
I created to test the emulated TMP102 device.

Enjoy!

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services