Skip to content

Advanced configuration

Most builds work without touching anything below — these files are here when you need them. Day-to-day app development needs none of this.

lv_conf.h

LVGL is vendored in third_party/lvgl/ and configured via crates/pd-lvgl-sys/lvgl/lv_conf.h, in the crate that holds the LVGL bindings and compiles the C sources. It overrides selected upstream defaults:

SymbolPicodroid valueWhy
LV_COLOR_FORMAT_DEFAULTLV_COLOR_FORMAT_RGB565_SWAPPED16-bit framebuffers rendered big-endian, the byte order the ST7789 / ST7796 panels take over SPI, so a band goes to the panel unswapped. Replaces the old LV_COLOR_DEPTH 16 + LV_COLOR_16_SWAP 1 pair, which LVGL 9.6 deprecates.
LV_DRAW_SW_SUPPORT_RGB5651Nothing renders into plain RGB565, but every bundled image is RGB565 and the swapped blender only accepts an RGB565 source under this switch.
LV_DRAW_SW_SUPPORT_RGB565A81Anti-aliased scaled / rotated images via ImageView.setScale. Without it scaled images render aliased — see LVGL release notes for 9.6.0.
LV_USE_LODEPNG / LV_USE_LIBPNG0Both PNG decoders disabled — PNG is decoded at PAPK-pack time, never on-device. See Bundled image assets.
LV_FONT_MONTSERRAT_*14 onlyMontserrat 14 is the theme face and LV_FONT_DEFAULT. The larger faces TextView.setTextSize can snap to are not LVGL’s stock ones: a board’s text_sizes key (MCU or board toml, 14;20;28;64 on the RP2350s, 14 on the RP2040) compiles ASCII-only subsets generated by scripts/gen-fonts.sh into crates/pd-lvgl-sys/lvgl/fonts/, at about half the flash of a stock face, and pd_fonts.c assembles the table the runtime reads.

Bumping LVGL: vendor at third_party/lvgl, then re-vet lv_conf.h against third_party/lvgl/lv_conf_template.h. Anything new defaults to upstream behavior.

.actrc

Lets you run the GitHub Actions workflows locally via the act tool, useful for catching workflow bugs before pushing to the repo:

-P ubuntu-latest=catthehacker/ubuntu:act-22.04

Install act:

Terminal window
brew install act # macOS
gh extension install nektos/gh-act # via gh CLI

Run the CI workflow locally:

Terminal window
act -W .github/workflows/ci_checks.yml -j building

The jobs of that workflow are building, testing, linting, examples, sim-smoke, formatting and java-formatting.

.actrc lives at the repo root so act picks it up automatically.

scripts/test.sh (host-target test wrapper)

Bare cargo test fails because the picodroid firmware crate is bare-metal (no host test harness) and there is no default cargo target set, so cargo can’t pick a host triple on its own. scripts/test.sh runs the whole workspace against the host triple, twice: once with the shrinker off and once with PICODROID_SHRINK=1, each against a helloworld PAPK built in the same mode (the tests that read the embedded framework classes need PICODROID_APK_PATH set when the build script runs). Both runs enable the line-numbers feature, as the simulator does.

Terminal window
./scripts/test.sh

The script takes no arguments. CI’s Testing job runs exactly this, so passing locally is a strong predictor of green CI.

It compiles the test binary with codegen-units = 16, opt-level = 2 and incremental builds rather than the workspace’s firmware-tuned test profile; PICODROID_TEST_FAST=0 restores the stock profile. It does not build the opt-in mem-diag or sched-diag features: scripts/test-memdiag.sh and scripts/test-scheddiag.sh run simulator soaks with them on.

If you’re chasing a specific failure, run the cargo test line from the script by hand with a -p <crate> or a test-name filter added.

Out-of-tree app builds

App projects under examples/ build as subprojects of the picodroid repo by default. To build an app that lives outside the repo against a picodroid checkout, point two Gradle properties at it:

Terminal window
./gradlew :myapp:assemblePapk \
-Ppicodroid.repoRoot=/path/to/picodroid-rs \
-Ppicodroid.sdkProjectPath=:sdk
  • picodroid.repoRoot — the picodroid source tree (holds tools/, sdk/, scripts/). Default: the build’s root project dir.
  • picodroid.sdkProjectPath — Gradle path of the :sdk project to compile against. Default :sdk.

This is path indirection only — there is no published Maven artifact or project template; the app still composes the picodroid build (e.g. via an included build).

The remaining picodroid.* properties are per-build switches that the top-level scripts set for you (scripts/build-apk.sh passes them as -P rather than through the environment, because a long-lived Gradle daemon would otherwise keep a stale value):

  • picodroid.shrink — 1/true applies the active release shrink map (--shrink; env fallback PICODROID_SHRINK=1).
  • picodroid.shrinkApp — also rename this app’s own classes and private members (--shrink-app; env fallback PICODROID_SHRINK_APP=1). Needs picodroid.shrink.
  • picodroid.stripDebug — drop the .class debug attributes pico-jvm never reads on a device (build-apk.sh --strip-debug; every device path passes it).
  • picodroid.keepLineNumbers — with stripDebug, keep LineNumberTable and SourceFile for a firmware built with the line-numbers feature (--keep-lines; what sim.sh and a PICODROID_LINE_NUMBERS=1 firmware build pass).
  • picodroid.apiContract — error (default), warn or off for the verifyApiContract check.

See Shrinker and Debugging for what each one changes.

Device cargo configuration

.cargo/config.toml holds the linker (flip-link), the link arguments and the probe-rs runner for device builds in tables keyed by cfg(...), not by target triple, so the same file works on stable and nightly cargo. It sets no default target. The details and the per-board aliases are in Cargo aliases.

Host builds on x86-64 Linux (the simulator, the tests) get --cfg aes_force_soft --cfg polyval_force_soft from the same file: the TLS client’s AES and POLYVAL use their software backends there, as they do on the device.

See also

  • Cargo aliases — board-specific build commands.
  • Shrinker — release-versioned renaming of framework class and member names, --shrink-app for the app’s own names, and retrace.sh for reading a shrunk log.
  • Porting guide — board.toml, FreeRTOSConfig, HAL contract.