7. Platform
The MicroEJ platform for MIMXRT595-EVK has been built against the MicroEJ Architecture for Cortex M33 (version 7.14.0) and the UI extension pack (version 13.0.5). This extension pack provides the library MicroUI-3.0, and this library has been designed:
- to replace a set of basic shapes renderings using a GPU instead of using software algorithms;
- to be extended by third-party UI libraries.
The MicroEJ platform for MIMXRT595-EVK provides some additional extended UI libraries to target the GCNanoLiteV GPU:
- VGLite : This library exposes the VGLite APIs to draw Vector Graphics. It allows drawing paths with either plain color (opaque and transparent) or gradient. It also allows applying matrix transformations dynamically to the rendered paths (translation, scale, rotation, perspective).
- VectorFont: This library allows to draw strings using TTF fonts. The rendered text can be filled with plain color or gradient. The text baseline can follow a line or a curve.
7.1. MicroUI Drawings
MicroUI provides several basic shapes rendering (pixel-oriented). MicroEJ platform for MIMXRT595-EVK overrides weak implementation (which performs the drawing in software) to use the GPU. The drawings are using the vg_lite APIs (i.e. vg_lite_blit
, vg_lite_draw
, …). The following functions are hardware accelerated (under the circumstances):
Shapes
- UI_DRAWING_fillRectangle
- UI_DRAWING_fillRoundRectangle
- UI_DRAWING_fillCircle
- UI_DRAWING_fillEllipse
- UI_DRAWING_fillCircleArc
- UI_DRAWING_fillEllipseArc
- DW_DRAWING_drawThickFadedPoint (fade == 1)
- DW_DRAWING_drawThickFadedLine (fade == 1)
- DW_DRAWING_drawThickFadedCircle (fade == 1)
- DW_DRAWING_drawThickFadedCircleArc (fade == 1)
- DW_DRAWING_drawThickFadedEllipse (fade == 1)
- DW_DRAWING_drawThickLine
- DW_DRAWING_drawThickCircle
- DW_DRAWING_drawThickEllipse
- DW_DRAWING_drawThickCircleArc
Images
- UI_DRAWING_drawImage (image not transparent)
- DW_DRAWING_drawFlippedImage (full image and not transparent)
- DW_DRAWING_drawRotatedImageNearestNeighbor (image not transparent)
- DW_DRAWING_drawRotatedImageBilinear (image not transparent)
- DW_DRAWING_drawScaledImageNearestNeighbor (image not transparent)
- DW_DRAWING_drawScaledImageBilinear (image not transparent)
MicroUI manages several RAW formats. A subset of these RAW formats is supported by the VG Lite blit
feature:
MicroUI RAW format | Bits per pixel | blit compatible format |
---|---|---|
ARGB8888 | 32 | VG_LITE_RGBA8888 |
RGB888 | 24 | |
RGB565 | 16 | VG_LITE_RGB565 |
ARGB1555 | 16 | VG_LITE_RGBA5551 |
ARGB4444 | 16 | VG_LITE_RGBA4444 |
A1 | 1 | |
A2 | 2 | |
A4 | 4 | VG_LITE_A4 |
A8 | 8 | VG_LITE_A8 |
C1 | 1 | |
C2 | 2 | |
C4 | 4 | |
AC11 | 2 | |
AC22 | 4 | |
AC44 | 8 | |
LARGB8888 | 8 | |
LRGB888 | 8 |
7.2. VG Lite Library
The MIMXRT595-EVK provides a native and a simulator implementation of the VGLite foundation library.
Both of these implementation support:
- The Vector Graphics APIs:
vg_lite_draw
vg_lite_draw_grad
- All matrix transformations.
For more detail about the VG Lite foundation library, see VG Lite Library.
Note
Clipping is managed using the MicroUI GraphicsContext setClip API.
7.2.1. Native Implementation
The VGLite foundation library is implemented over the vg_lite native library which uses the GCNanoLiteV GPU of the MIMXRT595-EVK.
Note
When a clip is applied to a MicroUI GraphicsContext, it will be internally managed using vg_lite scissor APIs.
7.2.2. Simulator Implementation
The MIMXRT595-VEE-IAR83 Virtual Device uses the Desktop rendering vector capabilities to render the MicroUI API for SVG, OpenVG, TrueType.
Note
The virtual device runs over Java2D which support vector graphics via Path2D. The default Java2D rendering quality is used, and the following information is ignored:
- VGLite path bounding box,
- VGLite drawing quality.
Warning
The following blending algorithms are not supported.
- VG_LITE_BLEND_SCREEN,
- VG_LITE_BLEND_MULTIPLY,
- VG_LITE_BLEND_ADDITIVE.
7.3. VectorFont Library
The VectorFont add-on library contains seven native methods which are implemented on board and simulator:
VectorFont.init()
: initializes the FreeType library which is used.VectorFont.loadTrueTypeFont(...)
: loads the font data from the file.VectorFontPainter.drawStringNative(...)
: draws a string.VectorFontPainter.drawStringArcNative(...)
: draws a curved string.VectorFont.stringWidthNative(...)
: computes the width (in pixels) of the string bounding box.VectorFontPainter.drawCharNative(...)
: draws a character.VectorFont.charWidthNative(...)
: computes the width (in pixels) of the character bounding box.LinearGradient.initNative(...)
: allocates a new gradient in memory.LinearGradient.closeNative(...)
: closes the gradient resource.
7.3.1. Native Implementation
The VectorFont native methods have been implemented in the low-level LLVECTOR_FONT
library. It is in
charge of the drawing algorithms: for each string’s character to draw, the corresponding glyph is
extracted using the FreeType library. A transformation matrix is computed
for each glyph to determine the character size and position on the screen based on the glyph metrics. A
renderer module for the FreeType engine, called ftvglite
, has been developed to render glyphs with the
VG Lite library. The transformation matrix and color information (alpha, gradient) to apply are set to
the renderer.
Note
The ftvglite
renderer is based on
Smooth rasterizer from the FreeType project. It has been modified to use VG Lite to render glyphs with the GPU.
Here is a summary of the LLVECTOR_FONT
natives:
VectorFont.init()
: is called at application startup. It initializes the FreeType library and sets the VG Lite renderer as the font renderer.VectorFont.loadTrueTypeFont(...)
: loads a font file from the given path and returns a handle of the allocated object. The font is loaded by the FreeType engine. A loaded font cannot be deallocated.VectorFontPainter.drawStringNative(...)
: draws a string loading each glyph character by character by FreeType library and rendering its outline with the VG Lite engine. Kerning information is used if available to compute character advance. VG Lite matrix implementation is used to compute transformations applied to each character (translation, rotation, scaling).VectorFontPainter.drawStringArcNative(...)
: draws a string around a circular arc. It uses almost the same techniques asdrawStringNative(...)
except that the transformations applied to each character are different.VectorFont.stringWidthNative(...)
: computes the string with the same algorithm asdrawStringNative(...)
but without rendering.VectorFontPainter.drawCharNative(...)
: draws a character loading its glyph with FreeType library and rendering its outline with the VG Lite engine. VG Lite matrix implementation is used to compute transformations applied to the character (translation, rotation, scaling).VectorFont.charWidthNative(...)
: computes the character with the same algorithm asdrawCharNative(...)
but without rendering.LinearGradient.initNative(...)
: allocates a new VG Lite gradient in memory.LinearGradient.closeNative(...)
: closes the gradient resource.
Note
FreeType is a free font engine written in C which supports many vector font formats. At the moment, the VectorFont the library only supports TrueType fonts (TTF).
7.3.2. Simulator
The implementation in the simulator relies on Java2D API, which natively supports TrueType fonts and gradient colors.
The drawString
methods (and the equivalent drawChars
) directly use Graphics2D.drawChars
from Java 2D API to
render text. The curved text implementation follows the same algorithm as the C native implementation and uses the
VG Lite Library implementation in the simulator to manage transformations.
Antialiasing is enabled on text rendering for drawString
and on global rendering for drawStringArc
.
VectorFont.init()
: does nothing on simulator.VectorFont.loadTrueTypeFont(...)
: loads a font file from the given path and returns a handle of the allocated object. It creates a newjava.awt.Font
with the given size, stored in a map to be retrieved by its handle.VectorFontPainter.drawStringNative(...)
: draws a string loading each glyph character by character directly using Graphics2D.drawChars from Java 2D API. Text antialiasing is set withRenderingHints.VALUE_TEXT_ANTIALIAS_ON
.VectorFontPainter.drawStringArcNative(...)
: draws a string around a circular arc. It uses almost the same techniques asdrawStringNative(...)
except that for each character, it extracts its shape and applies transformations with the transformation matrix from VG Lite Java API. The shape is then drawn withGraphics2D.fill
. Antialiasing is applied to shapes (RenderingHints.VALUE_ANTIALIAS_ON
).VectorFont.stringWidthNative(...)
: computes the string width as the sum of all its characters’ width.VectorFontPainter.drawCharNative(...)
: draws a character by extracting its shape and applying the given transformation matrix. The shape is then drawn withGraphics2D.fill
. Antialiasing is applied to the shape (RenderingHints.VALUE_ANTIALIAS_ON
).VectorFont.charWidthNative(...)
: returns the character bounding box width.LinearGradient.initNative(...)
: allocates a new instance ofjava.awt.LinearGradientPaint
.LinearGradient.closeNative(...)
: releases the gradient reference.
7.4. Network
7.4.1. Overview
The MicroEJ Platform provides a WiFi network service. It requires the connection of a Silicon Labs WF200 WiFi Expansion Kit (WF200 board) on the MIMXRT595-EVK board.
Once the WF200 board is connected to the MIMXRT595-EVK board, the MicroEJ application can use it.
The application uses the WiFi network service to connect an NTP server and update the watch date and time.
7.4.2. WF200 Board
The WF200 Expansion Kit board is developed by Silicon Labs.
It is connected to the MIMXRT595-EVK on the Non-Standard Arduino I/F connectors J27, J28, J29, J30 with a Nucleo Interposer board(v1.0 or v2.0). The Nucleo Interposer board can be requested from Silicon Labs with the WF200 board.
The NXP i.MX RT595 communicates with the WF200 devices using an SPI interface. The two switches on the WF200 board must be configured this way:
- Power source select switch: On-Board LDO.
- Host interface select switch: SPI.
NXP i.MX RT595 to WF200 signals connection table:
WF200 pin | WF200 Rasp. Pi Conn. | Nucleo Interposer V1.0 | Nucleo Interposer V2.0 | EVK RT595 | RT595 |
---|---|---|---|---|---|
SPI_MOSI | 19 | J6_14 | J6_14 | J28_4 | PIO5_1 |
SPI_MISO | 21 | J6_12 | J6_12 | J28_5 | PIO5_2 |
SPI_SCLK | 23 | J6_10 | J6_10 | J28_6 | PIO5_3 |
SPI_CS | 24 | J6_16 | J6_16 | J28_3 | PIO5_0 |
SPI_WIRQ | 36 | J6_18 | J6_18 | J28_2 | PIO4_29 |
GPIO_WIRQ | 31 | J6_20 | J6_20 | J28_1 | PIO4_28 |
GPIO_WUP | 32 | J4_4 | J4_2 | J27_7 | PIO4_26 |
RESETn | 33 | J4_2 | J4_1 | J27_8 | PIO4_27 |
The BSP automatically detects if a WF200 board is connected to the MIMXRT595-EVK board. If the WF200 board is not available, the FreeRTOS network tasks are not started, and the application behaves as if there was no network support.
If the MicroEJ Application does not use the network library, the MicroEJ Platform network code is not used (not linked in the binary file) even if a WF200 board is connected.
The WF200 connects a WiFi Access Point using credentials provided by the MicroEJ application.
7.4.3. Application
The MicroEJ Application uses a TimeService to define the date and time. The TimeService can be either a NetTimeService or the standard MicroEJ TimeService.
The NetTimeService requests the date and time to an NTP server. The standard MicroEJ Time Service requests the date and time from the MicroEJ Platform.
The NetTimeService induces a larger RAM size, a larger footprint, and extra MCU execution time. The application has been
developed to isolate the NetTimeService in a dedicated module. If this module is not used (not included in the com.microej.demo.watch.vglite
module.ivy file), the RAM size, FLASH size, MCU execution time are reduced.
The default NTP server is ntp.ubuntu.com:123
. Any other NTP server can be used.
The WiFi Access Point credentials are hardcoded in the NetTimeService class. They have to be updated before running the MicroEJ Application.
7.4.4. Implementation
By default, the NetTimeService is enabled in the application. The WiFi Access Point credentials still need to be provided.
Default credentials can be used, but a WiFi Access Point must be created as explained in WiFi Default Access Point.
These steps must be followed to configure the NetTimeService in the application:
- Ensure that the
com.microej.demo.watch.ntp
project is imported into MicroEJ SDK. - Ensure that the
com.microej.demo.watch.ntp
module dependency is included in thecom.microej.demo.watch.vglite
module.ivy file. - Set the Access Point Credentials in the
NetTimeService.java
file. - Set the NTP server in the
NetTimeService.java
file. - Run
Demo(Emb)
launcher in MicroEJ SDK. - Connect and configure the WF200 as explained in section WF200 Board.
- Build, link and deploy as usual.
On application startup, the connection to the WiFi Access point is performed, and if it is successful, an NTP request is made to the NTP server. It will update the date and time of the watchface. The watch hands are automatically moved to the new time position.
7.4.5. WiFi Default Access Point
The default WiFi Access Point SSID is RT595_demo
, and this is a WPA2 type Access Point that requires the password MicroEJ_Corp
.
This WiFi Access Point can be created using the HotSpot/Network sharing capability of an Android/IOS smartphone.
The following steps will create such Access Point:
- Open the Settings app.
- Select Wireless & Networks section.
- Choose Tethering & Portable Hotspot.
- Choose the
Set Up WiFi Hotspot
item to give the hotspot a name or SSID that must beRT595_demo
. - Select WPA2 as the security mode.
- Set password to
MicroEJ_Corp
. - Enable the WiFi Hotspot.
Once this Access Point is enabled, the application should be able to connect it and update the time and date from an NTP server.
7.4.6. Limitations
Using the NetTimeService brings some limitations to the watch demo:
- the boot time is increased as the MCU needs to initialize the WF200 device and the Network BSP stack.
- The Network BSP stack induces regular activity to monitor the different Network application message boxes. It has some effects on power consumption, even with the FlowerLP watchface.
- The watchfaces framerate could be slightly reduced during NTP requests.
7.4.7. Simulator
The simulator manages the MicroEJ Net library.
When the application runs on the simulator with the NetTimeService enabled, the WiFi Configuration mock windows pops up.
A new WiFi Access Point can be registered and saved. It will be available after a restart of the simulator.
The WiFi Access Point configuration can also be manually modified from the wifi/wificonfig.properties
file.
Warning
The simulator WiFi Configuration mock can not be used over a VPN network.
7.4.8. Disable Network
These steps must be followed to disable the NetTimeService in order to reduce the application footprint:
- Comment out the
com.microej.demo.watch.ntp
module in thecom.microej.demo.watch.vglite
module.ivy file. - (Optional) Resize the
core.memory.immortal.size
to 256 inbuild/common.properties
file then apply that modification in the launchers. - Empty the
Configuration -> Wi-Fi -> Wi-Fi configuration file
field of theDemo (Sim)
launcher. - Run
Demo(Emb)
launcher in MicroEJ SDK. - Build, link and deploy as usual.
7.5. Mono-Sandbox Firmware
The platform, the BSP, and the main application are designed to build a MicroEJ Multi-Sandbox Firmware (see Kernel Developer Guide). This chapter describes how to build a Mono-Sandbox Firmware instead of a Multi-Sandbox Firmware.
The main advantage is to reduce the RAM footprint. Indeed the Multi-Sandbox Firmware requires some large buffers (see Limitations). Consequently, the required memory banks must remain active, which prevents reducing the power consumption (see Power Management).
Note
The Mono-Sandbox Firmware format prevents installing additional watchfaces during the main application execution (see Compile Additional Watchface).
7.5.1. Mono-Sandbox Platform
A Mono-Sandbox Firmware can be built against a Multi-Sandbox Platform.
However, a Multi-Sandbox Platform requires implementing the low-level API of the Multi-Sandbox module (LLKERNEL_impl.h
), which becomes useless in the case of Mono-Sandbox Firmware.
- Open properties file
/mimxrt595_freertos-configuration/module.properties
. - Look for the property
com.microej.platformbuilder.module.multi.enabled
. - Change its value to
false
. - Rebuild the platform (see Platform Build).
Note
The Mono-Sandbox Platform stubs the Kernel & Features library. A RuntimeException
is thrown when a Kernel & Features API is called. However, this is not critical; the application will keep running.
7.5.2. Mono-Sandbox Application
The wearable application and the watchfaces have been designed to be Multi-Sandbox compatible using Kernel & Features library. This chapter does not describe how to remove the Kernel & Features library dependency: the application can run even if Kernel & Features API’s implementation throws some exceptions at runtime.
Run the main application on the simulator of the new platform (see Build the Demo). An exception is thrown on application startup; however, the application keeps running.
=============== [ Initialization Stage ] ===============
=============== [ Converting fonts ] ===============
=============== [ Converting images ] ===============
=============== [ Launching on Simulator ] ===============
Exception in thread "FeatureFinalizer" java.lang.RuntimeException
at java.lang.Throwable.fillInStackTrace(Throwable.java:82)
at java.lang.Throwable.<init>(Throwable.java:32)
at java.lang.Exception.<init>(Exception.java:14)
at java.lang.RuntimeException.<init>(RuntimeException.java:14)
at com.is2t.kf.KernelNatives.getNextStoppedFeatureToUpdate(KernelNatives.java:167)
at com.is2t.kf.FeatureFinalizer.run(FeatureFinalizer.java:38)
at java.lang.Thread.runWrapper(Thread.java:387)
Waiting for an application to be available
[WF Registry] Adding SportWatchface
[WF Registry] Adding FlowerWatchface
[WF Registry] Adding FlowerLPWatchface
[WF Registry] Starting SportWatchface
To prepare the compatibility with the Mono-Sandbox BSP, the main application must be very slightly modified.
It consists to not call the automatic features loader/installer service FeatureLoaderService
:
Open Java file
com.microej.Demo
.Comment the
FeatureLoaderService
registration in thekernelServiceRegistry
. The import block is automatically updated (the importscom.microej.demo.watch.util.services.FeatureLoaderService
andcom.microej.service.FeatureLoaderServiceImpl
are removed) :// [...] import com.nxp.rt595.util.PowerManagementHelper; import com.microej.demo.watch.util.services.ActivityService; import com.microej.demo.watch.util.services.HeartRateService; // [...] import com.microej.service.DefaultTimeService; import com.microej.service.HeartRateServiceImpl; // [...] public static void main(String[] args) { // [...] kernelServiceRegistry.register(PowerService.class, new PowerServiceImpl()); kernelServiceRegistry.register(StepsService.class, new StepsServiceImpl()); kernelServiceRegistry.register(ActivityService.class, new ActivityServiceImpl()); // kernelServiceRegistry.register(FeatureLoaderService.class, new FeatureLoaderServiceImpl()); // [...] }
Open Java file
com.nxp.rt595.util.PowerManagementHelper
.Comment the lines with
startService(FeatureLoaderService.class);
andstopService(FeatureLoaderService.class);
. The import block is automatically updated (the importcom.microej.demo.watch.util.services.FeatureLoaderService
is removed) :
// [...]
import com.microej.demo.watch.util.KernelServiceRegistry;
import com.microej.demo.watch.util.services.ActivityService;
import com.microej.demo.watch.util.services.HeartRateService;
import com.microej.demo.watch.util.services.NotificationService;
// [...]
private static void applyPerfProfile(int profile) {
// Start/Stop services depending of profile
switch (profile) {
case PERF_PROFILE_MAX_PERFS:
startService(StepsService.class);
startService(HeartRateService.class);
startService(PowerService.class);
startService(NotificationService.class);
startService(ActivityService.class);
//startService(FeatureLoaderService.class);
break;
case PERF_PROFILE_POWER_SAVING:
stopService(StepsService.class);
stopService(HeartRateService.class);
stopService(PowerService.class);
stopService(NotificationService.class);
stopService(ActivityService.class);
//stopService(FeatureLoaderService.class);
break;
default:
throw new IllegalArgumentException();
}
// [...]
}
- Build the application as usual.
If these steps are not performed, some errors will occur during the IAR linker step:
Error[Li005]: no definition for "Java_com_microej_kernel_FeatureInputStream_isFeatureAvailable" [referenced from [...]\mimxrt595_freertos-bsp\
projects\microej\platform\lib\microejapp.o]
Error[Li005]: no definition for "Java_com_microej_kernel_FeatureInputStream_init" [referenced from [...]\mimxrt595_freertos-bsp\projects\microej\
platform\lib\microejapp.o]
Error[Li005]: no definition for "Java_com_microej_kernel_FeatureInputStream_readIntoArray" [referenced from [...]\mimxrt595_freertos-bsp\
projects\microej\platform\lib\microejapp.o]
Error[Li005]: no definition for "Java_com_microej_kernel_FeatureInputStream_closeFeature" [referenced from [...]\mimxrt595_freertos-bsp\
projects\microej\platform\lib\microejapp.o]
Error while running Linker
7.5.3. Mono-Sandbox BSP
As described in BSP Architecture, the kf
group in the IAR project implements the low-level APIs of Multi-Sandbox Firmware and the automatic features loader/installer FeatureInputStream
.
First, disable these useless low-level API implementations:
- Open IAR project.
- Right-click on group
source / kf
. - Open the
Options...
window. - Check
Exclude from build
. - Click on
OK
.
Multi-Sandbox Firmware’s large buffers are now useless.
IAR does not allocate these buffers during the linker step because there are not referenced in the BSP.
However, the ram partition used are still powered on by default . The lowpower/src/power_manager.c
must be updated to improve the low-power consumption.
Some calls to the feature loader bsp API must also be commented out.
- Open linker file
/mimxrt595_freertos-bsp/projects/microej/lowpower/src/power_manager.c
. - Comment out all calls to
set_ram_partitions_power()
with&m_fo_start, &m_fo_end
or&m_kf_start, &m_kf_end
arguments. - Comment out calls to
USART_Feature_Loader_Enable();
andUSART_Feature_Loader_Disable();
. - Save the
power_manager.c
file.
Finally, build the BSP as usual and deploy the application on board. The same exception than the simulator is thrown; the application ignores it and keeps running.