With the advent of JetPack 6.2, there have been some changes to how the Jetson Orin Developer Kits handle GPIO. By default, GPIO is input-only. Let’s fix that. Looky here:
Introduction
One of the most endearing qualities of each JetPack release is giving people the chance to discover what is broken or changed between releases. It’s a great mental exercise — testing both will and fortitude. Some of this is understandable when going from one major release to the next. Ubuntu 20.04 to Ubuntu 22.04, for example. Some of it is what we might consider puzzling. It’s the little things that are the most fun part of the challenge!
If you’re not an embedded or system engineer, one of the more veiled aspects of the Jetson system (or any Linux box, for that matter) is the Device Tree. The idea behind the Device Tree is simple: it’s a map of the hardware layout of the machine. Each board is a little bit different, so each of the Device Trees is different. In other words, a device tree that works on one board doesn’t work on a board with a different layout.
Device Tree: Closer to the Metal
The overview is pretty simple: the Device Tree is a map that tells the kernel where the hardware resides. In a microcontroller, we think about reading and writing to different addresses. Sometimes it’s a memory location; other times it’s a hardware register, and so on. However, in Linux, there’s a level of indirection. The Device Tree associates names with addresses. When the Linux kernel talks to the hardware, it uses a name rather than a physical address.
To make this more efficient, a human-readable version of the Device Tree (extension .dts) is compiled into an object file (.dtb). There is a Device Tree compiler named dtc that can both compile and decompile source and object Device Tree code. The kernel reads the .dtb file, associates names with handles, and goes from there. Like compiled code, it includes an integrated symbol table along with fixups and other information.
There is a way to extend an existing Device Tree, which is called a Device Tree overlay. This enables modifying or adding information to the device tree without having to alter the base tree. By convention, a compiled device tree overlay has the extension .dtbo.
To give you a feel for scale, the base Device Tree in source form on a Jetson Orin Nano Developer Kit is around 1,100 lines. Because modifications to the Device Tree can easily break things — up to and including preventing the Jetson from booting — you can understand why Device Tree Overlays are useful development tools. They make it easier to narrow down where an issue might be occurring.
Matching Hardware to Drivers
Another responsibility of the Linux kernel and the Device Tree is associating a hardware signal with a given driver. Linux programmers tend to mix the terms “kernel module” and “driver” — both mean the same thing most of the time. The device tree can define information that the driver uses to interact with the hardware at that address. This is one of the more challenging aspects for most people. Drivers may have parameters, but it can be difficult to find out what those parameters are without a good grasp of the driver codebase. For example, the kernel will associate a GPIO pin with the tegra-gpio module.
This is easy to imagine in a simple instance like this, but remember that the GPIO pin may be part of the expansion header, which belongs to a pinmux, which is part of a bus — and on up to the root of the tree. You can view the expanded tree on a running system starting at /proc/device-tree.
Jetson Device Tree
For most Linux systems, like a PC, this is straightforward. Once the base Device Tree is in place (usually done by the manufacturer), you don’t have to mess with it. However, on a system like the Jetson — which, at its heart, is a development kit — most likely you’ll want to dive into the Device Tree.
The idea of naming hardware in the Device Tree sounds pretty good at first. But when you look at a signal flow on the Jetson, there’s a hidden issue. The signals flow both ways, of course. The Tegra SoC — the main chip on the Jetson module — has a large number of signals available, well over a thousand. There is a ball grid array (BGA) on the underside of the chip, which connects to the Jetson Module PCB. The Jetson Module has a 260-pin connector that attaches to the Jetson Carrier Board. Signals from the 260-pin connector are then routed to the various connectors and devices on the carrier board.
Routing is handled using multiplexers, which function like signal switchboards. Multiple input signals can be connected to a multiplexer, but only one (or a selected few) is passed through to the output at any given time. The selection is controlled by dedicated signal lines, which determine which input is routed to the output.
For example, on the Jetson Orin, there is a pinmux that controls which signals are sent/received by the expansion header pin.
Therein lies the issue. The pinmux can route several different signals from the input to one output, so the output can’t have the same name as the input signal. Therefore, signals have names that are specific to the board they are on. There’s a connector name, a carrier board name, a Jetson module name, and a Tegra SoC name. Sometimes they are the same; other times, they are not. It can be a little confusing the first time you see it.
Taming the Device Tree
At this point, we know a few things. The Device Tree is simple, but big. You can add bits and pieces here and there with a device tree overlay. Is there a civilized way to work with the Device Tree?
The short answer is that it depends on what you want to do. The Jetson has a tool called jetson-io, which allows you to configure the Jetson 40-pin Expansion Header, the CSI connector (for cameras), and the M.2 Key E slot.
There are entries in the Expansion Header section for a limited amount of hardware. The CSI connector section adds support for Raspberry Pi cameras based on the IMX219 and the IMX477. jetson-io is available in the /opt/nvidia/jetson-io directory. You’ll need to use sudo to run jetson-io.py to modify the pin usage, as this is a system-level change.
The Expansion Header section also allows you to select the default special functions for the pins, such as I2S2, SPI, UART, and PWM. Typically, PWM is not used on the Jetson, as there can be timing issues if you are not using the real-time capabilities of the ARM Cortex cores.
Getting Serious
When you need to access signals outside of the jetson-io experience, you’ll need reference resources. If you want to know everything, you will need the Jetson Orin NX Series and Jetson Orin Nano Series Pinmux. You can use this spreadsheet to generate the entire source for the Device Tree.
The Pinmux Spreadsheet has entries for all the signals on the Jetson Carrier Board. It is also overwhelming, with the main sheet being 1,100 rows by 60 columns. One of the columns is “Device Tree Pin Name,” which is the Linux name you use to work with that signal.
Perhaps an easier way to work with the expansion header is to use the Linux kernel source code. I have the headers and the Expansion Header include file in the JetsonHacks GitHub jetson-orin-gpio-patch repository, in the headers directory. These are available in the Jetson Orin BSP, copied over for convenience.
In either case, you can look up the pin names and use them to work on the Expansion Header. As an example, the repository has a file that configures Pin 7 as GPIO: pin7_as_gpio.dts. By default, Pin 7 is a GPIO pin, but it is configured to accept input only. When compiled and installed, the .dtbo file sets “nvidia,enable-input = <0x1>;” which configures the pin to accept both input and output. Instructions for compiling and installing the overlay are in the repository’s README.md file.
Conclusion
Exploring the Device Tree is certainly a challenge! The closer you get to the metal, the more you have to know. It’s not that it necessarily gets more difficult. In fact, each little part is easy to understand on its own. It’s just that the sheer volume of information you have to keep in mind is the difficult bit.
The post Device Tree Overlays on Jetson: Scary but fun! appeared first on JetsonHacks.