This chapter describes the interfaces and classes for embedded memory-mapped input and output (MMIO).
Memory mapped I/O is typically used for controlling hardware peripherals by reading from and writing to registers or memory blocks mapped to the hardware's system memory. The MMIO API allows for low-level control over the peripheral.
In order to access a specific memory block that a device has been mapped to, an application should first open and obtain an MMIODevice
instance for the memory-mapped I/O device, using its numerical ID, name, type (interface) or properties. This is an example of using the ID.
MMIODevice device = (MMIODevice) PeripheralManager.open(7);
This is an example of using its name and interface.
MMIODevice device = (MMIODevice) PeripheralManager.open("RTC", MMIODevice.class, null);
Once the peripheral is opened, the application can retrieve registers using methods of the MMIODevice
interface such as the MMIODevice.getByteRegister(String)
method.
RawByte seconds = (RawByte) device.getByteRegister("Seconds");
When done, the application should call the Peripheral.close()
method to release MMIO device.
device.close();
The following code give examples of using the MMIO API to communicate Real Time Clock device.
import com.oracle.deviceaccess.PeripheralException; import com.oracle.deviceaccess.PeripheralManager; import com.oracle.deviceaccess.PeripheralNotAvailableException; import com.oracle.deviceaccess.mmio.MMIODevice; import com.oracle.deviceaccess.mmio.MMIOEvent; import com.oracle.deviceaccess.mmio.MMIOEventListener; import com.oracle.deviceaccess.mmio.RawBlock; import com.oracle.deviceaccess.mmio.RawByte; import java.io.IOException; public class MMIOExample { static final int INTERRUPT = 0; MMIODevice rtc = null; public MMIOExample() { try { rtc = (MMIODevice) PeripheralManager.open("RTC", MMIODevice.class, (String[]) null); //The RTC device has 14 bytes of clock/control registers and 50 bytes // of general purpose RAM (see data sheet of the HITACHI HD146818 RTC) RawByte seconds = rtc.getByteRegister("Seconds"); RawByte secAlarm = rtc.getByteRegister("SecAlarm"); RawByte minutes = rtc.getByteRegister("Minutes"); RawByte minAlarm = rtc.getByteRegister("MinAlarm"); RawByte hours = rtc.getByteRegister("Hours"); RawByte hrAlarm = rtc.getByteRegister("HrAlarm"); RawByte registerA = rtc.getByteRegister("RegisterA"); RawByte registerB = rtc.getByteRegister("RegisterB"); RawByte registerC = rtc.getByteRegister("RegisterC"); RawByte registerD = rtc.getByteRegister("RegisterD"); RawBlock userRAM = rtc.getBlock("UserRam"); } catch (PeripheralException pe) { } catch (IOException ioe) { } finally { if (rtc != null) { try { rtc.close(); } catch (IOException ex) { } } } } // Sets the daily alarm for after some delay public void setAlarm(byte delaySeconds, byte delayMinutes, byte delayHours) throws IOException, PeripheralException { MMIODevice rtc = (MMIODevice) PeripheralManager.open("RTC", MMIODevice.class, (String[]) null); RawByte seconds = rtc.getByteRegister("Seconds"); RawByte secAlarm = rtc.getByteRegister("SecAlarm"); RawByte minutes = rtc.getByteRegister("Minutes"); RawByte minAlarm = rtc.getByteRegister("MinAlarm"); RawByte hours = rtc.getByteRegister("Hours"); RawByte hrAlarm = rtc.getByteRegister("HrAlarm"); RawByte registerB = rtc.getByteRegister("RegisterB"); // Directly read from/write to the registers using RawByte instances. byte currentSeconds = seconds.get(); byte currentMinutes = minutes.get(); byte currentHours = hours.get(); int i = (currentSeconds + delaySeconds) % 60; int j = (currentSeconds + delaySeconds) / 60; secAlarm.set((byte) i); i = (currentMinutes + delayMinutes + j) % 60; j = (currentMinutes + delayMinutes + j) / 60; minAlarm.set((byte) i); i = (currentHours + delayHours + j) % 24; hrAlarm.set((byte) i); rtc.setMMIOEventListener(INTERRUPT, new MMIOEventListener() { public void eventDispatched(MMIOEvent event) { try { MMIODevice rtc = (MMIODevice) event.getPeripheral(); RawByte registerC = rtc.getByteRegister("RegisterC"); // Check the Alarm Interrupt Flag (AF) if ((registerC.get() & 0X20) != 0) { // Notify application of alarm } } catch (IOException ex) { } catch (PeripheralNotAvailableException ex) { } } }); // Set the Alarm Interrupt Enabled (AIE) flag registerB.set((byte) (registerB.get() | 0X20)); } }
Alternatively, in this example, the value of RegisterC
could be automatically captured upon occurrence of an interrupt request from the Real Time Clock device as follows:
rtc.setMMIOEventListener(INTERRUPT, "RegisterC", new MMIOEventListener() { public void eventDispatched(MMIOEvent event) { byte v = (byte) event.getCapturedRegisterValue(); // Check the Alarm Interrupt Flag (AF) if ((v & 0X20) != 0) { // Notify application of alarm } } });
MMIO devices are opened by invoking one of the com.oracle.deviceaccess.PeripheralManager.open()
methods. The com.oracle.deviceaccess.mmio
permission allows access to be granted to MMIO devices as a whole. This permission must be requested in the JAD file under MIDlet-Permissions
or MIDlet-Permissions-Opt
, and the application must be digitally signed by a trusted authority to gain access to the APIs. Alternatively, the permission may be allowed for all applications in the untrusted
domain of the security policy file (policy.txt
).
Note that version 3.3 of the Oracle Java ME Embedded platform has discarded all functions from version 3.2 that employed the long
datatype.
The MMIODevice
class provides methods to retrieve memory-mapped registers and memory blocks of a peripheral device. Each memory-mapped I/O device is identified by a numerical ID and by a name. An MMIODevice
instance can be acquired by a call to MMIOManager.getDevice(int)
or MMIOManager.getDevice(java.lang.String)
.With memory-mapped I/O, peripheral devices can be controlled by directly reading or writing to memory areas representing the registers or memory blocks of the peripheral device. Each register or memory block is represented by a RawMemory
instance. All the mapped registers, including memory blocks, of an MMIO device can be retrieved by a call to the appropriate get...Registers()
method. The RawMemory
instance associated to a register has a fixed, determined index in the array returned by those methods. Each register or memory block is also usually assigned a name that can be used for name-based lookup.An application can register an MMIOEventListener
instance to monitor native events of the designated type fired by the peripheral device. To register a MMIOEventListener
instance, the application must call the setMMIOEventListener(int, MMIOEventListener)
method. The registered listener can later on be removed by calling the same method with a null
parameter. Asynchronous notification might not be supported by all memory-mapped devices. An attempt to set a listener on a memory-mapped device that does not supports it throws an InvalidOperationException
.
The MMIODevice
interface consists of the following methods:
RawBlock getAsRawBlock() throws java.io.IOException, PeripheralNotAvailableException
This method retrieves the complete memory area this device is mapped to as a RawBlock
instance.
RawBlock getBlock(java.lang.String name) throws java.io.IOException, PeripheralNotAvailableException
This method retrieves the designated memory block.
int getByteOrdering() throws java.io.IOException, PeripheralNotAvailableException
This method returns the byte ordering of this memory-mapped peripheral device. The three possible values are MMIODevice.BIG_ENDIAN
if big-endian, MMIODevice.LITTLE_ENDIAN
if little-endian, and MMIODevice.MIXED_ENDIAN
otherwise.
RawByte getByteRegister(java.lang.String name) throws java.io.IOException, PeripheralNotAvailableException
This method retrieves the designated register holding a byte value.
RawShort getShortRegister(java.lang.String name) throws java.io.IOException, PeripheralNotAvailableException
This method retrieves the designated register holding a short value.
RawInt getIntRegister(java.lang.String name) throws java.io.IOException, PeripheralNotAvailableException
This method retrieves the designated register holding an int value.
void setMMIOEventListener(int eventId, MMIOEventListener listener) throws java.io.IOException, PeripheralNotAvailableException
This method registers a MMIOEventListener
instance to monitor native events of the designated type fired by the peripheral device mapped to this MMIODevice
object. While the listener can be triggered by hardware interrupts, there are no real-time guarantees of when the listener is called. If the listener parameter is null,
the listener previously registered for the specified event type is removed. Only one listener can be registered at a particular time for a particular event type.
void setMMIOEventListener(int eventId, String capturedName, MMIOEventListener listener) throws java.io.IOException, PeripheralNotAvailableException
This method registers a MMIOEventListener
instance to monitor native events of the designated type fired by the peripheral device mapped to this MMIODevice
object. The captureName
parameter indicates the name of the register or memory block whose content is to be captured at the time of the underlying event occurs. While the listener can be triggered by hardware interrupts, there are no real-time guarantees of when the listener is called. If the listener parameter is null,
the listener previously registered for the specified event type is removed. Only one listener can be registered at a particular time for a particular event type.
void setMMIOEventListener(int eventId, byte[] captureBuffer, int capturedIndex, int capturedLength, MMIOEventListener listener) throws java.io.IOException, PeripheralNotAvailableException
This method registers a MMIOEventListener
instance to monitor native events of the designated type fired by the peripheral device mapped to this MMIODevice
object. When the event occurs, the memory is captured in the specified byte buffer, starting at the designated index and length. While the listener can be triggered by hardware interrupts, there are no real-time guarantees of when the listener is called. If the listener parameter is null,
the listener previously registered for the specified event type is removed. Only one listener can be registered at a particular time for a particular event type.
The MMIOEventListener
interface defines methods for getting notified of events fired by peripherals mapped to memory. A MMIOEventListener
can be registered using the MMIODevice.setMMIOEventListener(int, MMIOEventListener)
method.
The interface consists of only one method, void eventDispatched(MMIOEvent event)
. This method is invoked when an event is fired by a memory-mapped peripheral.
The RawMemory
interface provides generic methods for the different types of raw memory area to which a peripheral device's registers may be mapped.
The interface consists of only one method, java.lang.String getName()
. This method returns the name assigned to this RawMemory
instance.
The RawBlock
interface provides methods to access a continuous range of physical memory (raw memory). A RawBlock
instance can be obtained from a MMIODevice
instance. The index values map to physical memory addresses and are measured in bytes. The index values are relative to the base address of the raw memory area. The index value 0 corresponds to the base address of raw memory area. The byte ordering of the underlying raw memory area can be retrieved using the MMIODevice.getByteOrdering()
method.
The RawBlock
interface consists of the following methods:
This method returns the size in bytes of the raw memory area associated with this object.
This method reads the byte
at the given index in the raw memory area associated with this object.
void getBytes(int index, byte[] dst, int offset, int length)
This method reads bytes starting at the given index in the raw memory area associated with this object.
This method reads the int
at the given index in the raw memory area associated with this object.
void getInts(int index, int[] dst, int offset, int length)
This method reads integers starting at the given index in the raw memory area associated with this object.
This method reads the short
at the given index in the raw memory area associated with this object.
void getShorts(int index, short[] dst, int offset, int length)
This method reads short integers starting at the given index in the raw memory area associated with this object.
void setByte(int index, byte value)
This method writes the given byte
at the given index in the raw memory area associated with this object.
void setBytes(int index, byte[] src, int offset, int length)
This method writes bytes starting at the given index in the raw memory area associated with this object.
void setInt(int index, int value)
This method writes the given int
at the given index in the raw memory area associated with this object.
void setInts(int index, int[] src, int offset, int length)
This method writes integers starting at the given index in the raw memory area associated with this object.
The RawByte
interface provides methods for setting and getting the value of a register or memory area holding a byte value. A RawByte
instance can be obtained from a MMIODevice
instance.
The RawInt
interface provides methods for setting and getting the value of a register or memory area holding an int value. A RawInt
instance can be obtained from a MMIODevice
instance.
The RawShort
interface provides methods for setting and getting the value of a register or memory area holding a short value. A RawShort
instance can be obtained from a MMIODevice
instance.
The MMIOEvent
class encapsulates events fired by peripherals mapped to memory. The MMIOEvent
class consists of the following constructors and methods.
public MMIOEvent(MMIODevice device, int id)
This constructor creates a new MMIOEvent
with the specified device and ID. It is then time-stamped with the current time.
public MMIOEvent(MMIODevice device, int id, long timeStamp, int timeStampMicros)
This constructor creates a new MMIOEvent
with the specified device, ID and timestamp.
public MMIOEvent(MMIODevice device, int id, int capturedRegisterValue, long timeStamp, int timeStampMicros)
This constructor creates a new MMIOEvent
with the specified value and timestamp. The capturedRegisterValue
parameter is the captured value of the register designated upon registration, specified as a 32-bit integer.
public MMIOEvent(MMIODevice device, int id, byte[] capturedMemoryContent, long timeStamp, int timeStampMicros)
This constructor creates a new MMIOEvent
with the specified value and timestamp. The capturedRegisterContent
parameter is the captured content of the memory area or memory block designated upon registration.
The MMIODeviceConfig
class encapsulates the hardware addressing information, and static and dynamic configuration parameters of an MMIO device.Some hardware addressing parameter, and static and dynamic configuration parameters may be set to PeripheralConfig.DEFAULT
. Whether such default settings are supported is platform- as well as peripheral driver-dependent.An instance of MMIODeviceConfig
can be passed to the PeripheralManager.open(PeripheralConfig)
or PeripheralManager.open(Class, PeripheralConfig)
method to open the designated MMIO device with the specified configuration. A PeripheralConfigInvalidException
is thrown when attempting to open a peripheral device with an invalid or unsupported configuration.
The MMIODeviceConfig
class itself contains three nested classes.
static class MMIODeviceConfig.RawBlockConfig
The RawBlockConfig
class encapsulates the configuration parameters of a memory block.
static class MMIODeviceConfig.RawMemoryConfig
The RawMemoryConfig
class encapsulates the configuration parameters of a generic raw memory area.
static class MMIODeviceConfig.RawRegisterConfig
The RawRegisterConfig
class encapsulates the configuration parameters of a register.
The MMIODeviceConfig
class also contains three constants.
public static final int REGISTER_TYPE_BYTE
This is the type for a register holding a byte value.
public static final int REGISTER_TYPE_INT
This is the type for a register holding an integer value.
public static final int REGISTER_TYPE_SHORT
This is the type for a register holding a short integer value.
Finally, the MMIODeviceConfig
class consists of one constructor and four accessors.
public MMIODeviceConfig(long address, int size, int byteOrdering, MMIODeviceConfig.RawMemoryConfig[] memConfigs)
This constructor creates a new MMIODeviceConfig
with the specified hardware addressing information and configuration parameters. Note that if no raw block and raw register configuration is provided, the specified memory area will be mapped to the RawBlock
instance returned by a call to MMIODevice.getAsRawBlock()
.
This method returns the configured memory address of the MMIO device.
This method returns the configured byte ordering of the MMIO device.
public MMIODeviceConfig.RawMemoryConfig[] getRawMemoryConfigs()
This method returns the set of configured registers and memory blocks.
This method returns the configured size of the memory-mapped area of the MMIO device.
The abstract MMIODeviceConfig.RawMemoryConfig
class encapsulates the configuration parameters of a generic raw memory area. The abstract class consists of two methods.
The MMIODeviceConfig.RawBlockConfig
class extends the abstract MMIODeviceConfig.RawMemoryConfig
class and encapsulates the configuration parameters of a memory block. The class consists of one constructor and one accessor.
The MMIODeviceConfig.RawRegisterConfig
class extends the abstract MMIODeviceConfig.RawMemoryConfig
class and encapsulates the configuration parameters of a register. The class consists of one constructor and one accessor.
public MMIODeviceConfig.RawRegisterConfig(int offset, java.lang.String name, int type)
This constructor creates a new RawRegisterConfig
with the provided parameters.
This method returns the configured type of the value held by the register. See the constants in the MMIODeviceConfig
for possible values.
The MMIOEvent
class encapsulates events fired by peripherals mapped to memory..The class consists of four constructors and three methods.
public MMIOEvent(MMIODevice device, int id)
This constructor creates a new MMIOEvent
with the specified value and time-stamped with the current time.
public MMIOEvent(MMIODevice device, int id, byte[] capturedMemoryContent, long timeStamp, int timeStampMicros)
This constructor creates a new MMIOEvent
with the specified values and timestamp.
public MMIOEvent(MMIODevice device, int id, int capturedRegisterValue, long timeStamp, int timeStampMicros)
This constructor creates a new MMIOEvent
with the specified values and timestamp.
public MMIOEvent(MMIODevice device, int id, long timeStamp, int timeStampMicros)
This constructor creates a new MMIOEvent
with the specified value and timestamp.
public byte[] getCapturedMemoryContent()
This method returns the captured content of the memory area or memory block designated upon registration.
public int getCapturedRegisterValue()
This method returns the captured value of the register designated upon registration as a 32-bit integer.
This method returns the event ID.