linux的lcd屏幕调试

news2024/12/24 21:21:35

x2600-lcd的sat101cp50d24b1屏幕的驱动调试

1.硬件关联

屏幕型号:sat101cp50d24b1

原理图:

很显然,这是RGB666显示格式的屏幕,RGB管脚DATA0-DATA17--为数据线

DEN 数据使能线。
VSYNC 垂直同步信号线。
HSYNC 水平同步信号线。
PCLK 像素时钟信号线。
DEN VSYNC 、 HSYNC 和 PCLK 这四根是控制信号线;
RGB LCD 一般有两种驱动模式: DE 模式和 HV 模式,
这两个模式的区别是 DE 模式需要用到 DEN  信号线,而 HV 模式不需要用到 DEN  信号线,在 DE 模式下是可以不需要 HSYNC 信号线的,即使不接 HSYNC 信号线 LCD 也可以正常工作。

2.dts设备树配置 

RGB_LCD_SAT101CP50D24B1.dtsi的内容如下 

"DPU"的设备,通常指的是负责图像处理和输出到显示面板的硬件单元。
•status = "okay" 表示该设备应当被初始化并启用。
•ingenic,disable-rdma-fb = <1> 可能指禁用RDMA(Remote Direct Memory Access)帧缓冲功能。
•ingenic,rot_angle = <0> 设置初始旋转角度为0度。
•ingenic,layer-exported, layer-frames, layer-framesize 等属性配置了图层的导出状态、帧缓存数量和最大帧尺寸等,表明DPU支持多图层渲染和管理。
•memory-region = <&reserved_memory> 指定了DPU使用的内存区域。
•port 部分定义了与面板之间的连接端点,用于视频数据传输 

&dpu {
	status = "okay";
	ingenic,disable-rdma-fb = <1>;
	ingenic,rot_angle = <0>;
	//Defines the init state of composer fb export infomations.
	ingenic,layer-exported = <1 0 0 0>;
	ingenic,layer-frames   = <2 2 2 2>;
	ingenic,layer-framesize = <1024 600>, <1024 600>, <1024 600>, <1024 600>;   //Max framesize for each layer.
	layer,color_mode        = <0 0 0 0>;                                        //src fmt,
	layer,src-size          = <1024 600>, <1024 600>, <1024 600>, <1024 600>;   //Layer src size should smaller than framesize
    layer,target-size       = <1024 600>, <1024 600>, <1024 600>, <1024 600>;   //Target Size should smaller than src_size.
	layer,target-pos        = <0 0>, <0 0>, <0 0>, <0 0>;                       //target pos , the start point of the target panel.
	layer,enable            = <1 0 0 0>;                                        //layer enabled or disabled.
	ingenic,logo-pan-layer  = <0>;                                              //on which layer should init logo pan on.
	memory-region=<&reserved_memory>;
	port {
		dpu_out_ep: endpoint {
		    remote-endpoint = <&panel_sat101cp50d24b1_ep>;
	    };
	};
};

/ {
	display-dbi {
		compatible = "simple-bus";
		#interrupt-cells = <1>;
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <>;
		panel_sat101cp50d24b1 {
			compatible = "ingenic,sat101cp50d24b1-rgb";
			status = "okay";
			pinctrl-names = "default";
			pinctrl-0 = <&tft_lcd_pb_18bit>;
			ingenic,vdd-en-gpio = <&gpc 28 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
			/*ingenic,lcd-pwm-gpio = <&gpc 11 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;*/
			port {
				panel_sat101cp50d24b1_ep: endpoint {
					remote-endpoint = <&dpu_out_ep>;
				};
			};
		};
	};

	backlight {
		compatible = "pwm-backlight";
	        pinctrl-names = "default";
	        pinctrl-0 = <&pwm12_pc>;
		pwms = <&pwm 12 1000000>; /* arg1: pwm channel id [0~15]. arg2: period in ns. */
		brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
		default-brightness-level = <10>;
	};
};

其中,管脚定义:

3. dts和设备驱动的匹配关联

