Jetson-Nano GPIO 使用

1,简介

NVIDIA Jetson Nano 是一款紧凑的板卡,尺寸约为 70x45 毫米,配有一个大型散热器。它搭载了一颗非常强大的微芯片,即 NVIDIA Tegra X1,其中包含四个 ARM 应用处理器核心,以及 128 个图形处理单元(GPU)。GPU 不仅用于图形处理,因为如今与神经网络相关的一些有趣的应用,例如模式识别,随着处理单元数量的增加,可以更轻松地创建,并且性能更好。Tegra X1 的全版本(具有两倍 GPU 核心)设计用于一些非常多样的应用,包括游戏,但也用于汽车领域,可以支持自动停车,多摄像头视频拼接以及驾驶辅助功能(如车道控制、乘客避免和驾驶员警觉性监控)。

Jetson Nano 采用了小外形双列直插式内存模块(SO-DIMM)封装形式,已经插在一个紧凑的 100x80 毫米载板上,两者共同构成了开发套件。载板上有许多典型的计算机接口,如 USB 3.0、千兆以太网和视频接口(支持 4K 60fps!)。还有一些连接器非常类似于树莓派上的连接器。有一个 40 针扩展连接器,布局几乎与树莓派的连接器相同。还支持树莓派相机。

设备如下图:

粉色标记为连接器的引脚1。连接器 J44 上有一个板载串行控制台。第三方 USB-UART 适配器用于将其连接到 PC。颜色显示了 Adafruit USB-UART 接线和 FTDI USB-UART 接线。这里有一个用于自制 USB-UART 适配器的电路:构建 USB UART 串行适配器,它使用 FTDI 接线颜色约定(从 PC 端的视角看,黄色、橙色和黑色分别用于 RXD、TXD 和 GND)。

当将东西安装在机箱内时,按钮标头将非常方便。我希望将一个按钮连接到“ON”引脚,并在 DIS 引脚上跨接短接跳线,以禁用自动启动。

请注意,当从电源插座的桶接口供电 Jetson Nano 时,需要在 J48 上放置短接跳线。否则,开发板将期望从 micro USB 获取电源。

 J41 扩展头引脚定义

Linux(BCM)列包含两个数字。括号中的数字是类似于树莓派的 GPIO 编号,因此可以使用相同的 GPIO 库。

GPIO详细信息如下:

J41引脚列表汇总:

GPIO (BCM)名称引脚引脚名称GPIO (BCM)
3.3V输出125.0V 输出
I2C_2_SDA
I2C Bus 1
345.0V 输出
I2C_2_SCL
I2C Bus 1
56GND
GPIO216
(D4)
AUDIO_MCLK78UART_TX2

/dev/ttyTHS1
GND910UART_RX2
/dev/ttyTHS1
GPIO50
(D17)
UART_2_RTS1112I2S_4_SCLKGPIO79

(D18)
GPIO232
(D23)
SPI_2_SCK1314GND
GPIO194
(D22)
LCD_TE1516SPI_2_CS1GPIO232

(D23)
3.3V输出1718SPI_2_CS0GPIO15

(D24)
GPIO16
(D10)
SPI_1_MOSI1920GND
GPIO17
(D9)
SPI_1_MOSO2122SPI_2_MISOGPIO13

(D23)
GPIO18
(D11)
SPI_1_SCK2324SPI_1_CS0GPIO19

(D8)
GND2526SPI_1_CS1GPIO20
(D7)
I2C_1_SDA

I2C Bus 0
2728I2C_1_SCL

I2C Bus 0
GPIO149
(D5)
CAM_AF_EN2930GND
GPIO200
(D6)
GPIO_PZ03132LCD_BL_PWMGPIO168
(D12)
GPIO38
(D13)
GPIO_PE63334GND
GPIO76
(D19)
I2S_4_LRCK3536UART_2_CTSGPIO51
(D16)
GPIO12
(D26)
SPI_2_MOSI3738I2S_4_SDINGPIO77
(D20)
GND3940I2S_4_SDOUTGPIO78
(D21)

J41 GPIO 详细信息:

