<Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

news2024/12/22 14:29:14

<Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

交叉编译环境搭建:
<Linux开发> linux开发工具-之-交叉编译环境搭建

uboot移植可参考以下:
<Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分)
<Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分)
<Linux开发> -之-系统移植 uboot移植过程详细记录(第三部分)(uboot移植完结)

Linux内核及设备树移植可参考以下:
<Linux开发>系统移植 -之- linux内核移植过程详细记录(第一部分)
<Linux开发>系统移植 -之- linux内核移植过程详细记录(第二部分完结)

Linux文件系统构建移植参考以下:
<Linux开发>系统移植 -之- linux构建BusyBox根文件系统及移植过程详细记录
<Linux开发>系统移植 -之-使用buildroot构建BusyBox根文件系统

Linux驱动开发参考以下:
<Linux开发>驱动开发 -之-pinctrl子系统
<Linux开发>驱动开发 -之-gpio子系统
<Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的LED驱动

以下实验基于上述uboot和kernel系统移植,以及buildroot构建的BusyBox根文件系统。

一、前言

本文主要讲解基于pinctrl子系统和gpio子系统的前提下,编写beep驱动,并编写测试app测试beep的控制。

二、新增beep设备节点

参考-<Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的LED驱动的讲解,笔者使用的开发板上beep连接的是SNVS_TAMPER1这个io引脚,如下图:
在这里插入图片描述

在这里插入图片描述

可以在设备树中添加如下内容;
pinctrl节点添加如下:

路径:arch/arm/boot/dts/imx6ull-water-emmc.dts
pinctrl_beep: beepgrp {
			fsl,pins =01
				MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0
			>;
		};

在这里插入图片描述

可以看到pinctrl_beep节点是在iomuxc节点下的。

beep设备节点添加如下:

路径:arch/arm/boot/dts/imx6ull-water-emmc.dts
beep{
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "water-beep";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_beep>;
		beep-gpio= <&gpio5 1 GPIO_ACTIVE_HIGH>;
		status = "okay";
	}

在这里插入图片描述
注意各属性命名,后续beep驱动中会使用对应的属性名。。。。。

新增beep 节点和gpioled节点一样都是在/节点下的。

添加完上述两个节点后,重新编译设备树“make dtbs”,然后用新生成的dtb文件启动kernel,在设备的/sys/firmware/devicetree/base/目录下有如下:
在这里插入图片描述
在这里插入图片描述

新增beep节点完成,后面编写驱动和app来测试验证这个beep设备。

三、编写驱动

3.1 编写led驱动 模块挂载

编译单独的ko文件,然后动态挂载设备。
使用vscode新建一个工程;
(1)新建目录beep
在这里插入图片描述
(2)使用vscode打开beep目录
在这里插入图片描述
(3)新建beep.c
在这里插入图片描述
(4) 在beep.c中输入驱动代码

/***************************************************************
Copyright © OneFu Co., Ltd. 2018-2023. All rights reserved.
文件名 : beep.c
作者 : water
版本 : V1.0
描述 : 采用 pinctrl 和 gpio 子系统驱动 beep蜂鸣器。
其他 : 无
日志 : 初版 V1.0 2023/05/28 water创建
***************************************************************/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define BEEP_CNT 1              /* 设备号个数 */
#define BEEP_NAME "beep"        /* 名字 */
#define BEEPOFF 0                /* 关beep */
#define BEEPON 1                 /* 开beeo */

/* beep 设备结构体 */
struct beep_dev{
    dev_t devid;            /* 设备号 */
    struct cdev cdev;       /* cdev */
    struct class *class;    /* 类 */
    struct device *device;  /* 设备 */
    int major;              /* 主设备号 */
    int minor;              /* 次设备号 */
    struct device_node *nd; /* 设备节点 */
    int beep_gpio;           /* beep 所使用的 GPIO 编号 */
};
 
struct beep_dev beep; /* beep 设备 */

