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

【驱动】SPI驱动分析(六)-RK SPI驱动分析

前言

Linux的spi接口驱动实现目录在kernel\drivers\spi下。这个目录和一些层次比较明显的驱动目录布局不同,全放在这个文件夹下,因此还是只好通过看Kconfig 和 Makefile来找找思路

先看Makefile,里面关键几行:
obj-$(CONFIG_SPI_MASTER) += spi.o //这个是针对有spi控制器的soc选项,一般的soc都有spi控制器吧。
# SPI master controller drivers (bus) //下面的这些就是针对不同soc上的spi控制器的驱动了,我们可以通过make menuconfig的时候选上自己对应平台的

# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ALTERA)		+= spi-altera.o
obj-$(CONFIG_SPI_ARMADA_3700)		+= spi-armada-3700.o
............
obj-$(CONFIG_SPI_AXI_SPI_ENGINE)	+= spi-axi-spi-engine.o

下面这些就是针对于主机作为spi从设备的时候用的,暂时貌似没支持,毕竟现实中几乎没有用过,而是作为master端出现

# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME)		+= spi-slave-time.o
obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL)	+= spi-slave-system-control.o

再看Kconfig,第一个SPI选项我觉得有必要贴一下,首先只有选择它了才能进行后面的配置,其次它的help对spi的描述说的很清楚!

#
# SPI driver configuration
#
menuconfig SPIbool "SPI support"depends on HAS_IOMEMhelpThe "Serial Peripheral Interface" is a low level synchronousprotocol.  Chips that support SPI can have data transfer ratesup to several tens of Mbit/sec.  Chips are addressed with acontroller and a chipselect.  Most SPI slaves don't supportdynamic device discovery; some are even write-only or read-only.SPI is widely used by microcontrollers to talk with sensors,eeprom and flash memory, codecs and various other controllerchips, analog to digital (and d-to-a) converters, and more.MMC and SD cards can be accessed using SPI protocol; and forDataFlash cards used in MMC sockets, SPI must always be used.SPI is one of a family of similar protocols using a four wireinterface (select, clock, data in, data out) including Microwire(half duplex), SSP, SSI, and PSP.  This driver framework shouldwork with most such devices and controllers.

我们其次需要配上的选项就是SPI_MASTERCONFIG_SPI_ROCKCHIP(我手上的是RK的SDK)。

config SPI_MASTER
#	bool "SPI Master Support"booldefault SPIhelpIf your system has an master-capable SPI controller (whichprovides the clock and chipselect), you can enable thatcontroller and the protocol drivers for the SPI slave chipsthat are connected.config SPI_ROCKCHIPtristate "Rockchip SPI controller driver"helpThis selects a driver for Rockchip SPI controller.If you say yes to this option, support will be included forRK3066, RK3188 and RK3288 families of SPI controller.Rockchip SPI controller support DMA transport and PIO mode.The main usecase of this controller is to use spi flash as bootdevice.

于是从Makefile里得到如下语句和我们相关:

obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o

于是我们要分析的代码主要有:spi.c spi-rockchip.c,瞬间没压力了,就两个文件,呵呵

下面主要从三个方面来分析spi框架

  1. spi控制器驱动的实现(毕竟spi控制器的驱动还是有可能要接触的)
  2. spi设备的驱动(我们更多的是编写设备的驱动,还是以eeprom为例吧,虽然我很想以spi接口的nor flash驱动为例,但是那又会牵涉出mtd子系统,这个留在mtd子系统分析吧)
  3. spi核心层的实现(上面1、2都是以各自的驱动实现为目标,并不深入到spi核心层,也就是至于spi核心层怎么为我们提供的服务不去关心,只需要按spi核心层使用它提供的服务就是了。所以现在统一分析spi核心层,看它是怎么提供的服务)

spi控制器驱动的实现

spi-rockchip.c为例,直接看module_platform_driver

