I am going to show you how to build, deploy, and run a simple “Hello World!” application on a Raspberry Pi Zero, without an operating system, in Java. In the embedded world, this means making the green ACT LED blink.

Prerequisites1

Make sure you have the following hardware/software for this guide:

Check Your Environment

From terminal, let’s check to make sure all needed software is working. It you do not see something like the responses below, make sure you have the prerequisites installed.

First, let’s check Java.

$ java --version
openjdk 11.0.2 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)

Next, check the ARM cross compiler:

$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Finally, check for Gradle:

$ gradle --version

------------------------------------------------------------
Gradle 5.1.1
------------------------------------------------------------

Build time:   2019-01-10 23:05:02 UTC
Revision:     3c9abb645fb83932c44e8610642393ad62116807

Kotlin DSL:   1.1.1
Kotlin:       1.3.11
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM:          11.0.2 (Oracle Corporation 11.0.2+9)
OS:           Mac OS X 10.14.6 x86_64

Step By Step Guide

Step 1: Create a Gradle Wrapper

In terminal, create a directory for your project. Start by creating a gradle wrapper for your project. This enables a build to be run for this project without a local install gradle install, and for a known good gradle version.

$ mkdir helloworld
$ cd helloworld/
$ gradle wrapper --gradle-version 5.6.4

BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed

Step 2: Create settings.gradle

In the root of your project directory, create a settings.gradle file. Add the following to this file.

sourceControl {
  gitRepository("https://github.com/chuckb/raspbootin") {
    producesModule("com.github.chuckb.raspbootin:raspbootcom")
    producesModule("com.github.chuckb.raspbootin:raspbootin2")
  }
}

These settings enable the building of a serial bootloader that will run on your host and the Raspberry Pi Zero.

Step 3: Create build.gradle

Also in the root of your project directory, create the build.gradle. Add the following to this file.

buildscript {
  dependencies {
    classpath 'com.github.chuckb:HaikuVMPlugin:master-SNAPSHOT'
  }
  repositories {
    maven { url 'https://jitpack.io' }
  }
}

apply plugin: 'com.github.chuckb.haikuvm'

haikuvm {
  haikuVMConfig = "rpi"
  port = "/dev/tty.SLAB_USBtoUART"
}

These settings reference my HaikuVMPlugin plugin, which automates building and deploying of embedded Java projects. The port variable may need to be modified. We’ll get to that later.

Step 4: Create the application

Create a src/main/java directory off of the project root. Inside the java directory, create a Main.java file. Add the following to that file:

import haiku.vm.NativeCBody;
import haiku.vm.NativeCFunction;

@NativeCBody(cImpl ="volatile unsigned int* gpio = (unsigned int*)0x20200000UL;")

public class Main {
  @NativeCFunction(cImpl = "gpio[arg1] = arg2;")
  private static native void setGPIO(int offset, int value);  
        
  @NativeCFunction(cImpl = "return gpio[arg1];")
  private static native int getGPIO(int offset);

  public static final int GPIO_GPFSEL4 = 4;           // GPIO Function Select 4
  public static final int LED_GPFSEL = GPIO_GPFSEL4;
  public static final int GPIO_GPSET1 = 8;            // GPIO Pin Output Set 1
  public static final int GPIO_GPCLR1 = 11;           // GPIO Pin Output Clear 1
  public static final int LED_GPFBIT = 21;
  public static final int LED_GPSET = GPIO_GPSET1;
  public static final int LED_GPCLR = GPIO_GPCLR1;
  public static final int LED_GPIO_BIT = 15;
    
  /**
   * Main function entry point for app
   */
  public static void main(String[] args) {
    int tim;

    /* Write 1 to the GPIO init nibble in the Function Select GPIO peripheral register to set
        the GPIO pin for the ACT LED as an output */
    setGPIO(LED_GPFSEL, (1 << LED_GPFBIT) | getGPIO(LED_GPFSEL)&0xFFFFFFFF);
    
    while(true) {
      // Delay
      for(tim = 0; tim < 50000; tim++);

      /* Set the LED GPIO pin low ( Turn OK LED on for original Pi, and off for plus models ) */
      setGPIO(LED_GPCLR, (1 << LED_GPIO_BIT));

      for(tim = 0; tim < 50000; tim++);

      /* Set the LED GPIO pin high ( Turn OK LED off for original Pi, and on for plus models ) */
      setGPIO(LED_GPSET, (1 << LED_GPIO_BIT));
    }
  }
}

