Pi4J started with, and is best documented for, the Raspberry Pi. On a Raspberry Pi, the GPIO numbers you pass to Pi4J match the SoC’s own “BCM” numbering directly, so pin 16 on the header is BCM 23 as you can see in the GPIO header for, for instance, the Raspberry Pi 5.
Many other SBCs (Banana Pi, Orange Pi, and other Allwinner- or Rockchip-based boards) use a different SoC with its own GPIO controller and numbering scheme, even when the board physically matches the Raspberry Pi’s header layout. This page walks through the general process of finding the right GPIO addressing for such a board, using a Banana Pi M4 Zero (Allwinner H618) as an example.
Start with the manufacturer’s documentation. For the Banana Pi M4 Zero, the official pinout table lists physical pin 16 as PI15: GPIO bank I, pin 15.
Don’t assume every pin on a Raspberry-Pi-compatible header is actually a GPIO. On the Banana Pi M4 Zero, physical pin 22 — which is BCM 25 (a GPIO) on a Raspberry Pi — is wired to 3.3V power instead. Always check the pinout table before wiring!
gpiochipAllwinner chips group GPIOs into lettered banks of 32 pins each (PA0-PA31, PB0-PB31, and so on — see linux-sunxi.org/GPIO), exposed as /dev/gpiochip* character devices. Install libgpiod’s command-line tools and list the chips:
sudo apt install -y gpiod
gpiodetect
gpioinfo
On the Banana Pi M4 Zero this showed gpiochip0 with 32 lines and gpiochip1 with 288 lines. Since 288 = 9 × 32, matching banks A through I, gpiochip1 is the controller behind the 40-pin header — not the default gpiochip0.
gpiochip0 - 32 lines:
line 0: unnamed kernel input active-high [used]
line 1: unnamed kernel input active-high [used]
line 2: unnamed unused input active-high
...
gpiochip1 - 288 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
...
Each bank’s index (A=0, B=1, C=2, … I=8) times 32, plus the pin number within the bank, gives the absolute line offset on the chip. For PI15 with I=8: 8 × 32 + 15 = 271.
Confirm the offset with gpioset and an LED (or multimeter) before touching Java:
gpioset gpiochip1 271=1 # ON
gpioset gpiochip1 271=0 # OFF
Once verified, use .bus() to select the chip and .bcm() for the line offset (see FFM Provider: GPIO Chip Selection):
private static final int GPIO_LED = 271; // physical pin 16 = PI15 on gpiochip1
var ledRed = pi4j.create(DigitalOutput.newConfigBuilder(pi4j)
.id("led").name("LED").bus(1).bcm(GPIO_LED)
.shutdown(DigitalState.LOW).initial(DigitalState.LOW));
gpiodetect/gpioinfo to find which gpiochip actually serves the header.gpioset/gpioget before writing any Java code..bus() and .bcm() accordingly.