Create a MicroEJ Firmware From Scratch

This tutorial explains how to create a MicroEJ Firmware from scratch. It goes trough the typical steps followed by a Firmware developer integrating MicroEJ with a C Board Support Package (BSP) for a target device.

In this tutorial, the target device is a a Luminary Micro Stellaris. Though this device is no longer available on the market, it has two advantages:

  • The QEMU PC System emulator can emulate the device.
  • FreeRTOS provides an official Demo BSP.

Consequently, no board is required to follow this tutorial. Everything is emulated on the developer’s PC.

The tutorial should take 1 hour to complete (excluding the installation time of MicroEJ SDK and Windows Subsystem Linux (WSL)).

Intended Audience

The audience for this document is Firmware engineers who want to understand how MicroEJ is integrated to a C Board Support Package.

In addition, this tutorial should be of interest to all developers wishing to familiarize themselves with the low level components of a MicroEJ Firmware such as: MicroEJ Architecture, MicroEJ Platform, Low Level API and BSP connection.

Introduction

The following steps are usually followed when starting a new project:

  1. Pick a target device (that meets the requirements of the project).
  2. Setup a RTOS and a toolchain that support the target device.
  3. Adapt the RTOS port if needed.
  4. Install a MicroEJ Architecture that matches the target device/RTOS/toolchain.
  5. Setup a new MicroEJ Platform connected to the Board Support Package (BSP).
  6. Implement Low Level API.
  7. Validate the resulting MicroEJ Platform with the Platform Qualification Tools (PQT).
  8. Develop the MicroEJ Application.

This tutorial describes step by step how to go from the FreeRTOS BSP to a MicroEJ Application that runs on the MicroEJ Platform and prints the classic "Hello, World!".

In this tutorial:

  • The target device is a Luminary Micro Stellaris which is emulated by QEMU (QEMU Stellaris boards).
  • The RTOS is FreeRTOS and the toolchain is GNU CC fo ARM.

All modifications to FreeRTOS BSP made for this tutorial are available at https://github.com/MicroEJ/FreeRTOS/tree/tuto-microej-firmware-from-scratch.

Note

The implementation of the Low Level API and their validation with the Platform Qualification Tools (PQT) will be the topic of another tutorial.

Prerequisites

A code editor such as Visual Studio Code is also recommended to edit BSP files.

Overview

The next sections describe step by step how to build a MicroEJ Firmware that runs a HelloWorld MicroEJ Application on the emulated device.

The steps to follow are:

  1. Setup the development environment (assuming the prerequisites are satisfied).
  2. Get a running BSP
  3. Build the MicroEJ Platform
  4. Create the HelloWorld MicroEJ Application
  5. Implement the minimum Low Level API to run the application

This tutorial goes through trials and errors every Firmware developers may encounter. It provides a solution after each error rather than providing the full solution in one go.

Setup the Development Environment

This section assumes the prerequisites have been properly installed.

In WSL:

  1. Update apt’s cache: sudo apt-get update
  2. Install qemu-system-arm and GNU CC toolchain for ARM: sudo apt-get install -y qemu-system-arm gcc-arm-none-eabi build-essential subversion
  3. The rest of this tutorial will use the folder src/tuto-from-scratch/ in the Windows home folder.
  4. Create the folder: mkdir -p /mnt/c/Users/${USER}/src/tuto-from-scratch (the -p option ensures all the directories are created).
  5. Go into the folder: cd /mnt/c/Users/${USER}/src/tuto-from-scratch/
  6. Clone FreeRTOS and its submodules: git clone -b V10.3.1 --recursive https://github.com/FreeRTOS/FreeRTOS.git (this may takes some time)

Note

Use the right-click to paste from the Windows clipboard into WSL console. The right-click is also used to copy from the WSL console into the Windows clipboard.

Get Running BSP