static struct platform_driver rockchip_spi_driver = {.driver = {.name	= DRIVER_NAME,.pm = &rockchip_spi_pm,.of_match_table = of_match_ptr(rockchip_spi_dt_match),},.probe = rockchip_spi_probe,.remove = rockchip_spi_remove,
};

平台驱动的内部流程就不分析了,直接看匹配成功后rockchip_spi_probe的调用,但这里还是插入平台spi控制器设备端相关的代码:

  1. 使用spi_alloc_master函数为平台设备pdev分配一个SPI主设备结构体,并将其大小设置为sizeof(struct rockchip_spi)。这个函数会分配内存并初始化主设备结构体的各个字段。调用platform_set_drvdata函数将主设备结构体指针保存在平台设备的私有数据中,以便后续在驱动的其他函数中可以访问该指针。使用spi_master_get_devdata函数获取之前保存在私有数据中的主设备结构体指针rs
	master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi));if (!master)return -ENOMEM;platform_set_drvdata(pdev, master);rs = spi_master_get_devdata(master);
  1. 使用platform_get_resource函数获取SPI控制器的IO资源。这些资源包括寄存器地址、中断号等信息,向操作系统请求资源空间并建立起映射为以后所用。
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);rs->regs = devm_ioremap_resource(&pdev->dev, mem);if (IS_ERR(rs->regs)) {ret =  PTR_ERR(rs->regs);goto err_ioremap_resource;}
  1. 使用devm_clk_get函数获取SPI控制器所需的时钟,包括"apb_pclk"和"spiclk"。这些时钟用于控制SPI控制器的时序和传输速率。
	rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");if (IS_ERR(rs->apb_pclk)) {dev_err(&pdev->dev, "Failed to get apb_pclk\n");ret = PTR_ERR(rs->apb_pclk);goto err_ioremap_resource;}rs->spiclk = devm_clk_get(&pdev->dev, "spiclk");if (IS_ERR(rs->spiclk)) {dev_err(&pdev->dev, "Failed to get spi_pclk\n");ret = PTR_ERR(rs->spiclk);goto err_ioremap_resource;}
  1. 使用clk_prepare_enable函数使获取到的时钟生效,确保SPI控制器可以正常工作。
	ret = clk_prepare_enable(rs->apb_pclk);if (ret) {dev_err(&pdev->dev, "Failed to enable apb_pclk\n");goto err_ioremap_resource;}ret = clk_prepare_enable(rs->spiclk);if (ret) {dev_err(&pdev->dev, "Failed to enable spi_clk\n");goto err_spiclk_enable;}
  1. 调用spi_enable_chip函数使SPI芯片处于可用状态。这个函数会执行一些特定的SPI控制器寄存器的配置,以便使芯片可以正常通信。设置SPI主设备的属性。这些属性包括SPI总线类型、主设备指针、设备指针、最大频率等。
	spi_enable_chip(rs, 0);rs->type = SSI_MOTO_SPI;rs->master = master;rs->dev = &pdev->dev;rs->max_freq = clk_get_rate(rs->spiclk);
  1. 使用of_property_read_u32函数从设备节点中读取属性值。在这个例子中,它读取了"rx-sample-delay-ns"属性,并将其存储在rsd_nsecs变量中。调用get_fifo_len函数获取FIFO的长度。FIFO用于在SPI传输过程中暂存数据。
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",&rsd_nsecs))rs->rsd_nsecs = rsd_nsecs;rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) {dev_err(&pdev->dev, "Failed to get fifo length\n");ret = -EINVAL;goto err_get_fifo_len;
}
  1. 初始化自旋锁。自旋锁用于保护共享资源,防止多个进程同时访问造成冲突。设置设备的运行时PM状态为活动,并启用运行时PM。允许系统在不需要SPI设备时将其置于低功耗状态。
