Scaling Java - Embedded.com

Scaling Java

The advantages of Java as a programming language have led to a push toward smaller and simpler run-time environments. This article examines two of the smallest to date.

In this article I want to show you two microcontrollers I've worked with lately. Although they are superficially similar, each has different goals and correspondingly different designs. The first processor is Dallas Semiconductor's TINI (pronounced “tiny”). The other is the Parallax J-Stamp,[see Editors Note] a heavy-duty successor to the popular Basic Stamp. (Note: J-Stamp will be available in the third quarter of 2001; my comments in this article apply to a pre-release prototype unit.) Both use a form of Java as their main programming language.

Another language?

If you are firmly entrenched in the world of C programming, you may not be eager to learn Java. However, Java's standard library does a great job of handling multithreading, memory management, and network operations. In addition, since Java works on multiple platforms, it offers unique opportunities to develop part or all of your program on a desktop computer.

The idea behind Java is to compile a source program to a class file. A class file is like an executable image file, but instead of a specific machine code, the file contains instructions for the Java Virtual Machine (JVM). Each platform that supports Java supplies a JVM program that essentially emulates the make-believe Java microprocessor.

In theory, you can compile a Java source program into a class file on any platform, and that class file should run on any JVM. In theory. The reality is that not all JVMs are made equal. In addition, some platforms-notably embedded systems-don't support all the same library classes, so they won't execute arbitrary class files. However, as far as workstations go, it is relatively easy to write programs that will execute nearly anywhere. That's why Java is popular on the Internet.

TINI and J-Stamp both use standard Java tools to compile-against their custom libraries-ordinary class files. Then custom tools transform these class files into image files that can be downloaded to the microcontroller. TINI is indifferent to which Java compiler you use. The J-Stamp includes a very nice development environment that uses the well-regarded Jikes compiler (from IBM). However, you can potentially use other compilers if you like.

First look

The two devices are quite different in physical appearance. TINI looks like a memory SIMM. J-Stamp, on the other hand, is like a standard 24-pin IC package. Both chips-to use that term loosely-have carrier boards that you can use for development, although for a real design you'll likely integrate them onto a custom printed circuit board.Some of TINI's features include:

  • Built-in 10Base-T Ethernet interface
  • A Dallas Semiconductor 1-Wire interface
  • Two RS-232 ports

The J-Stamp sports:

  • An onboard 5V regulator
  • 16 general-purpose I/O pins that can become serial I/O ports, digital I/O, pulse inputs or outputs, and so on

Not only are these two devices physically different, they approach Java differently as well. TINI is practically a miniature PC. For the most part, whatever you can do on your PC's version of Java you can do on TINI. Of course, TINI has no GUI, but when it comes to multithreading, memory management, and network operations, the TINI is so close to a PC, you may not be able to tell the difference. This is a mixed blessing.

TINI is so PC-like that you use FTP to download programs to it and telnet into it to issue commands. The downside is that Java's multitasking and garbage collection of dynamic memory allocation makes it notoriously difficult to field real-time applications.J-Stamp takes a minimalist approach. Instead of trying to mimic Java completely, Parallax selected what they thought was important for the type of jobs small, inexpensive microcontrollers often tackle. There is no garbage collection, for example, and no Java-style multithreading (although there is a form of multithreading for certain tasks). Floating-point math is also absent. While these limitations may present challenges for certain programs, it makes it easy to respond quickly to external events.

Both devices have a large number of custom Java classes (libraries) that help you take advantage of their special hardware resources. For example, TINI has special classes for its 1-Wire port. The J-Stamp offers classes to drive LCDs, set up pins as UARTs, and manage push buttons.

The history of these devices shows you why they have the features they do (and, conversely, why they lack certain features). Dallas wants iButtons (small devices that use their 1-Wire protocol) to be used everywhere. While a PC can read an iButton, that's cost-prohibitive in many iButton application domains. The appearance of TINI allows iButtons to easily “get on the 'Net” for a far smaller price tag.Parallax, on the other hand, made its fortune with the Basic Stamp. It's ideal for quick and dirty projects that are I/O intensive. Connect a 9V battery to a Basic Stamp, and you are ready to go. The J-Stamp embraces this philosophy.

TINI Tim

The easiest way to start with the TINI daughtercard is to use the special carrier board Dallas supplies (although some third-party alternatives have special features). The initial set-up process is more complicated than the usual development setup. To begin you'll need a Java development system on your PC (or other workstation) and TINI's bootloader program.

To use the bootloader, you'll need a serial connection to your PC. The bootloader allows you to put TINI's firmware in place-something you'll want to do if/when Dallas upgrades the firmware. In addition, you can use the bootloader to store a default program that will run when the TINI starts. For development purposes, you'll probably make that program the TINI Slush shell. This shell is very much like a stripped-down Unix command prompt.