屏幕面板的适配关键词是:compatible = "ingenic,sat101cp50d24b1-rgb";
编写的驱动代码:
static const struct of_device_id panel_of_match[] = {
    { .compatible = "ingenic,sat101cp50d24b1-bgr", .data = (struct tft_config *)&sat101cp50d24b1_bgr_cfg, },
    { .compatible = "ingenic,sat101cp50d24b1-rgb", .data = (struct tft_config *)&sat101cp50d24b1_rgb_cfg, },
    {},
};

...........................

static struct platform_driver panel_driver = {
    .probe = panel_probe,
    .remove = panel_remove,
    .driver = {
        .name = "sat101cp50d24b1",
        .of_match_table = panel_of_match,
    },
};

当驱动和设备匹配以后 panel_probe 函数就会执行。在看 panel_probe 函数之前我们先简单了解一下 Linux 下 Framebuffer 驱动的编写流程
Linux 内核将所有的 Framebuffer 抽象为一个叫做 fb_info 的结构 体,fb_info 结构体包含了 Framebuffer 设备的完整属性和操作集合,因此每一个 Framebuffer 设 备都必须有一个 fb_info 。换言之就是, LCD 的驱动就是构建 fb_info ,并且向系统注册 fb_info 的过程。fb_info 结构体定义在 include/linux/fb.h 文件里面。
因此: panel_probe函数的主要工作内容为:
①、申请 fb_info
②、初始化 fb_info 结构体中的各个成员变量。
③、初始化 eLCDIF 控制器。
④、使用 register_framebuffer 函数向 Linux 内核注册初始化好的 fb_info。

4.完整的驱动代码

        遵循Linux内核的标准接口和编程规范的Linux驱动程序,涉及设备初始化、电源管理、GPIO控制等功能,为sat101cp50d24b1型号的LCD面板提供驱动支持:

panel_dev结构体:该结构体整合了设备信息、LCD面板信息、通用LCD框架、背光控制、电源状态以及多个GPIO控制对象(如VDD_EN、BL、RST、PWM)
panel_probe:探测并初始化LCD面板设备,注册到内核中;通过匹配设备树节点,获取相关GPIO引脚并进行初始化,注册LCD面板到内核的LCD框架中,同时处理面板的电源状态,以及可能的背光控制。

/*
 *
 * Copyright (C) 2016 Ingenic Semiconductor Inc.
 *
 * Author:zhxiao<zhihao.xiao@ingenic.com>
 *
 * This program is free software, you can redistribute it and/or modify it
 *
 * under the terms of the GNU General Public License version 2 as published by
 *
 * the Free Software Foundation.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/pwm_backlight.h>
#include <linux/delay.h>
#include <linux/lcd.h>
#include <linux/of_gpio.h>
#include <linux/fb.h>
#include <linux/backlight.h>

#include "../ingenicfb.h"
#include "../jz_dsim.h"

struct board_gpio {
	short gpio;
	short active_level;
};

struct panel_dev {
	/* ingenic frame buffer */
	struct device *dev;
	struct lcd_panel *panel;

	/* common lcd framework */
	struct lcd_device *lcd;
	struct backlight_device *backlight;
	int power;

	struct regulator *vcc;
	struct board_gpio vdd_en;
	struct board_gpio bl;
	struct board_gpio rst;
	struct board_gpio pwm;
	struct board_gpio disp;
};

static struct panel_dev *panel;

static void sat101cp50d24b1_power_on(struct lcd_panel *ppanel)
{
	struct panel_dev *panel_sat101cp50d24b1 = dev_get_drvdata(panel->dev);

	if(panel_sat101cp50d24b1->bl.gpio > 0){
		gpio_direction_output(panel_sat101cp50d24b1->bl.gpio, panel_sat101cp50d24b1->bl.active_level);
	}
	if(panel_sat101cp50d24b1->vdd_en.gpio > 0){
		gpio_direction_output(panel_sat101cp50d24b1->vdd_en.gpio, panel_sat101cp50d24b1->vdd_en.active_level);
	}
	if(panel_sat101cp50d24b1->disp.gpio > 0){
		gpio_direction_output(panel_sat101cp50d24b1->disp.gpio, panel_sat101cp50d24b1->disp.active_level);
	}
}

