Pinctrl子系统_04_Pinctrl子系统主要数据结构

引言

本节说明Pinctrl子系统中主要的数据结构,对这些数据结构有所了解,也就是对Pinctrl子系统有所了解了。

前面说过,要使用Pinctrl子系统,就需要去配置设备树。

以内核面向对象的思想,设备树可以分为两部分,一部分(左边)用来描述Controller,另一部分(右边)则是描述使用引脚(使用controller)的device

对于controller的部分,内核会抽象出一个 pinctrl_dev 结构体;对于 device 的部分,内核会抽象出一个 device 结构体,device 结构体中会有 pinctrl 方面的成员。

显然,这个 pinctrl 方面的成员肯定会和左边的 pinctrl_dev 结构体产生联系。

那么,它们之间是什么样的关系呢?

答:在我们了解完Pinctrl子系统的数据结构之后,他们之间的关系也就清晰了。

首先,在了解Pinctrl子系统的数据结构前,先回忆一下Pinctrl子系统的三大作用

  1. 引脚枚举与命名(Enumerating and naming ):这个pinctrl支持哪些引脚,这些引脚叫什么名字;
  2. 引脚复用(Multiplexing ):用作什么功能,比如用作GPIO、I2C或其他功能;
  3. 引脚配置(Configuration):配置具体的引脚属性,比如上拉、下拉、open drain、驱动强度等;

记住这三大作用,就可以比较形象的去理解相关的结构体了。

那么,在Pinctrl子系统中,是怎么去实现这三大作用的呢?

pinctrl_desc和pinctrl_dev

我们刚刚说,controller 的部分,内核会抽象出一个 pinctrl_dev 结构体,但是事实上我们并不需要自己构造出这个 pinctrl_dev 结构体,而是使用内核提供的注册接口(pinctrl_register函数),我们只需要提供一个pinctrl_desc,然后调用这个接口,接口的返回值就是一个指向 pinctrl_dev 结构体的指针

通过 pinctrl_devpinctrl_desc 这两个结构体,就可以描述一个 pincontroller

controller相关结构体说明

imx6ull 为例,来了解pinctrl子系统中,controller 主要的数据结构,看看代码中是如何通过这些数据结构,实现 pinctrl 的三大作用的。

以下是 imx6ull 的pinctrl节点:

在设备启动后,这个节点会被转换成一个平台设备,和对应的平台驱动匹配完成后,就会调用对应的 probe 函数。

probe函数的大致流程

根据 compatible 属性值("fsl,imx6ul-iomuxc"),可以找到对应的驱动文件是 pinctrl-imx6ul.c,对应的 probe 函数是 imx6ul_pinctrl_probe,imx6ul_pinctrl_probe中则会调用 imx_pinctrl_probe函数。

imx_pinctrl_probe 函数中,会定义一个结构体指针 imx_pinctrl_desc,指向一个 pinctrl_desc 结构体。

在之后的代码中,首先申请一段内存,用来保存 pinctrl_desc,然后填充 pinctrl_desc 结构体,最后调用 devm_pinctrl_register,进行注册。

三大作用的具体实现

上面是probe函数中相关操作的大致流程,下面来具体说一下,在 Pinctrl 子系统中,是怎么去实现上面说的三大作用(引脚枚举与命名,引脚复用,引脚配置)的。

实现的关键就在于 pinctrl_desc 结构体,下面依次说明。

引脚的枚举与命名

首先看第一个功能,引脚的枚举与命名。

需要注意一下,引脚的枚举与命名分为两种情况

  1. 单个引脚 的枚举与命名;
  2. 多个引脚 的枚举与命名;
单个引脚

单个引脚的枚举和命名,主要是通过 pinctrl_desc 结构体的 pins 成员和 npins 成员来实现的。

其中,pins 成员是一个结构体指针,指向一个 pinctrl_pin_desc 结构体,主要负责引脚的枚举与命名;而 npins 成员则是一个无符号的整型数据,用来记录引脚的总个数

在 probe 函数中,会对 pins 和 npins 赋值,大致流程如下:

其中,imx6ul_pinctrl_info 变量的类型是 imx_pinctrl_soc_info 结构体,他也有 pins 和 npins 成员:

可以看到,他的 pins 成员指向了一个 imx6ul_pinctrl_pads 变量,这个变量是一个结构体数组,我们稍后再说。

综上,相当于执行了:

imx_pinctrl_desc->pins = imx6ull_snvs_pinctrl_pads;

imx_pinctrl_desc->npins = ARRAY_SIZE(imx6ull_snvs_pinctrl_pads);

下面,看一下 imx6ul_pinctrl_pads 变量,他是一个结构体数组。通过对 IMX_PINCTRL_PIN 宏的分析,可以看到,这里主要定义了两个成员:

  1. number(第几个引脚,引脚的枚举)
  2. name (引脚的名字,引脚的命名)

 

总结一下,单个引脚的枚举与命名,主要的相关结构体是:

  1. pinctrl_pin_desc结构体;

多个引脚

上面说 pins 和 npins,他们是描述单个引脚。而在实际使用中,有时候会需要同时操作多个引脚group),比如i2c中我们要用到一组引脚,要如何同时操作多个引脚呢?

答:这个时候就要用到 pinctrl_ops 结构体了:

可以看到, pinctrl_ops结构体的成员全部都是函数指针,它们的功能如下:

struct pinctrl_ops {
    /* 返回已注册的group数
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     */
	int (*get_groups_count) (struct pinctrl_dev *pctldev);

    /* 返回指定group的名字
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - unsigned selector:group选择器,表示选择哪个group。
     */
	const char *(*get_group_name) (struct pinctrl_dev *pctldev,
				       unsigned selector);

    /* 返回指定group的引脚数组,并在num_pins中返回数组大小。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - unsigned selector:group选择器,表示选择哪个group。
     *  - const unsigned **pins:指向存储引脚数组的指针的指针。
     *  - unsigned *num_pins:指向存储引脚数组大小的变量的指针。
     */
	int (*get_group_pins) (struct pinctrl_dev *pctldev,
			       unsigned selector,
			       const unsigned **pins,
			       unsigned *num_pins);

    /* 可选的debugfs钩子函数,用于在debugfs中为特定引脚提供每个设备的信息。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - struct seq_file *s:序列文件结构体指针,用于在debugfs中显示信息。
     *  - unsigned offset:偏移量,表示特定引脚的偏移量。
     */
	void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
			  unsigned offset);

    /* 解析设备树中的“引脚配置节点”,并为其创建映射表条目。这些通过`map`和`num_maps`输出参数返回。此函数是可选的,对于不支持设备树的引脚控制驱动程序可以省略。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - struct device_node *np_config:设备树中的引脚配置节点。
     *  - struct pinctrl_map **map:指向映射表指针的指针,用于返回映射表条目。
     *  - unsigned *num_maps:指向存储映射表条目数量的变量的指针。
     */
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
			       struct device_node *np_config,
			       struct pinctrl_map **map, unsigned *num_maps);

    /* 释放通过`dt_node_to_map`创建的映射表条目。必须释放顶层`map`指针,以及映射表条目本身的任何动态分配成员。此函数是可选的,对于不支持设备树的引脚控制驱动程序可以省略。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - struct pinctrl_map *map:映射表指针,需要释放。
     *  - unsigned num_maps:映射表条目数量。
     */
	void (*dt_free_map) (struct pinctrl_dev *pctldev,
			     struct pinctrl_map *map, unsigned num_maps);
};

这里说明一下,pinctrl_ops结构体成员中,有一个很关键的函数指针 dt_node_to_map,他是用来处理设备树的,我们以后再说,这里先点一下。

所以,对于多个引脚(group),相关的结构体是:

  1. pinctrl_ops 结构体;

引脚复用

类似的,引脚的复用也是由一个结构体来实现:pinmux_ops

pinmux_ops 就是 "Pin Multiplexing Operations"的缩写,表示引脚复用操作。

可以看到,结构体内部主要也是一堆函数指针

其中,引脚的复用主要是通过 set_mux 成员来实现的,他也是一个函数指针:

这里目前只对set_mux成员做说明,后面如果有用到其他函数指针,到时候再补充。

struct pinmux_ops {
	int (*request) (struct pinctrl_dev *pctldev, unsigned offset);

	int (*free) (struct pinctrl_dev *pctldev, unsigned offset);

	int (*get_functions_count) (struct pinctrl_dev *pctldev);

	const char *(*get_function_name) (struct pinctrl_dev *pctldev,
					  unsigned selector);

	int (*get_function_groups) (struct pinctrl_dev *pctldev,
				  unsigned selector,
				  const char * const **groups,
				  unsigned *num_groups);

