RK3568平台(音频篇)RT5651解码芯片Codec驱动分析

一.Audio Codec的必要性

在理想状况下,对于录音过程,只需要将麦克风获取到的analog信号通过ADC转换为digital信号并存储即可,对于播放音过程,只需要将digital信号通过DAC转换为analog并输出到speaker播放即可。

但在实际的过程中,对于录音过程而言,会受到外界声源的干扰,麦克风自身对信号的衰减以及物理链路接口上引入的杂音等因素的影响,对于放音,可能会受digital数据本身的问题等因素的影响。

举个简单的例子,拿着手机或者固定电话和别人讲话的时候,虽然一边自己说话,一边听电话另外一端的人讲话,但是从听筒中并没有非常明显的听到自己的讲话声音。这中间就是一些Audio Codec在起作用,它们可以实现回音消除,噪音抵消,以及ALC/Limiter等,当然它也实现了最重要的AD和DA功能。

二.RT5651设备树配置

&i2c1 {status = "okay";i2c-scl-rising-time-ns = <300>;i2c-scl-falling-time-ns = <15>;rt5651: rt5651@1a {#sound-dai-cells = <0>;compatible = "rockchip,rt5651";reg = <0x1a>;clocks = <&cru SCLK_I2S_8CH_OUT>;clock-names = "mclk";status = "okay";};
};

其中:

status :指定设备状态为“正常”,表示该设备状态为正常运行;

i2c-scl-rising-time-ns:定义了SCL信号上升时间的最小值,单位是纳秒;

i2c-scl-falling-time-ns:定义了SCL信号下降时间的最小值,单位是纳秒;

接着定义I2C从设备节点rt5651,即音频编解码器的设备节点,其名称为 rt5651,I2C从设备7位地址为0x1a;

compatible:指定设备驱动程序的兼容性,即告诉内核该设备可以被哪些驱动程序所使用;

reg:指定了rt5651设备在I2C控制器上的设备地址;

clock-names:指定时钟名称,"mclk"表示MCLK时钟;

clocks:mclk时钟来自SCLK_I2S_8CH_OUT;

status :指定设备状态为“正常”,表示该设备状态为正常运行;

三.Codec驱动分析

rt5651驱动路径:

kernel-5.10\sound\soc\codecs\rt5651.c

rt5651_i2c_driver

这里我们需要关注一下i2c_driver结构体变量rt5651_i2c_driver :

static struct i2c_driver rt5651_i2c_driver = {.driver = {.name = "rt5651",.acpi_match_table = ACPI_PTR(rt5651_acpi_match),.of_match_table = of_match_ptr(rt5651_of_match),},.probe = rt5651_i2c_probe,.id_table = rt5651_i2c_id,
};

其成员:

driver.of_match_table:用于设备树匹配;

probe:当I2C驱动和I2C从设备信息匹配成功之后,就会调用probe函数;

id_table:id列表,用于和I2C从设备名称进行匹配;

I2C从设备驱动中的rt5651_i2c_id匹配成功,会执行probe探测函数:

static int rt5651_i2c_probe(struct i2c_client *i2c)  // 参数为I2C从设备
{struct rt5651_priv *rt5651;int ret;int err;rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651),   // 动态申请内存,数据结构类型为struct rt5651_privGFP_KERNEL);if (NULL == rt5651)return -ENOMEM;......ret = devm_snd_soc_register_component(&i2c->dev,   // 注册component&soc_component_dev_rt5651,rt5651_dai, ARRAY_SIZE(rt5651_dai));return ret;
}

执行probe函数后,这里重点看devm_snd_soc_register_component函数,

调用devm_snd_soc_register_component注册的component,该函数会动态申请一个component,并将其添加到全局链表component_list中,同时会建立dai_driver与component的关系。

codec驱动注册流程主要包含一下几个步骤:

(1) 构造一个struct snd_soc_component_driver实例,比如这里的soc_component_dev_rt5651,用于描述codec driver;需要初始化成员name、controls、dapm_widgets、dapm_routes等;

