Peripheral Access¶
Phase 4 — Track B — Module 5.1 · Application Development
Focus: Access and control hardware peripherals on the Jetson Orin Nano 8GB from Linux userspace — GPIO, PWM, UART, SPI, I2C, CAN, USB, storage, and backlight. Every interface is shown with both sysfs/chardev and library approaches.
Hub: 5. Application Development
Table of Contents¶
- GPIO (Linux)
- GPIO Naming — Alphanumeric to Numeric Assignment
- PWM (Linux)
- ADC (Linux)
- UART (Linux)
- SPI (Linux)
- I2C (Linux)
- CAN (Linux)
- USB Host Mode (Linux)
- USB Device Mode (Linux)
- NVMe / PCIe Storage (Linux)
- SD/MMC Card (Linux)
- Backlight (Linux)
- Projects
- Resources
1. GPIO (Linux)¶
Jetson Orin Nano exposes GPIOs through the gpiochip character device interface (/dev/gpiochipN). The legacy sysfs interface (/sys/class/gpio/) is deprecated — use libgpiod instead.
libgpiod tools¶
# List all GPIO chips
gpiodetect
# Show all lines on a chip
gpioinfo gpiochip0
# Read a GPIO input
gpioget gpiochip0 <line>
# Set a GPIO output high
gpioset gpiochip0 <line>=1
# Monitor GPIO events (rising/falling edge)
gpiomon gpiochip0 <line>
libgpiod in C¶
#include <gpiod.h>
struct gpiod_chip *chip = gpiod_chip_open("/dev/gpiochip0");
struct gpiod_line *line = gpiod_chip_get_line(chip, 42);
/* Output */
gpiod_line_request_output(line, "my-app", 0);
gpiod_line_set_value(line, 1);
/* Input */
gpiod_line_request_input(line, "my-app");
int val = gpiod_line_get_value(line);
gpiod_chip_close(chip);
libgpiod in Python¶
import gpiod
chip = gpiod.Chip('gpiochip0')
line = chip.get_line(42)
# Output
line.request(consumer="my-app", type=gpiod.LINE_REQ_DIR_OUT)
line.set_value(1)
# Input
line.request(consumer="my-app", type=gpiod.LINE_REQ_DIR_IN)
val = line.get_value()
Device tree GPIO configuration¶
GPIOs are assigned functions in the pinmux device tree. To use a pin as GPIO, it must be configured as GPIO (not an alternate function) in the pinmux spreadsheet. See Module 2 — Custom Carrier Board for pinmux configuration.
2. GPIO naming — alphanumeric to numeric assignment¶
Jetson uses a SoC-level naming scheme (e.g., GPIO09, PQ.05, SOC_GPIO42) that differs from the Linux line number within a gpiochip.
Finding the mapping¶
# Show chip + line for all GPIOs with their names
gpioinfo | grep -i "GPIO"
# Or use the Jetson-specific tool
sudo cat /sys/kernel/debug/gpio
NVIDIA's mapping table¶
NVIDIA publishes a GPIO mapping table in the Jetson Orin Nano Developer Kit User Guide and the pinmux spreadsheet. The key columns:
| SoC pad name | GPIO port.pin | gpiochip | Line number | 40-pin header |
|---|---|---|---|---|
SOC_GPIO42 |
PH.00 |
gpiochip0 | 106 | Pin 7 |
SOC_GPIO43 |
PH.01 |
gpiochip0 | 107 | Pin 11 |
Always verify with gpioinfo on your actual device — line numbers can shift between L4T versions.
3. PWM (Linux)¶
Orin Nano exposes PWM channels via the Linux PWM subsystem.
sysfs interface¶
# Export PWM channel (chip 0, channel 0)
echo 0 > /sys/class/pwm/pwmchip0/export
# Configure: 1 kHz, 50% duty cycle
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period # ns
echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle # ns
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
Common uses on Jetson¶
| Use case | PWM channel | Notes |
|---|---|---|
| Fan control | Dedicated fan PWM | Controlled by jetson_clocks or device tree pwm-fan node |
| LED brightness | GPIO-capable PWM pin | Requires pinmux set to PWM function |
| Servo motor | GPIO-capable PWM pin | 50 Hz, 1–2 ms pulse width |
| Backlight | Display backlight PWM | See Backlight |
4. ADC (Linux)¶
The Jetson Orin Nano SoM has limited ADC capability — no general-purpose ADC pins are exposed on the carrier connector. For analog sensing:
External ADC options¶
| ADC | Interface | Resolution | Channels | Common use |
|---|---|---|---|---|
| ADS1115 | I2C | 16-bit | 4 | Voltage, current, temperature sensors |
| MCP3008 | SPI | 10-bit | 8 | General-purpose analog input |
| INA226 | I2C | 16-bit | 2 (V + I) | Power monitoring |
Reading external ADC via IIO subsystem¶
If your external ADC has a Linux IIO driver:
# List IIO devices
ls /sys/bus/iio/devices/
# Read raw value
cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw
# Read scale
cat /sys/bus/iio/devices/iio:device0/in_voltage0_scale
Voltage = raw * scale (in millivolts).
5. UART (Linux)¶
Orin Nano exposes multiple UART ports. The debug console uses ttyTCU0 (Tegra Combined UART). Application UARTs appear as /dev/ttyTHS*.
Available UARTs¶
| Device | Use | Baud rate |
|---|---|---|
/dev/ttyTCU0 |
Debug console (bootloader + kernel) | 115200 |
/dev/ttyTHS0 |
Application UART 0 | Configurable |
/dev/ttyTHS1 |
Application UART 1 | Configurable |
Using UART from userspace¶
# Quick test with minicom
minicom -D /dev/ttyTHS0 -b 115200
# Or with stty + cat
stty -F /dev/ttyTHS0 115200 cs8 -cstopb -parenb
echo "hello" > /dev/ttyTHS0
cat /dev/ttyTHS0
Python (pyserial)¶
import serial
ser = serial.Serial('/dev/ttyTHS0', 115200, timeout=1)
ser.write(b'hello\n')
data = ser.readline()
ser.close()
6. SPI (Linux)¶
SPI buses appear as /dev/spidevX.Y (bus X, chip-select Y).
Enable SPI in device tree¶
SPI buses must be enabled in the pinmux and device tree. Use the pinmux spreadsheet to assign SPI function to the correct pins.
spidev test¶
Python (spidev)¶
import spidev
spi = spidev.SpiDev()
spi.open(0, 0) # bus 0, CS 0
spi.max_speed_hz = 1000000
response = spi.xfer2([0x01, 0x02, 0x03])
spi.close()
7. I2C (Linux)¶
I2C buses appear as /dev/i2c-N.
Scanning for devices¶
Reading/writing registers¶
# Read register 0x00 from device 0x50 on bus 1
sudo i2cget -y 1 0x50 0x00
# Write 0xFF to register 0x01
sudo i2cset -y 1 0x50 0x01 0xFF
Python (smbus2)¶
from smbus2 import SMBus
with SMBus(1) as bus:
data = bus.read_byte_data(0x50, 0x00)
bus.write_byte_data(0x50, 0x01, 0xFF)
Common I2C devices on Jetson carriers¶
| Device | Address | Purpose |
|---|---|---|
| EEPROM (carrier ID) | 0x50–0x57 | Board identification |
| INA3221 | 0x40–0x43 | Power monitoring (VIN, 3.3V, 5V) |
| IMU (BMI088, ICM-42688) | 0x68–0x69 | Inertial measurement (robotics) |
| RTC (DS3231) | 0x68 | Real-time clock (battery-backed) |
8. CAN (Linux)¶
CAN bus on Jetson requires an external CAN transceiver on the carrier board (the SoC has CAN controllers but no integrated PHY).
Setup¶
# Configure CAN interface (500 kbps)
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
# For CAN-FD
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
sudo ip link set can0 up
Send and receive¶
# Send a frame
cansend can0 123#DEADBEEF
# Receive (dump all frames)
candump can0
# Generate test traffic
cangen can0
Python (python-can)¶
import can
bus = can.interface.Bus(channel='can0', interface='socketcan')
# Send
msg = can.Message(arbitration_id=0x123, data=[0xDE, 0xAD, 0xBE, 0xEF])
bus.send(msg)
# Receive
msg = bus.recv(timeout=1.0)
print(f"ID: {msg.arbitration_id:#x}, Data: {msg.data.hex()}")
9. USB host mode (Linux)¶
Jetson Orin Nano supports USB 3.2 Gen 2 (10 Gbps) and USB 2.0 host ports.
Enumeration¶
# List connected USB devices
lsusb
# Show USB tree with speeds
lsusb -t
# Detailed device info
lsusb -v -d <vendor>:<product>
Common USB peripherals¶
| Device type | Driver | Notes |
|---|---|---|
| USB camera | UVC (uvcvideo) |
Works out of the box, see Multimedia |
| USB serial (FTDI, CP210x) | ftdi_sio, cp210x |
Appears as /dev/ttyUSB* |
| USB Ethernet | cdc_ether, r8152 |
Appears as eth* or usb* |
| USB storage | usb-storage |
Appears as /dev/sd* |
| USB audio | snd-usb-audio |
ALSA device |
10. USB device mode (Linux)¶
The Orin Nano dev kit's USB-C port supports device (gadget) mode for flashing and development.
USB gadget framework¶
# Load the USB gadget configfs
modprobe libcomposite
# Common gadgets:
# - g_ether: USB Ethernet gadget (device appears as network adapter on host)
# - g_serial: USB serial gadget (device appears as ttyACM on host)
# - g_mass_storage: USB mass storage gadget
Typical use cases¶
| Gadget | Use case |
|---|---|
| Ethernet (RNDIS/ECM) | SSH into Jetson over USB without network cable |
| Serial (ACM) | Debug console over USB |
| Mass storage | Expose a partition or file as USB drive |
11. NVMe / PCIe storage (Linux)¶
Most Jetson Orin Nano deployments use NVMe SSD for the root filesystem (faster and more reliable than SD card).
NVMe operations¶
# List NVMe devices
nvme list
# Check health
sudo nvme smart-log /dev/nvme0
# Benchmark
sudo fio --name=test --rw=randread --bs=4k --numjobs=4 \
--size=1G --runtime=30 --time_based --filename=/dev/nvme0n1
# Check PCIe link speed
sudo lspci -vv | grep -A 20 "Non-Volatile"
PCIe link verification¶
If the link trains at a lower speed than expected, check trace routing (see Module 2 — Carrier Board).
12. SD/MMC card (Linux)¶
SD card slot (if present on carrier) appears as /dev/mmcblk*.
# Check SD card info
sudo fdisk -l /dev/mmcblk1
# Mount
sudo mount /dev/mmcblk1p1 /mnt
# Check speed class
cat /sys/block/mmcblk1/device/speed_class
Production note: SD cards have limited write endurance. Use NVMe for root filesystem; reserve SD for optional data logging or field updates only.
13. Backlight (Linux)¶
If your carrier has an LCD with PWM-controlled backlight:
# List backlight devices
ls /sys/class/backlight/
# Get current brightness
cat /sys/class/backlight/<device>/brightness
# Get max brightness
cat /sys/class/backlight/<device>/max_brightness
# Set brightness (0 = off, max = full)
echo 128 > /sys/class/backlight/<device>/brightness
Configure the backlight PWM channel in the device tree for your display panel.
14. Projects¶
- Sensor dashboard: Read an I2C temperature sensor (e.g., TMP102) and a SPI ADC (e.g., MCP3008 for analog input), display values on a UART terminal at 1 Hz.
- CAN bus monitor: Build a CAN bus sniffer that logs all frames to a file with timestamps. Add filtering by arbitration ID.
- GPIO interrupt counter: Use
gpiomonor libgpiod event monitoring to count rising edges on an input pin. Measure maximum event rate. - USB gadget network: Configure the Jetson as a USB Ethernet gadget so a host laptop can SSH into it over a single USB-C cable.
15. Resources¶
| Resource | Description |
|---|---|
| Jetson Orin Nano Developer Kit User Guide | Pin header mapping, UART/SPI/I2C bus assignments |
| libgpiod documentation | Character device GPIO API (replaces sysfs) |
| Linux kernel SPI/I2C docs | Documentation/spi/ and Documentation/i2c/ in kernel source |
| SocketCAN documentation | Linux CAN subsystem, ip link, candump, cansend |
| NVMe CLI | nvme-cli package for NVMe management and diagnostics |
| 2. Custom Carrier Board | Pinmux, peripheral validation checklist |