I explain this application works in Dissecting Raspberry Pi Embedded Java Hello World. Suffice it to say, it blinks the green Pi ACT LED.

Step 5: Build And Deploy Raspberry Pi Zero Serial Bootloader Image

For this step, we will build the Raspberry Pi Zero binary image containing a serial bootloader, which will load the above app over a serial cable. This image will will be deployed to a micro SD card.

Go to the project root, and do this:

$ ./gradlew buildPiImage

You should see:

> Task :raspbootin:raspbootin2:make
rm -f *.o
rm -f kernel.img kernel.elf
rm -f kernel.list kernel.map
rm -f kernel
arm-none-eabi-as -I. -march=armv6 -mcpu=arm1176jzf-s -g start.s -o start.o
arm-none-eabi-gcc -DPLATFORM_RPI  -I. -std=c99 -Wall -pedantic -g -O0  main.c -c -o main.o
arm-none-eabi-gcc -DPLATFORM_RPI  -I. -std=c99 -Wall -pedantic -g -O0  uart.c -c -o uart.o
arm-none-eabi-ld --no-undefined start.o  main.o  uart.o  -Map kernel.map -o kernel.elf -T kernel.ld
arm-none-eabi-objcopy kernel.elf -O binary kernel.img

> Task :raspbootin:raspbootcom:make
g++ -O0 -W -Wall -g -c raspbootcom.cc -o raspbootcom.o
g++ -o raspbootcom raspbootcom.o

> Task :buildPiImage
-> /Users/chuck_benedict/Projects/helloworld/build/firmware/pi/files/kernel.img
-> /Users/chuck_benedict/Projects/helloworld/build/firmware/pi/files/config.txt
-> /Users/chuck_benedict/Projects/helloworld/build/firmware/pi/files/bootcode.bin
-> /Users/chuck_benedict/Projects/helloworld/build/firmware/pi/files/fixup.dat
-> /Users/chuck_benedict/Projects/helloworld/build/firmware/pi/files/start.elf

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.6.4/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 5s
2 actionable tasks: 2 executed

If the gradle task ends with BUILD SUCCESSFUL as above, change directory into build/firmware/pi.

To deploy the bootable image to your SD card, first you need to determine which device Mac assigned to your card. Plug in your card and then do this:

$ diskutil list

You will see something like this:

/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         960.2 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                 Apple_APFS Container disk1         960.0 GB   disk0s2

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +960.0 GB   disk1
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            492.5 GB   disk1s1
   2:                APFS Volume Preboot                 41.4 MB    disk1s2
   3:                APFS Volume Recovery                507.4 MB   disk1s3
   4:                APFS Volume VM                      11.8 GB    disk1s4

/dev/disk2 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                            RPIBOOT                *32.0 GB    disk2

I have a 32GB card, and disk2 is marked external, so I can be pretty sure, IN MY CASE, my card is /dev/disk2. YMMV.

Warning: Don’t screw this up or the following command can nuke your system. You have been warned.

Warning: This action will erase and overwrite your micro SD card! If you have Raspbian installed, or more importantly, any non-recoverable data on the card, back it up first.

Now do the following, substituting diskx for your device:

$ sudo umount /dev/diskx
$ sudo dd if=boot.img of=/dev/diskx bs=512

You should see:

67584+0 records in
67584+0 records out
34603008 bytes transferred in 17.837279 secs (1939926 bytes/sec)

Unplug your SD card and then plug it back in. Go to the Finder and look under Locations for RPIBOOT. Click on it and you should see a listing like the following:

a screen shot of the Finder showing a list of files to boot the Raspberry Pi
Raspberry Pi Image Directory Listing

Now you can eject your card and plug it into the Pi.

Step 6: Determine USB Serial Cable Device Name

I mentioned in step 3 that the port variable in the build.gradle might need to be adjusted. I am using the Adafruit USB serial cable based on the CP2102 chip. Be sure to follow the driver install instructions. You don’t have to use this cable. Any USB to serial cable that deals in 3.3V TTL signals will work. Whatever the case, you will need to know the device name that Mac gave to the cable. Plug in your cable and do this:

$ ls /dev/tty* | grep -i usb

In my case, I got:

/dev/tty.SLAB_USBtoUART

Fill in whatever name you got for the port variable.

Step 7: Plug In The Serial Cable Pins To The Raspberry Pi

I am assuming you have the Adafruit cable. Leave the red wire off for now. Hook the rest up as follows:

