Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
35934aa
(orin nx/nano) Add pinmux configuration warnings
tsar-boomba May 20, 2025
df047db
Remove gpio bit check (unnecessary); Add PWM SFIO check
tsar-boomba May 21, 2025
33316b6
Add tests for pinmux warnings
tsar-boomba May 22, 2025
7cbd21e
Remove pinmux check for PWM since driver sets bit automatically
tsar-boomba May 23, 2025
a001eac
Remove pinmux check from PWM constructor
tsar-boomba May 27, 2025
c89035d
Add pinmux support for Jetson Orin
tsar-boomba Jun 5, 2025
76097ca
Add pinmux checks for Xavier, X2, and X1
tsar-boomba Jun 5, 2025
a7a2dfd
Revert "Add pinmux checks for Xavier, X2, and X1"
tsar-boomba Jun 10, 2025
1e56d80
Remove unused register_addr function
tsar-boomba Jun 10, 2025
449d04d
Added CLI tool to return GPIO pin mux register address based on provi…
tganeshram Sep 17, 2025
32cc92e
Adding command for tool to pypi and Debian packages, test changes, an…
tganeshram Sep 17, 2025
4d11c35
hex output format correction
tganeshram Sep 17, 2025
be2fc02
import changes, test changes, tool instructions added to readme, new …
tganeshram Sep 18, 2025
1b3706b
New script to update pin_data_file JETSON_ORIN_PIN_DEFS and JETSON_OR…
tganeshram Sep 23, 2025
aadf4b6
edit pinmux lookup test based on new addresses
tganeshram Sep 23, 2025
6b52be8
update copyrights, move gpio pin data update tools to dev, update exi…
tganeshram Sep 23, 2025
70f1252
updating copyright dates
tganeshram Sep 23, 2025
566ebee
UnboundLocalError bug fix
tganeshram Sep 24, 2025
4c5903d
pinmux address change in test
tganeshram Sep 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ rules by running:
sudo udevadm control --reload-rules && sudo udevadm trigger
```

# Pinmux Lookup Tool

The `jetson-gpio-pinmux-lookup` command-line tool helps you find the pinmux register address for GPIO pins. This is useful for debugging or setting up pinmux configurations.

**Usage:**
```shell
jetson-gpio-pinmux-lookup <gpio_pin_number>
```

**Example:**
```shell
jetson-gpio-pinmux-lookup 7
# Output on Orin Device: GPIO Pin 7: Mux Register Address = 0x2430070
```

The tool accepts BOARD mode GPIO pin numbers (1-40) and returns the corresponding pinmux register address in hexadecimal format.

# Running the sample scripts

With the permissions set as needed, the sample applications provided in the
Expand Down Expand Up @@ -184,8 +201,11 @@ None.
It is possible that the GPIO you are trying to use is already being used
external to the current application. In such a condition, the Jetson GPIO
library will warn you if the GPIO being used is configured to anything but the
default direction (input). It will also warn you if you try cleaning up before
setting up the mode and channels. To disable warnings, call:
default direction (input). It will also warn you if:
* You try cleaning up before setting up the mode and channels.
* (Orin NX/Nano only) The pinmux for a requested pin is not properly confirgured to GPIO and the correct direction.

To disable warnings, call:
```python
GPIO.setwarnings(False)
```
Expand Down
31 changes: 31 additions & 0 deletions lib/python/Jetson/GPIO/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Pin Numbering Modes
BOARD = 10
BCM = 11
TEGRA_SOC = 1000
CVM = 1001

# The constants and their offsets are implemented to prevent HIGH from being
# used in place of other variables (ie. HIGH and RISING should not be
# interchangeable)

# Pull up/down options
_PUD_OFFSET = 20
PUD_OFF = 0 + _PUD_OFFSET
PUD_DOWN = 1 + _PUD_OFFSET
PUD_UP = 2 + _PUD_OFFSET

HIGH = 1
LOW = 0

# Edge possibilities
# These values (with _EDGE_OFFSET subtracted) must match gpio_event.py:*_EDGE
_EDGE_OFFSET = 30
RISING = 1 + _EDGE_OFFSET
FALLING = 2 + _EDGE_OFFSET
BOTH = 3 + _EDGE_OFFSET

# GPIO directions. UNKNOWN constant is for gpios that are not yet setup
UNKNOWN = -1
OUT = 0
IN = 1
HARD_PWM = 43
39 changes: 5 additions & 34 deletions lib/python/Jetson/GPIO/gpio.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from Jetson.GPIO.constants import *
from Jetson.GPIO import gpio_event as event
from Jetson.GPIO import gpio_pin_data
from Jetson.GPIO import gpio_cdev
Expand All @@ -32,40 +33,6 @@
if not os.access(_GPIOCHIP_ROOT, os.W_OK):
raise RuntimeError("The current user does not have permissions set to access the library functionalites. Please configure permissions or use the root user to run this. It is also possible that {} does not exist. Please check if that file is present.".format(_GPIOCHIP_ROOT))



# Pin Numbering Modes
BOARD = 10
BCM = 11
TEGRA_SOC = 1000
CVM = 1001

# The constants and their offsets are implemented to prevent HIGH from being
# used in place of other variables (ie. HIGH and RISING should not be
# interchangeable)

# Pull up/down options
_PUD_OFFSET = 20
PUD_OFF = 0 + _PUD_OFFSET
PUD_DOWN = 1 + _PUD_OFFSET
PUD_UP = 2 + _PUD_OFFSET

HIGH = 1
LOW = 0

# Edge possibilities
# These values (with _EDGE_OFFSET subtracted) must match gpio_event.py:*_EDGE
_EDGE_OFFSET = 30
RISING = 1 + _EDGE_OFFSET
FALLING = 2 + _EDGE_OFFSET
BOTH = 3 + _EDGE_OFFSET

# GPIO directions. UNKNOWN constant is for gpios that are not yet setup
UNKNOWN = -1
OUT = 0
IN = 1
HARD_PWM = 43

model, JETSON_INFO, _channel_data_by_mode = gpio_pin_data.get_data()
RPI_INFO = JETSON_INFO

Expand Down Expand Up @@ -159,6 +126,10 @@ def _do_one_channel(ch_info, direction, initial, consumer):
request = gpio_cdev.request_handle(ch_info.line_offset, cdev_direction, initial, consumer)

gpio_cdev.open_line(ch_info, request)

if _gpio_warnings:
gpio_cdev.check_pinmux(ch_info, direction)

_channel_configuration[ch_info.channel] = direction


Expand Down
89 changes: 89 additions & 0 deletions lib/python/Jetson/GPIO/gpio_cdev.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
import os
import fcntl
import ctypes
from dataclasses import dataclass
import mmap
import sys
import warnings
from Jetson.GPIO.gpio_pin_data import ChannelInfo
from Jetson.GPIO.constants import OUT, HARD_PWM

GPIO_HIGH = 1

Expand Down Expand Up @@ -282,4 +288,87 @@ def set_value(line_handle, value):
except (OSError, IOError) as e:
raise GPIOError(e.errno, "Setting line value: " + e.strerror)

_GPIO_IN_OUT_MASK = (1 << 6) | (1 << 4)
"""
A mask for the in/out bit and the tristate bit. We use this for the corrected register value.
"""

_MAP_MASK = mmap.PAGESIZE - 1

@dataclass
class PadCtlRegister:
"""
Simple dataclass for parsing the value of a PADCTL register.\n
bit 1:0 reserved\n
bit 3:2 pull up/down 0=none; 1=down; 2=up; 3=reserved\n
bit 4 tristate config 0=passthrough; 1=tristate\n
bit 6 input/output 0=output; 1=input\n
bit 10 gpio/sfio 0=gpio; 1=sfio\n
bit 12 schmt 0=disabled; 1=enable
"""
is_gpio: bool
is_input: bool
is_tristate: bool

def __init__(self, value: int):
self.is_gpio = (value & (1 << 10)) == 0
self.is_input = (value & (1 << 6)) != 0
self.is_tristate = (value & (1 << 4)) != 0

@property
def is_bidi(self) -> bool:
return self.is_input and not self.is_tristate

def check_pinmux(ch_info: ChannelInfo, direction: int) -> None:
if ch_info.reg_block_base_addr is None or ch_info.reg_offset is None:
warnings.warn("pinmux checks not implemented for current device.")
return

try:
mem_fd = os.open('/dev/mem', os.O_RDONLY | os.O_SYNC)
reg_address = ch_info.reg_block_base_addr + ch_info.reg_offset
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the data structure change i think this need to change also

reg_page_start = reg_address & ~_MAP_MASK
reg_page_offset = reg_address - reg_page_start

# Map 2 pages of /dev/mem starting from the page where the register starts to handle registers across the page boundary
with mmap.mmap(mem_fd, length=mmap.PAGESIZE * 2, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ, offset=reg_page_start) as devmem:
reg_value = int.from_bytes(devmem[reg_page_offset:reg_page_offset + 4], byteorder=sys.byteorder)
reg = PadCtlRegister(reg_value)

# If the register is in a bidrectional state (input enabled, no tristate) we can skip the checks
if reg.is_bidi:
return

is_out = direction == OUT
# If user sets direction to input, but register is output, warn user
if not is_out and not reg.is_input:
corrected_input = reg_value | _GPIO_IN_OUT_MASK
warnings.warn(
f"""
[WARNING] User requested input for channel "{ch_info.channel}", but it is set to output in pinmux. For more information on resolving this, please see
https://docs.nvidia.com/jetson/archives/r36.3/DeveloperGuide/HR/JetsonModuleAdaptationAndBringUp/JetsonOrinNxNanoSeries.html#generating-the-pinmux-dtsi-files

This can be resolved *temporarily* (until next restart) by running:
sudo busybox devmem 0x{reg_address:X} w 0x{corrected_input:X}
"""
)
return

# Same as above, but for when user requests output
if is_out and reg.is_input:
corrected_output = reg_value & ~_GPIO_IN_OUT_MASK
warnings.warn(
f"""
[WARNING] User requested output for channel "{ch_info.channel}", but it is set to input in pinmux. For more information on resolving this, please see
https://docs.nvidia.com/jetson/archives/r36.3/DeveloperGuide/HR/JetsonModuleAdaptationAndBringUp/JetsonOrinNxNanoSeries.html#generating-the-pinmux-dtsi-files

This can be resolved *temporarily* (until next restart) by running:
sudo busybox devmem 0x{reg_address:X} w 0x{corrected_output:X}
"""
)
return

except (OSError, IOError) as e:
warnings.warn('Could not open /dev/mem for pinmux check. If you want pinmux checks, make sure your user has permissions to read /dev/mem and that it exists. Error: ' + e)
finally:
os.close(mem_fd)
Loading