RK3568驱动指南|第十二篇 GPIO子系统-第129章 GPIO控制和操作实验

2024-01-13 12:52

本文主要是介绍RK3568驱动指南|第十二篇 GPIO子系统-第129章 GPIO控制和操作实验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第十二篇 GPIO子系统_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第129章 GPIO控制和操作实验

GPIO软件编程方式有多种,可以写驱动程序调用GPIO函数操作GPIO,也可以直接通过操作寄存器的方式操作GPIO,还可以通过sysfs方式实现对GPIO的控制。本章节我们来学习使用sysfs方式实现对GPIO的控制。

129.1 使用命令通过sysfs文件系统控制GPIO

129.1.1 内核配置

使用sysfs方式控制gpio,首先需要底层驱动的支持,需要在make menuconfig图形化配置界面中加入以下配置:

Device Drivers

->GPIO Support

->/sys/class/gpio/xxxx

图 129-1

129.1.2 GPIO编号计算

iTOP-RK3568有 5 组 GPIO bank:GPIO0~GPIO4,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分,常用以下公式计算引脚:

GPIO pin脚计算公式:pin = bank * 32 + number     //bank为组号,number为小组编号
GPIO 小组编号计算公式:number = group * 8 + X  

引脚编号=控制寄存器的寄存器基数+控制引脚寄存器位数。 在 rk3568 中, GPIO_number的计算方法为: n*32 + (K-A)*8 + x; 括号里面的 A、 B、 C、 D 分别代表数值 0、 1、 2、 3, 在计算时候分别对应即可。 

下面演示LED9用户LED灯的GPIO0_PB7 pin脚计算方法:

bank = 0;       //GPIO0_B7=> 0, bank ∈ [0,4]
group = 1;      //GPIO0_B7 => 1, group ∈ {(A=0), (B=1), (C=2), (D=3)}
X = 7;         //GPIO4_D7 => 5, X ∈ [0,7]
number = group * 8 + X = 1 * 8 + 7 =15
pin = bank*32 + number= 0 * 32 + 15 = 15;

图 129-2

/sys/class/gpio/export 用于将GPIO控制从内核空间导出到用户空间。/sys/class/gpio/unexport 用于取消GPIO控制从内核空间到用户空间的导出。 export 和 unexport,他们都是只写的。GpiochipX代表GPIO 控制器。

export用于将指定编号的 GPIO 引脚导出。在使用 GPIO 引脚之前,需要将其导出,导出成功之后才能使用它。注意 export 文件是只写文件,不能读取,将一个指定的编号写入到 export 文件中即可将对应的 GPIO 引脚导出,以GPIO0_PB7为例(pin计算值为15)使用export 文件进行导出(如果没有更换本章开始部分的内核设备树镜像,会导出不成功),导出成功如下图所示:

echo 15 > export

图 129-3

  会发现在/sys/class/gpio 目录下生成了一个名为 gpio15 的文件夹(gpioX,X 表示对应的编 号),该文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚。

unexport将导出的 GPIO 引脚删除。当使用完 GPIO 引脚之后,需要将导出的引脚删除,同样该文件也是只写文件、不可读,使用unexport 文件进行删除GPIO0_PB7,删除成功如下图所示:

 echo 15 > unexport

图 129-4

可以看到之前生成的 gpio15 文件夹就会消失!

需要注意的是,并不是所有 GPIO 引脚都可以成功导出,如果对应的 GPIO 已经被导出或者在内核中被使用了,那便无法成功导出,导出失败如下图所示:

图 129-5

出现上图报错的原因是该GPIO已经被其他GPIO使用,需要在内核中找到使用GPIO的驱动,并取消该驱动才可以正常使用GPIO。在使用GPIO15时,需要取消Linux内核源码中LED灯的配置,如下所示:

图 129-6

再次使用以下命令导出GPIO0_PB7引脚,导出成功之后进入gpio15文件夹如下图所示:

echo 15 > export

图 129-7

  可以看到gpio15文件夹下分别有active_low、device、direction、edge、power、subsystem、uevent、value八个文件,需要关心的文件是 active_low、direction、edge 以及 value 这四个属性文件,接下来分别介绍这四个属性文件的作用:

direction配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式)。

在“/sys/class/gpio/gpio15”目录下使用cat命令查看direction输入输出模式,如下图所示:

cat direction

图 129-8

 默认状态下的输入输出状态为“in”,由于direction为可读可写,可以使用以下命令将模式配置为输出,配置完成如下图所示

echo out > direction

cat direction

 

图 129-10

当 active_low 等于 0 时, value 值若为1则引脚输出高电平,value 值若为0则引脚输出低电平。当 active_low 等于 1 时 ,value 值若为0则引脚输出高电平,value 值若为1则引脚输出低电平。

edge控制中断的触发模式,该文件可读可写。在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式,四种触发模式的设置如下所示:

非中断引脚:echo "none" > edge

上升沿触发:echo "rising" > edge

下降沿触发:echo "falling" > edge

边沿触发:  echo "both" > edge

value: 设置高低电平,如果我们要把这个管脚设置成高电平,我们只需要给value设置成1即可,反之,则设置成0。使用命令 

echo 1 > value

反之,把GPIO设置成低电平,使用命令

echo 0 > value

图 129-11

129.2 使用C程序通过sysfs文件系统控制GPIO

129.2.1 控制GPIO输出实验

本小节代码在配套资料“iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\82_gpioctrl01”目录下。

实验要求:

通过GPIO输出应用程序控制GPIO口输出高低电平,以此来控制LED灯的亮灭。

实验步骤:

首先进入ubuntu的终端界面输入以下命令来创建 gpioctrl.c文件,如下图所示:

图 129-12

然后向该文件中添加以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int fd;                   // 文件描述符
int ret;                  // 返回值
char gpio_path[100];      // GPIO路径
int len;                  // 字符串长度// 导出GPIO引脚
int gpio_export(char *argv)
{fd = open("/sys/class/gpio/export", O_WRONLY); // 打开export文件if (fd < 0){printf("open /sys/class/gpio/export error \n"); // 打开文件失败return -1;}len = strlen(argv); // 获取参数字符串的长度ret = write(fd, argv, len); // 将参数字符串写入文件,导出GPIO引脚if (ret < 0){printf("write /sys/class/gpio/export error \n"); // 写入文件失败return -2;}close(fd); // 关闭文件
}// 取消导出GPIO引脚
int gpio_unexport(char *argv)
{fd = open("/sys/class/gpio/unexport", O_WRONLY); // 打开unexport文件if (fd < 0){printf("open /sys/class/gpio/unexport error \n"); // 打开文件失败return -1;}len = strlen(argv); // 获取参数字符串的长度ret = write(fd, argv, len); // 将参数字符串写入文件,取消导出GPIO引脚if (ret < 0){printf("write /sys/class/gpio/unexport error \n"); // 写入文件失败return -2;}close(fd); // 关闭文件
}// 控制GPIO引脚的属性
int gpio_ctrl(char *arg, char *val)
{char file_path[100]; // 文件路径sprintf(file_path, "%s/%s", gpio_path, arg); // 构建文件路径,格式为“gpio_path/arg”fd = open(file_path, O_WRONLY); // 打开文件if (fd < 0){printf("open file_path error \n"); // 打开文件失败return -1;}len = strlen(val); // 获取参数字符串的长度ret = write(fd, val, len); // 将参数字符串写入文件,控制GPIO引脚的属性if (ret < 0){printf("write file_path error\n"); // 写入文件失败return -2;}close(fd); // 关闭文件
}int main(int argc, char *argv[]) // 主函数
{sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]); // 构建GPIO路径,格式为“/sys/class/gpio/gpio引脚号”if (access(gpio_path, F_OK)) // 检查GPIO路径是否存在{gpio_export(argv[1]); // 不存在则导出GPIO引脚}else{gpio_unexport(argv[1]); // 存在则取消导出GPIO引脚}gpio_ctrl("direction", "out"); // 配置GPIO为输出模式gpio_ctrl("value", argv[2]);   // 控制GPIO输出高低电平gpio_unexport(argv[1]); // 最后取消导出GPIO引脚return 0; // 返回0表示程序正常退出
}

保存退出之后,使用以下命令设置交叉编译器环境,并对gpioctrl.c进行交叉编译,编译完成如下图所示:

export PATH=/usr/local/arm64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin:$PATH

aarch64-linux-gnu-gcc gpioctrl.c -o gpioctrl

图 129-13

最后将交叉编译生成的gpioctrl文件拷贝到开发板目录下运行即可,如下所示:

 

图 129-14

输入“./gpioctrl 15 1”命令LED灯点亮,输入“./gpioctrl 15 0”命令LED灯熄灭。

到此,实验结束。

129.2.2 控制GPIO输入实验

本小节代码在配套资料“iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\83_gpioctrl02”目录下。

实验要求:

通过GPIO输入应用程序读取GPIO口的输入电平。

实验硬件连接:

使用迅为iTOP-RK3568开发板,使用导线连接开发板背面的引脚GPIO1_B2,另一端连接到电源或者GND。

实验步骤:

首先进入ubuntu的终端界面输入以下命令来创建 gpioctrl.c文件,如下图所示:

图 129-15

