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

pinctrl子系统学习笔记

一、背景

cpu的gpio引脚可以复用成多个功能,如可以配置成I2C或者普通GPIO模式。配置方式一般是通过写引脚复用的配置寄存器,但是不同芯片厂商配置寄存器格式内容各不相同,设置引脚复用无法做到通用且自由的配置,只能在启动初始化时候在soc驱动初始化时对每个引脚配置好。 linux 3.0之后内核中抽象出了pinctrl子系统,每个soc注册设置引脚复用的方法以及将soc的每个引脚可选的复用功能。

二、pinctrl实现

2.1 API

# 用于soc向pinctrl系统中注册设置引脚复用方法以及设置引脚复用状态
# driver_data用于soc驱动私有数据,一般用来保存pin 引脚的可选复用功能列表。
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,struct device *dev, void *driver_data)# 设置引脚复用状态,用来设置引脚复用状态
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)# 用于具体设备驱动(i2c等)关联pinctrl节点,以及设置默认复用模式,设备树解析时调用
int pinctrl_bind_pins(struct device *dev)

2.2 数据结构

数据结构关系图:

在这里插入图片描述

这里主要有几个对象:

  1. pin_group 和function : 引脚复用一般是多个引脚组成一个group,一起设置复用状态的。多个引脚复用为某个功能,成为function。
  1. pin_conf :设置引脚的上下拉电阻等电气参数
  2. pin_mux:设置引脚复用

pinctrl_desc

核心数据结构是pinctrl_desc,pinctrl的全局描述。

struct pinctrl_desc {const char *name;/*系统种有多少个pinctrl*/const struct pinctrl_pin_desc *pins;unsigned int npins;/*引脚控制的操作集,不同芯片方案不同*/const struct pinctrl_ops *pctlops;const struct pinmux_ops *pmxops;const struct pinconf_ops *confops;struct module *owner;
};

pinctrl_pin_desc

描述系统中的所有引脚,drv_data保存驱动私有数据。

struct pinctrl_pin_desc {unsigned number;const char *name;void *drv_data;
};

pinctrl_ops

回调函数,获取pin group的操作,以及解析dts。

struct pinctrl_ops {/*获取系统中有多少个pin groups*/int (*get_groups_count) (struct pinctrl_dev *pctldev);/*获取指定group(由索引selector指定)的名称,由select确认*/const char *(*get_group_name) (struct pinctrl_dev *pctldev,unsigned selector);/*获取指定group的所用pin信息*/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);/*将对应驱动转换成pin map*/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);
};

pinconf_ops

配置管脚状态:pinctrl也提供管脚状态如(上下拉、开漏等)的接口。

struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONFbool is_generic;
#endif/*获取pin脚的当前状态*/int (*pin_config_get) (struct pinctrl_dev *pctldev,unsigned pin,unsigned long *config);/*设置pin脚状态*/int (*pin_config_set) (struct pinctrl_dev *pctldev,unsigned pin,unsigned long *configs,unsigned num_configs);/*获取或者设置指定pin group的配置项*/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);
};

pinmux_ops

设置或获取引脚复用情况,对应硬件是iomux。设置某个pin为某个function,通过set_mux设置function selecter。 一个group设置复用状态。

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);/*将指定的pin group(group_selector)设置为指定的function(func_selector)*/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;
};

pinctrl_map

pinctrl_map 某个gpio具体的引脚配置和复用状态,由dts中定义,dt_node_to_map函数解析,和具体设备驱动关联。

