Skip to content

Commit 094c1c5

Browse files
authored
1 add support for gpio (#3)
* Add GPIO support * Added examples * Updated README.md * Fixed docs generation
1 parent 215609e commit 094c1c5

File tree

12 files changed

+613
-138
lines changed

12 files changed

+613
-138
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ jobs:
5151

5252
- name: Build Pico
5353
run: cmake --build ${{github.workspace}}/build.pico --config ${{env.BUILD_TYPE}}
54-
54+
55+
- name: Package Pico tar ball
56+
run: cpack -B ${{github.workspace}}/build.pico --config ${{github.workspace}}/build.pico/CPackConfig.cmake -G TGZ
57+
5558
- name: Release
5659
uses: softprops/action-gh-release@v1
5760
if: startsWith(github.ref, 'refs/tags/')

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/build
22
/build.*
3-
/test/*.class
3+
/test/*.class
4+
/examples/*/build/*

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@
33
"files.associations": {
44
"*.inc": "cpp"
55
},
6+
"java.project.sourcePaths": [
7+
"cldc/src/javaapi/device",
8+
"examples/src"
9+
],
610
}

CMakeLists.txt

Lines changed: 147 additions & 108 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,44 @@
22

33
# Pico JVM
44

5-
This is a Java virtual machine for the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/), this project is based on the [CLDC](https://en.wikipedia.org/wiki/Connected_Limited_Device_Configuration) virtual machine and more specificly on the [phoneME](https://phonej2me.github.io) project from Sun/Oracle. The [phoneME](https://phonej2me.github.io) is a very old project that currently is not maintaned anymore. However I was able to find a github [repo](https://github.com/magicus/phoneME) that I used as a reference. This JVM is targeted to small embedded devices with limited resources so don't expected a full blown Java experience on [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/).
5+
This is a Java virtual machine for the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/), this project is based on the [CLDC](https://en.wikipedia.org/wiki/Connected_Limited_Device_Configuration) virtual machine and more specifically on the [phoneME](https://phonej2me.github.io) project from Sun/Oracle. The [phoneME](https://phonej2me.github.io) is a very old project that currently is not maintained anymore. However I was able to find a github [repo](https://github.com/magicus/phoneME) that I used as a reference. This JVM is targeted to small embedded devices with limited resources so don't expected a full blown Java experience on [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/).
66

77
The original [phoneME](https://phonej2me.github.io) project used a Makefile based build system, I converted the build system to CMake so I can use more modern tools and integration with modern CI/CD workflows. There are currently two main targets : Linux (used mainly for debugging) and Pico.
88

99
Currently the JVM support [CLDC 1.1](https://docs.oracle.com/javame/config/cldc/ref-impl/cldc1.1/jsr139/index.html) specification which is a limited subset of the Java J2SE specification and language.
1010

11-
## Running a Java application
11+
## Installation and setup
1212

13-
To run a Java application on the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) you will need to flash the Java virtual machine itself and than flash the Java application at the address `0x10100000`.
13+
Download the release package from the [Releases](https://github.com/orenskl/pico-jvm/releases) page of this repository, extract the package. The package contains the following content :
14+
15+
```
16+
├── bin
17+
├── doc
18+
├── lib
19+
└── pjvm-X.Y.Z.uf2
20+
```
21+
22+
The `bin` directory contains tools and scripts required to post process class and jar files to be able to run them on the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/).
23+
24+
The `doc` directory contains the javadoc for the device specific (e.g. GPIO) classes.
25+
26+
The `lib` directory contains the run-time class libraries (`classes.jar`)
27+
28+
The `pjvm-X.Y.Z.uf2` (where X.Y.Z is the version of the firmware) is the Java Virtual Machine UF2 file, this file needs to be flashed to the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) using [picotool](https://github.com/raspberrypi/picotool). The virtual machine already contains the run time classes so these are not required to be flashed separately.
1429

15-
The Java VM can be dowloaded from the [Releases](https://github.com/orenskl/pico-jvm/releases) page of this project. You can download the gzipped UF2 file, unpack it and flash it with the standard [picotool](https://github.com/raspberrypi/picotool).
30+
The `examples` directory in this repository contains some examples you can run with an [Ant](https://ant.apache.org) `build.xml` file. To build the examples and the following Hello World application you will need to setup the environment variable `JAVA_PICO_HOME` to point to the extracted package location.
31+
32+
For example if you extracted the package to `/opt/pjvm-X.Y.Z` you will need to setup the variable with the following command :
33+
34+
```
35+
export JAVA_PICO_HOME=/opt/pjvm-X.Y.Z
36+
```
37+
38+
You will also need [JDK 8](https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html) to build application, currently the latest versions of Java are not supported.
39+
40+
## Building and running a Java application
41+
42+
To run a Java application on the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) you will need to flash the Java virtual machine itself and than flash the Java application at the address `0x10100000`.
1643

1744
Lets say we have a simple hello world application :
1845

@@ -24,34 +51,52 @@ class Main {
2451
}
2552
```
2653

27-
The name of the class `Main` is currently fixed as the first class that is loaded by the VM. Compiler the class :
54+
**NOTE : The name of the class `Main` is currently fixed as the first class that is loaded by the VM.**
2855

29-
```
30-
javac -source 1.4 -target 1.4 -d main.dir -bootclasspath ../pico-jvm/build/classes.jar Main.java
31-
```
56+
1. Compile the class :
3257

33-
Make sure your `-bootclasspath` is correct and should point to the `classes.jar` that is built earilier
58+
```
59+
javac -source 1.4 -target 1.4 -d main.dir -bootclasspath $JAVA_PICO_HOME/lib/classes.jar Main.java
60+
```
3461
35-
Package the application as a JAR file :
62+
Make sure to setup you environment correctly so that `JAVA_PICO_HOME` points to the right place (see [here](#installation-and-setup))
3663
37-
```
38-
cd main.dir
39-
jar -cfM0 ../main.jar .
40-
```
64+
2. Preverify the classes
4165
42-
Now we need to wrap the JAR with a header so we can run it on the Pi Pico :
66+
Before running the compiled classes on the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) we will need to Preverify them. Preverifying is the process of post processing the class files so they can be run more efficiently on the target system. Preverifying is done with the `preverify` tool in the `bin` directory of the package.
4367
44-
```
45-
tools/wrapjar.sh main.jar main.jar.bin
46-
```
68+
```
69+
$JAVA_PICO_HOME/bin/preverify -d main.preverify -classpath $JAVA_PICO_HOME/lib/classes.jar main.dir
70+
```
4771
48-
The `wrapjar` script is located in the `tools` directory of this project. Now we can flash the application to address `0x10100000` using `picotool` :
72+
3. Package the application as a JAR file :
4973
50-
```
51-
picotool load build/main.jar.bin --offset 10100000
52-
```
74+
```
75+
cd main.preverify
76+
jar -cfM0 ../main.jar .
77+
```
78+
79+
4. Wrap the JAR file
80+
81+
Now we need to wrap the JAR with a header so we can run it on the Pi Pico :
82+
83+
```
84+
$JAVA_PICO_HOME/bin/wrapjar.sh main.jar main.jar.bin
85+
```
86+
87+
The `wrapjar.sh` script is located in the `bin` directory of the package.
88+
89+
5. Flash the binary file and reboot
90+
91+
Now we can flash the application to address `0x10100000` using `picotool` :
92+
93+
```
94+
picotool load build/main.jar.bin --offset 10100000
95+
```
96+
97+
Reboot your Pi Pico and you should see `Hello, World!` on your terminal
5398
54-
Reboot your Pi Pico and you should see `Hello, World!` on your terminal
99+
This repository includes an `example` directory with a complete [Ant](https://ant.apache.org) `build.xml` for each example that runs all the above steps in a single command.
55100
56101
## Building
57102
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
*
3+
* SPDX-License-Identifier: GPL-2.0-or-later
4+
* Copyright (C) 2024 Oren Sokoler (https://github.com/orenskl)
5+
*
6+
*/
7+
8+
package pico.hardware;
9+
10+
/**
11+
* A <code>GPIOPin</code> represents a single GPIO pin, it can be configured
12+
* to be either as an input or as an output. If configures as an input it can
13+
* have a pull up or pull down resistor. Each GPIO pin is identified by its
14+
* number, this number is passed directly to the hardware libray of the
15+
* device without any encoding or decoding.
16+
*/
17+
public class GPIOPin {
18+
19+
/**
20+
* Output direction for the GPIO pin
21+
*/
22+
public static final int OUT = 1;
23+
24+
/**
25+
* Input direction for the GPIO pin
26+
*/
27+
public static final int IN = 0;
28+
29+
/**
30+
* High (High voltage) for a GPIO pin
31+
*/
32+
public static final int HIGH = 1;
33+
34+
/**
35+
* Low (Low voltage 0V) for a GPIO pin
36+
*/
37+
public static final int LOW = 0;
38+
39+
/**
40+
* A pull up resistor is connected to the pin
41+
*/
42+
public static final int PULLUP = 1;
43+
44+
/**
45+
* A pull down resistor is connected to the pin
46+
*/
47+
public static final int PULLDOWN = 0;
48+
49+
/**
50+
* The GPIO pin number
51+
*/
52+
private int pinNumber;
53+
54+
/**
55+
*
56+
* Constructor for a GPIO pin
57+
*
58+
* @param pinNumber The pin number
59+
* @param pinType The pin direction ({@link GPIOPin#OUT} or {@link GPIOPin#IN})
60+
*
61+
* @throws IllegalArgumentException
62+
*
63+
*/
64+
public GPIOPin( int pinNumber, int pinType ) {
65+
if ((pinType != OUT) && (pinType != IN)) {
66+
throw new IllegalArgumentException();
67+
}
68+
this.pinNumber = pinNumber;
69+
gpio_init(pinNumber,pinType);
70+
}
71+
72+
/**
73+
*
74+
* Constructor for a GPIO pin with a pull up or pull down resistor
75+
*
76+
* @param pinNumber The pin number
77+
* @param pinType The pin direction ({@link GPIOPin#OUT} or {@link GPIOPin#IN})
78+
* @param pinPull The resistor type ({@link GPIOPin#PULLUP} or {@link GPIOPin#PULLDOWN})
79+
*
80+
* @throws IllegalArgumentException
81+
*
82+
*/
83+
public GPIOPin( int pinNumber, int pinType, int pinPull) {
84+
this(pinNumber,pinType);
85+
if ((pinPull != PULLUP) && (pinPull != PULLDOWN)) {
86+
throw new IllegalArgumentException();
87+
}
88+
gpio_set_pull(pinNumber,pinPull);
89+
}
90+
91+
/**
92+
*
93+
* Set the state of the pin to either HIGH or LOW
94+
*
95+
* @param pinState the state of the pin ({@link GPIOPin#HIGH} or {@link GPIOPin#LOW})
96+
*/
97+
public void set ( int pinState ) {
98+
gpio_set(this.pinNumber,pinState);
99+
}
100+
101+
/**
102+
* Get the state of the pin ({@link GPIOPin#HIGH} or {@link GPIOPin#LOW})
103+
*
104+
* @return state of the pin
105+
*/
106+
public int get () {
107+
return gpio_get(this.pinNumber);
108+
}
109+
110+
/*
111+
* Natives for the device hardware
112+
*/
113+
private static native void gpio_init ( int pinNumber , int pinType );
114+
private static native void gpio_set ( int pinNumber , int pinState );
115+
private static native int gpio_get ( int pinNumber );
116+
private static native void gpio_set_pull ( int pinNumber , int pinPull );
117+
118+
}

cldc/src/vm/os/pico/OS_pico.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#include "OS.hpp"
2525

26+
#include "pico/time.h"
27+
2628
static bool ticker_stopping = false;
2729
static bool ticker_running = false;
2830
static int sock_initialized = 0;
@@ -52,27 +54,31 @@ jlong offset() {
5254
}
5355

5456
#if SUPPORTS_MONOTONIC_CLOCK
55-
jlong Os::monotonic_time_millis() {
57+
jlong Os::monotonic_time_millis()
58+
{
5659
/*
5760
* Get the monotonic time in milliseconds from some unspecified starting
5861
* point. This clock must be monotonic and must have resolution and read
5962
* time not lower than that of Os::java_time_millis().
6063
*/
61-
return 0;
64+
return time_us_64() / 1000;
6265
}
6366
#endif
6467

65-
jlong Os::java_time_millis() {
68+
jlong Os::java_time_millis()
69+
{
6670
/*
6771
* Get the current system time, unit: millisecond, count time from
6872
* Jan. 1st, 1970. Need reduce the OS dependent offset time value, if
6973
* the offset exist
7074
*/
71-
return 0;
75+
return time_us_64() / 1000;
7276
}
7377

74-
void Os::sleep(jlong ms) {
78+
void Os::sleep(jlong ms)
79+
{
7580
/* let the current process sleep for ms seconds */
81+
sleep_ms(ms);
7682
}
7783

7884

0 commit comments

Comments
 (0)