Skip to content

C library to manage the SPI, I2C and GPIO header of the Nvidia JETSON boards for customized usage for Bridgesoft programs.

License

Notifications You must be signed in to change notification settings

bridge-software/JETSPI

 
 

Repository files navigation

JETGPIO library

C library to manage the GPIO header of the Nvidia JETSON boards

ORIN NOW SUPPORTED - NOTIFICATION OF ISSUES WELCOME

FUNCTIONALITY:

  • Supported models:

    • JETSON NANO and TX1

    • (BETA) JETSON ORIN NANO and ORIN NX

  • GPIO control of all the header pinout as input or output. Low latency, see also The need for speed below for some more information on this

  • Catching rising or falling edges in any header pin working as input. Timestamp of the event in nanoseconds in epoch format is provided

  • PWM (hardware) control on header pins 15 (Orin only) 32 & 33

  • I2C serial communication over pins: 27 (GEN1_I2C_SDA) & 28 (GEN1_I2C_SCL) and 3 (GEN2_I2C_SDA) & 5 (GEN2_I2C_SCL)

  • SPI serial communication over pins: 19 (SPI1_MOSI), 21 (SPI1_MISO), 23 (SPI1_SCK) & 24 (SPI1_CS0) and 37 (SPI2_MOSI), 22 (SPI2_MISO), 13 (SPI2_SCK) & 18 (SPI2_CS0)

  • No need of previous kernel configuration, no need to change the device tree, no need to reconfigure via /opt/nvidia/jetson-io/jetson-io.py or the like

INSTALLATION:

Clone/download the content into any folder in your JETSON, cd to that folder and type:

sudo make   
sudo make install                                             

That's it, the library should be installed and ready to be used. To uninstall the library:

sudo make uninstall

HOW TO:

You will find code examples to learn how to use the library in both: EXAMPLES_C & EXAMPLES_C++ folders, the first one contains all the C examples, the second one contains the same examples ready to compile in C++. To compile the examples you will find instructions in the comment section at the top of each of the example files

  • jetgpio_example.c & jetgpio_example.cpp show how to setup and use any of the pins as Inputs/Outputs, this will allow you to toggle pins from 0V (logic 0) to 3.3V (logic 1) or read the pin as an input where 3.3V at the pin is a logic 1. Note that when reading inputs, floating pins will throw unreliable results (as there is no actual input)

  • jetgpio_edge.c & jetgpio_edge.cpp show how to catch rising or falling edges in any pin working as Input, timestamp in epoch format in nanoseconds is provided

  • jetgpio_PWM_example.c & jetgpio_PWM_example.cpp show how to use the PWM funcionality at pin 32

  • test_PWM.c & test_PWM.cpp show again how to use the PWM funcionality with some LEDs connected and also capturing interruptions

  • jetgpio_i2c_example.c & jetgpio_i2c_example.cpp show how to use the i2c comms to talk to a MPU6050 gyroscope connected to i2c0 (pins 27 & 28)

  • spi_loop.c & spi_loop.cpp show how to run a simple loop test on the SPI port(s) by connecting together pins 19 & 21 for port SPI1 and pins 22 & 37 for port SPI2

DOCUMENTATION:

Some doxygen documentation here. As a rule of thumb, the library functions names and usage mimic the ones of the pigpio library (which I recommend if you work with Raspberry Pis). Learnt a lot from that one

THE NEED FOR SPEED:

I created a couple of little programs to measure reaction time e.g. how fast an output pin turns from 0 to 1 (3.3v), or how fast a change to an input pin is detected by the library, a diagram of the physical setup is shown below, basically I set up pin 38 as an output and pin 40 as an input and connect both through a resistor to observe the interaction:

jetson_speed

Compiling and running jetgpio_round_trip.c I am measuring the time from before executing the function that writes a logic 1 (3.3v) to pin 38 until the point when this is detected (by voltage level not edge interrupt) at pin 40. Here the intention is to measure the worst case scenario of a combination of 2 different actions:

  • a pin changes state from 0 to 1 (output)
  • a second pin detects a change on its state from 0 to 1 (input) being this change produced by the output pin

The results that I am getting for the round trip (total time to execute both actions) by running this program are:

Nano Classic Orin Nano
Minimum 1.3 us 3.1 us **
Maximum 1.8 us 4.2 us **

Compiling and running jetgpio_speed_edge.c I am trying to measure the time using a similar setup as described above, the difference here is that I am using the library function: gpioSetISRFunc() which basically goes through the linux gpio driver in order to catch rising and falling edges, the reason to use the linux driver for this has to do with the fact that catching interrupts from user space (this is a library after all) is basically 'problematic' for a number of reasons, in short, if driver performance and/or device tree stuff got in my way I would basically replace the current driver by my own, but that is beyond the scope of this library.

Nano Classic Orin Nano
Minimum 250 us 200 us
Maximum 700 us 1000 us

Note that this doesn't measure individual actions but the total time to execute both (round trip). It is clear that the timestamp produced by the linux driver is the one to blame for the slow reaction on detecting a change on the input pin, still interesting as there is no meaningful cpu waste as the hardware is producing the interrupt for us (no polling)

Compiling and running jetgpio_output.c I am writing high/low to pin 38 on a continuous loop, what I am getting on the oscilloscope are the following results:

Nano Classic Orin Nano
Average 0.6 us 2 us **

**Yes, the new Orin has a slower response/higher latency than the old Jetson Nano, this is due to the fact that writing to some registers is being monitored by an external Arm R5 MCU called SPE (Sensor Processing Engine). This CPU is an addition to what is called CPU Complex (the 6 Arm A78A cores that are described on the Orin Nano/NX specs), this CPU is running FreeRTOS and is completely independent from the main system. Some of the tasks performed by this CPU are clock and power supply management for peripherals inside the SOM e.g. PWM, GPIO... but it also plays a "firewall" role, in other words before writing to some registers in the standard CPU Complex the writing instructions have to pass through this "firewall" making the whole thing slower. This extra, out of the system security manager can be very useful on some applications but it has obviously a downside. Again sorting this out goes beyond the scope of any user space application (library) and it would imply flashing the Orin after modifying stuff, which is something along with other things like modifying the device tree (and reflashing probably) that I wanted to avoid when I created this library.

oscillo_output

JETSON NANO AND ORIN PINOUT:

The library uses the typical 40 pin header numbering, taking the dev kit as reference so for instance pin 3 is I2C_2_SDA, pin 1 is 3.3 VDC power and so on. You can check the official NVIDIA pinmux configuration for reference or if not available you can use the ones below:

https://jetsonhacks.com/nvidia-jetson-nano-j41-header-pinout/

https://jetsonhacks.com/nvidia-jetson-orin-nano-gpio-header-pinout/

The library has been tested on a Jetson Nano: tegra210 (TX1) and Jetson Orin Nano: tegra234

About

C library to manage the SPI, I2C and GPIO header of the Nvidia JETSON boards for customized usage for Bridgesoft programs.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 92.6%
  • C++ 6.1%
  • Other 1.3%