struct pinctrl_map {//device的名称const char *dev_name;//pin state的名称const char *name;//该map的类型enum pinctrl_map_type type;//pin controller device的名字const char *ctrl_dev_name;union {struct pinctrl_map_mux mux;struct pinctrl_map_configs configs;} data;
};enum pinctrl_map_type {PIN_MAP_TYPE_INVALID,//不需要任何配置,仅仅为了表示state的存在PIN_MAP_TYPE_DUMMY_STATE,//配置管脚复用PIN_MAP_TYPE_MUX_GROUP,//配置pinPIN_MAP_TYPE_CONFIGS_PIN,//配置pin groupPIN_MAP_TYPE_CONFIGS_GROUP,
};struct pinctrl_map_mux {//group的名字const char *group;//function的名字const char *function;
};struct pinctrl_map_configs {//该pin或者pin group的名字const char *group_or_pin;//configuration数组unsigned long *configs;//配置项的个数unsigned num_configs;
};

三、实现流程

linux6.1.11为例,pinctrl系统融入内核设备树解析以及内核设备驱动模型中支持。以zynq为例从dts配置解析入手,了解pinctrl的工作原理。dts中主要关注:

1)pinctrl 子系统:描述系统多少引脚,每个引脚有多少复用情况。

2)I2C、GPIO、SPI等driver默认配置的pinctrl复用设置

《zynq-7000.dtsi》中,如列出i2C和uart的复用配置,其中只是选择了i2c0_10_grp这个pin_group,并且配置为i2c0的复用功能,具体引脚的引脚号等信息是在代码中定义的。

mux 和 conf的作用?

