Jetson Nano GPIO control through direct memory access with C++ - implementation and examples?

I am in need of a solution to control the GPIO pins with low latency (1 us and below), to which end, I assume, I can only use direct memory access. When I tried this solution, trying to use pin 216 as output on JetPack 4.3 resulted in Linux hanging dead and throwing an i2c-related boot error from there on after. I am currently flashing the SD card with a JetPack 4.4. How exactly do I control GPIO pins through DMA, and are there examples along the lines of a “led flashing” sample?

Hi trueshadow97,

How about directly using the devmem tool to modify the register value of pin216 instead of using mmap on /dev/mem ?

Thanks for the quick reply!

Wish I knew about the existence of this tool. I’d still like to know if there’s some kind of guide to using GPIO through DMA this way, or at least a reliable reference with register addresses because crashing linux again with one low-level operation doesn’t sound like a fun idea.

Hi trueshadow97,

If you read the github link you posted, you shall find the register value in the headerfile.

So I take it the values there are correct, just the memory access method itself was
wrong?

Also, is there a source or reference documentation where I could get the memory addresses for GPIO pins that are not present in the header I linked?

Hi trueshadow97,

Please refer to Jetson TX1 TRM (technical reference manual) on our download center.

Thanks again. Do I understand correctly that the memory addresses for TX1 correspond to those for Nano?

Yes, TX1 and Nano are both T210 SoC so the address are compatible.

1 Like

Alright, so I’m at the point where I understand that I need to set bits in certain registers in order to assign the pins as inputs or outputs and drive the ouput pins high and low, or read said bits to read their states. What I can’t figure out still is how do the register addresses I have found in the Tegra X1 TRM correlate to the actual pins on Nano’s J41 header. In the Jetson TX1 SoM Datasheet, I have only found a “Pin Description” section that describes pins as if they were assigneed to eight ports A-H and numbered A1-H50 while according to the Jetson TX1 Tegra TRM, there are eight controllers with the total number of ports amounting to 31 and numbered A-Z, then AA-EE. In the TRM, in chapter 1.4, a system memory map is also mentioned, but I couldn’t find it in there. Basically, the question is, where can I find how does each GPIO pin on the J41 header correspond to the controller numbers and port names as they are laid out in the TRM, or how do said numbers and names from the datasheet correspond to those from the TRM?

Hi trueshadow97,
Which pin is mapped to which gpio controller can be find in Pinmux excel spreadsheet for Jetson-Nano.
For example: Pin 19 on 40-pin = SPI1_MOSI = GPIO3_PC.00
From TRM: GPIO1 has A,B,C,D GPIO2 has E,F,G,H so on
Each gpio controller has 8 ports. A0 to A7
GPIO controller base address=0x6000d000
For controller C: it is 0x6000d008
So GPIO_CNF register address for PC.00 is bit 0 of 0x6000d008
GPIO_OE=bit 0 of 0x6000d018
GPIO_OUT=bit 0 of 0x6000d028
Let me know if you still face issues in mapping GPIO controller to its register address.

Thanks & Regards,
Shubhi Garg

2 Likes

This is exactly what I needed, thank you very much!
Also, busybox devmem incurs a system call if I try to use it to read and write into the GPIO registers, which doesn’t suit my purpose since it introduces latency. I found out that reading and writing directly into /dev/mem wasn’t what caused my system to crash; I think when I wrote 0xFF into some of the registers, I’ve been setting bits I shouldn’t have been setting. So far I’ve already got three pins to work and I don’t see any reason why other pins should not.

So, to conclude for anyone who might face the same issue as me: in order to control Nano’s GPIO pins through direct memory access, one has to read and write into /dev/mem. The solution I’ve linked in the OP and this solution were sufficient references for me to understand how to do that in practice. Chapter 9 of the TRM explains in detail how GPIO works and reading it is advised to fully understand the code used in the reference solutions. The Jetson Nano Pinmux spreadsheet, available from the Download Center, is where one can find the register addresses and the exact bits that have to be set in order to work with the exact pin that’s intended to be operated.

Again, thanks to everyone who helped me figure this out.

Hi trueshadow97,
Good to hear that your problem is solved but I have some query.
devmem also opens /dev/mem and then it reads/writes, are you saying there is another system call which introduces latency? Means writing directly from /dev/mem takes less time than devmem tool?
Also, do you find any scope of improvement in our documentation? Liked you faced issue on how to map address with GPIO pins, please let me know.

Thanks,
Shubhi

If I am to use the devmem utility, I need to use it from my own program, and the only way to do so I have found is via

system(“busybox devmem”);

and where I found out about this, it’s also been said:

However, making a call to system command should be avoided due to the following reasons:

  1. It’s a very expensive and resource heavy function call

Which is unacceptable for my purposes since I need literally the lowest latency I can feasibly achieve and as low resource consumption as possible.

As for documentation improvement, I think it would be way more convenient if the address maps such as the address-to-pin map found in the Pinmux spreadsheet were linked to or added directly to the Technical Reference Manual. Would’ve saved me a day or two of searching the web and looking for answers.

Thanks for your feedback.