    /* 启用特定的muxing功能与特定的group。驱动程序无需确定启用此功能是否与该组中pin的其他用途冲突,这种冲突由pinmux子系统处理。
     *  - struct pinctrl_dev *pctldev: 指向pinctrl设备结构的指针,用于表示设置mux的pinctrl设备。
     *  - unsigned func_selector: 无符号整数,表示选择什么功能。
     *  - unsigned group_selector: 无符号整数,表示选择哪个group。
     */
	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,
			unsigned group_selector);

	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
				    struct pinctrl_gpio_range *range,
				    unsigned offset);

	void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset);

	int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset,
				   bool input);

	bool strict;
};

引脚配置

我们还可以将一个或一组引脚,设置成不同的配置,比如上拉,下拉,open drain(开漏)等等。

这是怎么操作的呢?

答:同样是通过一个结构体:pinconf_ops

pinconf_ops 就是"Pin Configuration Options"的缩写,表示引脚的配置操作。

可以看到,结构体内部主要还是一堆函数指针。

这里主要说明以下四个函数指针:

  1. pin_config_get:获取某个pin的配置;
  2. pin_config_set:设置某个pin的配置;
  3. pin_config_group_get:获取某个group的配置;
  4. pin_config_group_set:设置某个group的配置;

注册pinctrl_dev

填充完 pinctrl_desc 结构体之后,调用 devm_pinctrl_register pinctrl_register,就可以根据 pinctrl_desc 构造出 pinctrl_dev,并且把 pinctrl_dev 放入链表

devm_pinctrl_register
    pinctrl_register
    	struct pinctrl_dev *pctldev;
		pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);

		pctldev->owner = pctldesc->owner;
		pctldev->desc = pctldesc;
		pctldev->driver_data = driver_data;

		/* check core ops for sanity */
		ret = pinctrl_check_ops(pctldev);

		/* If we're implementing pinmuxing, check the ops for sanity */
		ret = pinmux_check_ops(pctldev);

		/* If we're implementing pinconfig, check the ops for sanity */
		ret = pinconf_check_ops(pctldev);

		/* Register all the pins */
		ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);

		list_add_tail(&pctldev->node, &pinctrldev_list);

总结

综上,对于controller,涉及的结构体主要有5个:

  1. pinctrl_desc:用于描述一个特定的引脚控制器(pinctrl)的配置信息,包括该控制器管理的引脚数量、引脚的功能、引脚的默认状态等。
  2. pinctrl_dev:代表一个具体的引脚控制器设备,它与`pinctrl_desc`结构体相关联,用于在系统中表示和管理一个特定的引脚控制器。
  3. pinctrl_ops :定义了对引脚控制器进行操作的一组函数指针,包括引脚的配置、引脚的状态读取、引脚的状态设置等操作。
  4. pinmux_ops:定义了对引脚复用(pin multiplexing)进行操作的一组函数指针,用于配置引脚的不同功能模式,例如将一个引脚配置为GPIO模式或者特定外设的模式。
  5. pinconf_ops:定义了对引脚配置(pin configuration)进行操作的一组函数指针,用于设置和获取引脚的一些特定属性,例如引脚的电压、上下拉设置等。

device相关结构体说明

上面主要是对左边controller相关的结构体说明,下面来讨论一下右边device相关的结构体。

dev_pin_info 结构体

在设备树中,使用pinctrl时,device节点格式如下:

/* For a client device requiring named states */
device {
    pinctrl-names = "active", "idle";
    pinctrl-0 = <&state_0_node_a>;
    pinctrl-1 = <&state_1_node_a &state_1_node_b>;
};

设备节点要么被转换为 platform_device,要么转换为其他结构体(比如i2c_client),但是里面都会有一个 device 结构体。在 device 结构体中会有一个 pins 成员,这个 pins 成员是一个结构体指针,指向一个 dev_pin_info 结构体。

dev_pin_info 结构体保存的就是这个 device 的 pinctrl 信息

下面是 dev_pin_info 结构体的定义:

可以看到,主要定义了:

  1. 一个指向 pinctrl 结构体的结构体指针p;
  2. 4个指向 pinctrl_state 结构体的结构体指针 default_state,init_state,sleep_state,idle_state。

结合device节点,分析理解一下 dev_pin_info 结构体,以下面的device节点为例:

右边的device节点中,定义了两种状态:

  1. 状态0:default(对应 controller 节点 state_0_node_a) ;
  2. 状态1:sleep(对应 controller 节点 state_1_node_a 和 state_1_node_b)。

那么,就会用这些节点,来构造 dev_pin_info 结构体中的 default_state sleep_state

可以看到,dev_pin_info 结构体中已经定义了 4 个pinctrl_state指针,如果要添加我们自定义的state,要怎么记录呢?

答:dev_pin_info 结构体中有一个 pinctrl 结构体,我们自定义的 state 就存放在这个 pinctrl 结构体中。

假设要添加一个自定义的state,名字叫做“plane”,意为飞行模式,那么节点会变成这样:

pinctrl 结构体中有一个 states 成员,这个成员就会以链表的形式保存所有state,根据状态的序号,依次分别是default,sleep,plane。

并且 dev_pin_info 结构体中原先就有定义的 default_state 和 sleep_state,他们也会指向 states 成员中保存的 default 和 sleep 状态信息。

综上,对应device节点,最重要的结构体当属 pinctrl_state 结构体。

当设备进入某种状态时,就要把引脚配置成对应的 state。

那么,我们如何构造 pinctrl_state 呢?

如何构造pinctrl_state?

以下图为例,device 节点中的 pinctrl-0(default状态) 使用的是 state_0_node_a 节点,那么自然就要根据 state_0_node_a 节点来构造出 default_state。

那么,怎么根据pinctrl节点构造state呢?

答:需要用到 pinctrl_ops 结构体中的 dt_node_to_map 成员了。

dt_node_to_map 就是 "device tree node ==》map",顾名思义,就是将设备树的节点转换成一系列的map结构体(即pinctrl_map结构体)的意思。

通过 dt_node_to_map,将 pinctrl 节点转换为 pinctrl_map,再由 pinctrl_map 转换为 pinctrl_setting,最后,pinctrl_setting 会被存入 pinctrl_state 中的 settings 链表。

 

那么,pinctrl_map pinctrl_setting 中,需要保存哪些信息呢?

答:对于 pinctrl 节点,他主要有两个作用:

  1. pin mux,引脚复用;
  2. pin cfg,引脚配置;

那么,显然,pinctrl_map pinctrl_setting 就需要将这两个信息(引脚的复用信息,引脚的配置信息)保存记录下来。

首先,看一下 pinctrl_map 结构体:

可以看到,pinctrl_map 内部有一个联合体(union)data,这个联合体有两个成员:

  1. pinctrl_map_mux,记录复用信息;
  2. pinctrl_map_configs,记录配置信息;

所以,pinctrl_map 既可以记录引脚的复用信息,也可以记录引脚的配置信息;

刚刚说了,pinctrl_map 还会转换出 pinctrl_setting,来看一下 pinctrl_setting 结构体:

可以看到,他也有一个联合体(union) data,并且这个data也有两个成员:

  1. pinctrl_setting_mux,记录复用信息;
  2. pinctrl_setting_configs,记录配置信息;

所以,与 pinctrl_map 一样,pinctrl_setting 也是既可以记录引脚的复用信息,也可以记录引脚的配置信息。

对比 pinctrl_map pinctrl_setting,可以发现两者高度类似:都可以保存引脚的复用信息,配置信息。

综上,我们知道了, 驱动程序会把 pinctrl子节点 转换成一系列(为什么说一系列?因为一个pinctrl子节点可能包含多个引脚)的 pinctrl_map pinctrl_setting 结构体,在 pinctrl_map pinctrl_setting 结构体中会保存引脚的配置信息,复用信息

并且 pinctrl_setting 结构体还会被存入 pinctrl_state,以后我们选择让这个设备进入某种状态时,就会根据这些setting,来设置那些引脚,选择引脚的功能,配置引脚的上下拉,驱动强度等等。

 

使用pinctr_setting

最后,我们来看一下 pinctrl_state 中的这一系列 setting,是如何被调用的,又是如何去配置引脚的

这主要会涉及 pinmux_ops 结构体中的 set_mux(设置复用)和 pinconf_ops 结构体中的 pin_config_set(设置引脚配置),pin_config_group_set(设置group配置)。

调用的流程如下:

