NVIDIA提供了python版本的GPIO库,但没有提供C版,并且python版本是通过文件句柄实现的,性能不行,需要C版本内存映射来操作GPIO。
根据官方文档 Tegra_X1_TRM_DP07225001_v1.3p.pdf 第9章表32,A~Z、AA、BB、CC、DD、EE、FF共有32个port,每4个port为一个controller,每个port控制8个GPIO针(pin)。寄存器地址范围000~FFF共4096个字节,每4个port的地址是交错的,如下表中A、B、C、D所示。
代码来自jetsonGPIO,gpio参数传入GPIO的设备地址,例如BCM=20/BOARD=38对应的设备地址是77,详见下表。
- // Export the given gpio to userspace;
- // Return: Success = 0 ; otherwise open file error
- int gpioExport(unsigned int gpio)
- {
- int fileDescriptor, length;
- char commandBuffer[MAX_BUF];
-
- fileDescriptor = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
- if (fileDescriptor < 0)
- {
- char errorBuffer[128];
- snprintf(errorBuffer, sizeof(errorBuffer), "gpioExport unable to open gpio%d", gpio);
- perror(errorBuffer);
- return fileDescriptor;
- }
-
- length = snprintf(commandBuffer, sizeof(commandBuffer), "%d", gpio);
- if (write(fileDescriptor, commandBuffer, length) != length)
- {
- perror("gpioExport");
- return fileDescriptor;
- }
- close(fileDescriptor);
-
- return 0;
- }
代码来自jetsonGPIO,gpio参数传入GPIO的设备地址,详见下表。
- // Set the direction of the GPIO pin
- // Return: Success = 0 ; otherwise open file error
- int gpioSetDirection(unsigned int gpio, unsigned int out_flag)
- {
- int fileDescriptor;
- char commandBuffer[MAX_BUF];
-
- snprintf(commandBuffer, sizeof(commandBuffer), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
-
- fileDescriptor = open(commandBuffer, O_WRONLY);
- if (fileDescriptor < 0)
- {
- char errorBuffer[128];
- snprintf(errorBuffer, sizeof(errorBuffer), "gpioSetDirection unable to open gpio%d", gpio);
- perror(errorBuffer);
- return fileDescriptor;
- }
-
- if (out_flag)
- {
- if (write(fileDescriptor, "out", 4) != 4)
- {
- perror("gpioSetDirection");
- return fileDescriptor;
- }
- }
- else
- {
- if (write(fileDescriptor, "in", 3) != 3)
- {
- perror("gpioSetDirection");
- return fileDescriptor;
- }
- }
- close(fileDescriptor);
- return 0;
- }
代码来自jetson-nano-gpio-example。其中,GPIO_ADDRESS 见下表中的内存映射地址。
- // read physical memory (needs root)
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- if (fd < 0) {
- fprintf(stderr, "usage : $ sudo %s (with root privilege)\n", argv[0]);
- exit(1);
- }
-
- // map a particular physical address into our address space
- int pagesize = getpagesize();
- int pagemask = pagesize-1;
-
- // This page will actually contain all the GPIO controllers, because they are co-located
- void *base = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (GPIO_ADDRESS & ~pagemask));
- if (base == NULL) {
- perror("mmap()");
- exit(1);
- }
该表是我根据jetson的地址规则计算的内存映射地址和设备地址。
| BCM | JETSON | GPIO | 内存映射地址 | 设备地址 |
| 4 | 7 | GPIO3_PBB.00 | 0x6000d60C | 216 |
| 26 | 37 | GPIO3_PB.04 | 0x6000d004 | 12 |
| 25 | 22 | GPIO3_PB.05 | 0x6000d004 | 13 |
| 27 | 13 | GPIO3_PB.06 | 0x6000d004 | 14 |
| 24 | 18 | GPIO3_PB.07 | 0x6000d004 | 15 |
| 23 | 16 | GPIO3_PDD.00 | 0x6000d704 | 232 |
| 13 | 33 | GPIO3_PE.06 | 0x6000d100 | 38 |
| 5 | 29 | GPIO3_PS.05 | 0x6000d408 | 149 |
| 22 | 15 | GPIO3_PY.02 | 0x6000d600 | 194 |
| 12 | 32 | GPIO3_PV.00 | 0x6000d504 | 168 |
| 6 | 31 | GPIO3_PZ.00 | 0x6000d604 | 200 |
| 20 | 38 | GPIO3_PJ.05 | 0x6000d204 | 77 |
| 21 | 40 | GPIO3_PJ.06 | 0x6000d204 | 78 |
| 19 | 35 | GPIO3_PJ.04 | 0x6000d204 | 76 |
| 18 | 12 | GPIO3_PJ.07 | 0x6000d204 | 79 |
| 1 | 28 | GPIO3_PJ.01 | 0x6000d204 | 73 |
| 0 | 27 | GPIO3_PJ.00 | 0x6000d204 | 72 |
| 3 | 5 | GPIO3_PJ.02 | 0x6000d204 | 74 |
| 2 | 3 | GPIO3_PJ.03 | 0x6000d204 | 75 |
| 14 | 8 | GPIO3_PG.00 | 0x6000d108 | 48 |
| 15 | 10 | GPIO3_PG.01 | 0x6000d108 | 49 |
| 17 | 11 | GPIO3_PG.02 | 0x6000d108 | 50 |
| 16 | 36 | GPIO3_PG.03 | 0x6000d108 | 51 |
| 10 | 19 | GPIO3_PC.00 | 0x6000d008 | 16 |
| 9 | 21 | GPIO3_PC.01 | 0x6000d008 | 17 |
| 11 | 23 | GPIO3_PC.02 | 0x6000d008 | 18 |
| 8 | 24 | GPIO3_PC.03 | 0x6000d008 | 19 |
| 7 | 26 | GPIO3_PC.04 | 0x6000d008 | 20 |