Jetson Nano J41 GPIO Expansion Header Mapping (derived from Jetson.GPIO data)
Connector
Pin #
RPi Connector
Label
RPi Default
SoC Pull
Module connector
signal name
Linux GPIO
Within Chip
Assumed Linux
GPIO Chip Base
Linux GPIO
13V3
25V0
3SDA1High
45V0
5SCL1High
6GND
7GPIO_GCLKHighGPIO92160216
8TXD0Low
9GND
10RXD0Low
11GPIO_GEN0LowUART1_RTS50050
12GPIO_GEN1LowI2S0_SCLK79079
13GPIO_GEN2LowSPI1_SCK14014
14GND
15GPIO_GEN3LowGPIO121940194
16GPIO_GEN4LowSPI1_CS12320232
173V30
18GPIO_GEN5LowSPI1_CS015015
19SPI_MOSILowSPI0_MOSI16016
20GND
21SPIO_MISOLowSPI0_MISO17017
22GPIO_GEN6LowSPI1_MISO13013
23SPI_SCLKLowSPI0_SCK18018
24SPI_CE0_NHighSPI0_CS019019
25GND
26SPI_CE1_NHighSPI0_CS120020
27ID_SD
28ID_SC
29GPIO5HighGPIO011490149
30GND
31GPIO6HighGPIO112000200
32GPIO12LowGPIO071680168
33GPIO13LowGPIO1338038
34GND
35GPIO19LowI2S0_FS76076
36GPIO16LowUART1_CTS51051
37GPIO26LowSPI1_MOSI12012
38GPIO20LowI2S0_DIN77077
39GND
40GPIO21LowI2S0_DOUT78078

​2,GPIO 控制

方法1 sysfs

79指的是Linux sysfs GPIO的gpio79。

从上列表格中我们看到Jetson Nano J41的Pinout,可以看到gpio79实际上是pin 12

# 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

GPIO 查看:

​方法2,使用NVIDIA官方提供的JetsonGPIO库

关于该函数库的具体说明,你可以在Jetson.GPIO · PyPI ()https://pypi.org/project/Jetson.GPIO/中了解

环境配置和安装库

安装PIP工具:

 sudo apt-get update
 sudo apt-get install python-pip
 sudo apt-get install python3-pip

下载安装Jetson.GPIO库,jetson nano原版本系统自带,但是也可以直接pip安装或者官网下载源代码安装:

# pip直接安装
sudo pip install Jetson.GPIO

sudo pip3 install Jetson.GPIO

# 或者下载代码进行安装
sudo python3 setup.py install

设置用户权限,为了使用Jetson GPIO库,必须首先设置正确的用户权限/组。创建新的gpio用户组。然后将用户添加到新创建的组中。:

sudo groupadd -f -r gpio
sudo usermod -a -G gpio your_user_name

注意:这里的your_user_name需要改成你自己的账号名,不然库无法正常使用

将99-gpio.rules文件复制到rules.d目录

如果是将源代码下载到Jetson.GPIO:

sudo cp lib/python/Jetson/GPIO/99-gpio.rules /etc/udev/rules.d/

如果是使用pip安装的Jetson.GPIO,则在虚拟环境中使用pip:

sudo cp venv/lib/pythonNN/site-packages/Jetson/GPIO/99-gpio.rules /etc/udev/rules.d/

重载rules规则来让文件生效,最后需要通过运行以下命令重新启动或重新加载udev规则:

sudo udevadm control --reload-rules && sudo udevadm trigger

例子使用

针对jetson.gpio库,官方也提供了一些简单的例程,例程存放在 /opt/nvidia/jetson-gpio/samples/路径下

cd /opt/nvidia/jetson-gpio/samples/

在samples目录下,示例程序如下:

应用程序功能如下:

  1. simple_input.py:该应用程序使用 BCM 引脚编号模式,并读取 40 引脚头部的引脚 12 处的值,并将该值打印到屏幕上。
  2. simple_out.py:该应用程序使用树莓派的 BCM 引脚编号模式,并在 BCM 引脚 18 处(或头部的引脚 12 处)每 2 秒输出交替的高低值。
  3. button_led.py:该应用程序使用板上引脚编号。它需要将按钮连接到引脚 18 和 GND,通过上拉电阻将引脚 18 连接到 3V3,以及将 LED 和限流电阻连接到引脚 12。该应用程序读取按钮状态,并在每次按下按钮时将 LED 保持亮1秒。
  4. button_event.py:该应用程序使用板上引脚编号。它需要将按钮连接到引脚 18 和 GND,通过上拉电阻将按钮连接到 3V3,以及将 LED 和限流电阻连接到引脚 12。该应用程序执行与 button_led.py 相同的功能,但是为了减少 CPU 使用率,它会对按钮按下事件进行阻塞等待,而不是连续检查引脚的值。
  5. button_interrupt.py:该应用程序使用板上引脚编号。它需要将按钮连接到引脚 18 和 GND,通过上拉电阻将按钮连接到 3V3,以及将 LED 和限流电阻连接到引脚 12,将第二个 LED 和限流电阻连接到引脚 13。该应用程序持续缓慢闪烁第一个 LED,并且仅当按下按钮时快速闪烁第二个 LED 五次。

