Linux clock子系统及驱动实例
文章目录
- 基本概念
- CLK子系统
- 时钟API的使用
- clock驱动实例
- 1、时钟树
- 2、设备树
- 3、驱动实现
- fixed_clk固定时钟实现
- factor_clk分频时钟实现
- gate_clk门控时钟实现
基本概念
晶振:晶源振荡器
PLL:Phase lock loop,锁相环。用于提升频率
OSC:oscillator的简写,振荡器
CLK子系统
Linux的时钟子系统由CCF(common clock framework)框架管理,CCF向上给用户提供了通用的时钟接口,向下给驱动开发者提供硬件操作的接口。各结构体关系如下:
CCF框架比较简单,只有这几个结构体。CCF框架分为了consumer、ccf和provider三部分。
consumer:
时钟的使用者,clock子系统向consumer的提供通用的时钟API接口,使其可以屏蔽底层硬件差异。提供给consumer操作的API如下:
struct clk *clk_get(struct device *dev, const char *id);
struct clk *devm_clk_get(struct device *dev, const char *id);
int clk_enable(struct clk *clk);//使能时钟,不会睡眠
void clk_disable(struct clk *clk);//使能时钟,不会睡眠
unsigned long clk_get_rate(struct clk *clk);
void clk_put(struct clk *clk);
long clk_round_rate(struct clk *clk, unsigned long rate);
int clk_set_rate(struct clk *clk, unsigned long rate);
int clk_set_parent(struct clk *clk, struct clk *parent);
struct clk *clk_get_parent(struct clk *clk);
int clk_prepare(struct clk *clk);
void clk_unprepare(struct clk *clk);
int clk_prepare_enable(struct clk *clk) //使能时钟,可能会睡眠
void clk_disable_unprepare(struct clk *clk) //禁止时钟,可能会睡眠
unsigned long clk_get_rate(struct clk *clk) //获取时钟频率
consumer在使用这些API时,必须先调用devm_clk_get()
或clk_get()
获取一个struct clk *
指针句柄,后续都通过传入该句柄来操作,struct clk相当于实例化一个时钟。
ccf:
clock子系统的核心,用一个struct clk_core
结构体表示,每个注册设备都对应一个struct clk_core
。
provider(时钟的提供者):
struct clk_hw
:表示一个具体的硬件时钟。
struct clk_init_data
:struct clk_hw结构体成员,用于表示该时钟下的初始化数据,如时钟名字name、操作函数ops等。
// include/linux/clk-provider.h
struct clk_hw{struct clk_core *core;struct clk *clk;const struct clk_init_data *init;
}struct clk_init_data{const char *name; //时钟名字const struct clk_ops *ops; //时钟硬件操作函数集合const char *const *parent_names; //父时钟名字const struct clk_parent_data *parent_data;const struct clk_hw **parent_hws;u8 num_parents;unsigned long flags;
}
struct clk_ops
:时钟硬件操作的函数集合,定义了操作硬件的回调函数,consumer在调用clk_set_rate()
等API时会调用到struct clk_ops
具体指向的函数,这个需要芯片厂商开发clock驱动时去实现。
//include/linux/clk-provider.hstruct clk_ops {int (*prepare)(struct clk_hw *hw);void (*unprepare)(struct clk_hw *hw);int (*is_prepared)(struct clk_hw *hw);void (*unprepare_unused)(struct clk_hw *hw);int (*enable)(struct clk_hw *hw);void (*disable)(struct clk_hw *hw);int (*is_enabled)(struct clk_hw *hw);void (*disable_unused)(struct clk_hw *hw);int (*save_context)(struct clk_hw *hw);void (*restore_context)(struct clk_hw *hw);unsigned long (*recalc_rate)(struct clk_hw *hw,unsigned long parent_rate);long (*round_rate)(struct clk_hw *hw, unsigned long rate,unsigned long *parent_rate);int (*determine_rate)(struct clk_hw *hw,struct clk_rate_request *req);int (*set_parent)(struct clk_hw *hw, u8 index);u8 (*get_parent)(struct clk_hw *hw);int (*set_rate)(struct clk_hw *hw, unsigned long rate,unsigned long parent_rate);int (*set_rate_and_parent)(struct clk_hw *hw,unsigned long rate,unsigned long parent_rate, u8 index);unsigned long (*recalc_accuracy)(struct clk_hw *hw,unsigned long parent_accuracy);int (*get_phase)(struct clk_hw *hw);int (*set_phase)(struct clk_hw *hw, int degrees);int (*get_duty_cycle)(struct clk_hw *hw,struct clk_duty *duty);int (*set_duty_cycle)(struct clk_hw *hw,struct clk_duty *duty);int (*init)(struct clk_hw *hw);void (*terminate)(struct clk_hw *hw);void (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
};
struct clk_ops中每个函数功能在include/linux/clk-provider.h
都有具体的说明,在开发clock驱动时,这些函数并不需要全部实现。下面列举几个最常用,也是经常需要实现的函数。
函数 | 说明 |
---|---|
recalc_rate | 通过查询硬件,重新计算此时钟的速率。可选,但建议——如果未设置此操作,则时钟速率初始化为0。 |
round_rate | 给定目标速率作为输入,返回时钟实际支持的最接近速率。 |
set_rate | 更改此时钟的速率。请求的速率由第二个参数指定,该参数通常应该是调用.round_rate返回。第三个参数给出了父速率,这对大多数.set_rate实现有帮助。成功返回0,否则返回-EERROR |
enable | 时钟enable |
disable | 时钟disable |
时钟API的使用
对于一般的驱动开发(非clock驱动),我们只需要在dts中配置时钟,然后在驱动调用通用的时钟API接口即可。
1、设备树中配置时钟
mmc0:mmc0@0x12345678{compatible = "xx,xx-mmc0";......clocks = <&peri PERI_MCI0>;//指定mmc0的时钟来自PERI_MCI0,PERI_MCI0的父时钟是periclocks-names = "mmc0"; //时钟名,调用devm_clk_get获取时钟时,可以传入该名字......};
以mmc的设备节点为例,上述mmc0指定了时钟来自PERI_MCI0,PERI_MCI0的父时钟是peri,并将所指定的时钟给它命名为"mmc0"。
2、驱动中使用API接口
简单的使用:
/* 1、获取时钟 */
host->clk = devm_clk_get(&pdev->dev, NULL); //或者devm_clk_get(&pdev->dev, "mmc0")if (IS_ERR(host->clk)) {dev_err(dev, "failed to find clock source\n");ret = PTR_ERR(host->clk);goto probe_out_free_dev;}/* 2、使能时钟 */
ret = clk_prepare_enable(host->clk);
if (ret) {dev_err(dev, "failed to enable clock source.\n");goto probe_out_free_dev;
}probe_out_free_dev:kfree(host);
在驱动中操作时钟,第一步需要获取struct clk指针句柄,后续都通过该指针进行操作,例如:
设置频率:
ret = clk_set_rate(host->clk, 300000);
获得频率:
ret = clk_get_rate(host->clk);
注意:devm_clk_get()的两个参数是二选一,可以都传入,也可以只传入一个参数。
像i2c、mmc等这些外设驱动,通常只需要使能门控即可,因为这些外设并不是时钟源,它们只有开关。如果直接调用clk_ser_rate函数设置频率,clk_set_rate会向上传递,即设置它的父时钟频率。例如在该例子中直接调用clk_set_rate函数,最终设置的是时钟源peri的频率。
clock驱动实例
clock驱动在时钟子系统中属于provider,provider是时钟的提供者,即具体的clock驱动。clock驱动在Linux刚启动的时候就要完成,比initcall
都要早期,因此clock驱动是在内核中进行实现。在内核的drivers/clk
目录下,可以看到各个芯片厂商对各自芯片clock驱动的实现:
下面以一个简单的时钟树,举例说明一个芯片的时钟驱动的大致实现过程:
1、时钟树
通常来说,一个芯片的时钟树是比较固定的,例如,以下时钟树:
时钟树的根节点一般是晶振时钟,上图根节点为24M晶振时钟。根节点下面是PLL,PLL用于提升频率。PPL0下又分频给PERI、DSP和ISP。PLL1分频给DDR和ENC。
对于PLL来说,PLL的频率可以通过寄存器设置,但通常是固定的,所以PLL属于固定时钟。
对PERI、DSP等模块来说,它们的频率来自于PLL的分频,因此这些模块的时钟属于分频时钟。
2、设备树
设备树中表示一个时钟源,应有如下属性,例如24Mosc:
clocks{osc24M:osc24M{compatible = "fixed-clock";#clock-cells = <0>;clock-output-name = "osc24M";clock-frequency = <24000000>;};
};
属性 | 说明 |
---|---|
compatible | 驱动匹配名字 |
#clock-cells | 提供输出时钟的路数。#clock-cells为0时,代表输出一路时钟 #clock-cells为1时,代表输出2路时钟。 |
#clock-output-names | 输出时钟的名字 |
#clock-frequency | 输出时钟的频率 |
3、驱动实现
clock驱动编写的基本步骤:
- 实现
struct clk_ops
相关成员函数 - 定义分配
struct clk_onecell_data
结构体,初始化相关数据 - 定义分配
struct clk_init_data
结构体,初始化相关数据 - 调用
clk_register
将时钟注册进框架 - 调用
clk_register_clkdev
注册时钟设备 - 调用
of_clk_add_provider
,将clk provider存放到of_clk_provider链表中管理 - 调用
CLK_OF_DECLARE
声明驱动
fixed_clk固定时钟实现
fixed_clk针对像PLL这种具有固定频率的时钟,对于PLL,我们只需要实现.recalc_rate
函数
设备树:
#define PLL0_CLK 0clocks{osc24M:osc24M{compatible = "fixed-clock";#clock-cells = <0>;clock-output-names = "osc24M";clock-frequency = <24000000>;};pll0:pll0{compatible = "xx, choogle-fixed-clk";#clock-cells = <0>;clock-id = <PLL0_CLK>;clock-frequency = <1000000000>;clock-output-names = "pll0";clocks = <&osc24M>;};
};
驱动:
#include <linux/clk-provier.h>
#include <linux/clkdev.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/delay.h>#define CLOCK_BASE 0X12340000
#define CLOCK_SIZE 0X1000struct xx_fixed_clk{void __iomem *reg;//保存映射后寄存器基址unsigned long fixed_rate;//频率int id;//clock idstruct clk_hw*;
};
static unsigned long xx_pll0_fixed_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{unsigned long recalc_rate;//硬件操作:查询寄存器,获得分频系数,计算频率然后返回return recalc_rate;
}static struct clk_ops xx_pll0_fixed_clk_ops = {.recalc_rate = xx_pll0_fixed_clk_recalc_rate,
};struct clk_ops *xx_fixed_clk_ops[] = {&xx_pll0_fixed_clk_ops,
};struct clk * __init xx_register_fixed_clk(const char *name, const char *parent_name,void __iomem *res_reg, u32 fixed_rate, int id, const struct clk_ops *ops)
{struct xx_fixed_clk *fixed_clk;struct clk *clk;struct clk_init_data init = {};fixed_clk = kzalloc(sizeof(*fixed_clk), GFP_KERNEL);if (!fixed_clk)return ERR_PTR(-ENOMEM);//初始化struct clk_init_data数据init.name = name;init.flags = CLK_IS_BASIC;init.parent_names = parent_name ? &parent_name : NULL;init.num_parents = parent_name ? 1 : 0;fixed_clk->reg = res_reg;//保存映射后的基址fixed_clk->fixed_rate = fixed_rate;//保存频率fixed_clk->id = id;//保存clock idfixed_clk->hw.init = &init;//时钟注册clk = clk_register(NULL, &fixed_clk->hw);if (IS_ERR(clk))kfree(fixed_clk);return clk;
}static void __init of_xx_fixed_clk_init(struct device_node *np)
{struct clk_onecell_data *clk_data;const char *clk_name = np->name;const char *parent_name = of_clk_get_parent_name(np, 0);void __iomem *res_reg = ioremap(CLOCK_BASE, CLOCK_SIZE);//寄存器基址映射u32 rate = -1;int clock_id, index, number;clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);if (!clk_data )return;number = of_property_count_u32_elems(np, "clock-id");clk_data->clks = kcalloc(number, sizeof(struct clk*), GFP_KERNEL);if (!clk_data->clks)goto err_free_data;of_property_read_u32(np, "clock-frequency", &rate);/*** 操作寄存器:初始化PLL时钟频率* ......*/for (index=0; index<number; index++) {of_property_read_string_index(np, "clock-output-names", index, &clk_name);of_property_read_u32_index(np, "clock-id", index, &clock_id);clk_data->clks[index] = xx_register_fixed_clk(clk_name, parent_name, res_reg, rate, clock_id, ak_fixed_clk_ops[pll_id]);if (IS_ERR(clk_data->clks[index])) {pr_err("%s register fixed clk failed: clk_name:%s, index = %d\n",__func__, clk_name, index);WARN_ON(true);continue;}clk_register_clkdev(clk_data->clks[index], clk_name, NULL);//注册时钟设备}clk_data->clk_num = number;if (number == 1) {of_clk_add_provider(np, of_clk_src_simple_get, clk_data->clks[0]);} else {of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);}return;err_free_data:kfree(clk_data);}CLK_OF_DECLARE(xx_fixed_clk, "xx,xx-fixed-clk", of_xx_fixed_clk_init);
factor_clk分频时钟实现
peri的时钟来自于Pll的分频,对于这类时钟,需要实现.round_rate
、.set_rate
、.recalc_rate
。
设备树:
#define PLL0_CLK 0
#defeine PLL0_FACTOR_PERI 0clocks{osc24M:osc24M{//晶振时钟compatible = "fixed-clock";#clock-cells = <0>;clock-output-names = "osc24M";clock-frequency = <24000000>;};pll0:pll0{//pll倍频时钟compatible = "xx, xx-fixed-clk";#clock-cells = <0>;clock-id = <PLL0_CLK>;clock-frequency = <1000000000>;clock-output-names = "pll0";clocks = <&osc24M>;//pll的父时钟为24M晶振};factor_pll0_clk:factor_pll0_clk{//pll分频时钟compatible = "xx,xx-pll0-factor-clk";#clock-cells = <1>;clock-id = <PLL0_FACTOR_PERI>;clock-output-names = "pll0_peri";clocks = <&pll0 PLL0_CLK>;//PERI子系统的父时钟为pll0};
};
驱动:
static long xx_factor_pll0_clk_round_rate(struct clk_hw *hw, unsigned long rate,unsigned long *parent_rate)
{unsigned long round_rate;//返回时钟实际支持的最接近速率return round_rate;
}
static int xx_factor_pll0_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
{int ret = 0;//操作寄存器,设置频率return ret;
}static unsigned long xx_factor_pll0_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{unsigned long recalc_rate;//查询寄存器,获得分频系数,计算频率然后返回return recalc_rate;}const struct clk_ops xx_factor_clk_ops = {.round_rate = xx_factor_pll0_clk_round_rate,//给定目标速率作为输入,返回时钟.set_rate = xx_factor_pll0_clk_set_rate,.recalc_rate = xx_factor_pll0_clk_recalc_rate,
}static void __init of_xx_factor_clk_init(struct device_node *np)
{//驱动入口//参考上述pll的注册,唯一不同的就是struct clk_ops的成员函数实现
}CLK_OF_DECLARE(xx_factor_clk, "xx,xx-factor-clk", of_xx_facotr_clk_init);
gate_clk门控时钟实现
门控就是开关,对于门控而言,我们只需要实现struct clk_ops的.enable和.disable
设备树:
#define PLL0_CLK 0
#defeine PLL0_FACTOR_PERI 0
#define PERI_MCI0 0mmc0:mmc0@0x12345678{compatible = "xx,xx-mmc0";......clocks = <&peri PERI_MCI0>;clocks-names = "mmc0";......};clocks{osc24M:osc24M{compatible = "fixed-clock";#clock-cells = <0>;clock-output-names = "osc24M";clock-frequency = <24000000>;};pll0:pll0{compatible = "xx, xx-fixed-clk";#clock-cells = <0>;clock-id = <PLL0_CLK>;clock-frequency = <1000000000>;clock-output-names = "pll0";clocks = <&osc24M>;};factor_pll0_clk:factor_pll0_clk{compatible = "xx,xx-pll0-factor-clk";#clock-cells = <1>;clock-id = <PLL0_FACTOR_PERI>;clock-output-names = "pll0_peri";clocks = <&pll0 PLL0_CLK>;};peri:peri{compatible = "xx,xx-gate-clk";#clock-cells = <1>;/*peri gate*/clock-id = <PERI_MCI0>;clock-output-names = "mci0_peri";clocks = <&factor_pll0_clk PLL0_FACTOR_PERI>;};
};
驱动:
static int xx_gate_clk_enable(struct clk_hw *hw)
{//寄存器操作,打开门控return 0;
}static int xx_gate_clk_disable(struct clk_hw *hw)
{//寄存器操作,门控关return 0;
}const struct clk_ops ak_gate_clk_ops = {.enable = xx_gate_clk_enable,.disable = xx_gate_clk_disable,
}static void __init of_xx_gate_clk_init(struct device_node *np)
{//参考上述fixed_clk的注册,几乎相同,只不过操作函数clk_ops的实现不一样
}CLK_OF_DECLARE(xx_gate_clk, "xx,xx-gate-clk", of_xx_gate_clk_init);
上述只是对clock驱动实现的简单举例,每个芯片厂商在clock驱动的实现上都有很大的差异。对于一般的驱动,只需要会简单的使用内核提供的时钟API接口即可。
相关文章:

Linux clock子系统及驱动实例
文章目录基本概念CLK子系统时钟API的使用clock驱动实例1、时钟树2、设备树3、驱动实现fixed_clk固定时钟实现factor_clk分频时钟实现gate_clk门控时钟实现基本概念 晶振:晶源振荡器 PLL:Phase lock loop,锁相环。用于提升频率 OSC:…...

GIS数据格式坐标转换(地球坐标WGS84、GCJ-02、火星坐标、百度坐标BD-09、国家大地坐标系CGCS2000)
文章目录前言一、坐标系1.地球坐标 (WGS84)2.国测局坐标系(GCJ-02、火星坐标系)3.百度坐标(BD-09)4.国家大地2000坐标系(CGCS2000)二、百度坐标系(BD-09) 与火星坐标系(GCJ-02)的转换1.核心代码2.转换验证百度地图高德地图腾讯地图三、火星坐标系 (GCJ-02) 与百度坐标系 (BD-09…...
流媒体传输系列文章汇总
流媒体传输系列文章汇总 文章目录流媒体传输系列文章汇总引言流媒体交互协议详解视频封装协议详解流媒体环境搭建其他引言 从去年开始编写有关流媒体传输相关知识的文章,已发表文章22篇,阅读量也超过了10万,为了方便各位阅读,本文…...

“万字“ Java I/O流讲解
Java I/O流讲解 每博一文案 谁让你读了这么多书,又知道了双水村以外还有一个大世界,如果从小你就在这个天地里,日出而作,日落而息。 那你现在就会和众乡亲抱同一理想:经过几年的辛劳,像大哥一样娶个满意的…...
数据库(Spring)事务的四种隔离级别
文章目录Spring(数据库)事务隔离级别分为四种(级别递减)1、Serializable(串行化)2、REPEATABLE READ(可重复读)3、READ COMMITTED(读以提交)4、Read Uncommit…...

RabbitMQ详解(一):RabbitMQ相关概念
RabbitMQ是目前非常热门的一款消息中间件,不管是互联网大厂还是中小企业都在大量使用。作为一名合格的开发者,有必要对RabbitMQ有所了解,本系列是RabbitMQ快速入门文章,主要内容包括RabbitMQ是什么、RabbitMQ核心概念、五种消息模…...

ICLR 2023 | GReTo:以同异配关系重新审视动态时空图聚合
©PaperWeekly 原创 作者 | 周正阳单位 | 中国科学技术大学论文简介动态时空图数据结构在多种不同的学科中均普遍存在,如交通流、空气质量观测、社交网络等,这些观测往往会随着时间而变化,进而引发节点间关联的动态时变特性。本文的主要…...
线程池分享总结
线程池介绍 可以复用线程池的每一个资源 控制资源的总量 为什么要使用线程池 问题一:反复创建线程开销大 问题二:过多的线程会占用太多内存 解决以上两个问题的思路 • 用少量的线程——避免内存占用过多 • 让这部分线程都保持工作,且可…...

AOSP Android11系统源码和内核源码
推荐阅读 商务合作 安全产品 安全服务 2023年招聘 安全培训服务 软件定制服务 Android系统定制服务 安全/软件开发的课程列表 1.下载repo工具 (1).创建bin,并加入到PATH中 mkdir ~/binPATH~/bin:$PATH (2).安装依赖库 sudo apt-get install bison g-mult…...

layui框架学习(6:基础菜单)
菜单是应用系统的必备元素,虽然网页中的导航也能作为菜单使用,但菜单和导航的样式和用途有所不同(不同之处详见参考文献5)。Layui中用不同的预设类定义菜单和导航的样式,同时二者依赖的模块也不一样。本文主要学习和记…...
第十三届蓝桥杯 C++ B组省赛 C 题——刷题统计(AC)
1.刷题统计 1.题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 aaa 道题目, 周六和周日每天做 bbb 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 nnn 题? 2.输入格式 输入一行包含三个整数 a,ba,ba,b 和 nnn. 3.输出…...

C++中的多态
【1】表现形式:同样的调用语句有多种不同的表现形态 【2】分类:静态联编和动态联编 静态联编有函数重载(运算符重载是特殊的函数重载),模板 【3】重点说下动态联编 【3.1】动态联编的实现需要以下步骤: 有继承关系、父类函数有virtual关…...
Swift如何保证线程安全
Swift可以通过以下几种方式来保证线程安全 使用互斥锁(Mutex):使用互斥锁可以防止多个线程同时访问共享数据,保证线程安全。 使用OSAtomic操作:OSAtomic操作可以在多线程环境中安全地执行原子操作。 使用DispatchQue…...

整型提升+算术转换——“C”
各位CSDN的uu们你们好呀,今天小雅兰的内容是之前操作符那篇博客中没有讲完的内容,整型提升这个小知识点也非常重要,那现在,就让我们进入操作符的世界吧 隐式类型转换 算术转换 操作符的属性 隐式类型转换 表达式求值的顺序一部…...

Freemarker介绍
2. Freemarker介绍 FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成 XML…...

【软件测试开发】Junit5单元测试框架
目录1. 注解Test 注解BeforeEach BeforeAllAfterEach AfterAll2. 断言 assertassertequalsassertTrue assertFalseassertNull assertNotNull3. 用例执行顺序方法排序,通过 Order 注解来排序4. 测试套件 Suite5. 参数化单参数stringsints6. 参数化多参数CsvSourceCsv…...

【C语言技能树】程序环境和预处理
Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接 我会一直往里填充内容哒! &…...

数据库的三大范式
1.为什么需要数据库设计 设计数据表的时候,要考虑很多的问题: 用户需要哪些数据,我们在数据表中要保存哪一些数据怎么保证数据表中的数据的正确性如何降低数据表的冗余度开发人员怎么才能更方便的使用数据库 如果数据库设计得不合理的话,可…...

【MT7628】开发环境搭建-Fedora12安装之后无法上网问题解决
1.按照如下图所示,打开Network Connections 2.点击Network Connections,弹出如下界面...

[Android Studio]Android 数据存储-文件存储学习笔记-结合保存QQ账户与密码存储到指定文件中的演练
🟧🟨🟩🟦🟪 Android Debug🟧🟨🟩🟦🟪 Topic 发布安卓学习过程中遇到问题解决过程,希望我的解决方案可以对小伙伴们有帮助。 📋笔记目…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...

高抗扰度汽车光耦合器的特性
晶台光电推出的125℃光耦合器系列产品(包括KL357NU、KL3H7U和KL817U),专为高温环境下的汽车应用设计,具备以下核心优势和技术特点: 一、技术特性分析 高温稳定性 采用先进的LED技术和优化的IC设计,确保在…...