Pinctrl子系统pinctrl_desc结构体进一步介绍

往期内容

本专栏往期内容:

  1. Pinctrl子系统和其主要结构体引入

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    – 末片,有往期内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有往期内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有往期内容观看顺序

img

前言

在上一篇文章中对Pincontroller进行了简单的介绍(Pinctrl子系统和其主要结构体引入),以及对设备树也进行了示范,对Pincontroller的结构体进行的引入,也就是起了个开头,知道了是用pinctrl_dev来指代一个Pincontroller,可以提到了可以通过提供一个pinctrl_desc再去调用某个函数来实现一个pinctrl_dev。那么接下来就进一步讲解。

那么接下来看看pinctrl_dev --> pinctrl_desc *desc --> pinctrl_ops、pinmux_ops、pinconf_ops

1. 作用1:描述、获得引脚 pinctrl_ops

使用pinctrl_ops来操作引脚,主要功能有二:

  • 来取出某组的引脚:get_groups_count、get_group_pins
  • 处理设备树中pin controller中的某个节点:dt_node_to_map,把device_node转换为一系列的pinctrl_mapimg
\Linux-4.9.88\include\linux\pinctrl\pinctrl.hstruct pinctrl_ops {int (*get_groups_count) (struct pinctrl_dev *pctldev);const char *(*get_group_name) (struct pinctrl_dev *pctldev,unsigned selector);int (*get_group_pins) (struct pinctrl_dev *pctldev,unsigned selector,const unsigned **pins,unsigned *num_pins);void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,unsigned offset);int (*dt_node_to_map) (struct pinctrl_dev *pctldev,struct device_node *np_config,struct pinctrl_map **map, unsigned *num_maps);void (*dt_free_map) (struct pinctrl_dev *pctldev,struct pinctrl_map *map, unsigned num_maps);
};

struct pinctrl_ops 结构体定义了全局引脚控制操作(pin control operations),这些操作需要由引脚控制器驱动程序实现。该结构体中的函数指针代表不同的操作接口,允许驱动程序通过这些接口与引脚控制子系统进行交互。

  • get_groups_count: 返回当前已注册的引脚组(pin group)数量。该函数用于获取系统中引脚组的总数。
  • get_group_name: 返回特定引脚组的名称。通过组选择器 selector 作为参数,驱动可以获取某个引脚组的名称。
  • get_group_pins: 返回与特定组选择器对应的引脚数组,并通过参数 pinsnum_pins 返回该数组的指针和引脚数量。此函数用于查询引脚组包含的具体引脚。
  • pin_dbg_show: 可选的 debugfs 显示挂钩,用于在调试文件系统(debugfs)中展示每个引脚的设备相关信息。它可以在调试时提供关于某个引脚的详细信息。
  • dt_node_to_map: 解析设备树(Device Tree)中的 “pin 配置节点” 并为其创建映射表项(mapping table entries)。这些映射表项通过 mapnum_maps 输出参数返回。该函数是可选的,适用于支持设备树的引脚控制器驱动。
  • dt_free_map: 释放通过 dt_node_to_map 创建的映射表项。顶层的 map 指针需要释放,同时还要释放映射表项中动态分配的成员。该函数是可选的,对于不支持设备树的引脚控制器驱动,可以忽略此函数。

这些操作为引脚控制子系统提供了操作引脚组、解析设备树节点、调试显示等功能接口。

2. 作用2:引脚复用 pinmux_ops

img

把某一组引脚配置成某一功能,GPIO模式??或是其它模式

\Linux-4.9.88\include\linux\pinctrl\pinmux.h
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);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;
};

