Skip to content
jabrenaPublic

About

JUno is an ahead-of-time compiler for running a practical subset of Java for Microcontrollers

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

449 Commits

Folders and files

Repository files navigation

JUno: Java for Arduino

JUno /ˈxu.no/ is an ahead-of-time compiler for running a practical subset of Java for Microcontrollers. It keeps javac as the Java frontend, performs closed-world linking on the development machine, and emits Assembly.

CI Builds

Motivation

Traditionally, Java programs require a JVM to run. However, in memory-constrained environments, running Java programs inside a JVM can be difficult. Juno enables developers to create small Java programs for microcontrollers such as Arduino.

Arduino boards supported

Arduino Uno Family

Arduino UNO Q
Arduino UNO Q
Arduino UNO R4 WiFi
Arduino UNO R4 WiFi
Arduino UNO R3 WiFi Rev2
Arduino UNO WiFi Rev2
Arduino UNO R3
Arduino UNO R3

Arduino Uno shields supported

Shield Image Supported features
LCD Keypad Shield LCD Keypad Shield 16x2 HD44780 character display, five-button keypad, and controllable backlight.
ELEGOO 2.8-inch TFT Touch Shield ELEGOO 2.8-inch TFT Touch Shield 240x320 ILI9341 display, resistive touch input, and an onboard microSD socket.
Arduino 9 Axis Motion Shield Arduino 9 Axis Motion Shield BNO055 heading, pitch, roll, gyroscope, and calibration data over I2C.
PCA9685 PWM & Servo Shield PCA9685 PWM and Servo Shield Sixteen independently controlled 12-bit PWM/servo channels over I2C.
AZDelivery Data Logger Shield AZDelivery Data Logger Shield SPI SD-card access. The shield's real-time clock is not currently exposed.
Arduino WiFi Shield Arduino WiFi Shield Wi-Fi, UDP, TCP, plain HTTP and the SNTP clock on the UNO R3 (shield firmware 1.1.0). No access point or HTTPS.
Grove Base Shield Grove Base Shield Grove digital, analog, I2C, and UART connectors.

Arduino Nano Family

Arduino Nano ESP32
Arduino Nano ESP32

Arduino Nano shields supported

Accessory Image Supported features
Arduino Nano Connector Carrier Arduino Nano Connector Carrier Passive carrier for the Arduino Nano ESP32: microSD card slot on SPI, four Grove sockets, and one Qwiic connector.

M5Stack boards supported

M5Stack Cardputer Adv
M5Stack Cardputer

Quick start

Requirements: Arduino CLI, JDK 27+, Maven 3.10+.

On macOS, install Arduino CLI with Homebrew and verify that it is on your PATH:

brew update
brew install arduino-cli
arduino-cli version

See Arduino's installation guide for direct downloads and other options.

sdk env install
./mvnw clean install

Blink

Blink runs unmodified on every supported board. Its built-in LED alternates on and off every 500 ms (one full cycle per second).

package io.github.jabrena.juno.api.hardware.gpio;

import io.github.jabrena.juno.hardware.ArduinoUno;
import io.github.jabrena.juno.hardware.gpio.DigitalOutput;
import io.github.jabrena.juno.util.Delay;

public final class Blink {

    public static void main(String[] args) {

        DigitalOutput led = DigitalOutput.of(ArduinoUno.getGpio().getBuiltinLed());

        while (true) {
            led.high();
            Delay.millis(500);

            led.low();
            Delay.millis(500);
        }
    }
}

The project provides a Maven plugin to help the user with the common operations. juno:upload generates the sketch, verifies it with arduino-cli, and flashes it in one step. Blink has no board restriction, so pick a target with -Djuno.board:

./mvnw -f juno-examples/pom.xml compile juno:upload \
  -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink \
  -Djuno.board=arduino-uno-q
# -Djuno.board=arduino-uno-r4-wifi
# -Djuno.board=arduino-uno-r3-wifi-rev2
# -Djuno.board=arduino-uno-r3
# -Djuno.board=arduino-nano-esp32

Select another supported board with -Djuno.board. The plugin auto-detects the port when exactly one matching board is connected; otherwise, specify it with -Djuno.port=<PORT>.

After uploading the program, you could monitor what happen in the board using the following command:

./mvnw -f juno-examples/pom.xml juno:monitor \
  -Djuno.board=arduino-uno-q

Maven plugin

The juno Maven plugin provides these goals. The commands below run them from the examples module; add -Djuno.main=<fully-qualified-class-name> and -Djuno.board=<id> when the entry point has no single-board @Board declaration.

Goal Purpose Command
juno:boards Lists the boards and serial ports detected by Arduino CLI without touching a board. ./mvnw -f juno-examples/pom.xml juno:boards
juno:install-deps Installs the Arduino core and optional libraries required by the examples. ./mvnw -f juno-examples/pom.xml juno:install-deps
juno:compile Generates the assembly, C++ runtime shim, and Arduino sketch wrapper. ./mvnw -f juno-examples/pom.xml compile juno:compile -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink -Djuno.board=arduino-uno-r4-wifi
juno:verify Generates the sketch and compiles it with Arduino CLI without using physical hardware. ./mvnw -f juno-examples/pom.xml compile juno:verify -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink -Djuno.board=arduino-uno-r4-wifi
juno:upload Generates, verifies, and uploads the sketch to the selected or detected board. ./mvnw -f juno-examples/pom.xml compile juno:upload -Djuno.main=io.github.jabrena.juno.api.hardware.gpio.Blink -Djuno.board=arduino-uno-r4-wifi
juno:monitor Opens the serial monitor for the selected or detected board. ./mvnw -f juno-examples/pom.xml juno:monitor -Djuno.board=arduino-uno-r4-wifi