This section presents how to get running BSP based on FreeRTOS that boots on the target device.

  1. Go into the target device sub-project: cd FreeRTOS/FreeRTOS/Demo/CORTEX_LM3S811_GCC

  2. Build the project: make

    Ignoring the warnings, the following error appears during the link:

    CC    hw_include/osram96x16.c
    LD    gcc/RTOSDemo.axf
    arm-none-eabi-ld: section .text.startup LMA [0000000000002b24,0000000000002c8f] overlaps section .data LMA [0000000000002b24,0000000000002b27]
    make: *** [makedefs:191: gcc/RTOSDemo.axf] Error 1
    

    Insert the following fixes in the linker script file named standalone.ld (thanks to http://roboticravings.blogspot.com/2018/07/freertos-on-cortex-m3-with-qemu.html).

    Note

    WSL can start the editor Visual Studio Code. type code . in WSL. . represents the current directory in Unix.

    diff --git a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/standalone.ld b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/standalone.ld
    --- a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/standalone.ld
    +++ b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/standalone.ld
    @@ -42,7 +42,15 @@ SECTIONS
             _etext = .;
         } > FLASH
    
    -    .data : AT (ADDR(.text) + SIZEOF(.text))
    +    .ARM.exidx :
    +    {
    +        *(.ARM.exidx*)
    +        *(.gnu.linkonce.armexidx.*)
    +    } > FLASH
    +
    +    _begin_data = .;
    +
    +    .data : AT ( _begin_data )
         {
             _data = .;
             *(vtable)
    

    This is the output of the git diff command. Lines starting with a - should be removed. Lines starting with a + should be added.

    Note

    The patch(1) can be used to apply the patch. Assuming WSL shell is in FreeRTOS/Demo/CORTEX_LM3S811_GCC directory:

    1. Install dos2unix utility: sudo apt install dos2unix
    2. Convert all files to unix line-ending: find -type f -exec dos2unix {} \;
    3. Copy the content of the code block in a file named linker.patch (every lines of the code block must be copied in the file).
    4. Apply the patch: patch -l -p4 < linker.patch.

    It is also possible to paste the diff directly into the console:

    1. In WSL, invoke patch -l -p4. The command starts, waiting for input on stdin (the standard input).
    2. Copy the diff and paste it in WSL
    3. Press enter
    4. Press Ctrl-d Ctrl-d (press the Control key + the letter d twice).
  3. Run the build again: make

  4. Run the emulator with the generated kernel: qemu-system-arm -M lm3s811evb -nographic -kernel gcc/RTOSDemo.bin

    The following error appears and then nothing:

    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    ssd0303: error: Unknown command: 0x80
    ssd0303: error: Unexpected byte 0xe3
    
  5. Press Ctrl-a x (press Control + the letter a, release, press x) to the end the QEMU session. The session ends with QEMU: Terminated.

    Note

    The errors can be safely ignored. They occur because the OLED controller emulated receive incorrect commands.

At this point, the target device is successfully booted with the FreeRTOS kernel.

FreeRTOS Hello World

This section describes how to configure the BSP to print text on the QEMU console.

The datasheet of the target device (LM3S811 datasheet) describes how to use the UART device and an example implementation for QEMU is available here).

Here is the patch that implements putchar(3) and puts(3) and prints Hello World.

diff --git a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
--- a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
+++ b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
@@ -134,9 +134,25 @@ SemaphoreHandle_t xButtonSemaphore;
 QueueHandle_t xPrintQueue;

 /*-----------------------------------------------------------*/
+#define UART0BASE ((volatile int*) 0x4000C000)
+
+int putchar (int c){
+    (*UART0BASE) = c;
+    return c;
+}
+
+int puts(const char *s) {
+    while (*s) {
+        putchar(*s);
+        s++;
+    }
+    return putchar('\n');
+}

 int main( void )
 {
+    puts("Hello, World! puts function is working.");
+
    /* Configure the clocks, UART and GPIO. */
    prvSetupHardware();

Rebuild and run the newly generated kernel: make && qemu-system-arm -M lm3s811evb -nographic -kernel gcc/RTOSDemo.bin (press Ctrl-a x to interrupt the emulator).

make: Nothing to be done for 'all'.
Hello, World! puts function is working.
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
ssd0303: error: Unknown command: 0x80
ssd0303: error: Unexpected byte 0xe3
QEMU: Terminated

With this two functions implemented, printf(3) is also available.

diff --git a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
--- a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
+++ b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
@@ -149,9 +149,11 @@ int puts(const char *s) {
        return putchar('\n');
 }

+#include <stdio.h>
+
 int main( void )
 {
-       puts("Hello, World! puts function is working.");
+       printf("Hello, World! printf function is working.\n");

        /* Configure the clocks, UART and GPIO. */
        prvSetupHardware();

At this point, the character output on the UART is implemented in the FreeRTOS BSP. The next step is to create the MicroEJ Platform and MicroEJ Application.

Create a MicroEJ Platform

This section describes how to create and configure a MicroEJ Platform compatible with the FreeRTOS BSP and GCC toolchain.

  • A MicroEJ Architecture is a software package that includes the MicroEJ Runtime port to a specific target Instruction Set Architecture (ISA) and C compiler. It contains a set of libraries, tools and C header files. The MicroEJ Architectures are provided by MicroEJ SDK.
  • A MicroEJ Platform is a port of a MicroEJ Architecture for a custom device. It contains the MicroEJ configuration and the BSP (C source files).

When selecting a MicroEJ Architecture, special care must be taken to ensure the compatibility between the toolchain used in the BSP and the toolchain used to build the MicroEJ Core Engine included in the MicroEJ Architecture.

The list of MicroEJ Architectures supported is listed here. MicroEJ Evaluation Architectures provided by MicroEJ Corp. can be downloaded from MicroEJ Architectures Repository.

There is no CM3 in MicroEJ Architectures Repository and the Arm® Cortex®-M3 MCU is not mentioned in the capabilities matrix. This means that the MicroEJ Architectures for Arm® Cortex®-M3 MCUs are no longer distributed for evaluation. Download the latest MicroEJ Architecture for Arm® Cortex®-M0 instead (the Arm® architectures are binary upward compatible from Arm®v6-M (Cortex®-M0) to Arm®v7-M (Cortex®-M3)).

Import the MicroEJ Architecture

This step describes how to import a MicroEJ Architecture.

  1. Start MicroEJ SDK on an empty workspace. For example, create an empty folder workspace next to the FreeRTOS git folder and select it.
  2. Keep the default MicroEJ Repository
  3. Download the latest MicroEJ Architecture for Arm® Cortex®-M0 instead: https://repository.microej.com/modules/com/microej/architecture/CM0/CM0_GCC48/flopi0G22/7.14.0/flopi0G22-7.14.0-eval.xpf
  4. Import the MicroEJ Architecture in MicroEJ SDK
    1. File > Import > MicroEJ > Architectures
    2. select the MicroEJ Architecture file downloaded
    3. Accept the license and click on Finish
../_images/tuto_microej_fw_from_scratch_import_architecture.PNG

Install an Evaluation License

This step describes how to create and activate an Evaluation License for the MicroEJ Architecture previously imported.

  1. Select the Window > Preferences > MicroEJ > Architectures menu.
  2. Click on the architectures and press Get UID.
  3. Copy the UID. It will be needed when requesting a license.
  4. Go to https://license.microej.com.
  5. Click on Create a new account link.
  6. Create an account with a valid email address. A confirmation email will be sent a few minutes after. Click on the confirmation link in the email and login with the account.
  7. Click on Activate a License.
  8. Set Product P/N: to 9PEVNLDBU6IJ.
  9. Set UID: to the UID generated before.
  10. Click on Activate.
    • The license is being activated. An activation mail should be received in less than 5 minutes. If not, please contact contact our support team.
    • Once received by email, save the attached zip file that contains the activation key.
  11. Go back to Microej SDK.
  12. Select the Window > Preferences > MicroEJ menu.
  13. Press Add….
  14. Browse the previously downloaded activation key archive file.
  15. Press OK. A new license is successfully installed.
  16. Go to Architectures sub-menu and check that all architectures are now activated (green check).
  17. Microej SDK is successfully activated.
../_images/tuto_microej_fw_from_scratch_activate_license.PNG

Create the MicroEJ Platform

This step describes how to create a new MicroEJ Platform using the MicroEJ Architecture previously imported.

  1. Select File > New > Platform Project.

  2. Ensure the Architecture selected is the MicroEJ Architecture previously imported.

  3. Ensure the Create from a platform reference implementation box is unchecked.

  4. Click on Next button.

  5. Fill the fields:

    • Set Device: to lm3s811evb
    • Set Name: to Tuto
../_images/tuto_microej_fw_from_scratch_create_platform.PNG

Setup the MicroEJ Platform

This step describes how to configure the MicroEJ Platform previously created. For more information on this topic, please refer to Platform Configuration.

The Platform Configuration Additions provide a flexible way to configure the BSP connection between the MicroEJ Platform and MicroEJ Application to the BSP. In this tutorial, the Partial BSP connection is used. That is, the MicroEJ SDK will output all MicroEJ files (C headers, MicroEJ Application microejapp.o, MicroEJ Runtime microejruntime.a, …) in a location known by the BSP. The BSP is configured to compile and link with those files.

For this tutorial, that means that the final binary is produced by invoking make in the FreeRTOS BSP.

  1. Install the Platform Configuration Additions by copying all the files within the content folder in the MicroEJ Platform folder.

    ../_images/tuto_microej_fw_from_scratch_add_platform_configuration_additions.PNG

    Note

    The content directory contains files that must be installed in a MicroEJ Platform configuration directory (the directory that contains the .platform file). It can be automatically downloaded using the following command line:

    svn export --force https://github.com/MicroEJ/VEEPortQualificationTools/tags/2.6.0/framework/platform/content [path_to_platform_configuration_directory]
    
  2. Edit the file bsp/bsp.properties as follow:

    # Specify the MicroEJ Application file ('microejapp.o') parent directory.
    # This is a '/' separated directory relative to 'bsp.root.dir'.
    microejapp.relative.dir=microej/lib
    
    # Specify the MicroEJ Platform runtime file ('microejruntime.a') parent directory.
    # This is a '/' separated directory relative to 'bsp.root.dir'.
    microejlib.relative.dir=microej/lib
    
    # Specify MicroEJ Platform header files ('*.h') parent directory.
    # This is a '/' separated directory relative to 'bsp.root.dir'.
    microejinc.relative.dir=microej/inc
    
  3. Edit the file modules.ivy and add the MicroEJ Architecture as a dependency:

    <dependencies>
           <dependency org="com.microej.architecture.CM0.CM0_GCC48" name="flopi0G22" rev="7.14.0">
                   <artifact name="flopi0G22" m:classifier="${com.microej.platformbuilder.architecture.usage}" ext="xpf"/>
           </dependency>
    </dependencies>
    
  4. Edit the file modules.properties and set the MicroEJ platform filename:

    # Platform configuration file (relative to this project).
    com.microej.platformbuilder.platform.filename=Tuto.platform
    
  5. Right-click on the platform project and click on Build Module.

  6. The following message appears in the console:

    module-platform:report:
            [echo]     ============================================================================================================
            [echo]     Platform has been built in this directory 'C:\Users\user\src\tuto-from-scratch\workspace/lm3s811evb-Platform-CM0_GCC48-0.0.1'.
            [echo]     To import this project in your MicroEJ SDK workspace (if not already available):
            [echo]      - Select 'File' > 'Import...' > 'General' > 'Existing Projects into Workspace' > 'Next'
            [echo]      - Check 'Select root directory' and browse 'C:\Users\user\src\tuto-from-scratch\workspace/lm3s811evb-Platform-CM0_GCC48-0.0.1' > 'Finish'
            [echo]     ============================================================================================================
    
    BUILD SUCCESSFUL
    
  7. Follow the instructions to import the generated platform in the workspace:

    ../_images/tuto_microej_fw_from_scratch_build_platform.png

At this point, the MicroEJ Platform is ready to be used to build MicroEJ Applications.

Create MicroEJ Application HelloWorld

  1. Select File > New > Standalone Application Project.

  2. Set the name to HelloWorld and click on Finish

    ../_images/tuto_microej_fw_from_scratch_new_microej_application_project.PNG
  3. Run the application in Simulator to ensure it is working properly. Right-click on HelloWorld project > Run As > MicroEJ Application

    ../_images/tuto_microej_fw_from_scratch_run_as_microej_application.PNG

The following message appears in the console:

=============== [ Initialization Stage ] ===============
=============== [ Launching on Simulator ] ===============
Hello World!
=============== [ Completed Successfully ] ===============

SUCCESS

Configure BSP Connection in MicroEJ Application

This step describes how to configure the BSP connection for the HelloWorld MicroEJ Application and how to build the MicroEJ Application that will run on the target device.

For a MicroEJ Application, the BSP connection is configured in the PROJECT-NAME/build/emb.properties file.

  1. Create a file HelloWorld/build/emb.properties with the following content:

    core.memory.immortal.size=0
    core.memory.javaheap.size=1024
    core.memory.threads.pool.size=4
    core.memory.threads.size=1
    core.memory.thread.max.size=4
    deploy.bsp.microejapp=true
    deploy.bsp.microejlib=true
    deploy.bsp.microejinc=true
    deploy.bsp.root.dir=[absolute_path] to FreeRTOS\\FreeRTOS\\Demo\\CORTEX_LM3S811_GCC
    

    Note

    Assuming the WSL current directory is FreeRTOS/FreeRTOS/Demo/CORTEX_LM3S811_GCC, use the following command to find the deploy.bsp.root.dir path with proper escaping:

    pwd | sed -e 's|/mnt/c/|C:\\\\|' -e 's|/|\\\\|g'
    
  2. Open Run > Run configurations…

  3. Select the HelloWorld launcher configuration

    ../_images/tuto_microej_fw_from_scratch_run_configurations.PNG
  4. Select Execution tab.

  5. Change the execution mode from Execute on Simulator to Execute on Device.

  6. Add the file build/emb.properties to the options files

    ../_images/tuto_microej_fw_from_scratch_run_configurations_execute_on_device.PNG
  7. Click on Run

=============== [ Initialization Stage ] ===============
Platform connected to BSP location 'C:\Users\user\src\tuto-from-scratch\FreeRTOS\FreeRTOS\Demo\CORTEX_LM3S811_GCC' using application option 'deploy.bsp.root.dir'.
=============== [ Launching SOAR ] ===============
=============== [ Launching Link ] ===============
=============== [ Deployment ] ===============
MicroEJ files for the 3rd-party BSP project are generated to 'C:\Users\user\src\tuto-from-scratch\workspace\HelloWorld\com.mycompany.Main\platform'.
The MicroEJ application (microejapp.o) has been deployed to: 'C:\Users\user\src\tuto-from-scratch\FreeRTOS\FreeRTOS\Demo\CORTEX_LM3S811_GCC\microej\lib'.
The MicroEJ platform library (microejruntime.a) has been deployed to: 'C:\Users\user\src\tuto-from-scratch\FreeRTOS\FreeRTOS\Demo\CORTEX_LM3S811_GCC\microej\lib'.
The MicroEJ platform header files (*.h) have been deployed to: 'C:\Users\user\src\tuto-from-scratch\FreeRTOS\FreeRTOS\Demo\CORTEX_LM3S811_GCC\microej\inc'.
=============== [ Completed Successfully ] ===============

SUCCESS

At this point, the HelloWorld MicroEJ Application is built and deployed in the FreeRTOS BSP.

MicroEJ and FreeRTOS Integration

This section describes how to finalize the integration between MicroEJ and FreeRTOS to get a working firmware that runs the HelloWorld MicroEJ Application built previously.

In the previous section, when the MicroEJ Application was built, several files were added to a new folder named microej/.

$ pwd
/mnt/c/Users/user/src/tuto-from-scratch/FreeRTOS/FreeRTOS/Demo/CORTEX_LM3S811_GCC
$ tree microej/
microej/
├── inc
│   ├── BESTFIT_ALLOCATOR.h
│   ├── BESTFIT_ALLOCATOR_impl.h
│   ├── LLBSP_impl.h
│   ├── LLMJVM.h
│   ├── LLMJVM_MONITOR_impl.h
│   ├── LLMJVM_impl.h
│   ├── LLTRACE_impl.h
│   ├── MJVM_MONITOR.h
│   ├── MJVM_MONITOR_types.h
│   ├── intern
│   │   ├── BESTFIT_ALLOCATOR.h
│   │   ├── BESTFIT_ALLOCATOR_impl.h
│   │   ├── LLBSP_impl.h
│   │   ├── LLMJVM.h
│   │   ├── LLMJVM_impl.h
│   │   └── trace_intern.h
│   ├── sni.h
│   └── trace.h
└── lib
    ├── microejapp.o
    └── microejruntime.a

3 directories, 19 files
  • The microej/lib folder contains the HelloWorld MicroEJ Application object file (microejapp.o) and the MicroEJ Runtime. The final binary must be linked with these two files.
  • The microej/inc folder contains several C header files used to expose MicroEJ Low Level APIs. The functions defined in files ending with the _impl.h suffix should be implemented by the BSP.

To summarize, the following steps remain to complete the integration between MicroEJ and the FreeRTOS BSP:

  • Implement minimal Low Level APIs
  • Invoke the MicroEJ Core Engine
  • Build and link the firmware with the MicroEJ Runtime and MicroEJ Application

Minimal Low Level APIs

The purpose of this tutorial is to demonstrate how to develop a minimal MicroEJ Architecture, it is not to develop a complete MicroEJ Architecture. Therefore this tutorial implements only the required functions and provides stub implementation for unused features. For example, the following implementation does not support scheduling.

The two headers that must be implemented are LLBSP_impl.h and LLMJVM_impl.h.

  1. In the BSP, create a folder named microej/src (next to the microej/lib and microej/inc folders).

  2. Implement LLBSP_impl.h in LLBSP.c:

    microej/src/LLBSP.c
    #include "LLBSP_impl.h"
    
    extern void _etext(void);
    uint8_t LLBSP_IMPL_isInReadOnlyMemory(void* ptr)
    {
      return ptr < &_etext;
    }
    
    /**
     * Writes the character <code>c</code>, cast to an unsigned char, to stdout stream.
     * This function is used by the default implementation of the Java <code>System.out</code>.
     */
    void LLBSP_IMPL_putchar(int32_t c)
    {
      putchar(c);
    }
    
    • The implementation of LLBSP_IMPL_putchar reuses the putchar implemented previously.
    • The rodata section is defined in the linker script standalone.ld. The flash memory starts at 0 and the end of the section is stored in the _etex symbol.
  3. Implement LLMJVM_impl.h in LLMJVM_stub.c (all functions are stubbed with a dummy implementation):

    microej/src/LLMJVM_stub.c
    #include "LLMJVM_impl.h"
    
    
    int32_t LLMJVM_IMPL_initialize()
    {
            return LLMJVM_OK;
    }
    
    int32_t LLMJVM_IMPL_vmTaskStarted()
    {
            return LLMJVM_OK;
    }
    
    int32_t LLMJVM_IMPL_scheduleRequest(int64_t absoluteTime)
    {
            return LLMJVM_OK;
    }
    
    int32_t LLMJVM_IMPL_idleVM()
    {
            return LLMJVM_OK;
    }
    
    int32_t LLMJVM_IMPL_wakeupVM()
    {
            return  LLMJVM_OK;
    }
    
    int32_t LLMJVM_IMPL_ackWakeup()
    {
            return LLMJVM_OK;
    }
    
    int32_t LLMJVM_IMPL_getCurrentTaskID()
    {
            return (int32_t) 123456;
    }
    
    void LLMJVM_IMPL_setApplicationTime(int64_t t)
    {
    
    }
    
    int64_t LLMJVM_IMPL_getCurrentTime(uint8_t system)
    {
       return 0;
    }
    
    int64_t LLMJVM_IMPL_getTimeNanos()
    {
            return 0;
    }
    
    int32_t LLMJVM_IMPL_shutdown(void)
    {
            return LLMJVM_OK;
    }
    

The microej folder in the BSP has the following structure:

$ pwd
/mnt/c/Users/user/src/tuto-from-scratch/FreeRTOS/FreeRTOS/Demo/CORTEX_LM3S811_GCC
$ tree microej/
microej/
├── inc
│   ├── BESTFIT_ALLOCATOR.h
│   ├── BESTFIT_ALLOCATOR_impl.h
│   ├── LLBSP_impl.h
│   ├── LLMJVM.h
│   ├── LLMJVM_MONITOR_impl.h
│   ├── LLMJVM_impl.h
│   ├── LLTRACE_impl.h
│   ├── MJVM_MONITOR.h
│   ├── MJVM_MONITOR_types.h
│   ├── intern
│      ├── BESTFIT_ALLOCATOR.h
│      ├── BESTFIT_ALLOCATOR_impl.h
│      ├── LLBSP_impl.h
│      ├── LLMJVM.h
│      ├── LLMJVM_impl.h
│      └── trace_intern.h
│   ├── sni.h
│   └── trace.h
├── lib
│   ├── microejapp.o
│   └── microejruntime.a
└── src
    ├── LLBSP.c
    └── LLMJVM_stub.c

4 directories, 21 files

Invoke MicroEJ Core Engine

The MicroEJ Core Engine is created and initialized with the C function SNI_createVM. Then it is started and executed in the current RTOS task by calling SNI_startVM. The function SNI_startVM returns when the MicroEJ Application exits. Both functions are declared in the C header sni.h.

diff --git a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
--- a/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
+++ b/FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
@@ -150,11 +150,14 @@ int puts(const char *s) {
 }

 #include <stdio.h>
+#include "sni.h"

 int main( void )
 {
        printf("Hello, World! printf function is working.\n");

+       SNI_startVM(SNI_createVM(), 0, NULL);
+
    /* Configure the clocks, UART and GPIO. */
    prvSetupHardware();