(2) 构造一个struct snd_soc_dai_driver,比如这里的rt5651_dai数组,用于描述dai和 pcm的能力和操作;需要初始化成员name、probe、playback、capture、ops等;

(3) 调用devm_snd_soc_register_component注册component;

devm_snd_soc_register_component函数第二个参数为soc_component_dev_rt5651

soc_component_dev_rt5651:

static const struct snd_soc_component_driver soc_component_dev_rt5651 = {.probe                  = rt5651_probe,.suspend                = rt5651_suspend,.resume                 = rt5651_resume,.set_bias_level         = rt5651_set_bias_level,.set_jack               = rt5651_set_jack,.controls               = rt5651_snd_controls,                 // kcontrol定义.num_controls           = ARRAY_SIZE(rt5651_snd_controls), .dapm_widgets           = rt5651_dapm_widgets,                 // widget定义 .num_dapm_widgets       = ARRAY_SIZE(rt5651_dapm_widgets),.dapm_routes            = rt5651_dapm_routes,                  // route定义  .num_dapm_routes        = ARRAY_SIZE(rt5651_dapm_routes),.use_pmdown_time        = 1,.endianness             = 1,
};

其中controls、dapm_widgets、dapm_routes是与dapm相关的,可以用来表述codec内部的音频路径。

DAPM简介:

DAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下。DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都在ASoc core中完成。DAPM根据当前激活的音频流(playback/capture)和声卡中的mixer等的配置来决定那些音频控件的电源开关被打开或关闭。

在datasheel里面描述了音频数据流具体路径细节,如下图:

 

上图中我们使用箭头标识了一条用于多媒体音频播放右声道的路径,音频通路是:

AIF1 Playback(snd_soc_dapm_dai_in类型的playback dai widget) --> AIF1RX :AIF表示音频数字接口;

AIF1RX --> IF1 DAC;

IF1 DAC --> IF1 DAC1 R;

IF1 DAC1 R --> DAC MIXR:通过rt5651_dac_r_mix(名称为INF1 Switch)控制通断,由MX29寄存器位14来实现静音控制(0非静音,1静音);

DAC MIXR -->  Audio DSP;

Audio DSP --> Stereo DAC MIXR:通过rt5651_sto_dac_r_mix(名称DAC R1 Switch)控制通断,由MX2A寄存器位6来实现静音控制(0非静音,1静音);

Stereo DAC MIXR --> DAC R1;

DAC R1 --> OUT MIXR :通过rt5651_out_r_mix(名称为DAC R1 Switch)控制通断,由MX52寄存器位0来实现静音控制(0非静音,1静音);

OUT MIXR -->  HPOVOL R:通过hpovol_r_control(名称为Switch)控制通断,由MX02寄存器位6来实现静音控制(0非静音,1静音);

HPOVOL R --> HPOR MIX:通过rt5651_hpo_mix(名称为HPO MIX HPVOL Switch)控制通断,由MX45寄存器位13来实现静音控制(0非静音,1静音);

HPOR MIX --> HP Amp;

HP Amp -> HPO R Playback:通过hpo_r_mute_control(名称为Switch)控制通断,由MX02寄存器位7来实现静音控制(0非静音,1静音);

HPO R Playback --> HPOR ;

HPOR  --> Headphones(最后一个path定义在Machine驱动中);

其中红色部分表示有相应的kcontrol,即需要switch打开,在该路径中 HPOL 为SND_SOC_DAPM_EP_SINK类型端点,但是路径中并没有SND_SOC_DAPM_EP_SOURCE类型端点。

kcontrol:

在sound/soc/codecs/rt5651.c定义了大量的kcontrol,包括普通kcontrol和dapm kcontrol:

通常,一个kcontrol代表着一个mixer(混音器),或者是一个mux(多路开关),又或者是一个音量控制器等等。

kcontrol的定义例如:

static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = {SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,RT5651_M_STO1_ADC_L1_SFT, 1, 1),SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,RT5651_M_STO1_ADC_L2_SFT, 1, 1),
};