Once you've loaded Slush into flash, you can use the bootloader to start it and use the bootloader's terminal mode (or any dumb terminal program) to log in to Slush from the serial port. There you can assign your TINI a name and IP address (TINI will also work with DHCP, if you have a DHCP server on your network).

Once TINI is set up, you can practically throw away the serial cable. Future Slush logins will be over the Ethernet interface via telnet. You can use FTP to store programs you want to execute.

FTP, of course, stands for File Transfer Protocol. Since TINI has no disk drive, what constitutes a file? TINI uses its non-volatile memory as a pseudo disk drive and manages a simple file system using that memory. Of course, the more memory you use as disk space, the less is available for other purposes.

A first program

To illustrate the build process, consider this very simple Java program:

public class FirstProg {
    public static void main(String
    args[]) {
        System.out.println(“Hi World”);
    }
}

Exactly how you transform this into a Java class file depends on your Java development environment. As a least common denominator, suppose you are using Sun's JDK, which is free and available at http://java.sun.com. You'd simply issue this command:

javac FirstProg.java

Since this is Java, the file name must match the class name (FirstProg ). You could run the program on your PC with the command:

java FirstProg

Your first impulse might be to download the FirstProg.class file directly to the TINI, but this won't work. Instead, you first have to run the class file through a program (TINIConverter ) to transform it into a file (probably FirstProg.tini ). This is the file that you send to TINI via FTP. Then you can log into Slush and run it like this:

java FirstProg.tini

What's the difference between a .class file and a .tini file? The .tini file has all the classes and their dependencies bundled together in one payload you can download to the TINI board.

If you want to run your program without Slush, you'll have to run it through a different conversion process and then load it via the serial port using the bootloader.This example uses the JDK from Sun, which is relatively bare-bones. Many people prefer to use a different graphical development environment, and most of these will work with TINI. You usually just need to set the CLASSPATH to point to the TINI classes instead of the standard Java classes.

One thing missing from TINI is debugging. You can pepper your code with print statements, of course, but that's not always the best way. However, since TINI is so full featured, you can often debug parts of your program on a PC or other workstation. But that won't help when you are debugging interactions with TINI-specific features like I/O or other capabilities not present on the PC.

Programming J-Stamp

Getting started with J-Stamp couldn't be any simpler. You provide a power source and a serial cable to the PC. That's it. Of course, you also need to connect whatever input and output devices you want to use. Parallax provides a special board that contains a small breadboard, but you can easily put together your own breadboard in just a few minutes.Programming the J-Stamp is like using any Java IDE. The provided software allows you to create Java source files, view TINI's documentation, and set options for the compile process.

When you are ready to download the program, you simply tell the editor to debug the program and it will download it to J-Stamp via a serial cable. If you like, the same cable can let you single step through the program, and examine the state of the program in general.

Since this is Java, you should be able to use the exact same program as before, right? It isn't quite that simple. You might think the reference to System.out.println would be a problem since J-Stamp has no place to print a message. However, assuming the serial cable is in place, the IDE will display the message in a special window.

The problem with the original code is that it specifies the standard main function that takes a String array as an argument. With J-Stamp there is no way to provide a command line argument, so it looks for a main function with no arguments. Java, like C++, allows you to create different functions that have the same name, differing only in their argument lists. To uniquely identify a function like main , you have to include its argument list. A main() function is not the same as main(String[]) , and since J-Stamp's runtime code looks for main() , you must supply that function. So the example is simply:

public class FirstProg {
    public static void main() {
    System.out.println(“Hi World”);
    }
}

Not much of a change, but still a difference between the two versions. Of course, if you really didn't want to change the existing code, you could write a stub main method that calls the main(String []) method.

One nice feature of J-Stamp is the debugger. While it isn't as powerful as a Java debugger on a workstation, being able to track the flow of your program really improves your productivity.

Other differences

While TINI is similar to a workstation's JVM, J-Stamp is not. However, both devices have some differences from standard Java as well as each other.

TINI has some slight differences from standard Java. For example, while objects can have finalizers (similar to a C++ destructor, but asynchronous), the TINI code does not automatically call them. Some serialization, reflection, and transcendental math functions are also absent. The 1.01 version of TINI doesn't properly support join , which makes threaded code harder to write, but Dallas is planning on fixing that problem soon.

