BeagleBone PRU GPIO: Pinmux Is the Fix, Not the Mask

Tom Garrett6 min read
Other ManufacturerPLC HardwareTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

The number that matters is the current through the external LED. A changing software bit produces no light unless the processor pad is routed to the header, configured as an output, and driving enough current through a suitable series resistor. In the reported setup, the LED worked from 3 V and GND and the onboard USR[1-3] LEDs toggled, so the program executed and the LED polarity was known. The unresolved boundary was the header-pin configuration.

The working correction for P9_16 used the GPIO peripheral through the PRU OCP master port. It set the pin direction to out, selected gpio in the pinmux state, and then wrote the GPIO set and clear registers. That is a GPIO-path solution, not proof that P9_16 operates as a direct pruout pin.

Electrical and timing limits

An LED that never changes indicates zero usable voltage swing at the header, an open current path, or a transition too short to observe. This is current and routing, not logic. Use a current-limiting resistor selected from R >= (VOUT - VF) / ILED, and check the processor documentation for the permitted output current. Driving an LED directly without a suitable resistor can damage the output pad or LED.

Quantity or state Observed or required condition Where to read it
External LED operation Lights when connected to 3 V and GND Bench wiring check
P9_11 mux state Reported as gpio config-pin current-mode output
GPIO direction Must be out for the demonstrated method /sys/class/gpio/gpio51/direction for the working P9_16 example
Pinmux selection gpio for GPIO-register access; pruout only for a supported direct PRU route Pinmux state and processor pin-mux table
Delay request 500000000/5 cycles per state Argument to __delay_cycles()
Measured period Two delays plus register-write and loop overhead Oscilloscope or logic analyzer at the header

The source labels each delay as one-half second, but the cycle count becomes a time only after applying the PRU clock rate used by the build and target. Measure the pin when timing matters rather than using LED appearance as the timing test.

PRU output paths compared

Criterion Direct PRU I/O GPIO peripheral through OCP
Software interface __R30 for output and __R31 for input GPIO_SETDATAOUT and GPIO_CLEARDATAOUT
Required mux A supported PRU output/input function such as pruout or pruin gpio
Pin eligibility Only header pads physically routed to the selected PRU signal Pads routed to an accessible GPIO bank, subject to ownership and reservation
Direction setup Defined by the selected direct PRU function GPIO direction must be output
Timing behavior Intended for deterministic, low-latency PRU pin access Peripheral transaction through the OCP path
Evidence-backed choice here P9_11 is not a direct PRU register pin; P9_25 was identified as direct-route capable but was not demonstrated working P9_16 worked with GPIO direction and pinmux initialization

Writing a header-pin bit mask to gpio1[GPIO_SETDATAOUT] selects the GPIO-peripheral path. Writing __R30 selects the direct PRU path. A macro in prugpio.h supplies a mask; it does not configure the pad, claim ownership, or change the GPIO direction.

Pin-selection decision

Use P9_16 with the demonstrated GPIO method when the goal is simply to obtain a working external LED output. The working initialization references gpio51 and labels the header pin as GPIO port 1, but its accompanying comment calls it “port 1 pin 18.” Those two descriptions conflict: global GPIO number 51 corresponds arithmetically to bank 1 plus offset 19 when banks contain 32 bits. Treat the sysfs path, pinmux path, and actual P9_16 macro definition as the controlling configuration; inspect the macro before substituting a hand-calculated mask.

For P9_25, the stated direct-path preparation command is config-pin P9_25 pruout. Use that approach only with code that drives the corresponding __R30 bit. Mixing a pruout mux with GPIO set/clear writes connects different signal paths and leaves the header unchanged.

The reported config-pin -l P9_16 output listed default gpio gpio_pu gpio_pd gpio_input pwm, with no pruout. The successful sample selected gpio, so no unlisted mode is required for that result.

Recommended P9_16 procedure

  1. Keep the remote-processor overlay selection used by the installation: uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-19-TI-00A0.dtbo.
  2. Connect the LED with correct polarity and a calculated current-limiting resistor.
  3. Enable PRU access to the peripheral interconnect by clearing CT_CFG.SYSCFG_bit.STANDBY_INIT.
  4. Add an initialization section that sets GPIO 51 to output and selects the gpio mux state for P9_16.
  5. Write P9_16 to the GPIO set register, delay, write it to the clear register, and delay again.
  6. Build and start the PRU program using the same remote-processor workflow that already toggles the onboard LEDs.
#pragma DATA_SECTION(init_pins, ".init_pins")
#pragma RETAIN(init_pins)
const char init_pins[] =
    "/sys/class/gpio/gpio51/direction\0out\0"
    "/sys/devices/platform/ocp/ocp:P9_16_pinmux/state\0gpio\0"
    "\0\0";
uint32_t *gpio1 = (uint32_t *)GPIO1;
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

while (1) {
    gpio1[GPIO_SETDATAOUT] = P9_16;
    __delay_cycles(500000000/5);
    gpio1[GPIO_CLEARDATAOUT] = P9_16;
    __delay_cycles(500000000/5);
}

The __halt() placed after this infinite loop is unreachable during normal execution. Stop the PRU through its controlling runtime rather than expecting the loop to fall through.

Output verification

  1. Read back the pinmux state and confirm that P9_16 is in gpio mode.
  2. Read /sys/class/gpio/gpio51/direction and confirm out.
  3. Probe P9_16 relative to board ground with a logic analyzer or oscilloscope. Look for alternating high and low levels before diagnosing the LED.
  4. If the header toggles but the LED does not, measure voltage across the LED and resistor, then correct polarity, continuity, or resistor sizing.
  5. If the header remains fixed, confirm that the running binary contains the .init_pins data, that the OCP master port is enabled, and that the code writes the GPIO bank containing the selected pin.

A working onboard USR LED proves only that PRU execution and that particular GPIO route work. It does not validate the header pad’s mux, direction, reservation, or mask.

Recurring configuration pitfalls

The most common failure is treating the mask, GPIO direction, and pinmux as one setting. They are separate controls. Another is assuming that config-pin -l alone defines every usable route; compare its result with the active pinmux state and the processor pin-mux table. Header functions can also be unavailable when another subsystem owns the pad, so check current ownership before changing the mux.

P9_11 reporting gpio does not make it a direct __R30/__R31 pin. A GPIO-path attempt requires the correct bank and bit, output direction, pad ownership, and GPIO mux. For a direct PRU design, select a pin with an explicit PRU route and keep the mux function matched to the register interface.

FAQ

How do I make the PRU toggle P9_16?

Set /sys/class/gpio/gpio51/direction to out, set the P9_16 pinmux state to gpio, clear STANDBY_INIT, and write P9_16 to GPIO_SETDATAOUT and GPIO_CLEARDATAOUT.

How do I tell whether to use __R30 or GPIO_SETDATAOUT?

Use __R30 only when the selected header pad has a direct PRU output route and is muxed to that function. Use GPIO_SETDATAOUT when the pad is muxed as gpio and the PRU accesses the GPIO peripheral through OCP.

How do I verify the PRU delay at the header?

Probe the header with an oscilloscope or logic analyzer and measure both high and low intervals. The expression 500000000/5 specifies cycles; convert it using the actual PRU clock rate for the target.

How do I troubleshoot a pin that stays fixed?

Check pinmux state, GPIO direction, pad ownership, the selected GPIO bank and mask, and STANDBY_INIT. If those states match the program but the pad still does not toggle, stop changing wiring or mux settings and escalate with the binary, active overlay, pin states, and scope capture to official BeagleBoard or processor-manufacturer support.

Back to blog