widget:

在sound/soc/codecs/rt5651.c定义了大量的widget:

widget把kcontrol和动态电源管理进行了有机的结合,同时还具备音频路径的连接功能,一个widget可以与他相邻的widge有某种动态的连接关系。

widget的定义例如:

SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,rt5651_sto1_adc_l_mix,ARRAY_SIZE(rt5651_sto1_adc_l_mix)),

route:

在sound/soc/codecs/rt5651.c定义了widget的链接路径:

系统中注册的各种widget需要互相连接在一起才能协调工作,连接关系通过snd_soc_dapm_route结构来定义.

在rt5651_dapm_widgets中我们可以找到位于多媒体音频播放右声道路径上的route:

{"IF1 DAC", NULL, "AIF1RX"},
{"IF1 DAC1 R", NULL, "IF1 DAC"},
{"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},  
{"Audio DSP", NULL, "DAC MIXR"},  
{"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
{"DAC R1", NULL, "Stereo DAC MIXR"},
{"OUT MIXR", "DAC R1 Switch", "DAC R1"}
{"HPOVOL R", "Switch", "OUT MIXR"},
{"HPOR MIX", "HPO MIX HPVOL Switch", "HPOVOL R"},
{"HP Amp", NULL, "HPOR MIX"},
{"HPO R Playback", "Switch", "HP Amp"},
{"HPOR", NULL, "HPO R Playback"},

rt5651_probe:

static int rt5651_probe(struct snd_soc_component *component)
{struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);  // 取出component->dev设备的driver_data,就是上面介绍的rt5651结构变量rt5651->component = component;   // 设置cpmponentsnd_soc_component_update_bits(component, RT5651_PWR_ANLG1,      // 向寄存器写入值,RT5651_PWR_ANLG1的值为0x63,寄存器地址0x63用于电源控制寄存器3RT5651_PWR_LDO_DVO_MASK, RT5651_PWR_LDO_DVO_1_2V);      // RT5651_PWR_LDO_DVO_MASK值为0x03 RT5651_PWR_LDO_DVO_1_2V值为2  因此这里向位[1:0]写入10'b// 即配置LDO output电压为1.2V    snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);   // Set the COMPONENT DAPM bias level,即dapm->bias_level=0rt5651_apply_properties(component);return 0;
}

rt5651_set_bias_level:

set_bias_level用于设置codec域的偏置电压,那什么是偏置电压呢?在电容式麦克风中,为了使麦克风的工作点稳定,需要加一个直流电压,这个直流电压就是偏置电压,偏置电压的作用主要有以下几个方面:

稳定麦克风的工作点;在没有偏置电压的情况下,麦克风的输出信号会受到温度、湿度等环境因素的影响,导致输出信号的偏移,而偏置电压可以保持麦克风的工作不变,保证输出信号的稳定性;

提高麦克风的灵敏度,偏置电压可以使麦克风的灵敏度增加,从而提高声音的捕获能力;

降低麦克风的噪声;偏移电压可以降低麦克风的噪声水平,使得麦克风的输出信号更清晰;

对于ALC5651芯片MICBIAS1引脚会输出一个偏置电压,提供给外置麦克风:

static int rt5651_set_bias_level(struct snd_soc_component *component,enum snd_soc_bias_level level)
{switch (level) {case SND_SOC_BIAS_PREPARE:      // 准备状态// 获取dapm->bias_level,待机->准备if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {// RT5651_PLL_MODE_1的值为0x83,寄存器0x83为ASRC控制寄存器,这里是判断位[15]、[12]、[9]是否为1// 其中位[15]为I2S1模式选择控制  0:正常模式  1:ASRC模式// 位[12]为I2S2模式选择控制  0:正常模式  1:ASRC模式 // 位[9] Select Control for ASRC Mode in DMIC1 Function 0:正常模式  1:ASRC模式if (snd_soc_component_read(component, RT5651_PLL_MODE_1) & 0x9200)                                                                                                                                                                                                             // RT5651_D_MISC的值为0xFA,寄存器地址0xFA为基本控制寄存器snd_soc_component_update_bits(component, RT5651_D_MISC,  0xc00, 0xc00); // 这里向位[11:10]写入11'b,芯片手册中并没有描述这两位有什么作用}break;case SND_SOC_BIAS_STANDBY:     // 待机状态// 获取dapm->bias_level,关闭状态->待机状态if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) {//  RT5651_PWR_ANLG1的值为0x63,寄存器地址0x63用于电源控制寄存器3snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,  // RT5651_PWR_VREF1位[15],VREF1 Power Control:0下电、1上电// RT5651_PWR_MB位[13],MBIAS Power Control:0下电、1上电// RT5651_PWR_BG位[11],MBIAS Bandgap Power Control:0下电、1上电// RT5651_PWR_VREF2位[4],VREF2 Power Control:0下电、1上电RT5651_PWR_VREF1 | RT5651_PWR_MB |  RT5651_PWR_BG | RT5651_PWR_VREF2,   RT5651_PWR_VREF1 | RT5651_PWR_MB |RT5651_PWR_BG | RT5651_PWR_VREF2);usleep_range(10000, 15000);// RT5651_PWR_FV1位[14],VREF1 Fast Mode Control:0 Fast VREF、1  Slow VREF, (For good analog performance)// RT5651_PWR_FV2位[0],VREF2 Fast Mode Control:0 Fast VREF、1  Slow VREF, (For good analog performance)snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,RT5651_PWR_FV1 | RT5651_PWR_FV2,RT5651_PWR_FV1 | RT5651_PWR_FV2);// RT5651_D_MISC的值为0xFA,寄存器地址0xFA为基本控制寄存器,芯片手册中并没有描述位[1]有什么作用snd_soc_component_update_bits(component, RT5651_D_MISC, 0x1, 0x1);}break;case SND_SOC_BIAS_OFF:        // 关闭状态snd_soc_component_write(component, RT5651_D_MISC, 0x0010);snd_soc_component_write(component, RT5651_PWR_DIG1, 0x0000);snd_soc_component_write(component, RT5651_PWR_DIG2, 0x0000);snd_soc_component_write(component, RT5651_PWR_VOL, 0x0000);snd_soc_component_write(component, RT5651_PWR_MIXER, 0x0000);/* Do not touch the LDO voltage select bits on bias-off */snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,~RT5651_PWR_LDO_DVO_MASK, 0);/* Leave PLL1 and jack-detect power as is, all others off */snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,~(RT5651_PWR_PLL | RT5651_PWR_JD_M), 0);break;default:break;}return 0;
}

rt5651_set_jack:

static int rt5651_set_jack(struct snd_soc_component *component,struct snd_soc_jack *jack, void *data)
{if (jack)rt5651_enable_jack_detect(component, jack, data);elsert5651_disable_jack_detect(component);return 0;
}

在ASoC中使用struct snd_soc_jack来描述jack,并提供了对其状态、引脚等进行管理和通知的功能。这里如何定义了jack,将会调用rt5651_enable_jack_detect,用于实现麦克风插入/拔出的检测。

rt5651_dai:

数字音频接口DAI,即Digital Audio Interfaces,顾名思义,DAI表示在板级或板间传输数字音频信号的方式。

由于ALC5651有两组I2S接口,可以同时用于耳机输出以及Line output;RK3568与ALC5651连线如下:

                    *              *                         * <------ * <---- MICRAM <--------PCM-> * <----------> * <-I2S------------I2S1-> *         **              *            |            * ------> * ----> Line output****************            |            *         *RK3568                |            *         *-----I2S2-> * ------> * ----> HEADPHONE***********ALC5651

codec dai和pcm配置信息通过结构体snd_soc_dai_driver描述,包括了dai的能力描述和操作接口;devm_snd_soc_register_component函数第三个参数为rt5651_dai,数组中长度为2,分别与ALC5651的两组I2S接口一一对应;

static struct snd_soc_dai_driver rt5651_dai[] = {{.name = "rt5651-aif1", // dai的名称,会赋值给与其关联的snd_soc_dai的name成员                                       // 音频数据链路是通过dai_name到ALC5651的component的dai_list链表中来查找dai的                .id = RT5651_AIF1,      // 0,dai的id.playback = {  // 声卡注册的时候会为其创建一个类型为snd_soc_dapm_dai_in的playback dai widget,其name以及sname均设置为"AIF1 Playback".stream_name = "AIF1 Playback",  .channels_min = 1,     // 最小通道数.channels_max = 2,     // 最大通道数.rates = RT5651_STEREO_RATES,.formats = RT5651_FORMATS,},.capture = {   // 声卡注册的时候会为其创建一个类型为snd_soc_dapm_dai_out的capture dai widget,其name以及sname均设置为"AIF1 Capture".stream_name = "AIF1 Capture",.channels_min = 1,.channels_max = 2,.rates = RT5651_STEREO_RATES,  // 支持的采样率 SNDRV_PCM_RATE_8000_96000  999~96000之间.formats = RT5651_FORMATS,     // 支持的位深度  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)},.ops = &rt5651_aif_dai_ops,},{.name = "rt5651-aif2",.id = RT5651_AIF2,   // 1,dai的id.playback = {.stream_name = "AIF2 Playback",.channels_min = 1,.channels_max = 2,.rates = RT5651_STEREO_RATES,.formats = RT5651_FORMATS,},.capture = {.stream_name = "AIF2 Capture",.channels_min = 1,.channels_max = 2,.rates = RT5651_STEREO_RATES,.formats = RT5651_FORMATS,},.ops = &rt5651_aif_dai_ops,},
};

其中:

name:codec dai的名称标识,dai_link通过配置codec dai_name来找到对应的codec dai;

capture:描述capture的能力;如回放设备所支持的声道数、采样率、音频格式;非常重要的字段;

playback:描述playback的能力;如录制设备所支持声道数、采样率、音频格式;非常重要的字段;

ops:codec dai的操作函数集,这些函数集非常重要,用于dai的时钟配置、格式配置、硬件参数配置。

rt5651_aif_dai_ops:

static const struct snd_soc_dai_ops rt5651_aif_dai_ops = {.hw_params = rt5651_hw_params,.set_fmt = rt5651_set_dai_fmt,.set_sysclk = rt5651_set_dai_sysclk,.set_pll = rt5651_set_dai_pll,
};

其中:

set_sysclk:用于设置系统时钟,对于codec dai来说系统时钟指的是ALC5651 i2s1接口的MCLK信号线输入的时钟,同时也是RK3399 i2s0接口的MCLK信号线输出的时钟(对应的时钟名称为clk_i2sout);当上层打开pcm设备时,需要回调该接口设置ALC5651的系统时钟,ALC5651才能正常工作;

set_pll:用于设置ALC5651的PLL的分频系数,ALC5651一般接了一个MCLK作为ALC5651的PLL输入时钟源,回调该函数基于MCLK来产生ALC5651 PLL时钟;

set_fmt:设置数字音频接口格式,具体见 include/sound/soc-dai.h;

SND_SOC_DAIFMT_I2S:数字音频接口是I2S格式,常用于多媒体音频;

SND_SOC_DAIFMT_RIGHT_J:数字音频接口是I2S右对齐格式;

SND_SOC_DAIFMT_LEFT_J:数字音频接口是I2S左对齐格式;

SND_SOC_DAIFMT_DSP_A:数字音频接口是PCM格式,常用于语音通话;

SND_SOC_DAIFMT_DSP_B:数字音频接口是PCM格式,常用于语音通话;

SND_SOC_DAIFMT_CBM_CFM:ALC5651作为主机,BCLK 和 LRCLK由ALC5651提供;

SND_SOC_DAIFMT_CBS_CFS:ALC5651作为从机,BCLK和LRCLK由SoC/CPU提供;

.......

hw_params:codec dai硬件参数设置,根据上层设定的声道数、采样率、数据格式,来配置codec dai相关寄存器;

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

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

相关文章

ES6新特性 面试高频题1

var、let 和 const 的区别 作用域 var是函数作用域&#xff0c;如果在一个代码块&#xff08;如 if 语句或 for 循环&#xff09;中声明&#xff0c;它仍然可以在整个函数内访问。 let const是块级作用域&#xff0c; 这意味着它们只在声明它们的代码块内可见。可变性 var 和 …

【学习】如何利用Python技术进行软件测试相关工作

Python是一种广泛使用的高级编程语言&#xff0c;它因其简洁的语法、强大的库支持和跨平台特性而受到开发者的喜爱。在软件测试领域&#xff0c;Python同样发挥着重要作用&#xff0c;它可以帮助测试人员编写自动化测试脚本、进行接口测试、性能测试、以及处理测试数据等。以下…

Camera定制修改

需求&#xff1a; Android13 MtkCamera右上角的前后摄切换点击范围小导致经常点击无反应&#xff0c;需增大view宽度 跟踪代码可找到对应资源文件&#xff1a;vendor\mediatek\proprietary\packages\apps\Camera2\feature\setting\cameraswitcher\res\ 根据vendor\mediatek\…

【Linux】进程信号_3

文章目录 八、进程信号2. 信号的保存3. 信号的处理 未完待续 八、进程信号 2. 信号的保存 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间的状态,称为信号未决(Pending)。 进程可以选择阻塞 (Block )某个信号。 被阻塞的信号产生时将保持在未决状态,直到…

华为开发者调试工具使用介绍(MDC)

MDC的开发过程的三大工具&#xff1a;MMC、MDS、Mind Studio&#xff0c;这三个工具完成了开发过程中的配置文件编写、代码编写以及AI模型的开发三个任务。除了开发&#xff0c;MDC还准备了两个调试工具&#xff0c;用于使用过程中数据的查看等。这一些调试工具分别对映射MDC中…

单目标应用:基于鳗鱼和石斑鱼优化器(Eel and grouper optimizer,EGO)的微电网优化(MATLAB代码)

一、微电网模型介绍 微电网多目标优化调度模型简介_vmgpqv-CSDN博客 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、鳗鱼和石斑鱼优化器求解微电网 2.1算法简介 鳗鱼和石斑鱼优化器&…

过滤器模式

过滤器模式 过滤器模式&#xff08;Filter Pattern&#xff09;是一种设计模式&#xff0c;它允许你使用不同的标准来过滤一组对象&#xff0c;通过逻辑运算以解耦的方式将这些标准组合起来。这种模式特别适用于希望对数据集进行灵活过滤的场景&#xff0c;而不需要修改现有代…

GPT-5:AI新纪元的开启与我们的未来

GPT-5 一年半后发布&#xff1f;对此你有何期待&#xff1f; IT之家6月22日消息&#xff0c;在美国达特茅斯工程学院周四公布的采访中&#xff0c;OpenAI首席技术官米拉穆拉蒂被问及GPT-5是否会在明年发布&#xff0c;给出了肯定答案并表示将在一年半后发布。此外&#xff0c;…

前端面试题(基础篇十)

一、JavaScript内置类型 JS 中分为七种内置类型&#xff0c;七种内置类型⼜分为两⼤类型&#xff1a;基本类型和对象 &#xff08; Object &#xff09;。 基本类型有六种&#xff1a; null &#xff0c; undefined &#xff0c; boolea n&#xff0c; number &#xff0c; …

MySQL简介:开源数据库的基石(一)

目录 引言&#xff1a;数据库领域的革新者 一、MySQL的发展历程&#xff1a;从开源先锋到行业领袖 二、MySQL的核心特性&#xff1a;性能、安全与灵活性并重 三、MySQL的应用场景&#xff1a;从Web开发到企业级应用的全面覆盖 四、MySQL在开源数据库中的地位&#xff1a;开…

梳理湖南省各市市场监督管理专项资金申请条件对象及认定补贴流程

第一章 总 则 第一条 为加强和规范湖南省市场监督管理专项资金管理&#xff0c;提高资金使用效益&#xff0c;根据《中华人民共和国预算法》《中共中央 国务院关于全面实施预算绩效管理的意见》《湖南省人民政府关于进一步深化预算管理制度改革的实施意见》(湘政发〔2021〕14号…

Excel直接打开csv文件后,数据不能正常显示的解决方法

很多处理公司数据的同事偶尔也会遇到使用Microsoft的Excel或者金山的WPS打开csv文件后&#xff0c;发现数据不能正常显示&#xff0c;其实csv属于一种数据库文件&#xff0c;遵循数据库存储的规则&#xff0c;建议使用导入的方式进行打开。 1.打开一张空白的Excel表&#xff0…

Spring Boot 集成 H2 数据库

1. 引言 Spring Boot 以其简洁的配置和快速开发能力&#xff0c;成为现代微服务架构的首选框架之一。而H2数据库作为一个轻量级的内存数据库&#xff0c;非常适合开发阶段作为嵌入式数据库进行单元测试和功能验证。本文将手把手教你如何在Spring Boot项目中集成H2数据库&#…

Open3D 显示带有强度的点云数据

目录 一、概述 1.1强度信息的意义 1.2应用场景 二、代码实现 三、实现效果 一、概述 在点云数据中&#xff0c;强度&#xff08;Intensity&#xff09;指的是激光雷达传感器在扫描环境时&#xff0c;每个点返回的反射强度值。这些强度值代表了激光脉冲返回的能量&#xff…

Python + Playwright(19):Clock 测试时间相关行为API

Python + Playwright(19):Clock 测试时间相关行为API 概述Clock API 的重要性Clock API 的详细说明初始化时钟并设置特定时间暂停时钟快进时钟代码示例高级用法模拟网络延迟测试异步操作实践建议测试前清理环境分离时间相关和非时间相关的测试使用明确的断言注意事项恢复时钟…

centos 破解密码

重启您的CentOS系统。 在GRUB引导加载器启动过程中&#xff0c;当看到启动画面时&#xff0c;按下e键进入编辑模式。 找到以 linux16 或 linux 开头的启动行。 在该行的末尾添加 rd.break 或者ro&#xff08;只读&#xff09;修改为 rw 加init/sysroot/bin/sh参数&#xff0…

IPQ5018 SPF12.2 CSU3 编译指南

编译和加载image 1. 从高通的门户网站下载高通技术公司(QTI)专有的CHIPCODE 2. 在编译默认配置时,下载QSDK的相关组件 3. 生成固件: a. 重新组装代码,生成QSDK 框架 b. 设置并创建QSDK c. 生成一个完整的固件镜像 4. flash 烧写软件映像 安装编译环…

torchaudio.load() 和 librosa.load() 的返回值区别

问题 之前都在使用librosa加载音频数据&#xff0c;今天看到一段代码是用torchaudio加载的音频&#xff0c;发现torchaudio加载的数据和librosa返回的结果不一致。 查看资料后做出以下对比&#xff1a; torchaudio.load 函数返回一个包含两个张量的元组: 音频数据张量,形状为…

Nacos详解

nacos官方文档&#xff1a;https://nacos.io/ 一、什么是nacos&#xff1f; Nacos是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 nacos官方文档&#xff1a;https://nacos.io/ nac…

C语言-二级指针应用场景

二级指针应用 引子:在线性表 销毁函数中,传入二级指针作为参数,可以实现对线性表的销毁操作。 //销毁已存在的线性表 void DestroyList(list_t **L){// Step 1: 检查L是否为非空指针if(L) // Step 2: 释放L指向的内存空间free(*L);// Step 3: 将L所指向的指针置为NULL&#xff…