static void sat101cp50d24b1_power_off(struct lcd_panel *ppanel)
{
	struct panel_dev *panel_sat101cp50d24b1 = dev_get_drvdata(panel->dev);

	if(panel_sat101cp50d24b1->bl.gpio > 0){
		gpio_direction_output(panel_sat101cp50d24b1->bl.gpio, !panel_sat101cp50d24b1->bl.active_level);
	}
	if(panel_sat101cp50d24b1->vdd_en.gpio > 0){
		gpio_direction_output(panel_sat101cp50d24b1->vdd_en.gpio, !panel_sat101cp50d24b1->vdd_en.active_level);
	}
	if(panel_sat101cp50d24b1->disp.gpio > 0){
		gpio_direction_output(panel_sat101cp50d24b1->disp.gpio, !panel_sat101cp50d24b1->disp.active_level);
	}
	return;
}

static struct lcd_panel_ops sat101cp50d24b1_ops = {
	.enable  = (void*)sat101cp50d24b1_power_on,
	.disable = (void*)sat101cp50d24b1_power_off,
};

static struct fb_videomode sat_videomode[] = {
	[0] = {
		.name = "1024x600",
		.refresh = 60,
		.xres = 1024,
		.yres = 600,
		.pixclock = (51200000),//KHz

		.left_margin = 160,
		.right_margin = 160,

		.upper_margin = 23,
		.lower_margin = 12,

		.hsync_len = 70,
		.vsync_len = 10,

		.sync = ~FB_SYNC_HOR_HIGH_ACT & ~FB_SYNC_VERT_HIGH_ACT,
		.vmode = FB_VMODE_NONINTERLACED,
		.flag = 0,
	},
};


struct lcd_panel lcd_panel = {
	.name = "sat101cp50d24b1",
	.num_modes = ARRAY_SIZE(sat_videomode),
	.modes = sat_videomode,
	.lcd_type = LCD_TYPE_TFT,
	.bpp = 18,
	.width = 1024,
	.height = 600,

	/*T40 RGB real line is 666, so, for RGB888, we discard low 2 bytes, config as follows:*/
	.dither_enable = 0,
	.dither.dither_red = 0,
	.dither.dither_green = 0,
	.dither.dither_blue = 0,

	.ops = &sat101cp50d24b1_ops,
};

#define RESET(n)\
	gpio_direction_output(panel->rst.gpio, n)
#define POWER_IS_ON(pwr)     ((pwr) <= FB_BLANK_NORMAL)
static int panel_set_power(struct lcd_device *lcd, int power)
{
	return 0;
}

static int panel_get_power(struct lcd_device *lcd)
{
	struct panel_dev *panel = lcd_get_data(lcd);

	return panel->power;
}

/**
 * @ panel_sat101cp50d24b1_lcd_ops, register to kernel common backlight/lcd.c frameworks.
 */
static struct lcd_ops panel_lcd_ops = {
	.set_power = panel_set_power,
	.get_power = panel_get_power,
};

static int of_panel_parse(struct device *dev)
{
	struct panel_dev *panel = dev_get_drvdata(dev);
	struct device_node *np = dev->of_node;
	enum of_gpio_flags flags;

	panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags);
	if(gpio_is_valid(panel->vdd_en.gpio)) {
		panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
		if(devm_gpio_request(dev, panel->vdd_en.gpio, "vdd-en") < 0) {
			printk("Failed to request vdd_en pin!\n");
		}
	} else {
		dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio);
	}

	panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags);
	if (gpio_is_valid(panel->bl.gpio)) {
		panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
		if (devm_gpio_request(dev, panel->bl.gpio, "backlight") < 0) {
			printk("Failed to request backlight pin!\n");
		}
	} else {
		dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio);
	}

	panel->disp.gpio = of_get_named_gpio_flags(np, "ingenic,disp-gpio", 0, &flags);
	if (gpio_is_valid(panel->disp.gpio)) {
		panel->disp.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
		if (devm_gpio_request(dev, panel->disp.gpio, "display") < 0) {
			printk("Failed to request display pin!\n");
		}
	} else {
		dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->disp.gpio);
	}

	return 0;
}