For example, verify the Grove Temperature and Humidity Sensor Pro monitor for a UNO WiFi Rev2 without uploading it:

./mvnw -f juno-examples/pom.xml compile juno:verify \
  -Djuno.main=io.github.jabrena.juno.api.hardware.device.grove.sensors.GroveDht22Monitor \
  -Djuno.board=arduino-uno-r3-wifi-rev2

Supported Java subset

Juno is an ahead-of-time compiler, not a JVM. It links a program closed-world from main, validates every reachable bytecode, and stops with a diagnostic (method, bytecode offset, unsupported operation) rather than emit code whose behavior it cannot guarantee. Valid Java is therefore not automatically valid Juno input.

Area Supported
Language core main() / main(String[]), static and instance methods, all eight primitive types, control flow and switch, fixed-size (also multidimensional) arrays, constant lookup tables kept in flash
Objects classes, inheritance, interfaces, enums, records, lambdas and method references
Exceptions throw, try/catch/finally, multi-catch, propagation between methods, try-with-resources
Library String and StringBuilder, Math, BigInteger/BigDecimal, LocalDateTime (SNTP), UUID, random numbers
Concurrency virtual threads and the JDK 27 preview StructuredTaskScope on one preemptive scheduler (up to four threads including main), monitors, ReentrantLock, atomics, ScopedValue
Board services GPIO, serial, clocks, LED matrix, mouse, Wi-Fi, HTTP/HTTPS, UDP/TCP, SD card, and stacked shields (pin conflicts are rejected at compile time)

Platform threads (new Thread) and Thread.ofVirtual() builders are rejected. Objects live in one fixed arena (8 KiB, 1 KiB on AVR), so the AVR boards fit smaller programs. The details are on the Java subset page, and runnable examples of each feature are under juno-examples.

Maven modules

This is a multi-module Maven build:

  • juno-api/ — the programming model: the Java-facing hardware API the compiler recognizes as intrinsics (api/) and the @Board annotations used to select a compilation target (annotations/). This is the only artifact programs compile against.
  • juno-compiler/ — the compiler (classfile, bytecode, linker, backend, …), which depends on juno-api. Builds the executable juno-compiler/target/juno-compiler-<version>.jar.
  • juno-maven-plugin/ — Maven goals for generating a sketch (juno:compile), compiling it with Arduino CLI (juno:verify), uploading it (juno:upload), and opening the serial monitor (juno:monitor).
  • juno-examples/ — example Java programs written against juno-api, built like any other Maven module so they're checked for compile errors on every build.
  • juno-site/ — the Roq/Quarkus static site generator behind the documentation site. docs/ is entirely generated from Markdown under juno-site/src/main/resources/content/ — see Documentation site below to regenerate it.
  • juno-third-parties/ — integrations maintained outside the core compiler, currently including the independent H8/300 firmware generator for the LEGO RCX, its S-record, and the generated Java representation consumed by juno-examples.

Architecture

Juno is an ahead-of-time compiler, not a virtual machine. An Arduino board has no JVM, so nothing is interpreted at run time: the Java program is compiled with javac as usual, and Juno then translates the resulting JVM bytecode into native ARM assembly that the Arduino toolchain builds into the sketch's firmware. The compiler is closed-world: it only sees the classes reachable from main, so it can resolve every call at build time, drop everything unused, and reject anything outside the supported subset before generating a single instruction. That is also why there is no dynamic class loading, reflection, or general heap.

From Java to a running board

 Hello.java ──javac──▶ Hello.class ──▶ Juno ──▶ Hello.S + HelloShim.cpp + HelloAsm.ino ──arduino-cli──▶ board
                                       │
                 classfile → bytecode → linker → lowering → optimize → backend
  1. Write and compile Java. Programs use the Juno hardware API and optionally select a board with @Board. Maven runs javac; Juno consumes the resulting .class files.
  2. Link and validate. Juno starts at main, keeps only reachable code, converts hardware calls into intrinsics, and rejects unsupported bytecode with a precise diagnostic.
  3. Lower and optimize. Reachable methods become Juno IR, where compiler passes simplify the program and report risks such as excessive arena use, recursion, or unsafe array access.
  4. Generate the sketch. The backend emits native assembly and a small C++ runtime shim. The Maven plugin packages them with a minimal .ino under target/juno/<Main>Asm/.
  5. Build and run. Arduino CLI compiles the generated sketch for the selected board. Use juno:verify to compile it, juno:upload to flash it, and juno:monitor to read its serial output.

References

About

JUno is an ahead-of-time compiler for running a practical subset of Java for Microcontrollers

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages