嵌入式驱动开发详解3(pinctrl和gpio子系统)

文章目录

  • 前言
  • pinctrl子系统
    • pin引脚配置
    • pinctrl驱动详解
  • gpio子系统
    • gpio属性配置
    • gpio子系统驱动
    • gpio子系统API函数
    • 与gpio子系统相关的of函数
  • pinctrl和gpio子系统的使用
    • 设备树配置
    • 驱动层部分
    • 用户层部分

前言

如果不用pinctrl和gpio子系统的话,我们开发驱动时需要先在设备树或者驱动文件中对pin进行配置成相应的功能引脚,然后如果是gpio功能的话就需要进行gpio初始化,如果是其他外设的话就需要进行其他外设的初始化,因为经常将引脚配置为gpio模式,因此linux内核针对pin的配置特意推出了pinctrl子系统,针对gpio的配置推出了gpio子系统,对于一些其他的外设模式有其他特定的子系统,这里不做讲解。

pinctrl子系统

大多数 SOC 的 pin 都是支持复用的,比如 I.MX6ULL 的 GPIO1_IO03 既可以作为普通的 GPIO 使用,也可以作为 I2C1 的 SDA 等等。此外我们还需要配置 pin 的电气特性,比如上/下 拉、速度、驱动能力等等。传统的配置 pin 的方式就是直接操作相应的寄存器,但是这种配置 方式比较繁琐、而且容易出问题(比如 pin 功能冲突)。pinctrl 子系统就是为了解决这个问题而引 入的,pinctrl 子系统主要工作内容如下:

  • ①、获取设备树中 pin 信息。
  • ②、根据获取到的 pin 信息来设置 pin 的复用功能
  • ③、根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。

对于我们使用者来讲,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始 化工作均由 pinctrl 子系统来完成,pinctrl 子系统源码目录为 drivers/pinctrl。

pin引脚配置

要使用 pinctrl 子系统,我们需要在设备树里面设置 PIN 的配置信息,毕竟 pinctrl 子系统要 根据你提供的信息来配置 PIN 功能,一般会在设备树里面创建一个节点来描述 PIN 的配置信息。
在dtsi 文件,有一个叫做 iomuxc 的节点就是配置对应的pin引脚信息,但是这个文件里面只设置了iomuxc寄存器的起始地址,剩下的具体配置是在具体的设备树dts文件中追加的,结合起来之后如下所示:

iomuxc: iomuxc@020e0000 
{
	compatible = "fsl,imx6ul-iomuxc";
	reg = <0x020e0000 0x4000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog_1>;
	imx6ul-evk {
		pinctrl_hog_1: hoggrp-1 {
			fsl,pins = < 
				MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 
				MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 
				MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 
				MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058 
			>; 
			......
		};
	}; 
};

对于一个 PIN 的配置主要包括两方面, 一个是设置这个 PIN 的复用功能,另一个就是设置这个 PIN 的电气特性。所以在每个子节点中类似UART1_RTS_B的定义就对应的设置好了 UART1_RTS_B 的复用功能和 UART1_RTS_B 的电气特性。例如,我们可以在pinfunc.h 这个头文件找到UART1_RTS_B的定义如下:

#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0

0x0090 0x031C 0x0000 0x5 0x0,这 5 个值的含义如下所示:

<mux_reg conf_reg input_reg mux_mode input_val>

三个reg就是对应前面所提到的iomuxc的基地址的偏移值,前三个刚好对应上复用功能寄存器,电气属性寄存器和输入寄存器,第四个和第五个就是复用功能寄存器的值和输入寄存器的值,而电气属性寄存器的值放在了宏定义MX6UL_PAD_UART1_RTS_B__GPIO1_IO19的后面0x17059 。

pinctrl驱动详解

关于pinctrl驱动的具体实现我这里不做过多赘述,我们只需要掌握怎么把设备树的pin给配置好就行,配置好之后pinctrl驱动就会自动的把引脚配置成想要的状态。由于内核都封装好了,所以只需大概将一下实现流程。
在这里插入图片描述如上图所示,pinctrl子系统的实现也是通过platform实现的,当pinctrl驱动与对应的compatible(在刚刚提到的pin配置的节点信息的最前面设置好了)匹配上之后就会执行probe函数,probe函数就会根据节点下面的pin配置给对应的寄存器写入对应的值。

gpio子系统

如果 pinctrl 子系统将一个 PIN 复用为 GPIO 的话,那么接下来就要用到 gpio 子系 统了。gpio 子系统顾名思义,就是用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO 为输入输出,读取 GPIO 的值等。gpio 子系统的主要目的就是方便驱动开发者使用 gpio,驱动 开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API 函数来操作 GPIO,Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程,极大的方便了驱动开 发者使用 GPIO。

gpio属性配置

/* 根节点下linux内核中的gpio1属性配置*/
/ {
…………
	soc {
	…………
		gpmi: gpmi-nand@01806000{
		…………
			aips1: aips-bus@02000000 {
			…………
				gpio1: gpio@0209c000 {
				compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
				reg = <0x0209c000 0x4000>;
				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
					     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
				gpio-controller;
				#gpio-cells = <2>;
				interrupt-controller;
				#interrupt-cells = <2>;
				};
			};
		};
	};
};

/* 根节点下手动添加某个设备节点*/
/ {
…………
	beep{
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "hbb-beep";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_beep>;
		beep-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;
		status = "okay";
	};
};

如上所示, GPIO子系统配置时是根据根节点下linux内核中的gpio1属性配置的,但是还需要gpio编号才能知道去配置哪个gpio,因此我们需要自己手动在根节点下手动添加某个设备节点(这里的节点跟上一个帖子的节点不同,这里仅仅只是设备树的节点,可以通过cd /proc/device-tree命令查看设备树节点是否添加成功) ,通过在自己写的驱动从设备树中读取出设备编号,然后将此编号通过gpio子系统的API函数输入来操作配置GPIO寄存器即可。在上面自己手动添加的节点中:

pinctrl-0 = <&pinctrl_beep>; //这个是前面提到的pinctrl属性配置
beep-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>; //这个就是gpio的编号设置,因此前面的beep-gpio跟驱动有关联

很多初次接触设备树的驱动开发人员很容易因为这个小问题栽了大跟头!因为我们所使用 的设备树基本都是在半导体厂商提供的设备树文件基础上修改而来的,而半导体厂商提供的设 备树是根据自己官方开发板编写的,很多 PIN 的配置和我们所使用的开发板不一样。比如 A 这 个引脚在官方开发板接的是 I2C 的 SDA,而我们所使用的硬件可能将 A 这个引脚接到了其他 的外设,比如 LED 灯上,接不同的外设,A 这个引脚的配置就不同。一个引脚一次只能实现一 个功能,如果 A 引脚在设备树中配置为了 I2C 的 SDA 信号,那么 A 引脚就不能再配置为 GPIO, 否则的话驱动程序在申请 GPIO 的时候就会失败。
检查 PIN 有没有被其他外设使用包括两个方 面:
①、检查 pinctrl 设置。
②、如果这个 PIN 配置为 GPIO 的话,检查这个 GPIO 有没有被别的外设使用。

gpio子系统驱动

在drivers/gpio/目录下的.c文件就是不同芯片厂商的gpio驱动文件,跟pinctrl子系统一样,通过linux驱动的分层与分离、平台设备驱动相关内容封装好了,我们做驱动开发只要能掌握GPIO子系统的API函数的使用就行,后期如果有想法深入研究内核的开发,可以仔细研究一下具体是怎么实现的。

gpio子系统API函数

对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定 的 GPIO,gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,gpio 子系统提供的常用的 API 函数有下面几个:
gpio_request :用于申请一个 GPIO 管脚,在使用一个 GPIO 之前一定要使用 gpio_request 进行申请,函数原型如下:

int gpio_request(unsigned gpio, const char *label)

gpio_free:如果不使用某个 GPIO 了,那么就可以调用 gpio_free 函数进行释放。函数原型如下:

void gpio_free(unsigned gpio)

gpio_direction_input:此函数用于设置某个 GPIO 为输入,函数原型如下所示:

int gpio_direction_input(unsigned gpio)

gpio_direction_output:此函数用于设置某个 GPIO 为输出,并且设置默认输出值,函数原型如下:

int gpio_direction_output(unsigned gpio, int value)

gpio_get_value:此函数用于获取某个 GPIO 的值(0 或 1),此函数是个宏,定义所示:

#define gpio_get_value __gpio_get_value 
int __gpio_get_value(unsigned gpio)

gpio_set_value:此函数用于设置某个 GPIO 的值,此函数是个宏,定义如下

#define gpio_set_value __gpio_set_value 
void __gpio_set_value(unsigned gpio, int value)

以上只说明了有哪几个函数,具体函数怎么用可自行百度更加详细。

与gpio子系统相关的of函数

首先展示五个跟设备树的节点获取相关的五个OF函数:
of_find_node_by_name:过节点名字查找指定的节点;
of_find_node_by_type:通过 device_type 属性查找指定的节点
of_find_compatible_node:根据 device_type 和 compatible 这两个属性查找指定的节点
of_find_matching_node_and_match:通过 of_device_id 匹配表来查找指定的节点
of_find_node_by_path:通过路径来查找指定的节点,这个是我们经常用的方法。

前面的GPIO子系统的函数可以配置gpio的寄存器,但是在驱动程序中需要先读取 gpio 属性内容,因此Linux 内核提供了几个与 GPIO 有关 的 OF 函数,常用的几个 OF 函数如下所示:
of_get_named_gpio:此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号, 此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编 号,此函数在驱动中使用很频繁! 函数原型如下:

int of_get_named_gpio(struct device_node *np, const char *propname, int index)

np:设备节点。
propname:包含要获取 GPIO 信息的属性名。
index:GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO 的编号,如果只有一个 GPIO 信息的话此参数为 0。
返回值:正值,获取到的 GPIO 编号;负值,失败。

还有一些其他的跟gpio相关的of函数,但是不怎么常用,比如of_gpio_named_count和of_gpio_count,可以获取pio配置的数量。

pinctrl和gpio子系统的使用

下面将展示一个具体的例子来说明pinctrl子系统和gpio子系统具体怎么用的。

设备树配置

设备树的配置可以看前面pinctrl的配置和在设备树根文件下对gpio信息的配置

驱动层部分

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>  //copy
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h> 
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define BEEP_CNT 1
#define BEEP_NAME "beep"
#define BEEP_ON 1
#define BEEP_OFF 0

struct beep_dev{
	dev_t devid; 
	int major;
	int minor;
	struct cdev cdev;
	struct class *class;
	struct device *device;
	struct device_node *nd;
	int beep_gpio;
};

struct beep_dev beep;

static int beep_open(struct inode *inode, struct file *file)
{
	file->private_data = &beep;
	return 0;
}

static ssize_t beep_write(struct file *file, const char __user *buf,
				size_t count, loff_t *off)
{
	unsigned char status;
	int ret;
	struct beep_dev *dev = file->private_data;
	ret = copy_from_user(&status,buf,count);
	if(ret < 0){
		printk("kernel write failed!!!");
		return -1;
	}
	printk("device write%d\r\n",status);
	if(status == BEEP_ON){
		gpio_set_value(dev->beep_gpio, 0);
	}else if(status == BEEP_OFF){
		gpio_set_value(dev->beep_gpio, 1);
	}
	return 0;
}

int beep_release(struct inode *inode, struct file *file)
{
	return 0;

}

static const struct file_operations beep_fops = {
	.owner	= THIS_MODULE,
	.open	= beep_open,
	.write	= beep_write,
	.release = beep_release,
};

static int __init gpioled_init(void)
{
	int ret;
	beep.nd = of_find_node_by_path("/beep");
	if(beep.nd == NULL){
		printk("beep node cant not find!!\r\n");
		ret = -1;
		goto fail_node;
	}else{
		printk("beep node found!!\r\n");
	}
	beep.beep_gpio = of_get_named_gpio(beep.nd,"beep-gpio",0);
	if(beep.beep_gpio < 0){
		printk("cant not get beep-gpio\r\n");
		ret = -1;
		goto fail_node;
	}
	printk("beep-gpio-num=%d\r\n",beep.beep_gpio);

	ret = gpio_direction_output(beep.beep_gpio,1);
	if(ret < 0){
		printk("can`t set gpio!!!\r\n");
	}

	if(beep.major){
		beep.devid = MKDEV(beep.major,beep.minor);
		ret = register_chrdev_region(beep.devid, BEEP_CNT, BEEP_NAME);
	}else{
		ret = alloc_chrdev_region(&beep.devid,0,BEEP_CNT,BEEP_NAME);
		beep.major = MAJOR(beep.devid);
		beep.minor = MINOR(beep.devid);
		printk("alloc_chrdev_region major=%d minor=%d\r\n",beep.major, beep.minor);
	}
	if (ret < 0) {
		printk("Could not register\r\n");
		goto fail_devid;
	}
	beep.cdev.owner = THIS_MODULE;
	cdev_init(&beep.cdev, &beep_fops);
	ret = cdev_add(&beep.cdev,beep.devid,BEEP_CNT);
	if(ret < 0){
		printk("Could not cdev\r\n");
		goto fail_cdev;
	}
	beep.class = class_create(THIS_MODULE,BEEP_NAME);
	if(IS_ERR(beep.class)){
		ret = PTR_ERR(beep.class);
		goto fail_class;
	}
	beep.device = device_create(beep.class,NULL,beep.devid,NULL,BEEP_NAME);
	if(IS_ERR(beep.device)){
		ret = PTR_ERR(beep.device);
		goto fail_device;
	}
	return 0;
fail_device:
	class_destroy(beep.class);
fail_class:
	cdev_del(&beep.cdev);
fail_cdev:
	unregister_chrdev_region(beep.devid,BEEP_CNT);
fail_devid:
fail_node:
	return ret;
}

static void __exit gpioled_exit(void)
{
	gpio_set_value(beep.beep_gpio,1);
	printk("beep_exit\r\n");
	cdev_del(&beep.cdev);
	unregister_chrdev_region(beep.devid,BEEP_CNT);

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

module_init(gpioled_init);
module_exit(gpioled_exit);
MODULE_LICENSE("GPL");	
MODULE_AUTHOR("hbb");

用户层部分

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include "string.h"


int main(int argc,char *argv[])
{
    int fd,ret;
    char *filename;
    unsigned char databuf;
    if(argc != 3){
        printf("Error Usage!!!\r\n");
        return -1;
    }
    filename = argv[1];
    fd = open(filename ,O_RDWR);
    if(fd < 0){
        printf("file %s open failed!\r\n",filename);
        return -1;
    }
    databuf = atoi(argv[2]);
    ret = write(fd,&databuf,sizeof(databuf));
    if(ret < 0){
        printf("BEEP control failed\r\n");
        close(fd);
        return -1;
    }
    ret = close(fd);
    if(ret < 0){
        printf("file %s close failed! \r\n",filename);
        return -1;
    }
    return 0;
}

到这里对pinctrl和gpio子系统的大致说明就结束了,后面有新的相关的重要的内容会继续进行更新。
对代码有兴趣的同学可以查看链接https://github.com/NUAATRY/imx6ull_dev

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/923084.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

低代码搭建crm系统实现财务管理功能模块

实例背景&#xff1a; CRM的项目&#xff0c;客户想要实现一个简单的财务记账功能&#xff0c;记录订单应收账款及收款记录。 具体要求&#xff1a; 1、要求收款时可以实时计算本次收款后的剩余应收。 2、要求记录AR的收款状态&#xff1a;未收款、部分收款、已收款。 实现…

C51相关实验

C51相关实验 LED //功能&#xff1a;1.让开发板的LED全亮&#xff0c;2,点亮某一个LED,3.让LED3以5Hz的频率闪动#include "reg52.h"#define LED P2 sbit led1 LED^1;void main(void) {LED 0xff;//LED全灭led1 0;while(1)//保持应用程序不退出{} }LED 输出端是高…

【测试工具JMeter篇】JMeter性能测试入门级教程(一)出炉,测试君请各位收藏了!!!

一、前言 Apache JMeter是纯Java的开源软件&#xff0c;最初由Apache软件基金会的Stefano Mazzocchi开发&#xff0c;旨在加载测试功能行为和测量性能。可以使用JMeter进行性能测试&#xff0c;即针对重负载、多用户和并发流量测试Web应用程序。 我们选择JMeter原因 是否测试过…

人工智能(AI)与机器学习(ML)基础知识

目录 1. 人工智能与机器学习的核心概念 什么是人工智能&#xff08;AI&#xff09;&#xff1f; 什么是机器学习&#xff08;ML&#xff09;&#xff1f; 什么是深度学习&#xff08;DL&#xff09;&#xff1f; 2. 机器学习的三大类型 &#xff08;1&#xff09;监督式学…

STM32WB55RG开发(5)----监测STM32WB连接状态

STM32WB55RG开发----5.生成 BLE 程序连接手机APP 概述硬件准备视频教学样品申请源码下载参考程序选择芯片型号配置时钟源配置时钟树RTC时钟配置RF wakeup时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙LED配置设置工程信息工程文件设置参考文档SVCCTL_A…

虚拟机CentOS系统通过Docker部署RSSHub并映射到主机

公告 &#x1f4cc;更新公告 20241124-该文章已同步更新到作者的个人博客&#xff08;链接&#xff1a;虚拟机CentOS系统通过Docker部署RSSHub并映射到主机&#xff09; 一、编辑 YUM 配置文件 1、打开 CentOS 系统中的 YUM 软件仓库配置文件 vim /etc/yum.repos.d/CentOS-Ba…

React(五)——useContecxt/Reducer/useCallback/useRef/React.memo/useMemo

文章目录 项目地址十六、useContecxt十七、useReducer十八、React.memo以及产生的问题18.1组件嵌套的渲染规律18.2 React.memo18.3 引出问题 十九、useCallback和useMemo19.1 useCallback对函数进行缓存19.2 useMemo19.2.1 基本的使用19.2.2 缓存属性数据 19.2.3 对于更新的理解…

【漏洞复现】|百易云资产管理运营系统/mobilefront/c/2.php前台文件上传

漏洞描述 湖南众合百易信息技术有限公司&#xff08;简称&#xff1a;百易云&#xff09;成立于2017年是一家专注于不动产领域数字化研发及服务的国家高新技术企业&#xff0c;公司拥有不动产领域的数字化全面解决方案、覆盖住宅、写字楼、商业中心、专业市场、产业园区、公建、…

远程控制软件:探究云计算和人工智能的融合

在数字化时代&#xff0c;远程控制工具已成为我们工作与生活的重要部分。用户能够通过网络远程操作和管理另一台计算机&#xff0c;极大地提升了工作效率和便捷性。随着人工智能&#xff08;AI&#xff09;和云计算技术的飞速发展&#xff0c;远程控制工具也迎来了新的发展机遇…

漫谈 module caching——PyCharm jupyter notebook 在导入模块被更新后无法及时同步问题

目录 引子&#xff1a;问题的发现何为 module caching见微知著&#xff1a;Python 中的缓存机制参考链接 引子&#xff1a;问题的发现 近日笔者用 PyCharm 创建了一个项目时不经意间发现了这个问题&#xff1a;事情发生在调试 Jupyter Notebook 的过程中。当笔者修改了自己编写…

企业数字化转型现状

国家数字经济战略背景 2018年以来&#xff0c;国家政府不断出台政策规范我国企业数字化治理市场。2018年9月颁布《关于发展数字经济稳定并扩大就业的指导意见》&#xff0c;支持建设一批数字经济创新创业孵化机构。积极推进供应链创新与应用&#xff0c;支持构建以企业为主导。…

《Python基础》之算数、比较、赋值、逻辑、位运算符

目录 简介 Python中常见的运算符 1、算数运算符 2、比较运算符 3、赋值运算符 4、逻辑运算符 5、位运算符 总结 简介 Python 提供了多种运算符&#xff0c;用于执行各种操作&#xff0c;包括算术运算、比较运算、逻辑运算、位运算、赋值运算等。以下是 Python 中常用的…

学习threejs,使用设置bumpMap凹凸贴图创建褶皱,实现贴图厚度效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshPhongMaterial高…

【CSP CCF记录】201809-2第14次认证 买菜

题目 样例输入 4 1 3 5 6 9 13 14 15 2 4 5 7 10 11 13 14 样例输出 3 思路 易错点&#xff1a;仅考虑所给样例&#xff0c;会误以为H和W两人的装车时间是一一对应的&#xff0c;那么提交结果的运行错误就会让你瞬间清醒。 本题关键是认识到H和W的装车时间不一定一一对应&…

道品智能科技移动式水肥一体机:农业灌溉施肥的革新之选

在现代农业的发展进程中&#xff0c;科技的力量正日益凸显。其中&#xff0c;移动式水肥一体机以其独特的可移动性、智能化以及实现水肥一体化的卓越性能&#xff0c;成为了农业领域的一颗璀璨新星。它不仅改变了传统的农业灌溉施肥方式&#xff0c;更为农业生产带来了高效、精…

【PCB设计】AD16教程:分配位号

1、前提条件 确保已经基本画完原理图 2、点击【Tools-Annotate Schematics】 3、依次点击【Reset All】、【Update Changes Lise】、【Close】 最后位号就被自动分配好了

20241125编译友善之臂的NanoPi R3S开发板【RK3566】STEP-BY-STEP版本

20241125编译友善之臂的NanoPi R3S开发板【RK3566】STEP-BY-STEP版本 2024/11/25 15:59 20241125编译友善之臂的NanoPi R3S开发板【RK3566】精简步骤 2024/11/25 19:37 viewproviewpro-ThinkBook-16-G5-IRH:~$ viewproviewpro-ThinkBook-16-G5-IRH:~$ df -h viewproviewpro-T…

uniapp实际开发遇到过的问题(持续更新中....)

1. 在ios模拟器上会出现底部留白的情况 解决方案&#xff1a; 在manifest.json文件&#xff0c;找到开源码视图配置&#xff0c;添加如下&#xff1a; "app-plus" : {"safearea":{"bottom":{"offset" : "none" // 底部安…

计算机网络:应用层知识点概述及习题

网课资源&#xff1a; 湖科大教书匠 1、概述 习题1 1 在计算机网络体系结构中&#xff0c;应用层的主要功能是 A. 实现进程之间基于网络的通信 B. 通过进程之间的交互来实现特定网络应用 C. 实现分组在多个网络上传输 D. 透明传输比特流 2 以下不属于TCP/IP体系结构应用层范畴…

数据治理:在企业数据管理中的关键角色与实现路径——《DAMA 数据管理知识体系指南》读书笔记- 第 3 章

文章目录 1. 数据治理的核心内涵与战略价值2. 数据治理的驱动因素&#xff1a;不仅仅是合规3. 数据治理的组织模型&#xff1a;选择适合企业结构的运营模式4. 实施数据治理的关键步骤&#xff1a;战略、制度和文化5. 数据治理工具的选择&#xff1a;支持业务与流程的高效管理6.…