方法3,使用C++ GPIO库

1. 下载库:

git clone https://github.com/pjueon/JetsonGPIO

2. 编译:

cd JetsonGPIO
mkdir build && cd build
cmake .. [OPTIONS]
OptionDefault valueDescription
-DCMAKE_INSTALL_PREFIX=/usr/localInstallation path
-DBUILD_EXAMPLES=ONBuild example codes in samples
-DJETSON_GPIO_POST_INSTALL=ONRun the post-install script after installation to set user permissions. If you set this OFF, you must run your application as root to use JetsonGPIO.

3. 安装库

sudo cmake --build . --target install

4. 编译Samples

你可以在构建目录中添加 cmake 选项 -DBUILD_EXAMPLES=ON 来构建 samples 目录中的示例代码。假设你当前在 build 目录下:

cmake .. -DBUILD_EXAMPLES=ON
cmake --build . --target examples 

5,写一个简单例子测试

#include <iostream>
#include <chrono>
#include <thread>
#include <signal.h>

#include <JetsonGPIO.h>

using namespace std;

static bool end_this_program = false;

inline void delay(int s)
{
        this_thread::sleep_for(chrono::seconds(s));
}

void signalHandler(int s)
{
        end_this_program = true;
}


int main()
{
        signal(SIGINT, signalHandler);

        int output_pin = 26; // BOARD pin 12, BCM pin 18

        GPIO::setmode(GPIO::BCM);

        GPIO::setup(output_pin, GPIO::OUT, GPIO::HIGH);

        cout << "Strating demo now! Press CTRL+C to exit" << endl;
        int curr_value = GPIO::HIGH;

        while (!end_this_program)
        {
                delay(3);
                cout << "Outputting " << curr_value << " to pin ";
                cout << output_pin << endl;
                GPIO::output(output_pin, curr_value);
                curr_value ^= GPIO::HIGH;
        }

        GPIO::cleanup();

        return 0;
}

编译方法:

# g++ simple_out.cpp -o simple_out -L./ -lJetsonGPIO -lpthread

运行结果:

方法4,使用驱动方法

1,修改设备树:

platform/t210/porg/kernel-dts/tegra210-porg-p3448-common.dtsi

gpio_try {
	compatible = "gpio-try";
	status = "okay";
	input-gpio = <&gpio TEGRA_GPIO(Z, 0) GPIO_ACTIVE_HIGH>;
	output-gpio = <&gpio TEGRA_GPIO(B, 6) GPIO_ACTIVE_LOW>;
};

2,写一个字符驱动

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>


#define GPIO_BASE_CNT		1		  	
#define GPIO_BASE_NAME		"gpiotry"	
struct gpiobase_dev{
	dev_t devid;			
	struct cdev cdev;	
	struct class *class;	
	struct device *device;	
	int major;				
	int minor;				
    struct device_node *nd;
    int gpioIdInput;     	
	int gpioIdOutput;   	
};

struct gpiobase_dev gpioBaseDev;	


static int gpiobase_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &gpioBaseDev;
	return 0;
}


static ssize_t gpiobase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    struct gpiobase_dev *dev = filp->private_data;

	if (cnt > 1) {
		printk("read length err!\r\n");
		return -EFAULT;
	}

    int gpioValue = gpio_get_value(dev->gpioIdInput);    
    if (gpioValue < 0) {
        printk("get gpio value failed!\r\n");
		return -EFAULT;
    }

    char databuf = gpioValue ? 1 : 0;

	int ret = copy_to_user(buf, &databuf, cnt);
	if(ret < 0) {
		printk("kernel read failed!\r\n");
		return -EFAULT;
	}

	return 0;
}