pinctrl0: pinctrl@700 {compatible = "xlnx,pinctrl-zynq";reg = <0x700 0x200>;syscon = <&slcr>;/*设置引脚的复用状态*/pinctrl_i2c0_default: i2c0-default {mux {/*pin_group*/groups = "i2c0_10_grp";/*复用功能为i2c0*/function = "i2c0";};conf {groups = "i2c0_10_grp";bias-pull-up; #上拉电阻slew-rate = <0>; #引脚转换速率io-standard = <1>;};};pinctrl_uart1_default: uart1-default {mux {groups = "uart1_10_grp";function = "uart1";};conf {groups = "uart1_10_grp";slew-rate = <0>;io-standard = <1>;};conf-rx {pins = "MIO49";bias-high-impedance;};conf-tx {pins = "MIO48";bias-disable;};};}
  1. 其他驱动如何关联pinctrl以及配置默认引脚复用?

对应驱动中的dts新增如下两个属性,在设备驱动device关联driver时,会解析如下字段,关联pinctrl驱动,并设置引脚复用状态,这里是选择pinctrl_i2c0_default。

&i2c0 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c0_default>;

3.1 驱动注册

《linux-6.1.11\drivers\pinctrl\pinctrl-zynq.c》

构造一个pinctrl_desc结构,然后注册到pinctrl系统中。

static struct pinctrl_desc zynq_desc = {.name = "zynq_pinctrl",.pins = zynq_pins,.npins = ARRAY_SIZE(zynq_pins),.pctlops = &zynq_pctrl_ops,.pmxops = &zynq_pinmux_ops,.confops = &zynq_pinconf_ops,.num_custom_params = ARRAY_SIZE(zynq_dt_params),.custom_params = zynq_dt_params,
#ifdef CONFIG_DEBUG_FS.custom_conf_items = zynq_conf_items,
#endif.owner = THIS_MODULE,
};static int zynq_pinctrl_probe(struct platform_device *pdev){pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &zynq_desc, pctrl);
}

pin引脚定义:

/*定义系统中引脚*/
static const struct pinctrl_pin_desc zynq_pins[] = {PINCTRL_PIN(0,  "MIO0"),PINCTRL_PIN(1,  "MIO1"),...
}/*引脚可选复用功能*/
enum zynq_pinmux_functions {ZYNQ_PMUX_can0,ZYNQ_PMUX_can1,ZYNQ_PMUX_ethernet0,ZYNQ_PMUX_ethernet1,
}/* pin groups 组,每个引脚功能对应的pin脚定义*/
static const unsigned int ethernet0_0_pins[] = {16, 17, 18, 19, 20, 21, 22, 23,24, 25, 26, 27};
static const unsigned int ethernet1_0_pins[] = {28, 29, 30, 31, 32, 33, 34, 35,36, 37, 38, 39};
static const unsigned int mdio0_0_pins[] = {52, 53};
static const unsigned int mdio1_0_pins[] = {52, 53};/*zynq维护的私有数据结构pin_group组信息,关联上述pin脚*/
static const struct zynq_pctrl_group zynq_pctrl_groups[] = {DEFINE_ZYNQ_PINCTRL_GRP(ethernet0_0),DEFINE_ZYNQ_PINCTRL_GRP(ethernet1_0),DEFINE_ZYNQ_PINCTRL_GRP(mdio0_0),DEFINE_ZYNQ_PINCTRL_GRP(mdio1_0),DEFINE_ZYNQ_PINCTRL_GRP(qspi0_0),DEFINE_ZYNQ_PINCTRL_GRP(qspi1_0),DEFINE_ZYNQ_PINCTRL_GRP(qspi_fbclk),DEFINE_ZYNQ_PINCTRL_GRP(qspi_cs1),DEFINE_ZYNQ_PINCTRL_GRP(spi0_0),
}

对应的ops实现这里不展开,具体写寄存器信息。

3.2 具体驱动关联pinctrl

具体i2c、spi等驱动初始化时如何设置引脚复用情况? dts中定义i2c选择pinctrl_i2c0_default的引脚复用。 pinctrl-names用于表示pinctrl_state,有init、default,init是在驱动初始化的状态,default是默认状态。 pinctrl-0 选择复用情况,这两个属性是pinctrl的标准属性,设备树解析框架中实现,在设备驱动匹配时关联。

&i2c0 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c0_default>;

时机:设备驱动匹配时关联,以及设置默认复用状态

关键函数:pinctrl_bind_pins

《linux-6.1.11\drivers\base\dd.c》

__driver_probe_device -> really_probe -> pinctrl_bind_pins
  • 解析dts,关联pinctrl_map

调用pinconf_generic_dt_node_to_map_all解析dts。关联pinctrl_i2c0_default的pinctrl_map。

pinctrl_bind_pins -> create_pinctrl -> pinctrl_dt_to_map -> pinconf_generic_dt_node_to_map_all 
  • 设置引脚复用
pinctrl_bind_pins -> pinctrl_select_state (选择default state) -> pinctrl_commit_state-> pinmux_disable_setting  (禁用旧的复用)-> pinmux_enable_setting  (设置新复用)-> pinconf_apply_setting  (设置引脚状态)
/*** pinctrl_bind_pins() - called by the device core before probe* @dev: the device that is just about to probe*/
int pinctrl_bind_pins(struct device *dev)
{int ret;if (dev->of_node_reused)return 0;dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);if (!dev->pins)return -ENOMEM;dev->pins->p = devm_pinctrl_get(dev);if (IS_ERR(dev->pins->p)) {dev_dbg(dev, "no pinctrl handle\n");ret = PTR_ERR(dev->pins->p);goto cleanup_alloc;}dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);if (IS_ERR(dev->pins->default_state)) {dev_dbg(dev, "no default pinctrl state\n");ret = 0;goto cleanup_get;}dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_INIT);if (IS_ERR(dev->pins->init_state)) {/* Not supplying this state is perfectly legal */dev_dbg(dev, "no init pinctrl state\n");ret = pinctrl_select_state(dev->pins->p,dev->pins->default_state);} else {ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);}if (ret) {dev_dbg(dev, "failed to activate initial pinctrl state\n");goto cleanup_get;}#ifdef CONFIG_PM/** If power management is enabled, we also look for the optional* sleep and idle pin states, with semantics as defined in* <linux/pinctrl/pinctrl-state.h>*/dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_SLEEP);if (IS_ERR(dev->pins->sleep_state))/* Not supplying this state is perfectly legal */dev_dbg(dev, "no sleep pinctrl state\n");dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_IDLE);if (IS_ERR(dev->pins->idle_state))/* Not supplying this state is perfectly legal */dev_dbg(dev, "no idle pinctrl state\n");
#endifreturn 0;/** If no pinctrl handle or default state was found for this device,* let's explicitly free the pin container in the device, there is* no point in keeping it around.*/
cleanup_get:devm_pinctrl_put(dev->pins->p);
cleanup_alloc:devm_kfree(dev, dev->pins);dev->pins = NULL;/* Return deferrals */if (ret == -EPROBE_DEFER)return ret;/* Return serious errors */if (ret == -EINVAL)return ret;/* We ignore errors like -ENOENT meaning no pinctrl state */return 0;
}