J-Stamp, however, has far more differences from standard Java. In particular:

  • The int type is 16 bits wide, instead of 32-bits.
  • The long type is not supported.
  • J-Stamp (like Java) doesn't support unsigned math. This causes problems with constants that have their high bit set (like 0xFA00) because the compiler will recognize this as too large to fit in a signed integer. With the 8-bit byte data type, the values range from –128 to 127. If you need unsigned bytes, use char which can range from 0 to 255.
  • Floating-point types (float and double ) are not supported.
  • There is no garbage collection. Once you allocate memory, it is never reclaimed.
  • Many standard Java class libraries are not available; others are different (because of data type differences, for example). In addition, J-Stamp has many libraries that don't appear in standard Java. These allow you to control the hardware and peripheral devices.
  • J-Stamp only supports one thread. However, you can manage multiple tasks with the Timer object.
  • J-Stamp strings and characters are composed of 1-byte ASCII characters, not 2-byte Unicode characters.
  • Interfaces are not available, although you can create abstract classes that other classes can extend.
  • The J-Stamp only supports single dimensioned arrays.

At first, this seems like quite a list. However, for embedded programming you often don't want the uncertainty of garbage collection, the performance hit of floating-point math, and the overhead of Unicode. The J-Stamp documentation proposes workaround solutions for most of these problems if they are important to you.

The real difference, of course, is what each device adds to standard Java. TINI, for example, has an entire class hierarchy devoted to communicating with 1-Wire devices. J-Stamp has a variety of classes to control digital I/O, generate PWM, and other specific microcontroller tasks.

One of the most interesting things about the J-Stamp is its use of Virtual Peripherals (VP). A VP is a built-in object that runs on a periodic interrupt. J-Stamp reserves a fixed number of slots for VPs; you can only have a limited number active at once. VPs allow you to do background processing without having to use threads (which J-Stamp does not support).

Perhaps the most common VP is the UART. This allows you to turn any one of J-Stamp's 16 I/O pins into a serial transmitter or receiver. If you want to transmit and receive, you'll have to use two VPs. Since the VPs operate as interrupt routines, the UART class can buffer characters, something the old Basic Stamp could not do.

Listing 1: A TINI example

import java.util.*;
import com.dalsemi.onewire.OneWireAccessProvider;
import com.dalsemi.onewire.adapter.DSPortAdapter;
import com.dalsemi.onewire.container.OneWireContainer12;
import com.dalsemi.system.BitPort;

public class Switch {

    OneWireContainer12[] buttons = new OneWireContainer12[4];
    byte[][] ary = new byte[4][];

     public static void pause(int ms) {
        try { Thread.sleep(ms); }
        catch (InterruptedException e) { }
    }

    public static void main(String args[]) throws Exception {
        System.out.println(“Here we go!”);
        DSPortAdapter pa = OneWireAccessProvider.getDefaultAdapter();
        pa.targetFamily(0x12); // find DS2406
        int i = 0;
        do {
            try {
                for (Enumeration e=pa.getAllDeviceContainers();
                 e.hasMoreElements();
                i++) {
                buttons[i] = (OneWireContainer12) e.nextElement();
                }
            }
            catch (Exception e) { System.out.println(“Exception”);}
        } while (i<>
        boolean b = true;
        for (i = 0; i<4; i++)="">
            ary[i] = buttons[i].readDevice();
            buttons[i].setLatchState(0,false,false,ary[i]);
            buttons[i].writeDevice(ary[i]);
        }

        while (true) {
            ary[0]=buttons[0].readDevice();
            if (!buttons[0].getLevel(0,ary[0])) {
                setLED(buttons[3],true,ary[3]);
                System.out.println(“On”);
            }
            ary[1]=buttons[1].readDevice();
            if (!buttons[1].getLevel(0,ary[1])) {
                setLED(buttons[3],false,ary[3]);
                System.out.println(“Off”);
            }
        }
    }

    synchronized static void setLED(int n, boolean state) throws Exception {
    ary[n] = buttons[n].readDevice();
    buttons[n].setLatchState(0,state,true,ary[n]);
    buttons[n].writeDevice(ary[n]);
    }
}

A TINI example

Have a look at Listing 1. This program accesses several DS2460 devices, which are 1-Wire devices that can monitor a switch and control an LED. Starting with the first portion of the code, you can identify several key points:

  • The OneWireContainer12 array will hold four DS2460 devices.
  • The pause routine simply sleeps for the specified number of milliseconds.
  • main locates the default 1-Wire adapter and searches for devices with a family code of 0x12 (the code for a DS2460). Then it fills the buttons array with the four devices it expects to find.
  • After finding the devices, the code reads each state, modifies it so that the LED for each device is off, and writes the state back to the device.
  • The final while loop within main acts like a flip-flop. When button 0 is active, the LED on device 3 turns on and stays on. When button 1 becomes active, this turns the LED off.
  • The helper function setLED handles the details of turning an LED on or off.