static ssize_t gpiobase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	struct gpiobase_dev *dev = filp->private_data;

	if (cnt > 1) {
		printk("write length err!\r\n");
		return -EFAULT;
	}

	unsigned char databuf;
	int ret = copy_from_user(&databuf, buf, cnt);
	if(ret < 0) {
		printk("kernel write failed!\r\n");
		return -EFAULT;
	}

	int writeValue = databuf ? 1 : 0;
	gpio_set_value(dev->gpioIdOutput, writeValue); 

	return 0;
}


static int gpiobase_release(struct inode *inode, struct file *filp)
{
	return 0;
}

static struct file_operations gpiobase_fops = {
	.owner = THIS_MODULE,
	.open = gpiobase_open,
	.read = gpiobase_read,
	.write = gpiobase_write,
	.release = 	gpiobase_release,
};


static int __init gpiobase_init(void)
{
    gpioBaseDev.nd = of_find_node_by_path("/gpio_try");
    if(gpioBaseDev.nd == NULL) {
        printk("gpioBaseDev node cant not found!\r\n");
        return -EINVAL;
    }
    else {
        printk("gpioBaseDev node has been found!\r\n");
    }

    gpioBaseDev.gpioIdInput = of_get_named_gpio(gpioBaseDev.nd, "input-gpio", 0);
    if(gpioBaseDev.gpioIdInput < 0) {
        printk("can't get input-gpio");
        return -EINVAL;
    }
    printk("input-gpio num = %d\r\n", gpioBaseDev.gpioIdInput);

	gpioBaseDev.gpioIdOutput = of_get_named_gpio(gpioBaseDev.nd, "output-gpio", 0);
    if(gpioBaseDev.gpioIdOutput < 0) {
        printk("can't get output-gpio");
        return -EINVAL;
    }
    printk("output-gpio num = %d\r\n", gpioBaseDev.gpioIdOutput);

    int ret = gpio_direction_input(gpioBaseDev.gpioIdInput);	
    if(ret < 0) {
        printk("can't set input gpio!\r\n");
    }
	ret = gpio_direction_output(gpioBaseDev.gpioIdOutput, 0);
	if(ret < 0) {
		printk("can't set output gpio!\r\n");
	}

	if (gpioBaseDev.major) {		
		gpioBaseDev.devid = MKDEV(gpioBaseDev.major, 0);
		register_chrdev_region(gpioBaseDev.devid, GPIO_BASE_CNT, GPIO_BASE_NAME);
	} else {					
		alloc_chrdev_region(&gpioBaseDev.devid, 0, GPIO_BASE_CNT, GPIO_BASE_NAME);	
		gpioBaseDev.major = MAJOR(gpioBaseDev.devid);	
		gpioBaseDev.minor = MINOR(gpioBaseDev.devid);	
	}
	printk("gpioBaseDev major=%d,minor=%d\r\n",gpioBaseDev.major, gpioBaseDev.minor);

	gpioBaseDev.cdev.owner = THIS_MODULE;
	cdev_init(&gpioBaseDev.cdev, &gpiobase_fops);

	cdev_add(&gpioBaseDev.cdev, gpioBaseDev.devid, GPIO_BASE_CNT);

	gpioBaseDev.class = class_create(THIS_MODULE, GPIO_BASE_NAME);
	if (IS_ERR(gpioBaseDev.class)) {
		return PTR_ERR(gpioBaseDev.class);
	}

	gpioBaseDev.device = device_create(gpioBaseDev.class, NULL, gpioBaseDev.devid, NULL, GPIO_BASE_NAME);
	if (IS_ERR(gpioBaseDev.device)) {
		return PTR_ERR(gpioBaseDev.device);
	}

	return 0;
}


static void __exit gpiobase_exit(void)
{
	cdev_del(&gpioBaseDev.cdev);
	unregister_chrdev_region(gpioBaseDev.devid, GPIO_BASE_CNT);

	device_destroy(gpioBaseDev.class, gpioBaseDev.devid);
	class_destroy(gpioBaseDev.class);
}

module_init(gpiobase_init);
module_exit(gpiobase_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("han");

 编译:

make ARCH=arm64

测试:

打开设备,通过操控设备操控GPIO

  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值