spin_lock_init(&rs->lock);pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
  1. 设置主设备的一些属性,例如自动运行时PM、总线号、模式位、芯片选择数量、设备节点等。同时设置主设备的回调函数。这些回调函数将在SPI传输中的不同阶段被调用,以执行相应的操作
	master->auto_runtime_pm = true;master->bus_num = pdev->id;master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;master->num_chipselect = 2;master->dev.of_node = pdev->dev.of_node;master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);master->set_cs = rockchip_spi_set_cs;master->prepare_message = rockchip_spi_prepare_message;master->unprepare_message = rockchip_spi_unprepare_message;master->transfer_one = rockchip_spi_transfer_one;master->handle_err = rockchip_spi_handle_err;
  1. 使用dma_request_slave_channel函数请求DMA通道,如果同时成功请求到了TX和RX的DMA通道,则设置DMA传输的地址和方向,并将相应的DMA通道设置为主设备的属性。
	rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx");if (IS_ERR_OR_NULL(rs->dma_tx.ch)) {/* Check tx to see if we need defer probing driver */if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {ret = -EPROBE_DEFER;goto err_get_fifo_len;}dev_warn(rs->dev, "Failed to request TX DMA channel\n");}rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx");if (!rs->dma_rx.ch) {if (rs->dma_tx.ch) {dma_release_channel(rs->dma_tx.ch);rs->dma_tx.ch = NULL;}dev_warn(rs->dev, "Failed to request RX DMA channel\n");}
  1. 使用pinctrl_lookup_state函数查找高速模式的引脚控制状态。检查查找高速模式的引脚控制状态是否成功。
	rs->high_speed_state = pinctrl_lookup_state(rs->dev->pins->p,"high_speed");if (IS_ERR_OR_NULL(rs->high_speed_state)) {dev_warn(&pdev->dev, "no high_speed pinctrl state\n");rs->high_speed_state = NULL;}
  1. 使用devm_spi_register_master函数注册SPI主设备。
	ret = devm_spi_register_master(&pdev->dev, master);if (ret) {dev_err(&pdev->dev, "Failed to register master\n");goto err_register_master;}

暂时不进入到spi核心层分析,这里我们只需要知道调用核心层的注册函数后,核心层会遍历所有注册到核心层的设备(实际最开始是加入到一个全局链表里,和I2C核心层的实现类似),然后尝试着添加每一个总线号为该控制器衍生出的总线号的设备到该spi控制器上,当然如果该spi控制器不支持某一个设备,那就取消添加这个设备,如果添加成功,那么该设备将会添加到spi总线上去,这条总线是spi核心层注册的,用来管理spi接口的设备和spi接口的驱动。

总结下probe函数的主要工作:

  • 分配和初始化SPI主设备结构体。
  • 获取并映射IO资源。
  • 获取和使能时钟。
  • 设置SPI主设备的属性和回调函数。
  • 请求并设置DMA通道。
  • 注册SPI主设备。

spi设备的驱动

以eeprom为例,我们分析下文件at25.c:

同样的,driver的注册过程我们就不深入了解了,其实就是一个总线设备驱动模型。我们直接看probe函数做了什么。

static const struct of_device_id at25_of_match[] = {{ .compatible = "atmel,at25", },{ }
};
MODULE_DEVICE_TABLE(of, at25_of_match);static struct spi_driver at25_driver = {.driver = {.name		= "at25",.of_match_table = at25_of_match,},.probe		= at25_probe,.remove		= at25_remove,
};
  1. 检查spi->dev.platform_data是否存在,如果不存在,则调用at25_fw_to_chip函数将固件信息转换为芯片描述,并将其存储在chip结构体中。如果存在,则直接将spi->dev.platform_data强制类型转换为spi_eeprom结构体,并将其赋值给chip
	/* Chip description */if (!spi->dev.platform_data) {err = at25_fw_to_chip(&spi->dev, &chip);if (err)return err;} elsechip = *(struct spi_eeprom *)spi->dev.platform_data;
  1. 根据chip结构体中的标志位判断EEPROM的地址长度是8位、16位还是24位,并将相应的值赋给addrlen变量。
	/* For now we only support 8/16/24 bit addressing */if (chip.flags & EE_ADDR1)addrlen = 1;else if (chip.flags & EE_ADDR2)addrlen = 2;else if (chip.flags & EE_ADDR3)addrlen = 3;else {dev_dbg(&spi->dev, "unsupported address type\n");return -EINVAL;}
  1. 通过发送AT25_RDSR指令读取EEPROM的状态寄存器。如果读取失败或状态寄存器中的AT25_SR_nRDY位为1,表示EEPROM不可用,返回错误码-ENXIO
	/* Ping the chip ... the status register is pretty portable,* unlike probing manufacturer IDs.  We do expect that system* firmware didn't write it in the past few milliseconds!*/sr = spi_w8r8(spi, AT25_RDSR);if (sr < 0 || sr & AT25_SR_nRDY) {dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr);return -ENXIO;}
  1. 使用devm_kzalloc函数为at25_data结构体分配内存,并使用GFP_KERNEL标志指定内存分配的上下文。初始化互斥锁at25->lock,用于保护共享资源的访问。将chip结构体和spi设备保存在at25_data结构体中。使用spi_set_drvdata函数将at25_data结构体指针存储在spi设备的私有数据中,以便在后续的函数中可以方便地访问。将地址长度addrlen保存在at25_data结构体的addrlen字段中。
	at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);if (!at25)return -ENOMEM;mutex_init(&at25->lock);at25->chip = chip;at25->spi = spi_dev_get(spi);spi_set_drvdata(spi, at25);at25->addrlen = addrlen;
  1. 创建应用层用来操作的文件,使用sysfs_bin_attr_init函数初始化at25->bin成员变量,其中at25->binstruct bin_attribute类型的变量。设置at25->bin的属性名称为"eeprom",访问权限为用户只读模式(S_IRUSR)。设置at25->bin的读回调函数为at25_bin_read,写回调函数为at25_bin_write
	sysfs_bin_attr_init(&at25->bin);at25->bin.attr.name = "eeprom";at25->bin.attr.mode = S_IRUSR;at25->bin.read = at25_bin_read;at25->mem.read = at25_mem_read;
  1. 根据chip的只读标志位(EE_READONLY),确定是否将写回调函数和写权限添加到at25->bin
	at25->bin.size = at25->chip.byte_len;if (!(chip.flags & EE_READONLY)) {at25->bin.write = at25_bin_write;at25->bin.attr.mode |= S_IWUSR;at25->mem.write = at25_mem_write;}
  1. 使用sysfs_create_bin_file函数将at25->bin添加到SPI设备的内核对象(spi->dev.kobj)中,以便将EEPROM字节通过sysfs导出。
	err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);if (err)return err;
  1. 如果chipsetup字段不为空,将调用chip.setup函数,并将at25->memchip.context作为参数传递。使用dev_info函数打印一条设备信息消息,包括EEPROM的大小、名称、是否只读以及页面大小。
if (chip.setup)chip.setup(&at25->mem, chip.context);dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",(at25->bin.size < 1024)? at25->bin.size: (at25->bin.size / 1024),(at25->bin.size < 1024) ? "Byte" : "KByte",at25->chip.name,(chip.flags & EE_READONLY) ? " (readonly)" : "",at25->chip.page_size);

该代码的功能是在SPI设备上探测并初始化一个EEPROM芯片,然后将EEPROM的字节通过sysfs导出,以便其他内核代码或用户空间程序可以方便地访问和操作EEPROM数据。

spi核心层的实现

主要看spi.c文件:

static int __init spi_init(void)postcore_initcall(spi_init); 

从这里可以知道spi_init的调用(也就是spi核心层的初始化)是在驱动加载前的。

调用kmalloc函数为SPI子系统分配一个大小为SPI_BUFSIZ的内核内存缓冲区,并将返回的指针赋值给buf

buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {status = -ENOMEM;goto err0;
}

调用bus_register函数注册SPI总线类型,将其添加到系统总线列表中。如果注册失败,将status设置为返回的错误码,并跳转到err1标签处进行错误处理。

status = bus_register(&spi_bus_type);
if (status < 0)goto err1;

调用class_register函数注册SPI主控制器类,将其添加到系统设备类列表中。如果注册失败,将status设置为返回的错误码,并跳转到err2标签处进行错误处理。

status = class_register(&spi_master_class);
if (status < 0)goto err2;

所有注册到核心层的spi控制器都属于这个class。

相关文章:

【驱动】SPI驱动分析(六)-RK SPI驱动分析

前言 Linux的spi接口驱动实现目录在kernel\drivers\spi下。这个目录和一些层次比较明显的驱动目录布局不同&#xff0c;全放在这个文件夹下&#xff0c;因此还是只好通过看Kconfig 和 Makefile来找找思路 先看Makefile&#xff0c;里面关键几行&#xff1a; obj-$(CONFIG_SPI…...

【Linux】基础IO--文件基础知识/文件操作/文件描述符

文章目录 一、文件相关基础知识二、文件操作1.C语言文件操作2.操作系统文件操作2.1 比特位传递选项2.2 文件相关系统调用2.3 文件操作接口的使用 三、文件描述符fd1.什么是文件描述符2.文件描述符的分配规则 一、文件相关基础知识 我们对文件有如下的认识&#xff1a; 1.文件 …...

Intellij IDEA 的安装和使用以及配置

IDE有很多种&#xff0c;常见的Eclipse、MyEclipse、Intellij IDEA、JBuilder、NetBeans等。但是这些IDE中目前比较火的是Intellij IDEA&#xff08;以下简称IDEA&#xff09;&#xff0c;被众多Java程序员视为最好用的Java集成开发环境&#xff0c;今天的主题就是IDEA为开发工…...

Zynq-Linux移植学习笔记之67- 国产ZYNQ上通过GPIO模拟MDC/MDIO协议

1、背景介绍 模块上有9个PHY&#xff0c;其中两个PHY通过ZYNQ PS端的MDIO总线连接&#xff0c;其余7个PHY单独通过GPIO进行控制&#xff0c;需要实现GPIO模拟MDC/MDIO协议。 2、vivado工程设计 vivado工程内为每个PHY建立两个GPIO IP核&#xff0c;分别用来代表MDC和MDIO&…...

Zookeeper(一)在WSL单机搭建Zookeeper伪集群

目录 Zookeeper1 启动单个Zookeeper实例1.1 下载Zookeeper安装包并解压1.2 添加环境变量1.3 修改默认配置1.4 新建数据存储目录和日志目录1.5 启动Zookeeper1.6 停止Zookeeper 2 搭建Zookeeper集群2.1 新建集群目录2.2 配置环境变量2.3 创建节点目录2.4 修改配置2.5 创建节点ID…...

QT(18):QString

目录 QStringQTypedArrayDataQTypedArrayDataQLatin1StringQStringLiteral乱码 QStringRef QString QString 存储16位QChar的字符串&#xff0c;其中每个QChar对应一个 UTF-16代码单元。QString 使用&#xff08;写入时复制copy-on-write&#xff09;来减少内存使用并避免不必…...

宏工科技通过CMMI三级认证,软件研发能力获国际权威认可

近日&#xff0c;宏工科技子公司湖南宏工软件成功通过CMMI三级认证并正式获得资质证书&#xff0c;斩获全球软件领域最权威的认证之一&#xff0c;标志着宏工科技在软件技术开发、研发管理、项目管理等多方面获得国际权威认证。 CMMI全称是Capability Maturity Model Integrati…...

2次MD5加密——用于分布式对话

用户端 &#xff1a; 指发起请求并与服务器进行交互的终端设备或应用程序。它可以是电脑、智能手机等。 用户端负责发送请求给服务端&#xff0c;并接收和处理服务端返回的响应。 服务端 &#xff1a; 是指提供服务、接收和处理用户端请求的计算机系统或应用程序。 它监听来自用…...

用Java制作简易版的王者荣耀

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import j…...

android 保活的一种有效的方法

android 保活的一种有效的方法 为什么要保活 说起程序的保活&#xff0c;其实很多人都觉得&#xff0c;要在手机上进行保活&#xff0c;确实是想做一些小动作&#xff0c;其实有些正常的场景也是需要我们进行保活的&#xff0c;这样可以增强我们的用户体验。保活就是使得程序…...