static struct tft_config sat101cp50d24b1_bgr_cfg = {
	.pix_clk_inv = 0,
	.de_dl = 0,
	.sync_dl = 0,
	.vsync_dl = 0,
	.color_even = TFT_LCD_COLOR_EVEN_BGR,
	.color_odd = TFT_LCD_COLOR_ODD_BGR,
	.mode = TFT_LCD_MODE_PARALLEL_666,
};

static struct tft_config sat101cp50d24b1_rgb_cfg = {
	.pix_clk_inv = 0,
	.de_dl = 0,
	.sync_dl = 0,
	.vsync_dl = 0,
	.color_even = TFT_LCD_COLOR_EVEN_RGB,
	.color_odd = TFT_LCD_COLOR_ODD_RGB,
	.mode = TFT_LCD_MODE_PARALLEL_666,
};

static const struct of_device_id panel_of_match[] = {
	{ .compatible = "ingenic,sat101cp50d24b1-bgr", .data = (struct tft_config *)&sat101cp50d24b1_bgr_cfg, },
	{ .compatible = "ingenic,sat101cp50d24b1-rgb", .data = (struct tft_config *)&sat101cp50d24b1_rgb_cfg, },
	{},
};

/**
 * @panel_probe
 *
 *	1. register to ingenicfb.
 *	2. register to lcd.
 *	3. register to backlight if possible.
 *
 *	@pdev
 *
 *	@return -
 * */
static int panel_probe(struct platform_device *pdev)
{
	int ret = 0;
	struct backlight_properties props;   //backlight properties
	const struct of_device_id *priv;

	memset(&props, 0, sizeof(props));
	panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL);
	if (NULL == panel) {
		dev_err(&pdev->dev, "Failed to alloc memory!");
		return -ENOMEM;
	}
	panel->dev = &pdev->dev;
	dev_set_drvdata(&pdev->dev, panel);

	/* panel pinctrl parse */
	ret = of_panel_parse(&pdev->dev);
	if (ret < 0) {
		goto err_of_parse;
	}

	panel->lcd = lcd_device_register("panel_lcd", &pdev->dev, panel, &panel_lcd_ops);
	if (IS_ERR_OR_NULL(panel->lcd)) {
		dev_err(&pdev->dev, "Error register lcd!");
		ret = -EINVAL;
		goto err_of_parse;
	}

	priv = of_match_node(panel_of_match, pdev->dev.of_node);
	lcd_panel.tft_config = (struct tft_config *)priv->data;

	/* TODO: should this power status sync from uboot */
	panel->power = FB_BLANK_POWERDOWN;
	panel_set_power(panel->lcd, FB_BLANK_UNBLANK);

	ret = ingenicfb_register_panel(&lcd_panel);
	if (ret < 0) {
		dev_err(&pdev->dev, "Failed to register lcd panel!\n");
		goto err_lcd_register;
	}

	return 0;

err_lcd_register:
	lcd_device_unregister(panel->lcd);
err_of_parse:
	kfree(panel);
	return ret;
}

static int panel_remove(struct platform_device *pdev)
{
	struct panel_dev *panel = dev_get_drvdata(&pdev->dev);

	panel_set_power(panel->lcd, FB_BLANK_POWERDOWN);
	return 0;
}


static struct platform_driver panel_driver = {
	.probe = panel_probe,
	.remove = panel_remove,
	.driver = {
		.name = "sat101cp50d24b1",
		.of_match_table = panel_of_match,
	},
};

module_platform_driver(panel_driver);

 5.驱动代码的解析

panel_probe函数:

1. 初始化变量:定义并初始化backlight_properties结构体props,用于存储背光设备的属性。初始化返回值ret为0,表示成功。
2. 分配内存:使用kzalloc为panel_dev结构体分配内存,如果分配失败,则打印错误信息并返回-ENOMEM错误码。
3. 设置设备驱动数据:将平台设备的dev赋值给panel->dev,并用dev_set_drvdata设置设备驱动的私有数据为panel。
4. 解析设备树:调用of_panel_parse函数解析设备树中的面板信息。如果解析失败,则记录错误并跳转到错误处理部分。
5. 注册LCD设备:尝试使用lcd_device_register函数注册LCD设备,如果注册失败,返回-EINVAL错误码并跳转到错误处理。
6. 获取平台设备匹配信息:使用of_match_node函数获取设备树中与当前设备匹配的信息,并据此设置LCD面板的配置。
7. 初始化电源状态:设置面板的初始电源状态为FB_BLANK_POWERDOWN,然后调用panel_set_power函数将面板设置为可用状态FB_BLANK_UNBLANK。这里有一个待办事项(TODO)提示,表明电源状态通常应该从引导加载程序(如uboot)同步,但当前实现没有这样做。
8. 注册LCD面板:调用ingenicfb_register_panel函数注册LCD面板,如果注册失败,则打印错误信息并跳转到错误处理。

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

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