在这里插入图片描述

相关文章:

pinctrl子系统学习笔记

一、背景 cpu的gpio引脚可以复用成多个功能&#xff0c;如可以配置成I2C或者普通GPIO模式。配置方式一般是通过写引脚复用的配置寄存器&#xff0c;但是不同芯片厂商配置寄存器格式内容各不相同&#xff0c;设置引脚复用无法做到通用且自由的配置&#xff0c;只能在启动初始化…...

使用vue-element 的计数器inputNumber,传第三个参数

使用vue-element 的计数器inputNumber。 其中的change 事件中&#xff0c;默认自带两个参数&#xff0c;currentValue和oldValue&#xff0c;分别代表改变后的数和改变前的数&#xff0c; 如果想要传第三个参数&#xff0c; change"(currentValue, oldValue) > numCha…...

如何从0构建一个flask项目,直接上实操!!!

项目结构 首先&#xff0c;创建一个项目目录&#xff0c;结构如下&#xff1a; flask_app/ │ ├── app.py # Flask 应用代码 ├── static/ # 存放静态文件&#xff08;如CSS、JS、图片等&#xff09; │ └── style.css # 示例…...

Mongoose连接数据库操作实践

文章目录 介绍特点&#xff1a;Mongoose 使用&#xff1a;创建项目并安装&#xff1a;连接到 MongoDB&#xff1a;定义 Schema&#xff1a;创建模型并操作数据库&#xff1a;创建文档&#xff1a;查询文档&#xff1a;更新文档&#xff1a;删除文档&#xff1a;使用钩子&#x…...

centos 7.9 freeswitch1.10.9环境搭建

亲测版本centos 7.9系统–》 freeswitch1.10.9 一、下载插件 yum install -y git alsa-lib-devel autoconf automake bison broadvoice-devel bzip2 curl-devel libdb4-devel e2fsprogs-devel erlang flite-devel g722_1-devel gcc-c++ gdbm-devel gnutls-devel ilbc2...

Gitlab服务管理和仓库项目权限管理

Gitlab服务管理 gitlab-ctl start # 启动所有 gitlab 组件&#xff1b; gitlab-ctl stop # 停止所有 gitlab 组件&#xff1b; gitlab-ctl restart # 重启所有 gitlab 组件&#xff1b; gitlab-ctl status …...

LLMs之Llama-3:Llama-3.3的简介、安装和使用方法、案例应用之详细攻略

LLMs之Llama-3&#xff1a;Llama-3.3的简介、安装和使用方法、案例应用之详细攻略 目录 相关文章 LLMs之LLaMA&#xff1a;LLaMA的简介、安装和使用方法、案例应用之详细攻略 LLMs之LLaMA-2&#xff1a;LLaMA 2的简介(技术细节)、安装、使用方法(开源-免费用于研究和商业用途…...

OpenCV函数及其应用

1. 梯度处理的Sobel算子函数 功能 Sobel算子是一种用于边缘检测的离散微分算子&#xff0c;它结合了高斯平滑和微分求导&#xff0c;用于计算图像亮度的空间梯度。 参数 src&#xff1a;输入图像。 dst&#xff1a;输出图像。 ddepth&#xff1a;输出图像的深度。 dx&#xff…...

vulnhub靶场【DriftingBlues】之3