kibana安装

kibana安装下载注意事项 地址&#xff1a;curl -O https://artifacts.elastic.co/downloads/kibana/kibana-7.16.3-linux-x86_64.tar.gz 下载后直接解压启动即可 1. 但需要使用非root用户启动 &#xff0c;root用户启动会报错 2. kibana需要和elasticsearch版本一致 不然…...

LV.12 D19 ADC实验 学习笔记

一、ADC简介 1.1 ADC ADC(Analog to Digital Converter)即模数转换器&#xff0c;指一个能将模拟信号转化为数字信号的电子元件 1.2 ADC主要参数 分辨率 ADC的分辨率一般以输出二进制数的位数来表示&#xff0c;当最大输入电压一定时&#xff0c;位数越高&#xff0c…...

ubuntu配置免密登录vscode

1、配置免密登录 &#xff08;1&#xff09;在windows系统cmd下运行命令 ssh-keygen 一路回车&#xff0c;将会在C:\Users\用户名\.ssh目录下生成两个文件&#xff1a;id_rsa和id_rsa.pub。如下图所示。 &#xff08;2&#xff09;进入.ssh目录。如果想使用root用户&#xff0…...

软件工程--面向对象分析用通俗语言20小时爆肝总结!(包含用例图、活动图、类图、时序图......)

面向对象方法分为面向对象分析&#xff08;OOA&#xff09;、面向对象设计&#xff08;OOD&#xff09;、面向对象编程&#xff08;OOP&#xff09;&#xff0c;本文详细介绍面向对象分析 本文参考教材&#xff1a;沈备军老师的《软件工程原理》大多图片来源其中 目录 面向对…...

HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙专栏-11】

文章目录 ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化@Observed 类装饰器说明装饰器参数类装饰器的使用@ObjectLink 变量装饰器说明装饰器参数同步类型允许装饰的变量类型被装饰变量的初始值举例装饰器的限制条件观察变化和行为表现观察的变化框架行为使用场景1.…...

网络通信安全的坚固防线双向认证技术详解

目录 什么是双向认证 双向认证的工作原理 双向认证的实现方式 双向认证的重要性 双向认证的挑战 安全最佳实践 小结 什么是双向认证 双向认证&#xff0c;又称为双向身份验证或双向鉴别&#xff0c;是一种在通信双方之间建立信任关系的安全机制。在通信过程中&#xff0…...

Appium+python+unittest搭建UI自动化框架

阅读本小节&#xff0c;需要读者具备如下前提条件&#xff1a; 1. 掌握一种编程语言基础&#xff0c;如java、python等。 2. 掌握一种单元测试框架&#xff0c;如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架&#xff0c;移动端APP测试框架…...

使用paddledetection的记录

首先在这里使用的是是paddle--detection2.7的版本。 成功进行训练 目录&#xff1a; 目录 数据集准备 配置文件的修改 使用的是BML的平台工具&#xff1a; !python -m pip install paddlepaddle-gpu2.5 -i https://mirror.baidu.com/pypi/simple --user %cd /home/aistudio…...

MySQL数据库的备份与恢复

在管理MySQL数据库时&#xff0c;备份和恢复是保证数据安全和完整性的关键环节。本文将指导您如何有效地备份MySQL数据库&#xff0c;并在需要时进行数据恢复。 请注意&#xff0c;如果没有 mysql> 的标志&#xff0c;说明我们是在外面终端进行的操作 创建备份文件路径 在…...

Pycharm配置jupyter使用notebook详细指南(可换行conda环节)

本教程为事后记录&#xff0c;部分图片非实操图片。 详细记录了pycharm配置jupyter的方法&#xff0c;jupyter添加其他conda环境的方法&#xff0c;远程密码调用jupyter的方法&#xff0c;修改jupyter工作目录的方法。 文章目录 一、入门级配置1. Pycharm配置Conda自带的jupyt…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...