相关文章

vue-print-nb插件来实现打印功能——打印布局及尺寸处理

之前写过一篇文章是关于vue-print-nb插件实现打印功能&#xff0c; vue插件——vue-print-nb 实现打印功能:http://t.csdnimg.cn/ahuxp 但是在实际使用过程中&#xff0c;打印的效果不尽如人意。下面把打印页面和遇到的问题做一下汇总&#xff1a; 1.html代码——给打印元素绑…

vivado Aurora 8B/10B IP核(6)-本地流量控制(Native Flow Control)

Aurora 8B/10B 协议包括本地流控制&#xff08;NFC&#xff09;接口&#xff0c;其允许接收机通过指定必须 放入数据流的空闲数据跳数来控制接收数据的速率。 甚至可以通过请求发送器临时发送空闲&#xff08;XOFF&#xff09; 来完全关闭数据流.NFC 通常用于防止 FIFO 溢出条…

Python | Leetcode Python题解之第52题N皇后II

题目&#xff1a; 题解&#xff1a; class Solution:def totalNQueens(self, n: int) -> int:def backtrack(row: int) -> int:if row n:return 1else:count 0for i in range(n):if i in columns or row - i in diagonal1 or row i in diagonal2:continuecolumns.add…

【Unity基础】TextMeshPro组件学习过程记录

目录 1.TextMeshPro组件渲染创建文本RTL Editor字体Font Asset字体加粗&#xff0c;下划线等字体大小控制字体颜色控制字体渐变控制字符间隔、单词间隔、行间距、段落间距控制WrappingUV映射控制代码 2.TextMeshPro组件AssetFace InfoGeneration Setting 3.使用Dynamic SDF Sys…

Java基础_JDBC

JDBC 概述步骤项目创建流程代码改进 使用Statement的问题&#xff1a;SQL注入&#xff08;1&#xff09;SQL注入&#xff08;2&#xff09;PreparedStatement1、防止SQL注入2、批处理 事务连接池建立数据库连接实现 日志 概述 Java数据库连接&#xff0c;&#xff08;Java Dat…

机器学习:驱动现代交通运输革命的AI智慧引擎

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

POCEXP编写—多线程

POC&EXP编写—多线程 1. 前言2. 多进程&多线程2.1. 多进程2.1.1. 案例 2.2. 多线程2.2.1. 案例&#xff1a; 2.3. POC的案例&#xff08;模板&#xff09; 3. UA头设置3.1. 随机UA头3.1.1. 案例3.1.2. 模板拼接 4. 代理Proxy4.1. 单代理案例4.2. 多代理案例4.2.1. 请求…

2024年最新linux安装harbor

linux安装harbor Harbor官方介绍这里就不照搬了&#xff0c;说直白点&#xff1a;Harbor就是私有的 Docker Hob 镜像仓库。 前置条件&#xff1a;安装好docker,docker-compose 1、安装harbor离线包&#xff08;在线安装形式不稳定&#xff0c;由于网络原因中间可能中断&…

C++ 小游戏:战斗之旅

一、游戏名称&#xff1a;战斗之旅 游戏规则 角色选择&#xff1a;玩家可以选择不同的角色&#xff0c;每个角色都有不同的属性和技能。商城&#xff1a;玩家可以访问商城购买不同的装备&#xff0c;包括武器和回复物品。战斗&#xff1a;玩家可以与其他角色进行战斗。在战斗…

盲人定位设备:为视障人士独立出行铺设智慧之路

