We use GPIO to talk to external devices on the NVIDIA Jetson Nano. Looky here:
One of the nice things about the Jetson Nano is that there is an expansion header which is useful for General Purpose Input Output (GPIO). You may have thought about turning a light on or off as the output of your program, or would like a read a press from an external button. That’s where GPIO is useful!
In this article, we’ll cover how to control GPIO output by turning a Light Emitting Diode (LED) on and off. This is probably one of the most basic examples on how to use GPIO.
As you may have heard, the GPIO pin layout on the Jetson Nano is compatible with the 40 pin layout of a Raspberry Pi (RPi). Also, there is a Jetson GPIO python library which is mostly compatible with RPi.GPIO. Jetson.GPIO is preinstalled in the standard Jetson Nano disk image.
With that said, note that the electrical characteristics of the GPIO expansion header on the Jetson Nano are not the same as a Raspberry Pi. In particular, the Jetson Nano flows much less current on the GPIO pins than the RPi.
For example, a RPi can drive a LED directly from the GPIO pins, whereas a Jetson leaves the LED dimly lit because there is not enough current. The Jetson needs a little help. As you will see, a switching transistor comes to the rescue!
There are a couple of ways to use this article. The first way is to work your way through everything, and use your pearl catcher to grab the wisdom being thrown about. If you’re more pragmatic, jump around to the bits and pieces you find useful. Be forewarned that there be maths here, we’re using electricity, and things could go horribly wrong if you’re not careful. Other than that, play and have some fun.
Here are the parts we are going to use in this circuit:
- A 5mm red LED
- A P2N2222 Transistor
- 1 330Ω resistor
- 1 10kΩ resistor
- Hookup wire
- A breadboard to connect everything together
The easiest way to acquire the parts is to get a collection, such as this “Electronic Fun Kit“. There are many of these types of kits available for experimenting with Raspberry Pi and Arduinos. You may also want to acquire some extra resistors or such. Sparkfun and Adafruit are good sources.
Here’s the thing about LEDs. They don’t use power linearly. Like little pigs they’ll suck so much current up that they will destroy themselves in a puff of magic smoke if left to their own devices. But we can make sure that does not happen.
By adding a resistor (in this application it is called a current limiting resistor), we will limit the amount of current that the LED is able draw. We select the resistor based on Ohm’s Law.
Oh My! Maths …
One of the fundamental rules in electronics is Ohm’s law. You have probably heard about it. Specifically:
Ohm’s law states that the current through a conductor between two points is directly proportional to the voltage across the two points. Introducing the constant of proportionality, the resistance, one arrives at the usual mathematical equation that describes this relationship:
where I is the current through the conductor in units of amperes, V is the voltage measured across the conductor in units of volts, and R is the resistance of the conductor in units of ohms. The main point to remember is that current, voltage and resistance are all related.
And what does that mean to us? In short, we can set the limit on the amount of current that the LED can actually draw by cleverly selecting a proper resistor. This is because a resistor’s current value responds directly proportional to the applied voltage. All we need to know is a couple of things about the LED to calculate the proper resistor value.
First, LEDs have what is called a Forward Voltage, which is basically the minimum voltage difference between the cathode and anode (different terms for this is the minus and plus sides) that you need to supply to an LED. Another thing that we need for our calculation is the Forward Current which is the maximum amount of current that the LED is able to handle continously.
In the LED data sheets, you will see Forward Voltage as $V_F$ and Forward Current as $I_F$.
The LED in this example has a Forward Current of 20mA and a Forward Voltage of 2.0V. We will be using the Jetson Nano 5V pin to drive the LED, so we subtract the Forward Voltage from the 5V and divide by 20mA (0.020A), just like Ohm’s Law tell us to:
We get a result of 150Ω This is the value to flow the maximum amount of current that is safe for this particular LED. A couple of things to note here. First, resistors don’t tend to come in a 150Ω flavor. Even if they did, they have some tolerance built in, which indicates they can have some variance from the actual stated resistance. This is usually a small percentage, but smaller inexpensive resistors may be around 20%! This means that the resistor can be in a range of 120-180Ω for one rated at 150Ω. Because we live in a modern age, we can use an online calculator to help us for this calculation.
Tyrell:Blade Runner, 1982
The light that burns twice as bright burns half as long – and you have burned so very, very brightly, Roy.
Maybe not quite as drastically as the movie quote, but running an LED at maximum current will effect its lifespan. Typically people end up using between 220 and 470Ω resistors for this application. We will be using a generic 330Ω.
About that Transistor
That takes care of protecting our little LED friend. But as we were talking about, because a Jetson Nano GPIO pin is not strong enough to power the LED by itself it needs a little help. We will use a Transistor which will act as a switch to provide current to the LED.
Transistors amplify power. We will be using a Bipolar Junction Transistor (BJT). BJTs are available in two flavors, PNP and NPN. We will be using a NPN transistor, which is what the majority of low power switching circuits use. If you want a deeper background see: A practical guide to transistors and their use. A BJT is made up of three pieces of silicon. A NPN transistor has a piece of P-Type silicon (the Base) sandwiched between two pieces of N-Type silicon (the Collector and the Emitter).
Fun Fact: If you don’t know what P-Type and N-Type mean, here’s a quick explanation. A silicon crystal by itself is an insulator. Adding a minute amount of impurities turn the silicon from a good insulator to a viable (but not great) conductor (hence the name semiconductor). A process called Doping introduces impurities into the pure silicon crystal in order to modify the conductivity. Typically Boron (P-Doping) and Phosphorus (N-Doping) are used. Combining P-Type and N-Type silicon allows electricity to flow.
We are making the most fundamental transistor switch circuit. A normal switch would require a mechanical device to physically flip the circuit. Our switch here will be controlled by the current sent from the Jetson GPIO pin to the transistor. The control signal from the Jetson flows into the Base of the transistor, the Emitter connects to ground, and the output is tied to the Collector.
Here’s a schematic of the circuit we will be using:
- L1 is our 5V LED
- R1 is the current limiting resistor for the LED
- Q1 is the transistor we’ve been talking about, a P2N2222
- R2 is the Base Resistor which tells how much current to let flow in the circuit.
- For this circuit, use a NPN BJT transistor
Calculating the Transistor Bit
There’s one more bit of mystery. When the Jetson GPIO is low (0V), the transistor is in cutoff mode. It looks like an open circuit between the Collector and the Emitter.
However, there is amount of current applied to the Base at which point the transistor starts to “saturate”. This then acts like a short circuit between the Collector and the Emitter. At that point, current flows and our LED lights up, all nice and happy.
In our example the Base current is determined by a Base Resistor which sits between the Jetson GPIO pin and the base of the transistor. The Base Resistor performs much the same function as the current limiting resistor on the LED. Note that the saturation of the transistor is determined by current, not voltage in a BJT.
There’s a little more math involved to figure out what value the Base Resistor should be.
This reads as the current on the Base of the transistor is equal to the desired current at the Collector divided by the gain of the transistor. You remember that transistors are amplifiers, and have an associated gain. The term hFE in the transistor data sheet is the gain number. For this particular transistor, it is equal to 100. If we provide 0.00020A to the Base of the transistor, we should get 20mA at the Collector.
There’s one more little trick. We need to use Ohm’s Law one more time. We know that the GPIO of the Jetson is 3.3V. We divide that by the 0.00020A to get the Resistance, right? Nope. It turns out that there is a 0.7V drop between the Base and the Emitter that we need to take into account. This drop is attributable to the N-P junction of the Base to the Emitter in the transistor. So:
In this circuit, the 13000Ω value of the Base resistor is the maximum resistance that you can have to get 20mA at the Collector.
You will notice that in our circuit we threw in a 10kΩ resistor instead of the 13kΩ. This is for a couple of reasons. First, we know that the LED won’t draw more than 20mA because of the limiting resistor from earlier. Second, 13kΩ is not a common resistor value, so we need to substitute. If you want to be safe, you would tend to go up a size rather than down. But we live wild! And we have a fire extinguisher.
There are also transistor calculators online if you need to check your maths.
We’re now ready to wire everything up and give it a spin. Both LEDs and Transistors flow current in only one direction, and have a + and – side. For the LED, + is the anode, – is the cathode. On a 5mm LED, the + side usually has a longer leg, and usually the – side has a flat spot on the rim of the bulb.
For the Transistor, the Collector goes to the + side, and the Emitter goes to the – side. The arrangement of the pins depends on the particular part chosen.
Given the schematic above, here’s a wiring diagram:
You will need to examine your transistor. The Collector, Base, and Emitter are different depending on which part number you have. We’re using a P2N2222 here. We will be wiring the red wire to +5V on Pin 2 on the Jetson, the black wire to GND on pin 6, and the transistor Base through the base resistor on Pin 12. Pin 12 is selected for the demo examples below.
Once everything is wired up, we’re ready to run some software to blink our light.
We can control our LED from the command line. Here are some useful commands:
# Map GPIO Pin
# gpio79 is pin 12 on the Jetson Nano
$ echo 79 > /sys/class/gpio/export
# Set Direction
$ echo out > /sys/class/gpio/gpio79/direction
# Bit Bangin'!
$ echo 1 > /sys/class/gpio/gpio79/value
$ echo 0 > /sys/class/gpio/gpio79/value
# Unmap GPIO Pin
$ echo 79 > /sys/class/gpio/unexport
# Query Status
$ cat /sys/kernel/debug/gpio
In the above code, the 79 refers to a translation of the Linux sysfs GPIO named gpio79. If we look at the Jetson Nano J41 Header Pinout, we can see that gpio79 is physically pin 12 of the header.
Note: Except for the power, ground, I2C and UART pins, the header pins are GPIO in the Jetson default configuration. Any extra names in the Header Pinout refer to preferred usage if the user makes changes to the device tree and reassigns the pins.
In order to be able to access the GPIO pins, you need to have the proper permissions. This can be accomplished in a couple of ways. First, you can run your commands from a super user terminal. Open the Terminal and execute:
$ sudo su
You are then able to execute the commands with the correct permissions. Also, the permissions can be assigned to a group which you are a member. This is typically done by:
$ sudo groupadd -f -r gpio
$ sudo usermod -a -G gpio your_user_name
Install custom udev rules by copying the 99-gpio.rules file into the rules.d directory:
$ sudo cp /opt/nvidia/jetson-gpio/etc/99-gpio.rules /etc/udev/rules.d/
Please note that for the new rule to take place, you may either need to reboot or reload the udev rules by issuing this command:
sudo udevadm control --reload-rules && sudo udevadm trigger
This sequence is from the Jetson-GPIO Python library documentation, which is installed in the default Jetson Nano image at: /opt/nvidia/jetson-gpio/doc/README.txt.
There is an official Jetson.GPIO library for Python. The Jetson.GPIO library aims to be compatible with RPi.GPIO. We can run the sample for simple output to control our LED:
$ cd /opt/nvidia/jetson-gpio/samples
$ sudo ./run_sample.sh simple_out.py
The run_sample.sh script sets up the paths to the Jetson.GPIO library and calls simple_out.py to flash the LED that is connected to pin 12 on the GPIO header.
This is just touching the Jetson.GPIO library, it is much richer than just this. We’ll examine more functions in subsequent articles.
While it seems like a lot to know to turn LEDs on and off, we now have the foundation to control external devices over the Jetson GPIO Header. In our next installment of the GPIO series, we’ll take a look at input through the GPIO header. Stay tuned!
Here’s some useful information from the NVIDIA Jetson Nano Forum. PinballWizard writes:
The Jetson Nano carrier board uses TXB0108 bidirectional voltage-level translators on the GPIOs to go from the module’s 1.8 V levels to the headers 3.3 V levels. The data sheet for the TXB0108 states “With regard to capacitive loads, TXB translators are designed to drive up to 70 pF without issue.” The capacitance of my test leads is above 70 pF, so I tried an oscilloscope with 10 MΩ, 16 pF probes and the Jetson Nano outputs work fine. With both the multimeter and oscilloscope connected, I get a 56 MHz oscillation on the outputs. The multimeter reads the average, which is ~1.55 V.
The TXB0108 also has a 4 kΩ output impedance. That combined with the 70 pF capacitance limit means that any load on the Jetson Nano’s GPIOs should be both high impedance and low capacitance.