然后向该文件中添加以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int fd;              // 文件描述符
int ret;             // 返回值
char gpio_path[100]; // GPIO路径
int len;             // 字符串长度
char file_path[100]; // 文件路径
char buf[2];         // 用于读取 GPIO 值的缓冲区// 导出 GPIO 引脚
int gpio_export(char *argv)
{fd = open("/sys/class/gpio/export", O_WRONLY); // 打开 export 文件if (fd < 0){printf("open /sys/class/gpio/export error\n"); // 打开文件失败return -1;}len = strlen(argv);         // 获取参数字符串的长度ret = write(fd, argv, len); // 将参数字符串写入文件,导出 GPIO 引脚if (ret < 0){printf("write /sys/class/gpio/export error\n"); // 写入文件失败return -2;}close(fd); // 关闭文件
}// 取消导出 GPIO 引脚
int gpio_unexport(char *argv)
{fd = open("/sys/class/gpio/unexport", O_WRONLY); // 打开 unexport 文件if (fd < 0){printf("open /sys/class/gpio/unexport error\n"); // 打开文件失败return -1;}len = strlen(argv);         // 获取参数字符串的长度ret = write(fd, argv, len); // 将参数字符串写入文件,取消导出 GPIO 引脚if (ret < 0){printf("write /sys/class/gpio/unexport error\n"); // 写入文件失败return -2;}close(fd); // 关闭文件
}// 控制 GPIO 引脚的属性
int gpio_ctrl(char *arg, char *val)
{sprintf(file_path, "%s/%s", gpio_path, arg); // 构建文件路径,格式为 "gpio_path/arg"fd = open(file_path, O_WRONLY);              // 打开文件if (fd < 0){printf("open file_path error\n"); // 打开文件失败return -1;}len = strlen(val);         // 获取参数字符串的长度ret = write(fd, val, len); // 将参数字符串写入文件,控制 GPIO 引脚的属性if (ret < 0){printf("write file_path error\n"); // 写入文件失败return -2;}close(fd); // 关闭文件
}// 读取 GPIO 引脚的值
int gpio_read_value(char *arg)
{sprintf(file_path, "%s/%s", gpio_path, arg); // 构建文件路径,格式为 "gpio_path/arg"fd = open(file_path, O_RDONLY);              // 打开文件if (fd < 0){printf("open file_path error\n"); // 打开文件失败return -1;}ret = read(fd, buf, 1); // 读取文件内容到缓冲区if (!strcmp(buf, "1")){printf("The value is high\n"); // GPIO 引脚值为高电平return 1;}else if (!strcmp(buf,"0")){printf("The value is low\n"); // GPIO 引脚值为低电平return 0;}close(fd); // 关闭文件return -1;}int main(int argc, char *argv[]) // 主函数
{int value;sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]); // 构建 GPIO 路径,格式为 "/sys/class/gpio/gpio引脚号"if (access(gpio_path, F_OK))                           // 检查 GPIO 路径是否存在{gpio_export(argv[1]); // 不存在则导出 GPIO 引脚}else{gpio_unexport(argv[1]); // 存在则取消导出 GPIO 引脚}gpio_ctrl("direction", "in");       // 配置 GPIO 为输入模式value = gpio_read_value("value");   // 读取 GPIO 引脚的值printf("The value is %d\n", value); // 打印读取的 GPIO 引脚的值gpio_unexport(argv[1]);             // 最后取消导出 GPIO 引脚return 0; // 返回 0 表示程序正常退出
}

保存退出之后,使用以下命令设置交叉编译器环境,并对gpioctrl.c进行交叉编译,编译完成如下图所示:

export PATH=/usr/local/arm64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin:$PATH

aarch64-linux-gnu-gcc gpioctrl.c -o gpioctrl

图 129-16

最后将交叉编译生成的gpioctrl文件拷贝到开发板目录下运行即可。

为了测试输入高电平的状况,作者使用了杜邦线将开发板背面的3.3V接到了GPIO1_PB2 pin脚上,然后再次使用以下命令来进行状态的检测,如下图所示:

chmod 777 gpioctrl

./gpioctrl 42

图 129-17

可以看到GPIO1_PB2 pin脚打印的value值为高,所以gpio的状态打印正确。

同理,我们将GPIO1_PB2 pin脚接到GND,再次运行程序,如下图所示:

图 129-18

可以看到GPIO1_PB2 pin脚打印的value值为0,所以gpio的状态打印正确。

至此GPIO输入应用程序在开发板的测试就完成了。

这篇关于RK3568驱动指南|第十二篇 GPIO子系统-第129章 GPIO控制和操作实验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/601523

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

动手学深度学习【数据操作+数据预处理】

import osos.makedirs(os.path.join('.', 'data'), exist_ok=True)data_file = os.path.join('.', 'data', 'house_tiny.csv')with open(data_file, 'w') as f:f.write('NumRooms,Alley,Price\n') # 列名f.write('NA

线程的四种操作

所属专栏:Java学习        1. 线程的开启 start和run的区别: run:描述了线程要执行的任务,也可以称为线程的入口 start:调用系统函数,真正的在系统内核中创建线程(创建PCB,加入到链表中),此处的start会根据不同的系统,分别调用不同的api,创建好之后的线程,再单独去执行run(所以说,start的本质是调用系统api,系统的api

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

Java IO 操作——个人理解

之前一直Java的IO操作一知半解。今天看到一个便文章觉得很有道理( 原文章),记录一下。 首先,理解Java的IO操作到底操作的什么内容,过程又是怎么样子。          数据来源的操作: 来源有文件,网络数据。使用File类和Sockets等。这里操作的是数据本身,1,0结构。    File file = new File("path");   字