前言 靶机&#xff1a;DriftingBlues-3&#xff0c;IP地址192.168.1.60 攻击&#xff1a;kali&#xff0c;IP地址192.168.1.16 都采用虚拟机&#xff0c;网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24 信息收集 使用nmap扫描端口 网站探测 访…...

文件上传—阿里云OSS对象存储

目录 一、OSS简介 二、OSS基本使用 1. 注册账号 2. 基本配置 (1) 开通OSS (2) 创建存储空间 (3) 修改权限 (4) 配置完成&#xff0c;上传一张图片&#xff0c;检验是否成功。 (5) 创建AccessKey 三、Java项目集成OSS 1. 导入依赖 2. Result.java代码&#xff1a; …...

mybatis-plus超详细讲解

mybatis-plus &#xff08;简化代码神器&#xff09; 地址&#xff1a;https://mp.baomidou.com/ 目录 mybatis-plus 简介 特性 支持数据库 参与贡献 快速指南 1、创建数据库 mybatis_plus 2、导入相关的依赖 3、创建对应的文件夹 4、编写配置文件 5、编写代码 …...

【Linux】--- 进程的概念

【Linux】--- 进程的概念 一、进程概念二、PCB1.什么是PCB2.什么是task_struct&#xff08;重点&#xff01;&#xff09;3.task_struct包含内容 三、task_struct内容详解1.查看进程&#xff08;1&#xff09;通过系统目录查看&#xff08;2&#xff09;通过ps命令查看&#xf…...

Unity NTPComponent应用, 实现一个无后端高效获取网络时间的组件

无后端高效获取网络时间的组件 废话不多说&#xff0c;直接上源码m_NowSerivceTime 一个基于你发行游戏地区的时间偏移&#xff0c; 比如北京时区就是 8, 巴西就是-3&#xff0c;美国就是-5using Newtonsoft.Json; 如果这里报错&#xff0c; 就说明项目没有 NewtonsoftJson插件…...

go语言使用zlib压缩[]byte

在Go语言中&#xff0c;可以使用compress/flate和compress/zlib包来实现对[]byte数据的Zlib压缩。下面是一个简单的示例&#xff0c;展示如何使用这些包来压缩一个字节切片&#xff1a; go package main import ( "bytes" "compress/zlib" "fmt"…...

Windows 配置 Tomcat环境

Windows配置Tomcat 1. 介绍 Tomcat是一个开源的、轻量级的Java应用服务器&#xff0c;在Java Web开发领域应用广泛。以下是关于它的详细介绍&#xff1a; 一、基本概念与背景 定义&#xff1a;Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;下…...

【python从入门到精通】-- 第六战:列表和元组

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…...

Python | 数据可视化中常见的4种标注及示例

在Python的数据可视化中&#xff0c;标注&#xff08;Annotation&#xff09;技术是一种非常有用的工具&#xff0c;它可以帮助用户更准确地解释图表中的数据和模式。在本文中&#xff0c;将带您了解使用Python实现数据可视化时应该了解的4种标注。 常见的标注方式 文本标注箭…...

LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)

完整代码见&#xff1a;zaizai77/Cherno-OpenGL: OpenGL 小白学习之路 高级GLSL 内建变量 顶点着色器 gl_PointSoze : float 输出变量&#xff0c;用于控制渲染 GL_POINTS 型图元时&#xff0c;点的大小。可用于粒子系统。将其设置为 gl_Position.z 时&#xff0c;可以使点…...

Scala学习记录

dao --------> 数据访问 mode ------> 模型 service ---->业务逻辑 Main -------> UI:用户直接操作&#xff0c;调用Service 改造UI层&#xff1a;...

vue使用pdfh5.js插件,显示pdf文件白屏

pdfh5&#xff0c;展示文件白屏&#xff0c;无报错 实现效果图解决方法(降版本)排查问题过程发现问题查找问题根源1、代码写错了&#xff1f;2、预览文件流的问题&#xff1f;3、pdfh5插件更新了&#xff0c;我的依赖包没更新&#xff1f;4、真相大白 彩蛋 实现效果图 解决方法…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...