在快速发展的数字时代&#xff0c;科技的每一次跃进都在悄然改变我们的生活方式。对于盲人朋友而言&#xff0c;一款名为“蝙蝠避障”集实时避障于一身的盲人定位设备&#xff0c;正成为他们探索世界、实现独立出行的有力助手。这款设备&#xff0c;不仅重新定义了无障碍出行的…

YOLOv8+PyQt5输电线路缺陷检测(目前最全面的类别检测,可以从图像、视频和摄像头三种路径检测)

1.效果视频&#xff1a;YOLOv8PyQt5输电线路缺陷检测&#xff08;目前最全面的类别检测&#xff0c;可以从图像、视频和摄像头三种路径检测&#xff09;_哔哩哔哩_bilibili 资源包含可视化的输电线路缺陷检测系统&#xff0c;可识别图片和视频当中出现的五类常见的输电线路缺陷…

新书速览|ChatGLM3大模型本地化部署、应用开发与微调

实战文本生成、智能问答、信息抽取、财务预警应用开发&#xff0c;掌握ChatGLM3大模型部署、开发与微调技术 01 本书内容 《ChatGLM3大模型本地化部署、应用开发与微调》作为《PyTorch 2.0深度学习从零开始学》的姊妹篇&#xff0c;专注于大模型的本地化部署、应用开发以及微…

Linux基本指令(3)

目录 时间相关的指令&#xff1a; 1.在显示方面&#xff0c;使用者可以设定欲显示的格式&#xff0c;格式设定为一个加好后接数个标记&#xff0c;其中常用的标记列表如下&#xff1a; 2.在设定时间方面&#xff1a; 3.时间戳&#xff1a; Cal指令&#xff1a; find指令&a…

Kubernetes 声明式语言 YAML

什么是 YAML YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种可读的数据序列化语言&#xff0c;通常用于配置文件、数据序列化和交换格式。YAML 的设计目标是易读易写&#xff0c;并且能够映射到动态语言中的数据结构 YA加粗样式ML 是 JSON 的超集&#xff0…

纯血鸿蒙APP实战开发——Navigation实现多设备适配案例

介绍 在应用开发时&#xff0c;一个应用需要适配多终端的设备&#xff0c;使用Navigation的mode属性来实现一套代码&#xff0c;多终端适配。 效果图预览 使用说明 将程序运行在折叠屏手机或者平板上观看适配效果。 实现思路 本例涉及的关键特性和实现方案如下&#xff1a…

MyBatis(注解方式操作)

文章目录 1.注解方式操作文件目录1.快速入门&#xff08;完整步骤&#xff09;1.pom.xml&#xff08;完整&#xff09;2.resources/jdbc.properties外部配置文件&#xff08;根据实际情况修改参数&#xff09;3.在resources/mybatis-config.xml&#xff08;完整&#xff09;中配…

仓库管理系统(WMS)是什么?有哪些功能?

阅读本文&#xff0c;你将了解&#xff1a;1、仓库管理&#xff08;WMS&#xff09;是什么&#xff1f; 2、仓库管理系统&#xff08;WMS&#xff09;有什么功能 3、使用仓库管理系统能给企业带来什么好处 一、仓库管理系统是什么 WMS&#xff0c;全称Warehouse Management S…

借助Aspose.SVG图像控件,在线将 PNG 转换为 XML

Aspose.SVG for .NET 是用于SVG文件处理的灵活库&#xff0c;并且与其规范完全兼容。API可以轻松加载&#xff0c;保存和转换SVG文件&#xff0c;以及通过其文档对象模型&#xff08;DOM&#xff09;读取和遍历文件的元素。API独立于任何其他软件&#xff0c;使开发人员无需使用…

BGP配置和应用案例

策略路由的配置步骤 l 策略路由的配置步骤如下&#xff1a; 创建route-map 通过ACL匹配感兴趣的数据&#xff0c;定义策略动作 在指定接口下通过ip policy 命令应用route-map l 最终实现对通过该接口进入设备的数据进行检查&#xff0c;对匹配的数据执行规定的策略…

注意力机制(四)(多头注意力机制)

​&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;《深度学习基础知识》 相关专栏&#xff1a; ⚽《机器学习基础知识》 &#x1f3d0;《机器学习项目实战》 &#x1f94e;《深度学习项目实…