当前位置: 首页 > news >正文

嵌入式驱动开发详解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 0struct 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

相关文章:

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

文章目录 前言pinctrl子系统pin引脚配置pinctrl驱动详解 gpio子系统gpio属性配置gpio子系统驱动gpio子系统API函数与gpio子系统相关的of函数 pinctrl和gpio子系统的使用设备树配置驱动层部分用户层部分 前言 如果不用pinctrl和gpio子系统的话&#xff0c;我们开发驱动时需要先…...

【C++】IO库(一):IO类

IO 库 C 不直接处理输入输出&#xff0c;而是通过定义一族定义在标准库当中的类型来处理IO。 8.1 IO 类 为了支持不同种类的 IO 处理操作&#xff0c;除了 istream 和 ostream 之外&#xff0c;标准库还定义了其它 IO 类型。这些类型分别定义在三个独立的头文件当中&#xf…...

uniapp介入极光推送教程 超级详细

直接按照下面教程操作 一步一步来 很快就能 完成 下面的文章非常详细 &#xff0c;我就不班门弄斧了 直接上原文链接 https://blog.csdn.net/weixin_52830464/article/details/143823231...

阿里云整理(一)

阿里云整理 1. 介绍规模 2. 专业名词2.1 专有网络VPC2.2 安全组SG2.3 云服务器ECS2.4 资源组2.5 部署集2.5 web测试 1. 介绍 ‌阿里云是一家提供云计算和人工智能服务的科技公司&#xff0c;成立于2009年&#xff0c;总部位于杭州。‌它为全球客户提供全方位的云服务&#xff…...

论文笔记 网络安全图谱以及溯源算法

​ 本文提出了一种网络攻击溯源框架&#xff0c;以及一种网络安全知识图谱&#xff0c;该图由六个部分组成&#xff0c;G <H&#xff0c;V&#xff0c;A&#xff0c;E&#xff0c;L&#xff0c;S&#xff0c;R>。 1|11.知识图 ​ 网络知识图由六个部分组成&#xff0c…...

室内定位论文速递(11.23-11.25)

多传感器姿态估计的Delta滤波器和卡尔曼滤波器设计在球形移动测绘系统中的应用 关键词 球形机器人;姿态估计;传感器融合;卡尔曼滤波器;Delta滤波器;移动测绘;LiDAR 研究问题 球形移动测绘系统中的惯性姿态估计过滤技术尚未得到充分研究。由于其内在的滚动运动,该系统…...

英伟达推出了全新的小型语言模型家族——Hymba 1.5B

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

云网络基础- TCP/IP 协议

文章目录 典型服务模式TCP/IP 协议设置和查看IPIP地址的分类:IP地址组成: 网络位主机位组成克隆:产生一台新的虚拟机win2008 典型服务模式 • C/S,Client/Server架构 – 由服务器提供资源或某种功能 – 客户机使用资源或功能 TCP/IP 协议 • TCP/IP是最广泛支持的通信协议集合…...

android 音效可视化--Visualizer

Visualizer 是使应用程序能够检索当前播放音频的一部分以进行可视化。它不是录音接口&#xff0c;仅返回部分低质量的音频内容。但是&#xff0c;为了保护某些音频数据的隐私&#xff0c;使用 Visualizer 需要 android.permission.RECORD_AUDIO权限。传递给构造函数的音频会话 …...

Python人工智能项目报告

一、实践概述 1、实践计划和目的 在现代社会&#xff0c;计算机技术已成为支撑社会发展的核心力量&#xff0c;渗透到生活的各个领域&#xff0c;应关注人类福祉&#xff0c;确保自己的工作成果能够造福社会&#xff0c;同时维护安全、健康的自然环境&#xff0c;设计出具有包…...

DockerFile 构建基础镜像