If you aren't familiar with 1-Wire, this may seem to be a lot of work just to light some LEDs, but the idea is that all of these devices are attached to a single wire (hence the name). This wire acts like a tiny network, and TINI controls that network using the specialized 1-Wire classes provided by Dallas.

Other than the special classes, programming TINI is similar to programming any Java platform. I've even compiled many open source programs (including a Web server) to run on TINI with very few, if any, changes.

The TINI example code includes a Web server that you can run directly or modify for your own purposes. In addition, an excellent Web server is available as open source that supports standard Java servlets. If you haven't encountered servlets before, these small Java programs extend a Web server and are used by many Java-aware servers.You can download the servlet development kit from Sun, and even practice writing servlets on your PC before you move to writing them for TINI. You can write custom servlets that allow you to interact with hardware attached to TINI without modifying the Web server's source code.

A J-Stamp example

Since J-Stamp doesn't use 1-Wire, an example flip-flop program wouldn't be a fair comparison. The main code would be as simple as this:

while (true) {
    if (CPU.readPin(CPU.pin0))
        CPU.writePin(CPU.pin3,true);
    if (CPU.readPin(CPU.pin1))
        CPU.writePin(CPU.pin3,false);
}

Listing 2 shows a more realistic example. This sends the current state to another device using the serial port.

Listing 2: A J-Stamp example

import jstamp.core.*;

public class SerialFlipFlop {

    final static int SERIAL_TX_PIN = CPU.pin2;
    final static int SERIAL_RTS_PIN = CPU.pin3;

    Uart txUart = new Uart( Uart.dirTransmit, SERIAL_TX_PIN, Uart.dontInvert,
                SERIAL_RTS_PIN, Uart.invert, Uart.speed14400, Uart.stop1 );

    public void go() {
        boolean state = false;

        while (true) {
            if    (CPU.readPin(CPU.pin0) && state == false) {
                state = true;
                txUart.sendString(“1”);
            }
            if    (CPU.readPin(CPU.pin1) && state == true) {
                state = false;
                txUart.sendString(“0”);
            }
        }
    }

    public static void main() {
     new SerialFlipFlop().go();
    }
}

Creating the Uart object automatically creates a VP. You can unload it later if you need its slot for another VP, but if you don't care, the VP automatically starts running and you never have to worry about it.

The Uart class, like all the VPs, looks like an ordinary Java class. However, it makes extensive use of native methods and you can't add VPs of your own design; only the ones provided by Parallax are available.

Instead of reading switches, J-Stamp can use its other sophisticated I/O commands to read a variety of sensors. For example, the CPU.pulseIn can measure a pulse width (useful for reading a tachometer, for example). You could use CPU.rcTime to measure the time it takes for a capacitor to charge (or discharge) through a resistor. With a known capacitor and a thermistor, you could measure temperature using this command. You can also measure other resistive or capacitive sensors like joysticks, hygristors, or level sensors.

Does one size fit all?

When faced with choices, it is only human nature to try to determine which is best. Of course, in many situations-including this one-best is a hard word to define. No single tool is best for every situation. Both of these devices are strong contenders, but comparing them is like contrasting the proverbial apple and orange.

TINI seems to be a natural choice for replacing a PC with a small, inexpensive module. The price tag is much less than a PC/104 board ($50 for a board with 512KB and $67 with 1MB of RAM). The built-in Ethernet port makes it simple to connect it to a network and use it as a Web server, or even a gateway between legacy devices and the network.

J-Stamp is not at all a PC replacement. However, it isn't supposed to be. J-Stamp's strength is that you can rapidly put together a system that has 16 versatile I/O pins. Remember, these pins aren't just for digital I/O; they can generate pulses, act as serial ports, and perform a host of other useful functions. In addition to the easy setup and design, J-Stamp offers a useful debugger that makes you even more efficient.

Both TINI and J-Stamp bring the power of Java to the embedded world. Although they seem superficially similar, they approach Java from different angles. If you understand the design goals of each device, you'll have no trouble selecting the right one for your application.

Al Williams got his start developing monitoring systems for the Strategic Petroleum Reserve nearly 20 years ago. Since then, he's developed systems around many microprocessors and in many different languages. Watch for Al's upcoming book on embedded Internet systems from McGraw Hill. His e-mail address is .

Editor's note: As we go to press, another company, Systronix, has announced a similar product called JStamp. Parallax and Systronix are now haggling over trademark ownership and it is not clear which product, if either, might wind up with a new name once this process is complete. ESP does not support either party in this dispute.

Back

Resources

Return to June 2001 Table of Contents

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.