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:
| Symbol | Picodroid value | Why |
|---|---|---|
LV_COLOR_FORMAT_DEFAULT | LV_COLOR_FORMAT_RGB565_SWAPPED | 16-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_RGB565 | 1 | Nothing 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_RGB565A8 | 1 | Anti-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_LIBPNG | 0 | Both PNG decoders disabled — PNG is decoded at PAPK-pack time, never on-device. See Bundled image assets. |
LV_FONT_MONTSERRAT_* | 14 only | Montserrat 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.04Install act:
brew install act # macOSgh extension install nektos/gh-act # via gh CLIRun the CI workflow locally:
act -W .github/workflows/ci_checks.yml -j buildingThe 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.
./scripts/test.shThe 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:
./gradlew :myapp:assemblePapk \ -Ppicodroid.repoRoot=/path/to/picodroid-rs \ -Ppicodroid.sdkProjectPath=:sdkpicodroid.repoRoot— the picodroid source tree (holdstools/,sdk/,scripts/). Default: the build’s root project dir.picodroid.sdkProjectPath— Gradle path of the:sdkproject 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/trueapplies the active release shrink map (--shrink; env fallbackPICODROID_SHRINK=1).picodroid.shrinkApp— also rename this app’s own classes and private members (--shrink-app; env fallbackPICODROID_SHRINK_APP=1). Needspicodroid.shrink.picodroid.stripDebug— drop the.classdebug attributes pico-jvm never reads on a device (build-apk.sh --strip-debug; every device path passes it).picodroid.keepLineNumbers— withstripDebug, keepLineNumberTableandSourceFilefor a firmware built with theline-numbersfeature (--keep-lines; whatsim.shand aPICODROID_LINE_NUMBERS=1firmware build pass).picodroid.apiContract—error(default),warnorofffor theverifyApiContractcheck.
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-appfor the app’s own names, andretrace.shfor reading a shrunk log. - Porting guide — board.toml, FreeRTOSConfig, HAL contract.