1.准备东西 DockerFile 文件 以及安装docker环境 文件内容如下&#xff1a; # 使用Alpine Linux作为基础镜像 FROM --platformlinux/amd64 nginx:1.27.2-alpine # 维护者信息 LABEL maintainer"xu_yhao163.com" ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV …...

卷积神经网络学习记录

目录 神经网络基础定义&#xff1a; 基本组成部分 工作流程 卷积层&#xff08;卷积定义&#xff09;【CONV】&#xff1a; 卷积层&#xff08;Convolutional Layer&#xff09; 特征提取&#xff1a;卷积层的主要作用是通过卷积核&#xff08;或滤波器&#xff09;运算提…...

5种常见的k8s云原生数据管理方案详解

Kubernetes&#xff08;K8s&#xff09;是云原生架构的核心组件&#xff0c;提供高效的容器编排和管理功能。在数据存储方面&#xff0c;K8s通过PersistentVolumes&#xff08;PV&#xff09;和PersistentVolumeClaims&#xff08;PVC&#xff09;机制实现数据持久化&#xff0…...

[C++]了解内置类型升级

内置类型升级 1.调用模板T时&#xff0c;为什么可以使用T()类型的匿名对象来传参2.内置类型被升级成为类后的使用事项 1.调用模板T时&#xff0c;为什么可以使用T()类型的匿名对象来传参 当我们在定义或声明一个函数时&#xff0c;如果想使用模板T类型的默认构造&#xff08;例…...

docker镜像源配置、换源、dockerhub国内镜像最新可用加速源(仓库)

一、临时拉取方式 在docker pull后先拼接镜像源域名&#xff0c;后面拼接拉取的镜像名 $ docker pull dockerpull.org/continuumio/miniconda3 二、永久配置方式 vim修改/etc/docker/daemon.json&#xff0c;并重启docker服务。 # 创建目录 sudo mkdir -p /etc/docker# 写…...

什么是 WPF 中的依赖属性?有什么作用?

依赖属性&#xff08;Dependency Property&#xff09;是 WPF 的一个核心概念&#xff0c;它为传统的 .NET 属性提供了增强功能&#xff0c;支持绑定、样式、动画和默认值等功能。通过依赖属性&#xff0c;WPF 提供了一种灵活的数据驱动的方式来处理 UI 属性。 1. 什么是依赖属…...

241125学习日志——[CSDIY] [ByteDance] 后端训练营 [16]

CSDIY&#xff1a;这是一个非科班学生的努力之路&#xff0c;从今天开始这个系列会长期更新&#xff0c;&#xff08;最好做到日更&#xff09;&#xff0c;我会慢慢把自己目前对CS的努力逐一上传&#xff0c;帮助那些和我一样有着梦想的玩家取得胜利&#xff01;&#xff01;&…...

如何优化 PHP 性能?

以下是一些常见的优化 PHP 性能的方法&#xff1a; 启用缓存&#xff0c;例如使用 OPcache 来加速 PHP 脚本的执行。合理使用数据库索引&#xff0c;优化数据库查询语句。避免不必要的计算和重复操作&#xff0c;尽量复用数据和结果。减少文件包含的数量和复杂度。优化代码逻辑…...

【Linux服务器】内存问题排查

概述 项目制作过程中经常出现内存问题&#xff0c;在该处对排查思路进行汇总&#xff0c;也对常见问题进行总结&#xff0c;以期待下一次遇到相似问题时可以快速排查&#xff0c;然后解决问题 排查流程总结 首先检查内存的整体情况 使用工具htop和seme快速得知系统内存使用的…...

ModuleNotFoundError: No module named ‘simple_knn‘

【报错】复现 GaussianEditor 时引用 3D Gaussian Splatting 调用simple_knn 时遇到 ModuleNotFoundError: No module named ‘simple_knn‘ 报错&#xff1a; 【原因】 之前安装时直接进行配置pip install simple-knn 【解决办法】 查看 requirements.txt&#xff0c;才发现需…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...