struct pinmux_ops 结构体定义了引脚复用(pinmux)操作,主要用于实现支持引脚复用功能的引脚控制器驱动程序。该结构体提供了一系列回调函数,允许引脚控制器子系统与引脚复用功能进行交互。

  • request: 核心功能调用,用于判断特定的引脚是否可以被用于复用。在实际选择复用设置前,核心会调用该函数来请求引脚。驱动程序可以通过返回负值拒绝该请求。
  • free: 与 request() 相反,释放被请求的引脚。这是在引脚复用完成后释放引脚的回调函数。
  • get_functions_count: 返回当前引脚复用驱动中可选择的复用功能数量。
  • get_function_name: 根据复用选择器 selector 返回某个复用功能的名称。核心通过调用此函数来确定应将某个设备映射到哪个复用设置。
  • get_function_groups: 根据功能选择器 selector 返回与该复用功能相关的引脚组名称数组,并通过 groupsnum_groups 返回受影响的组及其数量。可以与 pinctrl_ops 中的函数结合使用以获取受影响的引脚。
  • set_mux: 启用特定的复用功能与引脚组关联。该函数根据 func_selector 选择特定的复用功能,并根据 group_selector 选择一组引脚进行复用设置。驱动程序不需要检测复用冲突,系统会自动处理引脚冲突。
  • gpio_request_enable: 请求并启用某个引脚的 GPIO 模式。如果引脚控制器支持每个引脚单独复用为 GPIO 模式,则需要实现此函数。参数包括 GPIO 范围和在该范围内的引脚偏移量。
  • gpio_disable_free: 释放之前启用的 GPIO 复用设置,与 gpio_request_enable 作用相反。
  • gpio_set_direction: 对于需要引脚复用的 GPIO 控制器,当 GPIO 配置为输入或输出时可能需要不同的设置。该函数允许控制引脚方向(输入或输出)。
  • strict: 如果为真,则不允许引脚同时作为 GPIO 和复用其他功能使用。在批准引脚请求之前,会严格检查 gpio_ownermux_owner 以防止冲突。

pinmux_ops 提供了驱动与引脚复用子系统之间的交互接口,用于管理引脚复用、GPIO 配置、引脚组和功能的分配。

3. 作用3:引脚配置 pinconf_ops

img

上拉?下拉?等等

\Linux-4.9.88\include\linux\pinctrl\pinconf.h
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONFbool is_generic;
#endifint (*pin_config_get) (struct pinctrl_dev *pctldev,unsigned pin,unsigned long *config);int (*pin_config_set) (struct pinctrl_dev *pctldev,unsigned pin,unsigned long *configs,unsigned num_configs);int (*pin_config_group_get) (struct pinctrl_dev *pctldev,unsigned selector,unsigned long *config);int (*pin_config_group_set) (struct pinctrl_dev *pctldev,unsigned selector,unsigned long *configs,unsigned num_configs);int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,const char *arg,unsigned long *config);void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned offset);void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned selector);void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned long config);
};

struct pinconf_ops 结构体定义了引脚配置操作,用于支持引脚配置功能的驱动程序实现。它包含一系列函数指针,这些函数用于获取和设置单个引脚及引脚组的配置。

  • is_generic: (可选)如果引脚控制器希望使用通用接口,设置该标志以告诉框架其为通用接口。
  • pin_config_get: 获取特定引脚的配置。如果请求的配置在该控制器上不可用,返回 -ENOTSUPP;如果可用但被禁用,返回 -EINVAL
  • pin_config_set: 配置单个引脚的设置。该函数接受引脚的配置参数和数量,允许驱动程序在特定引脚上设置多个配置。
  • pin_config_group_get: 获取特定引脚组的配置。该函数通过选择器返回整个引脚组的配置,便于一次性读取多个引脚的设置。
  • pin_config_group_set: 配置引脚组内所有引脚的设置。与 pin_config_set 类似,但作用于整个引脚组。
  • pin_config_dbg_parse_modify: (可选)用于调试文件系统的功能,允许修改引脚配置。
  • pin_config_dbg_show: (可选)调试文件系统中的显示钩子,提供特定引脚的设备信息。
  • pin_config_group_dbg_show: (可选)调试文件系统中的显示钩子,提供特定引脚组的设备信息。
  • pin_config_config_dbg_show: (可选)调试文件系统中的显示钩子,解码并显示驱动程序的引脚配置参数。

4. 使用pinctrl_desc注册得到pinctrl_dev

分析的文件:

  • drivers\pinctrl\freescale\pinctrl-imx6ul.c📎pinctrl-imx6ul.c
  • pincontroller的驱动程序文件 。pinctrl-imx.c 文件是 Linux 内核中针对 NXP(之前是 Freescale)i.MX 系列 SoC(系统芯片)的引脚控制器驱动程序实现。这驱动程序通常用于管理和配置 SoC 中的引脚,允许用户和其他系统组件以灵活的方式控制引脚的功能和行为。是一个更通用的驱动,支持多个 i.MX 系列的 SoC。提供了一些基础的、通用的功能或结构,其中关键的是imx_pinctrl_probe函数

imx_pinctrl_probe内部调用了核心层(core.c📎core.c)devm_pinctrl_register(里面又调用了pinctrl_register),就可以根据pinctrl_desc构造出pinctrl_dev,并且把pinctrl_dev放入链表:

\Linux-4.9.88\drivers\pinctrl\freescale\pinctrl-imx.c:
int imx_pinctrl_probe(struct platform_device *pdev,struct imx_pinctrl_soc_info *info)
{struct regmap_config config = { .name = "gpr" }; // 定义寄存器映射配置结构体struct device_node *dev_np = pdev->dev.of_node; // 获取设备的设备树节点struct pinctrl_desc *imx_pinctrl_desc; // 指向 pinctrl 描述符的指针struct device_node *np; // 设备树节点指针struct imx_pinctrl *ipctl; // 指向 i.MX pinctrl 结构的指针struct resource *res; // 资源结构体指针struct regmap *gpr; // 指向寄存器映射的指针int ret, i; // 返回值和循环变量// 检查传入的 pinctrl 信息是否有效if (!info || !info->pins || !info->npins) {dev_err(&pdev->dev, "wrong pinctrl info\n"); // 打印错误信息return -EINVAL; // 返回无效参数错误}info->dev = &pdev->dev; // 将设备指针赋值给 info 结构体// 检查是否有与 GPR 兼容的设备if (info->gpr_compatible) {gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible); // 查找寄存器映射if (!IS_ERR(gpr)) // 如果没有错误regmap_attach_dev(&pdev->dev, gpr, &config); // 绑定寄存器映射到设备}/* 为此驱动程序创建状态持有者等 */ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); // 分配内存用于 ipctl 结构if (!ipctl) // 检查内存分配是否成功return -ENOMEM; // 返回内存不足错误// 检查是否需要使用 SCU(系统控制单元)if (!(info->flags & IMX8_USE_SCU)) {// 为每个引脚分配内存以存储寄存器地址info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *info->npins, GFP_KERNEL);if (!info->pin_regs) // 检查内存分配是否成功return -ENOMEM; // 返回内存不足错误// 初始化每个引脚的寄存器for (i = 0; i < info->npins; i++) {info->pin_regs[i].mux_reg = -1; // 默认多路复用寄存器未定义info->pin_regs[i].conf_reg = -1; // 默认配置寄存器未定义}// 获取平台设备的内存资源res = platform_get_resource(pdev, IORESOURCE_MEM, 0);ipctl->base = devm_ioremap_resource(&pdev->dev, res); // 映射资源到虚拟地址if (IS_ERR(ipctl->base)) // 检查映射是否成功return PTR_ERR(ipctl->base); // 返回映射错误// 检查设备树中是否定义了 "fsl,input-sel" 属性if (of_property_read_bool(dev_np, "fsl,input-sel")) {np = of_parse_phandle(dev_np, "fsl,input-sel", 0); // 解析设备树句柄if (!np) {dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n"); // 打印错误信息return -EINVAL; // 返回无效参数错误}ipctl->input_sel_base = of_iomap(np, 0); // 映射输入选择基地址of_node_put(np); // 释放设备树节点引用if (!ipctl->input_sel_base) {dev_err(&pdev->dev,"iomuxc input select base address not found\n"); // 打印错误信息return -ENOMEM; // 返回内存不足错误}}}// 分配内存用于 pinctrl 描述符imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),GFP_KERNEL);if (!imx_pinctrl_desc) // 检查内存分配是否成功return -ENOMEM; // 返回内存不足错误// 填充 pinctrl 描述符结构体imx_pinctrl_desc->name = dev_name(&pdev->dev); // 设置 pinctrl 名称imx_pinctrl_desc->pins = info->pins; // 设置引脚描述符imx_pinctrl_desc->npins = info->npins; // 设置引脚数量imx_pinctrl_desc->pctlops = &imx_pctrl_ops; // 设置 pinctrl 操作imx_pinctrl_desc->pmxops = &imx_pmx_ops; // 设置 pinmux 操作imx_pinctrl_desc->confops = &imx_pinconf_ops; // 设置 pinconf 操作imx_pinctrl_desc->owner = THIS_MODULE; // 设置模块拥有者// 调用设备树解析函数ret = imx_pinctrl_probe_dt(pdev, info);if (ret) {dev_err(&pdev->dev, "fail to probe dt properties\n"); // 打印错误信息return ret; // 返回错误}// 设置 ipctl 结构中的信息ipctl->info = info;ipctl->dev = info->dev;platform_set_drvdata(pdev, ipctl); // 将 ipctl 数据绑定到平台设备// 注册 pinctrl 设备ipctl->pctl = devm_pinctrl_register(&pdev->dev,imx_pinctrl_desc, ipctl);if (IS_ERR(ipctl->pctl)) {dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); // 打印错误信息return PTR_ERR(ipctl->pctl); // 返回注册错误}dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); // 打印初始化成功信息return 0; // 返回成功
}

可以看到,在其probe函数中主要是去配置pinctrl_desc,然后调用devm_pinctrl_register去构建pinctrl_dev

\Linux-4.9.88\drivers\pinctrl\core.c:
struct pinctrl_dev *devm_pinctrl_register(struct device *dev,struct pinctrl_desc *pctldesc,void *driver_data)
{struct pinctrl_dev **ptr, *pctldev; // 定义指向 pinctrl_dev 的指针// 为资源管理分配内存,大小是指针大小,使用 devm (device managed) 内存管理机制ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) // 检查内存分配是否成功return ERR_PTR(-ENOMEM); // 如果分配失败,返回内存不足错误// 调用 `pinctrl_register()` 注册 pinctrl 控制器pctldev = pinctrl_register(pctldesc, dev, driver_data);if (IS_ERR(pctldev)) { // 检查注册是否成功devres_free(ptr); // 如果注册失败,释放分配的资源return pctldev; // 返回错误指针}// 将注册的 pinctrl_dev 设备保存在资源管理指针中*ptr = pctldev;devres_add(dev, ptr); // 将该资源与设备关联,确保设备卸载时自动释放资源return pctldev; // 返回成功注册的 pinctrl_dev 设备
}

先是分配pinctrl_dev,然后调用pinctrl_register()函数去注册pinctl控制器,来指代一个pincontroller, 核心工作是为设备分配并初始化 pinctrl_dev 结构体,并将其注册到 pin control 子系统中。它通过操作检查确保实现的功能完整,处理 pin 的注册和状态设置

/*** pinctrl_register() - 注册一个 pin 控制器设备* @pctldesc: 描述 pin 控制器的结构体* @dev: 父设备* @driver_data: 驱动程序的私有数据*/
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,struct device *dev, void *driver_data)
{struct pinctrl_dev *pctldev; // 定义 pin 控制器设备结构体指针int ret; // 用于保存函数返回值的变量// 检查输入参数的有效性,如果描述符为空或描述符的名字为空,返回错误指针if (!pctldesc)return ERR_PTR(-EINVAL);if (!pctldesc->name)return ERR_PTR(-EINVAL);// 分配内存为 pin 控制器设备结构体,并初始化为 0pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);if (pctldev == NULL) {dev_err(dev, "failed to alloc struct pinctrl_dev\n"); // 输出分配失败的错误消息return ERR_PTR(-ENOMEM); // 返回内存不足的错误}// 初始化 pin 控制器设备结构体pctldev->owner = pctldesc->owner; // 赋值设备的所有者pctldev->desc = pctldesc; // 关联描述符pctldev->driver_data = driver_data; // 关联驱动私有数据INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); // 初始化 `pin_desc_tree` 为 radix 树,用于描述 pinINIT_LIST_HEAD(&pctldev->gpio_ranges); // 初始化 GPIO 范围的链表pctldev->dev = dev; // 关联设备结构mutex_init(&pctldev->mutex); // 初始化互斥锁// 核查核心操作接口的完整性,确保驱动实现了必要的功能ret = pinctrl_check_ops(pctldev);if (ret) {dev_err(dev, "pinctrl ops lacks necessary functions\n"); // 输出缺少必要操作的错误消息goto out_err; // 如果失败,跳转到错误处理}// 如果实现了 pinmux 操作,检查其操作的完整性if (pctldesc->pmxops) {ret = pinmux_check_ops(pctldev);if (ret)goto out_err;}// 如果实现了 pinconfig 操作,检查其操作的完整性if (pctldesc->confops) {ret = pinconf_check_ops(pctldev);if (ret)goto out_err;}// 注册所有的 pindev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); // 注册 pinsif (ret) {dev_err(dev, "error during pin registration\n"); // 输出 pin 注册失败的错误消息pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); // 如果失败,释放 pin 资源goto out_err; // 跳转到错误处理}// 加入到全局的 pin 控制器设备列表mutex_lock(&pinctrldev_list_mutex);list_add_tail(&pctldev->node, &pinctrldev_list); // 将设备添加到设备列表的尾部mutex_unlock(&pinctrldev_list_mutex);// 获取 pinctrl 句柄pctldev->p = pinctrl_get(pctldev->dev);// 尝试查找并选择设备的默认和睡眠状态if (!IS_ERR(pctldev->p)) {// 查找并选择默认状态pctldev->hog_default = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);if (IS_ERR(pctldev->hog_default)) {dev_dbg(dev, "failed to lookup the default state\n");} else {if (pinctrl_select_state(pctldev->p, pctldev->hog_default))dev_err(dev, "failed to select default state\n");}// 查找睡眠状态pctldev->hog_sleep = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_SLEEP);if (IS_ERR(pctldev->hog_sleep))dev_dbg(dev, "failed to lookup the sleep state\n");}// 初始化 debugfs 调试文件系统pinctrl_init_device_debugfs(pctldev);return pctldev; // 返回注册成功的 pin 控制器设备结构体指针out_err:mutex_destroy(&pctldev->mutex); // 销毁互斥锁kfree(pctldev); // 释放设备结构体内存return ERR_PTR(ret); // 返回错误指针
}
  • 在drivers\pinctrl\freescale\pinctrl-imx6ul.c📎pinctrl-imx6ul.c中注册了平台驱动后,其 probe 先通过设备树匹配找到对应的 pinctrl_info,然后传递给通用的 pinctrl-imx.cprobe 函数。这确保了驱动能够正确识别和初始化针对特定硬件的引脚配置。 所以pinctrl-im6ull.c是通用的。
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{const struct of_device_id *match;struct imx_pinctrl_soc_info *pinctrl_info;match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);if (!match)return -ENODEV;pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;return imx_pinctrl_probe(pdev, pinctrl_info); //这里就是上文中pinctrl-imx.c中定义的
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单的kafkaredis学习之redis

简单的kafka&redis学习之redis 2. Redis 2.1 什么是Redis Redis是一种面向 “Key-Value” 数据类型的内存数据库&#xff0c;可以满足我们对海量数据的快速读写需求&#xff0c;Redis是一个 NoSQL 数据库&#xff0c;NoSQL的全称是not only sql&#xff0c;不仅仅是SQL&…

Java 输入与输出(I\O)之对象流与对象序列化

什么是Java的对象流&#xff1f; Java对象流是用于存储和读取基本数据类型数据或对象数据的输入输出流。 Java的对象流可分为两种&#xff1a; 1&#xff0c;对象输入流类ObjectInputStream 用于从数据源读取对象数据&#xff0c;它是可以读取基本数据类型数据或对象数据的输…

GitHub 上传项目保姆级教程

构建项目仓库 登录 GitHub 并进入主页。点击右上角的 New 按钮&#xff0c;进入创建新仓库页面。输入仓库名称和描述&#xff08;可选&#xff09;&#xff0c;选择是否公开&#xff08;Public&#xff09;或私有&#xff08;Private&#xff09;。可以选择是否初始化仓库&…

计算机网络:网络层 —— 路由选择与静态路由配置

文章目录 路由选择路由选择的基本概念路由选择算法路由选择策略 路由器的工作原理路由表静态路由配置默认路由特定主机路由 路由选择 路由选择&#xff08;Routing&#xff09;是网络层的一个关键功能&#xff0c;负责在源和目的地之间选择最佳路径&#xff0c;以确保数据包高…

Pytest-Bdd-Playwright 系列教程(5):仅执行测试用例的收集阶段

Pytest-Bdd-Playwright 系列教程&#xff08;5&#xff09;&#xff1a;仅执行测试用例的收集阶段 一、为什么需要仅收集测试用例二、应用场景三、方法详解【方法1】&#xff1a;添加pytest.ini文件的addopts配置项【方法2】&#xff1a;通过命令行参数运行 四、CI/CD 环境下的…

联想笔记本电脑睡眠后打开黑屏解决方法

下载联想机器睡眠无法唤醒修复工具 下载地址&#xff1a;https://tools.lenovo.com.cn/exeTools/detail/id/233/rid/6182522.html 使用完后重启电脑&#xff0c;问题解决。

(11)(2.1.6) Hobbywing DroneCAN ESC(一)

文章目录 前言 1 连接和配置 2 参数说明 前言 具有 CAN 接口&#xff08;including these&#xff09;的业余 ESC 支持 DroneCAN&#xff0c;它允许自动驾驶仪通过 CAN 控制 ESC /电机&#xff0c;并检索单个转速、电压、电流和温度。 具有 CAN 接口&#xff08;including …

AI助力医疗:未来的医生会是机器人吗?

内容概要 在这一场医疗科技的新浪潮中&#xff0c;AI医疗正以前所未有的速度渗透到各个角落。随着技术的飞速进步&#xff0c;人工智能成为了推动医疗领域革新的重要力量。从精准诊断到个性化治疗&#xff0c;AI正在帮助医生们更快速、准确地分析患者的病情&#xff0c;提高了…

HTMLCSS:3D旋转动画机器人摄像头

效果演示 创建了一个3D机器人摄像头效果。 HTML <div class"modelViewPort"><div class"eva"><div class"head"><div class"eyeChamber"><div class"eye"></div><div class&quo…

大型商场应急响应系统开发:SpringBoot篇

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

记录一次查询优化

一.背景描述 1.1问题和情况 生产环境&#xff0c;有一张按每天一份数据的表&#xff08;下面简称表1&#xff09;&#xff0c;跨天查询较慢&#xff0c;跨月查询甚至超时查询一天内的数据速度不怎么慢查询是分页的表1按照日期做了子分区&#xff0c;一个月一个子分区 1.2造成…

头歌C语言数据结构课程实验(栈的应用)

第1关&#xff1a;利用栈实现整数的十进制转八进制 本关必读 栈是基础的数据结构&#xff0c;元素操作遵循后进先出的原理。本关卡基于数组存储实现了栈的基本操作。 该方案将栈存储在一片连续空间里&#xff0c;并通过data、top和max三个属性元素。组织成为一个结构&#xf…

Java | Leetcode Java题解之第521题最长特殊序列I

题目&#xff1a; 题解&#xff1a; class Solution {public int findLUSlength(String a, String b) {return !a.equals(b) ? Math.max(a.length(), b.length()) : -1;} }

《使用Gin框架构建分布式应用》阅读笔记:p212-p233

《用Gin框架构建分布式应用》学习第12天&#xff0c;p212-p233总结&#xff0c;总22页。 一、技术总结 1.JavaScript知识点 (1)class、method (2)function, arrow function, (3)fetch() (4)Promise, then() 2.bootstrap 第5章主要涉及前端技术的运用&#xff0c;作为后…

NVR录像机汇聚管理EasyNVR多个NVR同时管理融合汇聚管理系统

流媒体视频融合与汇聚管理系统能够实现对各类模块化服务的统一管理和配置&#xff0c;整合、管理和共享应用服务&#xff0c;并通过标准接口为业务平台和其他第三方平台提供便捷的数据调用功能。为确保该系统的成功实施和稳定运行&#xff0c;在建设方案中除了考虑基础的架构设…

服务器的免密登录和文件传输

在天文学研究中&#xff0c;通常会采用ssh登录服务器&#xff0c;把复杂的计算交给服务器&#xff0c;但是如果你没有进行额外的配置&#xff0c;那么登录服务器&#xff0c;以及和服务器进行文件传输&#xff0c;每次都要输入账号和密码&#xff0c;比较不方便&#xff0c;Win…

【Nas】X-Doc:jellyfin“该客户端与媒体不兼容,服务器未发送兼容的媒体格式”问题解决方案

【Nas】X-Doc&#xff1a;jellyfin“该客户端与媒体不兼容&#xff0c;服务器未发送兼容的媒体格式”问题解决方案 当使用Jellyfin播放视频时出现“该客户端与媒体不兼容&#xff0c;服务器未发送兼容的媒体格式”&#xff0c;这是与硬件解码和ffmpeg设置有关系&#xff0c;具体…

沪深A股上市公司数据报告分析

数据分析报 目录 数据分析报告 1.引言 1.1 背景介绍 1.2 报告目的 1.3 报告范围 1.4 关键术语定义 2. 数据收集与预处理 2.1 数据来源概述 2.2 数据收集过程 2.3 数据预处理步骤 3. 数据可视化 3.1分析地区对公司数量的影响 3.2分析行业分类是否影响公…

Mysql当中的各种log

一、MySQL日志文件类型 重做日志&#xff08;redo log&#xff09;回滚日志&#xff08;undo log&#xff09;二进制日志&#xff08;binlog&#xff09;错误日志&#xff08;errorlog&#xff09;慢查询日志&#xff08;slow query log&#xff09;一般查询日志&#xff08;g…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-29

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-29 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-29目录1. Does your LLM truly unlearn? An embarrassingly simple approach to recover unlearned knowledge摘要研究背景问题…