a screen shot of the Adafruit serial cable connecting to the Raspberry Pi Zero
Adafruit Serial Cable To Raspberry Pi Hookup

The bootloader uses UART0, so if you are using another cable, use this pinout as a guide.

Plug in the USB side to your workstation.

Step 8: Deploy The Application

Now for the anti-climactic fun. Go to the root project directory and type:

$ ./gradle deploy

You will see a lot of output. I have included it here in case you want to compare.

> Task :haikulink
Looking for 'HaikuVM.properties' in path: '/Users/chuck_benedict/Projects/helloworld';'/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/config'
Loaded from '/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/config/HaikuVM.properties'

$Version 1.4.3 $ $Id: HaikuVM.java 765 2017-04-30 10:32:24Z genom2 $

user .h/.c/.cpp files from /Users/chuck_benedict/Projects/helloworld into /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility
Copy HaikuVM-VM into '/Users/chuck_benedict/Projects/helloworld/build'.
        Because '/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/HaikuAppMain.c' is newer than '/Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/HaikuAppMain.c'.

/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/.settings
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/examples
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/examples/HaikuVM
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/platforms
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/platforms/pi
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/aotVariants
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/gcVariants
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/lib
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/lib/ldscripts
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/./haikuVM/src/utility

#################### closure start on haiku.bcm.lib.HaikuMicroKernel
included; haiku.bcm.lib.HaikuMicroKernel.main([Ljava/lang/String;)V
included:   haiku.vm.MicroKernel.clinitHaikuMagic()V
included:   haiku.vm.MicroKernel.panic(II)V
included:   Main.main([Ljava/lang/String;)V
included:     Main.getGPIO(I)I
included:     Main.setGPIO(II)V
included:   java.lang.Thread.currentThread()Ljava/lang/Thread;
virtual :   stop()V
#### rescan because:
###### usage of (invokevirtual || invokeinterface) for message --> stop()V
###### usage of message --> Main.getGPIO(I)I
###### usage of message --> Main.main([Ljava/lang/String;)V
###### usage of message --> Main.setGPIO(II)V
###### usage of message --> haiku.vm.MicroKernel.clinitHaikuMagic()V
###### usage of message --> haiku.vm.MicroKernel.panic(II)V
###### usage of message --> java.lang.Thread.currentThread()Ljava/lang/Thread;
###### usage of new Class (1 bc) --> Main
###### usage of new Class (1 bc) --> java.lang.Thread
###### usage of new Class (2 bc) --> haiku.vm.MicroKernel
included:   java.lang.NullPointerException.<init>(Ljava/lang/String;)V
included:     java.lang.RuntimeException.<init>(Ljava/lang/String;)V
included:       java.lang.Exception.<init>(Ljava/lang/String;)V
included:         java.lang.Throwable.<init>(Ljava/lang/String;)V
included:   java.lang.ArrayStoreException.<init>()V
included:     java.lang.RuntimeException.<init>()V
included:   java.lang.IndexOutOfBoundsException.<init>(Ljava/lang/String;)V
included:   java.lang.StringBuilder.<init>()V
included:     java.lang.Object.<init>()V
virtual :   append(Ljava/lang/String;)Ljava/lang/StringBuilder;
virtual :   append(I)Ljava/lang/StringBuilder;
virtual :   toString()Ljava/lang/String;
included:   java.lang.NoSuchMethodError.<init>(Ljava/lang/String;)V
included:     java.lang.Error.<init>(Ljava/lang/String;)V
included:   java.lang.StackOverflowError.<init>(Ljava/lang/String;)V
included:   java.lang.OutOfMemoryError.<init>(Ljava/lang/String;)V
included:   java.lang.ClassCastException.<init>(Ljava/lang/String;)V
included:   java.lang.ArrayIndexOutOfBoundsException.<init>(I)V
included:   java.lang.InternalError.<init>(Ljava/lang/String;)V
included:     java.lang.VirtualMachineError.<init>(Ljava/lang/String;)V
included:   java.lang.ArithmeticException.<init>(Ljava/lang/String;)V
included#   java.lang.Object.toString()Ljava/lang/String;
included:   java.lang.System.identityHashCode(Ljava/lang/Object;)I
included:     java.lang.System.getDataAddress(Ljava/lang/Object;)I
included#   java.lang.Thread.stop()V
virtual :   setStateAndSwitch(I)I
included#   java.lang.Thread.setStateAndSwitch(I)I
virtual :   fillInStackTrace()Ljava/lang/Throwable;
included#   java.lang.Throwable.toString()Ljava/lang/String;
included#   java.lang.Throwable.fillInStackTrace()Ljava/lang/Throwable;
included#   java.lang.String.toString()Ljava/lang/String;
#### rescan because:
###### usage of (invokevirtual || invokeinterface) for message --> append(I)Ljava/lang/StringBuilder;
###### usage of (invokevirtual || invokeinterface) for message --> append(Ljava/lang/String;)Ljava/lang/StringBuilder;
###### usage of (invokevirtual || invokeinterface) for message --> fillInStackTrace()Ljava/lang/Throwable;
###### usage of (invokevirtual || invokeinterface) for message --> setStateAndSwitch(I)I
###### usage of (invokevirtual || invokeinterface) for message --> toString()Ljava/lang/String;
###### usage of message --> java.lang.ArithmeticException.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.ArrayIndexOutOfBoundsException.<init>(I)V
###### usage of message --> java.lang.ArrayStoreException.<init>()V
###### usage of message --> java.lang.ClassCastException.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.Error.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.Exception.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.IndexOutOfBoundsException.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.InternalError.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.NoSuchMethodError.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.NullPointerException.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.Object.<init>()V
###### usage of message --> java.lang.OutOfMemoryError.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.RuntimeException.<init>()V
###### usage of message --> java.lang.RuntimeException.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.StackOverflowError.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.StringBuilder.<init>()V
###### usage of message --> java.lang.System.getDataAddress(Ljava/lang/Object;)I
###### usage of message --> java.lang.System.identityHashCode(Ljava/lang/Object;)I
###### usage of message --> java.lang.Throwable.<init>(Ljava/lang/String;)V
###### usage of message --> java.lang.VirtualMachineError.<init>(Ljava/lang/String;)V
###### usage of new Class (1 bc) --> java.lang.ArithmeticException
###### usage of new Class (1 bc) --> java.lang.ArrayIndexOutOfBoundsException
###### usage of new Class (1 bc) --> java.lang.ArrayStoreException
###### usage of new Class (1 bc) --> java.lang.ClassCastException
###### usage of new Class (1 bc) --> java.lang.Error
###### usage of new Class (1 bc) --> java.lang.Exception
###### usage of new Class (1 bc) --> java.lang.IndexOutOfBoundsException
###### usage of new Class (1 bc) --> java.lang.InternalError
###### usage of new Class (1 bc) --> java.lang.NoSuchMethodError
###### usage of new Class (1 bc) --> java.lang.NullPointerException
###### usage of new Class (1 bc) --> java.lang.OutOfMemoryError
###### usage of new Class (1 bc) --> java.lang.RuntimeException
###### usage of new Class (1 bc) --> java.lang.StackOverflowError
###### usage of new Class (1 bc) --> java.lang.StringBuilder
###### usage of new Class (1 bc) --> java.lang.System
###### usage of new Class (1 bc) --> java.lang.VirtualMachineError
included:   java.lang.Exception.<init>()V
included:   java.lang.Throwable.<init>()V
included#   java.lang.StringBuilder.toString()Ljava/lang/String;
included:   java.lang.String.<init>([C)V
included#   java.lang.StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
included#   java.lang.StringBuilder.append(I)Ljava/lang/StringBuilder;
included:   java.lang.String.valueOf(I)Ljava/lang/String;
#### rescan because:
###### usage of message --> java.lang.Exception.<init>()V
###### usage of message --> java.lang.String.<init>([C)V
###### usage of message --> java.lang.String.valueOf(I)Ljava/lang/String;
###### usage of message --> java.lang.Throwable.<init>()V
virtual :   append(C)Ljava/lang/StringBuilder;
included#   java.lang.StringBuilder.append(C)Ljava/lang/StringBuilder;
included:   java.lang.String.<init>(C)V
#### rescan because:
###### usage of (invokevirtual || invokeinterface) for message --> append(C)Ljava/lang/StringBuilder;
###### usage of message --> java.lang.String.<init>(C)V
#################### closure complete!


Effective configuration for 'rpi':
  AOTVariant = HAIKU_AOTBytecodeAsJump
  APP_BASE = /Users/chuck_benedict/Projects/helloworld/build
  APP_NAME = Main
  Align = 4
  ArduinoCore = null
  ArduinoDir = null
  AsuroTiming = null
  BOOTCLASSPATH = null
  Baud = null
  CC = null
  CC_OPT = null
  CFLAGS = 
  CLIBS = 
  CPUARCH = null
  CXX = null
  CXX_OPT = ${HAIKU_CC_OPT}
  Char = HAIKU_CHAR_16
  Clock = null
  Config = rpi
  Extends = root4c
  Extension = .undefined Extension
  GC = HAIKU_ConservativGC
  GenerateFullVM = null
  HAIKUVM4C = ./haikuVM
  HOME = /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK
  IncrementalGCSlice = HAIKU_MemorySize/5
  InitialMainThreadStackSize = 500
  InitialOtherThreadStackSize = 100
  LDFLAGS = 
  LINKER = $(HAIKU_CXX)
  Lower_MCU = null
  MCU = null
  MCU_LD = null
  MemorySize = 30000
  MicroKernel = haiku.bcm.lib.HaikuMicroKernel
  MillisDividend = 128
  MillisDivisor = 125
  MillisPrescale = 64
  Mode = HAIKU_32_32
  Output = $(HAIKU_APP_NAME)$(HAIKU_EXTENSION)
  PanicExceptions = NullPointerException | NoSuchMethodError | OutOfMemoryError | ClassCastException | InternalError | ArrayIndexOutOfBoundsException | StackOverflowError | ArithmeticException
  PanicSupport = 1
  Port = null
  Programmer = null
Warning: unsupported value 'rpi' for property 'Target'!
  Target = rpi
  Threads = 0
  TimerInterrupt = null
  Upload = null
  UserMain = null
  VM_BASE = ../../HaikuVM


#################### closure start on java.lang.Thread
#################### closure complete!



#################### closure start on java.lang.String
#################### closure complete!


link > haiku.bcm.lib.HaikuMicroKernel.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/bootstrap/master-SNAPSHOT/b3079486a387e0207b93dd54d2d9fa5b6c18a003/bootstrap-master-SNAPSHOT.jar
  const class_t haiku_bcm_lib_HaikuMicroKernel__class PROGMEM = {
        & haiku_vm_MicroKernel__class,
        SIZEOF_haiku_bcm_lib_HaikuMicroKernel,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.Throwable.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_Throwable__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_java_lang_Throwable,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.Object.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_Object__class PROGMEM = {
        NULL,
        SIZEOF_java_lang_Object,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.StringBuilder.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_StringBuilder__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_java_lang_StringBuilder,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.String.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_String__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_java_lang_String,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.System.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_System__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_java_lang_System,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

  PREPROCESSING haikuReleaseLock: java.lang.Thread.haikuReleaseLock(Ljava/lang/Object;)V
link > java.lang.Thread.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_Thread__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_java_lang_Thread,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > haiku.vm.MicroKernel.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/bootstrap/master-SNAPSHOT/b3079486a387e0207b93dd54d2d9fa5b6c18a003/bootstrap-master-SNAPSHOT.jar
  const class_t haiku_vm_MicroKernel__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_haiku_vm_MicroKernel,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.NullPointerException.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_NullPointerException__class PROGMEM = {
        & java_lang_RuntimeException__class,
        SIZEOF_java_lang_NullPointerException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.RuntimeException.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_RuntimeException__class PROGMEM = {
        & java_lang_Exception__class,
        SIZEOF_java_lang_RuntimeException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.Exception.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_Exception__class PROGMEM = {
        & java_lang_Throwable__class,
        SIZEOF_java_lang_Exception,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.ArrayStoreException.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_ArrayStoreException__class PROGMEM = {
        & java_lang_RuntimeException__class,
        SIZEOF_java_lang_ArrayStoreException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.IndexOutOfBoundsException.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_IndexOutOfBoundsException__class PROGMEM = {
        & java_lang_RuntimeException__class,
        SIZEOF_java_lang_IndexOutOfBoundsException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.NoSuchMethodError.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_NoSuchMethodError__class PROGMEM = {
        & java_lang_Error__class,
        SIZEOF_java_lang_NoSuchMethodError,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.Error.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_Error__class PROGMEM = {
        & java_lang_Throwable__class,
        SIZEOF_java_lang_Error,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.StackOverflowError.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_StackOverflowError__class PROGMEM = {
        & java_lang_Error__class,
        SIZEOF_java_lang_StackOverflowError,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.OutOfMemoryError.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_OutOfMemoryError__class PROGMEM = {
        & java_lang_Error__class,
        SIZEOF_java_lang_OutOfMemoryError,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.ClassCastException.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_ClassCastException__class PROGMEM = {
        & java_lang_RuntimeException__class,
        SIZEOF_java_lang_ClassCastException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.ArrayIndexOutOfBoundsException.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_ArrayIndexOutOfBoundsException__class PROGMEM = {
        & java_lang_IndexOutOfBoundsException__class,
        SIZEOF_java_lang_ArrayIndexOutOfBoundsException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.InternalError.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_InternalError__class PROGMEM = {
        & java_lang_VirtualMachineError__class,
        SIZEOF_java_lang_InternalError,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.VirtualMachineError.class from /Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/lib/nxt/classes.jar
  const class_t java_lang_VirtualMachineError__class PROGMEM = {
        & java_lang_Error__class,
        SIZEOF_java_lang_VirtualMachineError,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > java.lang.ArithmeticException.class from /Users/chuck_benedict/.gradle/caches/modules-2/files-2.1/com.github.chuckb.haikuVM/haikuRT/master-SNAPSHOT/207b6d3a7213bb212e2886745d366b7f3d415f6c/haikuRT-master-SNAPSHOT.jar
  const class_t java_lang_ArithmeticException__class PROGMEM = {
        & java_lang_RuntimeException__class,
        SIZEOF_java_lang_ArithmeticException,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

link > Main.class from /Users/chuck_benedict/Projects/helloworld/build/classes/java/main/Main.class
  const class_t Main__class PROGMEM = {
        & java_lang_Object__class,
        SIZEOF_Main,
  };
into   /Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility/haikuJava.c

Building makefile for all subdirectories in your given directory '/Users/chuck_benedict/Projects/helloworld/build' ...
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/tools/avr/share/tk8.4
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/optiboot
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/atmega8
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/stk500v2
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/lilypad/src
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/caterina-LilyPadUSB
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/bt
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/atmega
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/bootloaders/caterina
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/cores/arduino
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/atmegaxxu2/arduino-usbdfu
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/atmegaxxu2/arduino-usbserial
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/DRIVERS/PM
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/DRIVERS/INTC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/DRIVERS/USART
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/DRIVERS/GPIO
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/DRIVERS/FLASHC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/UTILS/DEBUG
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/COMPONENTS/MEMORY/DATA_FLASH/AT45DBX
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/BOARDS/EVK1105
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/BOARDS/ARDUINO
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src/SOFTWARE_FRAMEWORK/SERVICES/MEMORY/CTRL_ACCESS
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifi_dnld/src
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/PM
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/INTC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/PDCA
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/TC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/EBI/SMC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/RTC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/USART
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/GPIO
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/EIC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/FLASHC
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/UTILS/DEBUG
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/COMPONENTS/MEMORY/DATA_FLASH/AT45DBX
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/BOARDS/EVK1105
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/BOARDS/ARDUINO
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/MEMORY/CTRL_ACCESS
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/LWIP/lwip-1.3.2/src/core/ipv4
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/LWIP/lwip-1.3.2/src/core
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/LWIP/lwip-1.3.2/src/netif
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/LWIP/lwip-port-1.3.2/HD/if/netif
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/DELAY
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/hardware/arduino/firmwares/wifishield/wifiHD/src
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/haikuVM/src/platforms/pi
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/haikuVM/src/platforms
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/haikuVM/src/gcVariants
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/haikuVM/src/utility
/Users/chuck_benedict/Projects/helloworld/build/haikuVMSDK/haikuVM/src
/Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/platforms/pi
/Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/platforms
/Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/gcVariants
/Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src/utility
/Users/chuck_benedict/Projects/helloworld/build/HaikuVM/src
totalMethods=      42
totalBClength=     983
Warnings:
totalConstLength=  507
Warning: unsupported value 'rpi' for property 'Target'!
totalClassesLength=145

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.6.4/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 11s
9 actionable tasks: 9 executed

If it ends with BUILD SUCCESSFUL, you should have noticed a new terminal window pop up with something like the following:

a screen shot of the Mac serial bootloader console window opening after successful deployment
Serial Bootloader Console Window

Now connect the red wire from the serial cable to pin 2 on the Pi.

Your new terminal window should show something like:

a screen shot of the Mac serial bootloader console window showing deployment of the hello world application
Serial Bootloader Console Window With Loaded Hello World App

Last but not least, the green LED on your Pi should be blinking. If it is, congrats, you have just deployed a bare-metal embedded Java app on a Raspberry Pi Zero!

a green blinking led
Raspberry Pi Zero Embedded Java Hello World Running
  1. I will be testing and expanding the test coverage across platforms and boards, but this is where I am for now.