really_probe
	pinctrl_bind_pins
		pinctrl_select_state
			/* Apply all the settings for the new state */
			list_for_each_entry(setting, &state->settings, node) {
				switch (setting->type) {
                /* 引脚复用 */
				case PIN_MAP_TYPE_MUX_GROUP:
					ret = pinmux_enable_setting(setting);
							ret = ops->set_mux(...);
				break;

                /* 引脚配置:单引脚,多引脚 */
				case PIN_MAP_TYPE_CONFIGS_PIN:
				case PIN_MAP_TYPE_CONFIGS_GROUP:
					ret = pinconf_apply_setting(setting);
                        switch (setting->type) {
                    	case PIN_MAP_TYPE_CONFIGS_PIN:
							ret = ops->pin_config_set(...);
                        break;
	                    case PIN_MAP_TYPE_CONFIGS_GROUP:
		                    ret = ops->pin_config_group_set(...);
                        break;
	                    default:
		                    return -EINVAL;
                        }
					break;
				default:
					ret = -EINVAL;
				    break;
			}		

这样,左右两边的结构体(controller和device)就产生了联系,当设备进入某种状态时,就可以将引脚设置为对应的配置。

当我们对上述的结构体都有了初步的了解之后,后面就可以开始进行更深入的分析了。

以上就是本节全部内容。

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

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

相关文章

ssrf漏洞

SSRF漏洞概述和演示 SSRF&#xff08;Server-Side Request Forgery&#xff0c;服务器端请求伪造&#xff09;是一种常见的Web应用程序安全漏洞。它允许攻击者诱使服务器端应用程序发起任意HTTP(S)请求到内部系统或者网络&#xff0c;而这些请求通常是正常情况下服务器自身为了…

MYSQL | 数据库到底是怎么来的?

“以史为鉴&#xff0c;可以让我们更深刻地理解现在&#xff0c;预见未来。” 要想知道一件东西是怎么发生的, 我们不妨把时间拨回关系型数据库被提出前后来探索。在信息技术飞速发展的今天&#xff0c;回望数据库管理系统的演进之路&#xff0c;我们可以深刻理解到技术进步如…

产品推荐 - 基于6U VPX的双TMS320C6678+Xilinx FPGA K7 XC7K420T的图像信号处理板

综合图像处理硬件平台包括图像信号处理板2块&#xff0c;视频处理板1块&#xff0c;主控板1块&#xff0c;电源板1块&#xff0c;VPX背板1块。 一、板卡概述 图像信号处理板包括2片TI 多核DSP处理器-TMS320C6678&#xff0c;1片Xilinx FPGA XC7K420T-1FFG1156&#xff0c;1片…

20240309-1-校招前端面试常见问题-前端框架及常用工具

校招前端面试常见问题【5】——前端框架及常用工具 React Q&#xff1a;请简述一下虚拟 DOM 的概念&#xff1f; 基于 React 进行开发时所有的 DOM 构造都是通过虚拟 DOM 进行&#xff0c;每当数据变化时&#xff0c;React 都会重新构建整个 DOM 树&#xff0c;然后 React 将…

selenium之PO设计模式

初识PO模式 PO&#xff08;PageObject&#xff09;是一种设计模式。简单来说就是把一些繁琐的定位方法、元素操作方式等封装到类中&#xff0c;通过类与类之间的调用完成特定操作。 PO被认为是自动化测试项目开发实践的最佳设计模式之一。 在学习PO模式前&#xff0c;可以先…

力扣日记3.8-【回溯算法篇】37. 解数独

力扣日记&#xff1a;【回溯算法篇】37. 解数独 日期&#xff1a;2023.3.8 参考&#xff1a;代码随想录、力扣 37. 解数独 题目描述 难度&#xff1a;困难 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只…

存货计价方式 比较-移动平均和批次计价

SAP常用的存货计价方式有 标准价格移动平均价格批次计价 标准价格常用于制造企业&#xff0c;今天的方案比较主要集中在销售型企业常用的移动平均价和批次计价 批次计价&#xff1a; 移动平均&#xff1a; 两种计价方式的Pros&Cons 比较 批次计价 移动平均优点 1…

基于单片机的水平角度仪系统设计

目 录 摘 要 I Abstract II 引 言 1 1控制系统设计 3 1.1系统方案设计 3 1.2系统工作原理 4 2硬件设计 6 2.1单片机 6 2.1.1单片机最小系统 6 2.1.2 STC89C52单片机的性能 7 2.2角度采集电路 8 2.2.1 ADXL345传感器的工作原理 9 2.2.2 ADXL345传感器倾角测量的原理 9 2.2.3 AD…

YOLOv8优化策略:特征融合篇 | GELAN(广义高效层聚合网络)结构来自YOLOv9

🚀🚀🚀本文改进:使用GELAN改进架构引入到YOLOv8 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1.YOLOv9介绍 论文: 2402.13616.pdf (arxiv.org) 摘要: 如今的深度学习方法重点关注如何设计最合适…

用 ChatGPT 搭配 STAR 原则,准备英文面试超轻松

用 ChatGPT 搭配 STAR 原则&#xff0c;准备英文面试超轻松 ChatGPT 除了可以帮忙改简历&#xff0c;在你的求职历程中&#xff0c;ChatGPT 也可以帮忙练英文面试。在我们实测之后&#xff0c;发现 ChatGPT 在练习英文面试上&#xff0c;不仅能针对你的回答给予回馈&#xff0…

Docker下Jenkins打包java项目并部署

docker 构建Jenkins sudo docker run --namezen_haslett --userjenkins --privilegedtrue --volume/home/cyf/server/jenkins/jenkins_home:/var/jenkins_home -v /usr/lib/jvm/java-17-openjdk-amd64:/usr/lib/jvm/java-17-openjdk-amd64 -v /usr/lib/maven/apache-mav…

FFmpeg--AAC音频解码流程

文章目录 AAC 组成函数分析读aac帧写aac帧aac的head参数设置 运行结果 AAC 组成 AAC音频格式&#xff1a;是⼀种由MPEG-4标准定义的有损⾳频压缩格式 ADTS:是AAC音频的传输流格式 AAC音频文件的每一帧由ADTS Header和AAC Audio Data组成 每⼀帧的ADTS的头⽂件都包含了⾳频的采…

ArmSoM Rockchip系列产品 通用教程 之 GPIO 使用

1. GPIO简介​ GPIO&#xff0c;全称 General-Purpose Input/Output&#xff08;通用输入输出&#xff09;&#xff0c;是一种在计算机和嵌入式系统中常见的数字输入输出接口。它允许软件控制硬件的数字输入和输出&#xff0c;例如开关、传感器、LED灯等。GPIO通常由一个芯片或…

C++矢量运算与java矢量运算

矢量运算 概述&#xff1a; 矢量运算是一种基于向量的数学运算&#xff0c;它遵循特定的法则。以下是矢量运算的一些基本原理&#xff1a; 矢量加法&#xff1a;可以使用平行四边形法则或三角形法则来执行。当两个矢量相加时&#xff0c;可以将它们的起点放在同一个点上&…

【硬件设计】(更新中)以 UCC27710 为例设计栅极驱动器元件选型(资料摘抄)

还没更新完。。。。。。。 【仅作自学记录&#xff0c;不出于任何商业目的。如有侵权&#xff0c;请联系删除&#xff0c;谢谢&#xff01;】 本文摘抄翻译自&#xff1a; Bootstrap Network Analysis: Focusing on the Integrated Bootstrap Functionality (infineon.com)Boo…

[nlp入门论文精读] | Transformer

写在前面 最近工作从CV转向了NLP&#xff0c;于是空余时间便跟着哔哩哔哩李沐老师的视频学习。其实研一NLP课程讲论文的时候&#xff0c;我们小组就选择了经典的Attention和Bert&#xff0c;但还有很多细节并不完全理解&#xff0c;实际使用时也很困惑。 因此这个系列就来记…

【Android 内存优化】KOOM 快手开源框架线上内存监控方案-源码剖析

文章目录 前言OOMMonitorInitTask.INSTANCE.initOOMMonitor.INSTANCE.startLoopsuper.startLoopcall() LoopState.Terminate dumpAndAnalysisdumpstartAnalysisService回到startLoop方法总结 前言 这篇文章主要剖析KOOM的Java层源码设计逻辑。 使用篇请看上一篇: 【Android …

Kubesphere前端项目分析

1 KubeSphere console功能导图 模块&#xff1a; 命令行工具 (kubectl) 日志&#xff08;Logging&#xff09; 平台设置&#xff08;Platform Settings&#xff09; 服务组件&#xff08;Service Components&#xff09; 监控和警报&#xff08;Monitoring & Alerting&…

手写分布式配置中心(六)整合springboot(自动刷新)

对于springboot配置自动刷新&#xff0c;原理也很简单&#xff0c;就是在启动过程中用一个BeanPostProcessor去收集需要自动刷新的字段&#xff0c;然后在springboot启动后开启轮询任务即可。 不过需要对之前的代码再次做修改&#xff0c;因为springboot的配置注入value("…

pytest教程-15-多个fixture以及重命名

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了fixture的yield关键字&#xff0c;本小节我们讲解一下使用多个fixture的方法。 使用多个fixture 如果用例需要用到多个fixture的返回数据&#xff0c;fixture也可以return一个元组、list或字…