/*
* @description : 打开设备
* @param – inode : 传递给驱动的 inode
* @param – filp : 设备文件,file 结构体有个叫做 private_data 的成员变量
* 一般在 open 的时候将 private_data 指向设备结构体。
* @return : 0 成功;其他 失败
*/
static int beep_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &beep; /* 设置私有数据 */
    return 0;
}

/*
* @description : 从设备读取数据
* @param – filp : 要打开的设备文件(文件描述符)
* @param - buf : 返回给用户空间的数据缓冲区
* @param - cnt : 要读取的数据长度
* @param – offt : 相对于文件首地址的偏移
* @return : 读取的字节数,如果为负值,表示读取失败
*/
static ssize_t beep_read(struct file *filp, char __user *buf,
                        size_t cnt, loff_t *offt)
{
    return 0;
}
 
/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param – offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t beep_write(struct file *filp, const char __user *buf,
                            size_t cnt, loff_t *offt)
{
    int retvalue;
    unsigned char databuf[1];
    unsigned char beepstat;
    struct beep_dev *dev = filp->private_data;

    retvalue = copy_from_user(databuf, buf, cnt);
    if(retvalue < 0) {
        printk("kernel write failed!\r\n");
        return -EFAULT;
    }

    beepstat = databuf[0]; /* 获取状态值 */

    if(beepstat == BEEPON) { 
        gpio_set_value(dev->beep_gpio, 0); /* 打开 beep */
    } else if(beepstat == BEEPOFF) {
        gpio_set_value(dev->beep_gpio, 1); /* 关闭 beep */
    }
    return 0;
}

/*
* @description : 关闭/释放设备
* @param – filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int beep_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/* 设备操作函数 */
static struct file_operations beep_fops = {
    .owner = THIS_MODULE,
    .open = beep_open,
    .read = beep_read,
    .write = beep_write,
    .release = beep_release,
};

/*
* @description : 驱动入口函数
* @param : 无
* @return : 无
*/
static int __init water_beep_init(void)
{
    int ret = 0;

    /* 设置 beep 所使用的 GPIO */
    /* 1、获取设备节点: beep */
    beep.nd = of_find_node_by_path("/beep");
    if(beep.nd == NULL) {
        printk("beep node cant not found!\r\n");
        return -EINVAL;
    } else {
        printk("beep node has been found!\r\n");
    }

    /* 2、 获取设备树中的 gpio 属性,得到 LED 所使用的 LED 编号 */
    beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpio", 0);
    if(beep.beep_gpio < 0) {
        printk("can't get beep-gpio");
        return -EINVAL;
    }
    printk("beep num = %d\r\n", beep.beep_gpio);

    /* 3、设置 GPIO5_IO01 为输出,并且输出高电平,默认关闭 beep */
    ret = gpio_direction_output(beep.beep_gpio, 1);
    if(ret < 0) {
        printk("can't set gpio!\r\n");
    }

    /* 注册字符设备驱动 */
    /* 1、创建设备号 */
    if (beep.major) { /* 定义了设备号 */
        beep.devid = MKDEV(beep.major, 0);
        register_chrdev_region(beep.devid, BEEP_CNT,
                                    BEEP_NAME);
    } else { /* 没有定义设备号 */
        alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, 
                                    BEEP_NAME); /* 申请设备号 */
        beep.major = MAJOR(beep.devid); /* 获取分配号的主设备号 */
        beep.minor = MINOR(beep.devid); /* 获取分配号的次设备号 */
    }
    printk("beep major=%d,minor=%d\r\n",beep.major,
                                    beep.minor); 

    /* 2、初始化 cdev */
    beep.cdev.owner = THIS_MODULE;
    cdev_init(&beep.cdev, &beep_fops);

    /* 3、添加一个 cdev */
    cdev_add(&beep.cdev, beep.devid, BEEP_CNT);

    /* 4、创建类 */
    beep.class = class_create(THIS_MODULE, BEEP_NAME);
    if (IS_ERR(beep.class)) {
    return PTR_ERR(beep.class);
    }

    /* 5、创建设备 */
    beep.device = device_create(beep.class, NULL,
                            beep.devid, NULL, BEEP_NAME);
    if (IS_ERR(beep.device)) {
        return PTR_ERR(beep.device);
    }
    return 0;
}

/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit water_beep_exit(void)
{
    /* 注销字符设备驱动 */
    cdev_del(&beep.cdev); /* 删除 cdev */
    unregister_chrdev_region(beep.devid, BEEP_CNT); /* 注销 */

    device_destroy(beep.class, beep.devid);
    class_destroy(beep.class);
}

module_init(water_beep_init);
module_exit(water_beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("water");

(5) 配置linux头文件
同时按下ctrl+shitf+P,显示如下:
在这里插入图片描述
选择“c/c++:编辑配置(JSON)”,添加linux的头文件,注意是绝对路径,内容如下:

 "/home/water/imax/NXP/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/include",
                "/home/water/imax/NXP/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include",
                "/home/water/imax/NXP/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/generated/"

在这里插入图片描述
(6) 编写Makefile

ARCH=arm 
CROSS_COMPILE=arm-linux-gnueabihf-

KERNELDIR := /home/water/imax/NXP/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/
CURRENT_PATH := $(shell pwd)
obj-m := beep.o

KBUILD_CFLAGS += -fno-pie

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean


在这里插入图片描述
(7) 编译

make

编译成功如下:
在这里插入图片描述
在这里插入图片描述

出现一下错误,,新增:

ARCH=arm 
CROSS_COMPILE=arm-linux-gnueabihf-
KBUILD_CFLAGS += -fno-pie

在这里插入图片描述 出现以下错误,需将kernel内核顶级目录的Makefile下修改下面句子:
在这里插入图片描述
路径:/home/water/imax/NXP/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/Makefile.
读者更具自己的kernel路径修改…
原:

ARCH		?= $(SUBARCH)
CROSS_COMPILE	?= $(CONFIG_CROSS_COMPILE:"%"=%)

改:

 ARCH		?= arm
CROSS_COMPILE	?= arm-linux-gnueabihf-

(8) 放到设备中挂载
在文件系统中新建文件夹,如下:

mkdir -p /home/water/imax/nfs/buildrootfs/lib/modules/4.1.15+

将前面编译的ko驱动文件放到4.1.15+目录

cp beep.ko  /home/water/imax/nfs/buildrootfs/lib/modules/4.1.15+

在这里插入图片描述

使用depmod命令提示下列错误:
在这里插入图片描述
原因:作者使用buildroot构建busybox时没有是能depmod,
解决方法:重新buildroot构建busybox使能depmod.
buildroot构建参考:<Linux开发>系统移植 -之-使用buildroot构建BusyBox根文件系统
进入buildroot目录下,运行:
sudo make busybox-menuconfig 在这里插入图片描述
在这里插入图片描述
重新编译:

sudo make FORCE_UNSAFE_CONFIGURE=1

替换原根文件系统:(记得先保留/root/water_soft/,否则会被删掉 之前开发的内容)

sudo rm -r buildrootfs
mkdir  buildrootfs
cd buildrootfs
cp ../../NXP/buildroot/buildroot-2020.05/output/images/rootfs.tar  .
tar -vxf rootfs.tar
sudo rm rootfs.tar

重新运行depmod
在这里插入图片描述
又发生错误,我们新建这个/lib/modules/4.1.15+目录即可:

mkdir -p  /libmodules/4.1.15+

在这里插入图片描述
新曾的beep.ko文件需要放到/lib/modules/4.1.15+目录下,然后在/lib/modules/4.1.15+下在运行:

depmod

运行之后在同级目录下的 modules.dep文件会有文件记录,如下:

# cat modules.dep 
beep.ko:

挂载驱动:

modprobe beep.ko 

在这里插入图片描述
上述就是动态挂载的过程,正常挂载beep设备,并获取了对应的设备号等信息。

3.2 beep驱动并入内核一起编译

由于kernel没有专门针对beep的驱动,那么我们讲究将beep设备放到led的驱动目录下吧。
新建文件:drivers/leds/beep-water.c
在beep-water.c输入以下内容:

驱动内容与3.1节的驱动内容保持一致。

3.3 添加makefile编译项

在drivers/leds/leds-water.c同级目录下找到Makefile文件,添加一下内容:

路径:drivers/leds/Makefile
obj-$(CONFIG_BEEP_WATER)			+= beep-water.o

在这里插入图片描述

3.4 添加menuconfig选项

在3.3节中,我们把驱动添加进Kernel了,那怎么样才能编译这个驱动呢?我们添加的Makefile内容中有CONFIG_BEEP_WATER 这个宏,只要这个宏为true那么就会编译beep-water.o所对于的beep-water.c文件了。
在Kconfig文件末尾添加如下内容:

路径:drivers/leds/Kconfig
config BEEP_WATER
	tristate "beep support for water imax6ull board"
	help
	  This option enables support for the imax water beep.

添加完上述内容保存后,就可以通过“make menuconfig”来配置使用这个led驱动了。

3.5 使用menuconfig配置驱动

在kernel跟目录运行“make menuconfig”后,如下步骤配置;
(1) 选择 “Device Drivers —>”
在这里插入图片描述
(2) 选择 “LED Support —>”
在这里插入图片描述
(3) 选择 “beep Support for water imax6ull board —>”
在这里插入图片描述

选中之后按“Y”,在行前的尖括号里会出现*,表示编译进内核;然后用键盘左右键选择"Save",保存配置;保存的路径使用默认的路径,如下,然后OK即可。
在这里插入图片描述
配置完驱动编译,重新编译kernel,然后使用新的kernel启动。

四、编写测试beep的app

在ubuntu下新建目录:/home/water/imax/soft/beep,并新建文件beep_water_app.c,然后输入一下内容:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

/*************************************************************** 
 * Copyright © onefu Co., Ltd. 2019-2023. All rights reserved. 
 * 文件名 : beep_water_app.c 
 * 作者 : water 
 * 版本 : V1.0 
 * 描述 : beep 驱测试APP。 
 * 其他 : 使用方法:./beep_water_app /dev/beep <1>|<2>
 *                argv[2] 0:关闭beep
 *                argv[2] 1:打开beep
 * 日志 : 初版V1.0 2023/05/28 water创建 
 * ***************************************************************/ 

#define BEEPOFF 0
#define BEEPON  1

/* 
* @description : main主程序 
* @param - argc : argv数组元素个数 
* @param - argv : 具体参数 
* @return : 0 成功;其他 失败 
*/ 
int main(int argc, char *argv[])
{
    int fd, retvalue;               //fd: 文件描述符 用以对文件操作    retvalue:存放函数操作后的返回值
    char *filename;                 //filename:文件名,有主函数参数传入赋值
    unsigned char databuf[1];       //定义的buf,用来读写数据用 

    if(argc != 3){                  //判断主函数传入的函数的参数的个数
        printf("Error Usage!\r\n");
        return -1;
    }

    filename = argv[1];              //获取第1个参数,存放的是文件的路径(即要操作的设备文件路径)
    
    fd = open(filename,O_RDWR);                         /*打开驱动文件*/
    if(fd < 0){
        printf("Can't open file %s\r\n",filename);      /*打开失败,输出提示*/
        return -1;
    }

    databuf[0] = atoi(argv[2]);                         /* 要执行的操作:打开或关闭 */

    retvalue = write(fd, databuf, sizeof(databuf));     /*向设备驱动写入数据*/
    if(retvalue < 0){
        printf("BEEP Control Failed!\r\n",filename);     /*写入错误输出提示*/
    }

    retvalue = close(fd);                               /*关闭文件*/
    if(retvalue < 0){
        printf("Can't close file %s\r\n",filename);     /*关闭错误输出提示*/
        return -1;
    }

    return 0;
}
//编译指令: arm-linux-gnueabihf-gcc  beep_water_app.c  -o  beep_water_app

编译app:

 arm-linux-gnueabihf-gcc  beep_water_app.c  -o  beep_water_app

在这里插入图片描述

五、运行测试

将编译生成的 beep_water_app 执行文件拷贝到文件系统的/root/water_soft/beep/目录下:
在这里插入图片描述

在Securecrt终端运行如下命令:

 cd /root/water_soft/beep/
./beep_water_app  /dev/beep  1

在这里插入图片描述

运行之后,即可观看开发板beep状态为开。
如果是./beep_water_app /dev/beep 0则beep为关。
作者实际现象是正常开关的,读者可以自行测试自己的开发板。

六、总结

我们结合pinctrl子系统和gpio子系统,完成了beep的驱动开发,开发beep蜂鸣器的驱动,其原理与led是一样的,都是通过控制gpio引脚输出高低电平来控制设备的。

先通过控制简单的led、beep等设备,熟悉掌握pinctrl子系统和gpio子系统,后面我们在深入开发比较复杂的驱动。

一步一脚印,法路自然成。

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

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

相关文章

如何在华为OD机试中获得满分?Java实现【人民币转换】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

认识Servlet---1

hi ,大家好,今天为大家带来Servlet相关的知识,并且实现第一个程序 &#x1f389;1.什么是Servlet &#x1f389;2.使用Servlet写一个hello程序 &#x1f33b;&#x1f33b;&#x1f33b;1.创建项目 &#x1f33b;&#x1f33b;&#x1f33b;2.引入依赖 &#x1f33b;&…

GitHub基本概念

创建日期: 2018-09-22 09:50:06 Git & GitHub Git是一个版本控制软件&#xff1a; 读作[gɪt] ,拼音读作gē y te。 Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed an…

STM32之温湿度LCD显示并上传服务器

目录 项目需求 项目框图 硬件清单 LCD1602介绍及实战 硬件接线 引脚封装 代码实现 DHT11介绍及实战 硬件接线 引脚封装 代码实现 项目设计及实现 项目设计 项目实现 项目需求 使用温湿度传感器模块&#xff08; DHT11 &#xff09;获取温度及湿度&#xff0c…

推荐计算机领域的几本入门书籍

人工智能入门&#xff1a; 人工智能&#xff1a;现代方法&#xff08;第4版&#xff09;揭示AI与chatgpt的奥秘&#xff0c;详解人工智能的发展与未来&#xff01; 推荐理由&#xff1a;系统性总结人工智能的方方面面&#xff0c;国际人工智能领域专家斯图尔特罗素撰写人工智能…

YOLO-NAS对象检测算法再一次颠覆YOLO系列算法——已超越YOLOv8

对象检测彻底改变了机器感知和解释人类世界的方式。这是计算机视觉中一项特别关键的任务,使机器能够识别和定位图像或视频中的物体。如自动驾驶汽车、面部识别系统等。推动对象检测进步的一个关键因素是发明了神经网络架构。强大的神经网络推动了对象检测的进步,增强了计算机…

Meta Learning

Meta Learning&#xff08;元学习&#xff09;是一种机器学习技术&#xff0c;它的核心思想是学习如何学习。 Meta Learning的目标是从以前的学习经验中学习到通用的学习策略和模式&#xff0c;以便在新的任务上快速适应和学习。 Meta Learning的核心思想是将学习任务视为元任…

Vivado下阻塞赋值和非阻塞赋值的对比

Verilog 基础知识 中已经介绍过了阻塞赋值和非阻塞赋值的区别&#xff0c;下面通过一个在Vivado中的简单例子来直观的反映两者的不同。 首先给出设计源代码如下。 module block(a,b,c,clk,x);input x;input clk;output reg a,b,c;always(posedge clk) begina x; //阻塞赋值…

零钱兑换,凑零钱问题,从暴力递归到动态规划(java)

凑零钱问题&#xff0c;从暴力递归到动态规划 leetcode 322 题 零钱兑换暴力递归&#xff08;这个会超时&#xff0c;leetcode 跑不过去&#xff09;递归缓存 leetcode 322 题 零钱兑换 322 零钱兑换 - 可以打开链接测试 给你一个整数数组 coins &#xff0c;表示不同面额的硬…

[MAUI]模仿Chrome下拉标签页的交互实现

文章目录 创建粘滞效果的圆控件贝塞尔曲线绘制圆创建控件创建形变可控形变形变边界形变动画 创建手势控件创建页面布局更新拖拽物位置其它细节 项目地址 今天来说说怎样在 .NET MAUI 中制作一个灵动的类标签页控件&#xff0c;这类控件常用于页面中多个子页面的导航功能。 比如…

《数据库应用系统实践》------ 公园游客日流量管理系统

系列文章 《数据库应用系统实践》------ 公园游客日流量管理系统 文章目录 系列文章一、需求分析1、系统背景2、 系统功能结构&#xff08;需包含功能结构框图和模块说明&#xff09;3&#xff0e;系统功能简介 二、概念模型设计1&#xff0e;基本要素&#xff08;符号介绍说明…

【阅读笔记】概率预测之MQ-RNN(含Pytorch代码实现)

本文作为自己阅读论文后的总结和思考&#xff0c;不涉及论文翻译和模型解读&#xff0c;适合大家阅读完论文后交流想法&#xff0c;关于论文翻译可以查看参考文献。论文地址&#xff1a;https://arxiv.org/abs/1711.11053 MQ-RNN 一. 全文总结二. 研究方法三. 结论四. 创新点五…

谷歌推出免费AI编程神器Colab,欲将Copilot拉下神坛

在如今的AI编码工具领域&#xff0c;微软旗下的Github Copilot可以算得上是一家独大&#xff0c;而作为老对手的谷歌显然并不愿屈服于此。 近日&#xff0c;谷歌通过其官网高调发文宣布&#xff0c;将为研发工具Google Colaboratory&#xff08;Colab&#xff09;加入全新的AI…

DAY 68 redis高可用的主从复制、哨兵、cluster集群

Redis 高可用 什么是高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供正常服…

RT-Thread memheap 开启多块 SRAM的方法

验证环境 NUCLEO-L476RG 开发板&#xff0c;板载 STM32L476RGT6&#xff08;96K SARM1 32K SRAM2&#xff09; Win10 64 位 Keil MDK 5.36 RT-Thread 5.0.1 版本&#xff08;2023-05-28 master 主线&#xff09; 功能描述 最近在研究 RT-Thread 内存的管理&#xff0c;熟…

Linux内核源码分析 2:Linux内核版本号和源码目录结构

一、Linux的版本 1. 稳定版和开发版 Linux内核主要分为两种版本&#xff1a; 稳定版&#xff08;长期支持版&#xff09;&#xff1a;稳定版的内核具有工业级的强度&#xff0c;可以广泛地应用和部署。而每一代新推出的稳定版内核大部分都只是修正了一些Bug或是加入了一些新的…

【网络协议详解】——FTP系统协议(学习笔记)

目录 &#x1f552; 1. 概述&#x1f552; 2. 工作原理&#x1f558; 2.1 两个连接 &#x1f552; 3. 相关命令与处理&#x1f558; 3.1 接入命令&#x1f558; 3.2 文件管理命令&#x1f558; 3.3 数据格式化命令&#x1f558; 3.4 端口定义命令&#x1f558; 3.5 文件传输命令…

计算机组成原理 期末复习笔记

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 第一章 计算机系统概论计算机软件的发展 计算机硬件的基本组成 计算机系统的层次结构 计算机的性能指标 第二章 数据表示 与 第三章 数据运算与运…

Go语言实现JDBC

Go语言操作数据库 Go语言提供了关于数据库的操作,包下有sql/driver 该包用来定义操作数据库的接口&#xff0c;这保证了无论使用哪种数据库&#xff0c;操作方式都是相同的; 准备工作: 下载驱动 需要在代码所在文件夹下执行相应的命令 go get github.com/go-sql-driver/mys…

DAY 69 rsync远程同步

rsync介绍 rsync简介 rsync&#xff08;Remote Sync&#xff0c;远程同步&#xff09;是一个开源的快速备份工具&#xff0c;可以在不同主机之间镜像同步整个目录树&#xff0c;支持增量备份&#xff0c;并保持链接和权限&#xff0c;且采用优化的同步算法&#xff0c;传输前…