GPIO usage for J401 carrier board on JetPack 6.x

Enabling GPIO on JetPack 6 (Orin Nano / NX) Using Register

Since Nvidia dropped the support of GPIO sysfs on JetPack 6, it’s impossible to access read/write GPIO values from /sys/class/gpio folder. Please refer the following link for possible ways of using GPIO.

Jetson Module Adaptation and Bring-Up >> Jetson Orin NX and Nano Series

Before we start, it’s highly recommended to go through the link above, at least you need to grasp the idea:

  • You can generate the corresponding dtsi files and copy them to corresponding directories, assemble the rootfs and flash your device to persist the GPIO configuration.
  • Or you can dynamically enable the GPIO pin using register provided in the TRM (Technical Reference Manual), which we will show this method in this article. No reflash is required and you may use systemd with custom shell script to persist the configuration.

What You Might Need

Install Necessary Packages

Suppose you have a working J401 carrier board with an Orin NX/Nano module, flashed the latest JetPack 6.x. Once you power the device, please install the following packages:

sudo apt-get update
sudo apt-get install devmem2 gpiod

Check your current I/O configurations

sudo /opt/nvidia/jetson-io/jetson-io.py

Select Configure Jetson 40pin Header

From the display above, you may know which pins are used for special purpose and which pins are unused.

Enable GPIO Pin for Output

Hardware Connections

Select which unused pin in 40 Pin Header you wish to use. In this example we’ll use Pin 31 in 40 Pin Header to light up a LED module.

Tools to prepare:

Connect the module as following:

Grove Connector Pin Name J401 40 Pin Header
5V Pin 2
GND Pin 39
NC No connect
SIG Pin 31

The LED module takes the digital input of SIG, when SIG is HIGH, BLUE LED will light up, otherwise it stays off. We’ll set Pin 31 on board to output mode and write values to LED module.

After connecting the hardware, we need to enable our Pin 31 on bard, which is also called GPIO11 in Jetson SODIMM Signal Name and GPIO3_PQ.06/unused_SOC_GPIO33 in customer usage. We need the later one (You can find them in Pinmux Spreadsheet), refer to Changing PinMux

  • Get the Pinmux register address:
    • In TRM, click System Components → Multi-Purpose I/O Pins and Pin Multiplexing (PinMux) → Pinmux Registers.

    • Search for pin name SOC_GPIO33

    • Get complete pin name. In our case, it’s PADCTL_G3_SOC_GPIO33_0, with offset 0x70.

    • Go to TRM, and in Table 1-15: Pad Control Grouping, find the G3 pad control block = PADCTL_A0 entry.

    • On the Memory Architecture page, click Memory Mapped I/O → Address Map.

    • Search for PADCTL_A0, The base address is PADCTL_A0 = 0x02430000, and the pinmux register address is

PADCTL base address + offset.

And we get our Pinmux register address = 0x02430000 + 0X70 = 0x02430070

  • Get current register value with devmem2, and write value 0x400 to enable this pin for GPIO output mode.
# Check current value
sudo devmem2 0x02430070

# Write value
sudo devmem2 0x02430070 w 0x400
  • Using gpioset to write test it:

Set it to LOW

sudo gpioset --mode=wait `gpiofind "PQ.06"`=0

Set it to HIGH

sudo gpioset --mode=wait `gpiofind "PQ.06"`=1

Note that in gpioset command, usually you need use gpiofind to get the corresponding number in gpiod.

If everything went well, you should be able to see your LED light up:

Enable GPIO for Input

Alternative, according to the register operation table and the description in NV’s documentation. You can write 0x450 to corresponding register to set your GPIO pin for input mode.

sudo devmem2 0x02430070 w 0x450

We use a shell script to monitor GPIO’s reading using gpioset. This time we use a MCU to write HIGH/LOW to Jetson device, let’s see if it can read values properly.

Hardware Connection

We use a XIAO ESP32S3 D10 pin to write HIGH/LOW values.

And we upload the following sketch:

void setup() {
  // initialize digital pin2  as an output.
  Serial.begin(115200);
  pinMode(D10, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  Serial.println("Write HIGH");
  digitalWrite(D10, HIGH);
  delay(1000);                       // wait for a second
  Serial.println("Write LOW");
  digitalWrite(D10, LOW);
  delay(1000);                       // wait for a second
}

In jetson, we create the following script to monitor the GPIO value:

#!/bin/bash

# get gpio line information
gpio_info=$(gpiofind "PQ.06")

# check if gpio can be found
if [ -z "$gpio_info" ]; then
    echo "GPIO PQ.06 not found"
    exit 1
fi

# extract gpio chip info and offset
gpiochip=$(echo "$gpio_info" | cut -d ' ' -f 1)
offset=$(echo "$gpio_info" | cut -d ' ' -f 2)

# ctrl + c to terminate
trap "echo 'Terminating...'; exit 0" SIGINT

echo "Monitoring GPIO PQ.06 ($gpiochip $offset)... Press Ctrl+C to exit."

# enter the loop, read gpio value every second
while true; do
    value=$(gpioget "$gpiochip" "$offset")
    echo "$(date '+%Y-%m-%d %H:%M:%S') - GPIO PQ.06 value: $value"
    sleep 1
done

Save it as monitor_gpio.sh, grant the execute permission:

chmod +x ./monitor_gpio.sh

Execute the script:

sudo ./monitor_gpio.sh

You can see the monitor result:

For easy reference, we put Arduino’s serial port output with the Jetson’s gpioget result in the same screen:

40-Pin Expansion Header GPIO Usage Considerations

The same is for Orin Nano and Orin NX, they share the similar design with Jetson Nano’s 40 Pin Header.

1 Like

Hi there,

Gill Jarard WHO?

Man this is Great work, I can’t believe Nvidia’s lack of consistency on this,Probably a post on the subject monthly asking this too!
The GPIO control is a game changer for any Hardware wanting some AI easy like. You put this together very nice… WAY to GO!

I’m sure it will help a lot of folks! :+1:

GL :slight_smile: PJ :v:

And in it’s own thread! :heart_eyes: