驱动中的device和device_driver结构体

device和device driver是Linux驱动开发的基本概念。Linux kernel的思路很简单:驱动开发,就是要开发指定的软件(driver)以驱动指定的设备,所以kernel就为设备和驱动它的driver定义了两个数据结构,分别是device和device_driver。

1. struct device

/*** struct device - The basic device structure* @parent:	The device's "parent" device, the device to which it is attached.* 		In most cases, a parent device is some sort of bus or host* 		controller. If parent is NULL, the device, is a top-level device,* 		which is not usually what you want.* @p:		Holds the private data of the driver core portions of the device.* 		See the comment of the struct device_private for detail.* @kobj:	A top-level, abstract class from which other classes are derived.* @init_name:	Initial name of the device.* @type:	The type of device.* 		This identifies the device type and carries type-specific* 		information.* @mutex:	Mutex to synchronize calls to its driver.* @bus:	Type of bus device is on.* @driver:	Which driver has allocated this* @platform_data: Platform data specific to the device.* 		Example: For devices on custom boards, as typical of embedded* 		and SOC based hardware, Linux often uses platform_data to point* 		to board-specific structures describing devices and how they* 		are wired.  That can include what ports are available, chip* 		variants, which GPIO pins act in what additional roles, and so* 		on.  This shrinks the "Board Support Packages" (BSPs) and* 		minimizes board-specific #ifdefs in drivers.* @driver_data: Private pointer for driver specific info.* @power:	For device power management.* 		See Documentation/power/devices.txt for details.* @pm_domain:	Provide callbacks that are executed during system suspend,* 		hibernation, system resume and during runtime PM transitions* 		along with subsystem-level and driver-level callbacks.* @pins:	For device pin management.*		See Documentation/pinctrl.txt for details.* @msi_list:	Hosts MSI descriptors* @msi_domain: The generic MSI domain this device is using.* @numa_node:	NUMA node this device is close to.* @dma_mask:	Dma mask (if dma'ble device).* @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all* 		hardware supports 64-bit addresses for consistent allocations* 		such descriptors.* @dma_pfn_offset: offset of DMA memory range relatively of RAM* @dma_parms:	A low level driver may set these to teach IOMMU code about* 		segment limitations.* @dma_pools:	Dma pools (if dma'ble device).* @dma_mem:	Internal for coherent mem override.* @cma_area:	Contiguous memory area for dma allocations* @archdata:	For arch-specific additions.* @of_node:	Associated device tree node.* @fwnode:	Associated device node supplied by platform firmware.* @devt:	For creating the sysfs "dev".* @id:		device instance* @devres_lock: Spinlock to protect the resource of the device.* @devres_head: The resources list of the device.* @knode_class: The node used to add the device to the class list.* @class:	The class of the device.* @groups:	Optional attribute groups.* @release:	Callback to free the device after all references have* 		gone away. This should be set by the allocator of the* 		device (i.e. the bus driver that discovered the device).* @iommu_group: IOMMU group the device belongs to.* @iommu_fwspec: IOMMU-specific properties supplied by firmware.** @offline_disabled: If set, the device is permanently online.* @offline:	Set after successful invocation of bus type's .offline().** At the lowest level, every device in a Linux system is represented by an* instance of struct device. The device structure contains the information* that the device model core needs to model the system. Most subsystems,* however, track additional information about the devices they host. As a* result, it is rare for devices to be represented by bare device structures;* instead, that structure, like kobject structures, is usually embedded within* a higher-level representation of the device.*/
struct device {struct device		*parent;struct device_private	*p;struct kobject kobj;const char		*init_name; /* initial name of the device */const struct device_type *type;struct mutex		mutex;	/* mutex to synchronize calls to* its driver.*/struct bus_type	*bus;		/* type of bus device is on */struct device_driver *driver;	/* which driver has allocated thisdevice */void		*platform_data;	/* Platform specific data, devicecore doesn't touch it */void		*driver_data;	/* Driver data, set and get withdev_set/get_drvdata */struct dev_links_info	links;struct dev_pm_info	power;struct dev_pm_domain	*pm_domain;#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAINstruct irq_domain	*msi_domain;
#endif
#ifdef CONFIG_PINCTRLstruct dev_pin_info	*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQstruct list_head	msi_list;
#endif#ifdef CONFIG_NUMAint		numa_node;	/* NUMA node this device is close to */
#endifu64		*dma_mask;	/* dma mask (if dma'able device) */u64		coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations such descriptors. */unsigned long	dma_pfn_offset;struct device_dma_parameters *dma_parms;struct list_head	dma_pools;	/* dma pools (if dma'ble) */struct dma_coherent_mem	*dma_mem; /* internal for coherent memoverride */
#ifdef CONFIG_DMA_CMAstruct cma *cma_area;		/* contiguous memory area for dmaallocations */
#endif/* arch specific additions */struct dev_archdata	archdata;struct device_node	*of_node; /* associated device tree node */struct fwnode_handle	*fwnode; /* firmware device node */dev_t			devt;	/* dev_t, creates the sysfs "dev" */u32			id;	/* device instance */spinlock_t		devres_lock;struct list_head	devres_head;struct klist_node	knode_class;struct class		*class;const struct attribute_group **groups;	/* optional groups */void	(*release)(struct device *dev);struct iommu_group	*iommu_group;struct iommu_fwspec	*iommu_fwspec;bool			offline_disabled:1;bool			offline:1;
};

struct device 是 Linux 设备模型中用于描述设备的基础结构体,包含设备驱动程序中几乎所有的关键信息。这个结构体的每个成员都代表设备的不同属性或控制与管理功能。

主要成员变量

  1. struct device *parent
    • 设备的父设备指针。大多数情况下,父设备是某种总线或控制器(如 PCI 控制器)。如果为 NULL,则表示该设备是顶层设备。
  2. struct device_private *p
    • 保存设备私有数据的指针,用于设备模型核心管理设备的内部数据。通常开发者不直接操作这个字段。
  3. struct kobject kobj
    • kobject 是 Linux 内核中的一种对象管理机制,kobj 用于在 /sys 文件系统中表示设备,通过它可以导出设备的属性到用户空间。
  4. const char *init_name
    • 设备的初始名称,用于在注册时给设备指定名称。
    • 注1:在设备模型中,名称是一个非常重要的变量,任何注册到内核中的设备,都必须有一个合法的名称,可以在初始化时给出,也可以由内核根据“bus name + device ID”的方式创造。
  5. const struct device_type *type
    • 设备类型指针,定义了设备的类型及其类型特定信息。
  6. struct mutex mutex
    • 设备互斥锁,用于同步对该设备的操作,避免多个线程同时访问设备驱动的共享资源时引发冲突。
  7. struct bus_type *bus
    • 指向设备所在的总线类型(如 PCI、I2C、SPI 等)的指针,用于描述设备属于哪个总线。这里要留意一下,后面会讲到平台总线
  8. struct device_driver *driver
    • 指向分配该设备的驱动程序结构体的指针,表示当前哪个驱动程序在控制这个设备。
  9. void *platform_data
    • 平台相关的数据指针。对于嵌入式或 SoC 硬件,platform_data 通常指向特定设备的硬件配置数据,例如可用的端口、芯片变体等。它帮助减少驱动程序中的板级特定代码。
  10. void *driver_data
    • 驱动程序的私有数据,驱动可以通过 dev_set_drvdata()dev_get_drvdata() 来设置和获取该字段。
  11. struct dev_links_info links
    • 存储与设备之间的拓扑关系信息,如设备间的依赖性。
  12. struct dev_pm_info power
    • 设备电源管理信息。包含电源状态、挂起、恢复等操作相关的字段,涉及设备的电源管理。
  13. struct dev_pm_domain *pm_domain
    • 设备电源管理域的指针,定义系统挂起、休眠、恢复时需要执行的回调函数。
  14. struct irq_domain *msi_domain
    • 当设备使用 Message Signaled Interrupts (MSI) 时,指向管理设备 MSI 中断的域。
  15. struct dev_pin_info *pins
    • 引脚管理信息,设备在引脚控制方面的数据结构,用于 GPIO 和 pinctrl 子系统。
  16. struct list_head msi_list
    • 保存设备的 MSI 描述符的链表头。
  17. int numa_node
    • 设备所在的 NUMA(Non-Uniform Memory Access)节点。
  18. u64 *dma_mask
    • DMA 掩码,用于描述设备支持的 DMA 地址范围。设备使用 DMA 时,用来表示设备能够访问的物理内存地址空间的最大范围。
  19. u64 coherent_dma_mask
    • dma_mask 类似,但专门用于一致性内存的 DMA 掩码。
  20. unsigned long dma_pfn_offset
    • DMA 内存与物理内存之间的偏移量。
  21. struct device_dma_parameters *dma_parms
    • DMA 参数,低层驱动可以通过它告知 IOMMU 关于段限制等特性。
  22. struct list_head dma_pools
    • 设备的 DMA 池列表头,表示设备的 DMA 内存池。
  23. struct dma_coherent_mem *dma_mem
    • 用于管理一致性 DMA 内存的内部数据结构。
  24. struct cma *cma_area
    • 用于 DMA 分配的连续内存区域指针。
  25. struct dev_archdata archdata
    • 设备的体系结构特定数据。不同平台可以利用这个字段扩展额外的体系结构相关的信息。
  26. struct device_node *of_node
    • 指向与设备相关的设备树节点。对于使用设备树的系统,of_node 记录设备在设备树中的描述信息。
  27. struct fwnode_handle *fwnode
    • 设备的固件节点,通常用于指向 ACPI 或设备树中的设备描述。
  28. dev_t devt
    • 设备的 dev_t 类型,设备号,表示设备的主设备号和次设备号,用于创建设备节点。
  29. u32 id
    • 设备实例 ID,用于标识同类设备的不同实例。
  30. spinlock_t devres_lock
    • 设备资源锁,用于保护设备的资源列表。
  31. struct list_head devres_head
    • 设备资源链表头,记录与设备相关的资源(如内存、I/O 端口等)。
  32. struct klist_node knode_class
    • 用于将设备添加到设备类链表中的节点。
  33. struct class *class
    • 设备的类,用于分类设备(如输入设备、网络设备等)。设备类定义设备的行为及其属性。
  34. const struct attribute_group **groups
    • 可选的属性组,用于定义设备在 /sys 文件系统中暴露的额外属性。
  35. void (*release)(struct device *dev)
    • 设备的释放回调函数,当所有对设备的引用都释放后,调用该函数释放设备占用的资源。
  36. struct iommu_group *iommu_group
    • 设备所属的 IOMMU 组指针。IOMMU 组用于管理设备之间的内存隔离。
  37. struct iommu_fwspec *iommu_fwspec
    • 由固件提供的 IOMMU 特定属性。

状态标志位

  1. bool offline_disabled:1
    • 标志位,指示设备是否永久在线,如果设置为 true,设备无法进入离线状态。
  2. bool offline:1
    • 标志位,指示设备是否离线。

struct device 是 Linux 设备模型中非常重要的结构体,负责设备的管理与控制。它包含了设备在总线上的位置信息、与驱动程序的关联、DMA 信息、电源管理、IOMMU 等多种设备相关的属性。在实际使用时,struct device 通常是被嵌入到更高级的设备结构中,用于表示具体的硬件设备,比如平台platfrom_device结构体中。其实这些成员内核开发者也给了详细的注解。

2. struct device_driver

/*** struct device_driver - The basic device driver structure* @name:	Name of the device driver.* @bus:	The bus which the device of this driver belongs to.* @owner:	The module owner.* @mod_name:	Used for built-in modules.* @suppress_bind_attrs: Disables bind/unbind via sysfs.* @probe_type:	Type of the probe (synchronous or asynchronous) to use.* @of_match_table: The open firmware table.* @acpi_match_table: The ACPI match table.* @probe:	Called to query the existence of a specific device,*		whether this driver can work with it, and bind the driver*		to a specific device.* @remove:	Called when the device is removed from the system to*		unbind a device from this driver.* @shutdown:	Called at shut-down time to quiesce the device.* @suspend:	Called to put the device to sleep mode. Usually to a*		low power state.* @resume:	Called to bring a device from sleep mode.* @groups:	Default attributes that get created by the driver core*		automatically.* @pm:		Power management operations of the device which matched*		this driver.* @p:		Driver core's private data, no one other than the driver*		core can touch this.** The device driver-model tracks all of the drivers known to the system.* The main reason for this tracking is to enable the driver core to match* up drivers with new devices. Once drivers are known objects within the* system, however, a number of other things become possible. Device drivers* can export information and configuration variables that are independent* of any specific device.*/
struct device_driver {const char		*name;struct bus_type		*bus;struct module		*owner;const char		*mod_name;	/* used for built-in modules */bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */enum probe_type probe_type;const struct of_device_id	*of_match_table;const struct acpi_device_id	*acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;
};

struct device_driver 是 Linux 内核中用于描述设备驱动程序的基本结构体,它用于表示设备驱动的属性和操作。该结构体负责跟踪系统中已知的所有驱动程序,并为新设备和驱动程序之间进行匹配提供基础。

主要成员变量

  1. const char *name
    • 驱动程序的名称。在设备和驱动之间进行匹配时,设备的名称和驱动的名称会进行比较。
  2. struct bus_type *bus
    • 驱动程序所依附的总线类型。每个驱动程序都属于某个总线类型,例如 PCI、I2C、SPI 等。
  3. struct module *owner
    • 模块的所有者,指向实现该驱动的模块(内核模块)结构体。它确保驱动所在模块在使用期间不会被卸载。
  4. const char *mod_name
    • 模块的名称。对于内建模块(built-in modules),这个字段用于指明模块的名字。
  5. bool suppress_bind_attrs
    • 控制是否通过 sysfs 禁止手动绑定/解绑设备。如果设置为 true,则无法通过 /sys 文件系统中的 bind 和 unbind 文件手动进行设备和驱动的绑定/解绑。
  6. enum probe_type probe_type
    • 控制驱动程序的 probe 操作的类型,可以是同步的(synchronous)或异步的(asynchronous)。它决定了驱动程序在处理设备时,probe 函数是阻塞执行还是非阻塞执行。
  7. const struct of_device_id *of_match_table
    • 用于设备树(Device Tree)的匹配表。驱动程序可以通过该表与设备树中的设备节点进行匹配。
  8. const struct acpi_device_id *acpi_match_table
    • 用于 ACPI(高级配置与电源接口)的匹配表。驱动程序通过该表与系统的 ACPI 表进行匹配,从而识别设备。

驱动操作接口

  1. **int (*probe)(struct device *dev)**** **
    • probe 函数用于在设备检测到时调用,它用于检查该驱动是否可以支持指定的设备,并在可以支持时绑定设备和驱动。返回 0 表示成功,非零表示失败。
    • 所谓的"probe”,是指在Linux内核中,如果存在相同名称的device和device_driver(注:还存在其它方式),内核就会执行device_driver中的probe回调函数,而该函数就是所有driver的入口,可以执行诸如硬件设备初始化、字符设备注册、设备文件操作ops注册等动作。
    • 这里先不讲,在bus中再提
  2. int (*remove)(struct device *dev)
    • 当设备被从系统中移除时调用,用于解除设备与驱动的绑定并释放相关资源。通常在卸载设备时调用。
  3. void (*shutdown)(struct device *dev)
    • 系统关闭时调用,用于关闭设备并确保其处于安静状态。这通常在系统关机或重启时调用。
  4. int (*suspend)(struct device *dev, pm_message_t state)
    • 将设备挂起(进入低功耗模式)时调用。挂起操作通常在设备空闲或系统进入休眠模式时触发。
  5. int (*resume)(struct device *dev)
    • 将设备从挂起状态恢复到正常运行状态时调用,通常在系统恢复时或设备被再次使用时调用。

其他成员

  1. const struct attribute_group **groups
    • 驱动程序导出的默认属性组。内核会自动创建这些属性组,使驱动程序可以将配置或状态信息通过 /sys 文件系统提供给用户空间。
  2. const struct dev_pm_ops *pm
    • 设备电源管理操作的指针。通过该指针,驱动程序可以定义设备的电源管理操作(如挂起、恢复、系统睡眠等)。
  3. struct driver_private *p
    • 驱动程序核心的私有数据字段。只有驱动程序核心可以访问该字段,通常开发者不需要直接使用这个字段。

struct device_driver 是 Linux 驱动模型中用于描述设备驱动程序的核心结构体,它定义了驱动程序的各种操作接口(如 proberemoveshutdownsuspendresume 等),并包含了一些驱动程序的元数据(如名称、所属总线类型、匹配表等)。通过这个结构体,驱动程序可以被内核识别,并通过合适的接口与设备进行绑定、控制和管理。

3. 驱动开发的基本步骤

设备模型框架下,设备驱动的开发是一件很简单的事情,主要包括2个步骤:

步骤1:分配一个struct device类型的变量,填充必要的信息后,把它注册到内核中。

步骤2:分配一个struct device_driver类型的变量,填充必要的信息后,把它注册到内核中。

完成这两步,内核会在何时的时机对他们进行匹配,当然匹配的前提是这两个结构体中的name是相同的(同一bus的情况下)

但是,一般情况下,Linux驱动开发很少直接使用device和device_driver,因为内核在它们之上又封装了一层,如soc device、platform device等等,而这些层次提供的接口更为简单、易用(也正是因为这个原因,并不会过多涉及device、device_driver等模块的实现细节)。

就比如platform device,很多情况下不需要我们自己去填充,只需要在设备树(后续会讲)中去定义好设备的相关信息(寄存器?中断资源?引脚?),平台就会自己帮我们注册号platform device。而platform其实依靠的也是bus总线,关于总线和平台设备具体的会另开文章讲解。

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

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

相关文章

低组装滚珠导轨:承载力强,适应多样工况!

在自动化行业中,高质量、高效率的生产线是确保产品品质和生产效率的关键。而低组装型滚珠导轨作为生产线中的重要组件之一,能够提供精准的直线运动控制,为自动化设备的稳定运行和高精度检测提供可靠支持。 相对于传统的导轨系统来说&#xff…

汇编语言笔记2

7.MASM,NASM,ATT,ARM的介绍 MASM:Windows下编译汇编指令的软件,可以在DOSBox下运行 NASM:优化版的MASM,主要用于Linux操作系统 ATT:Linux默认的汇编风格(但不友好) ARM:非PC(IOT设备)的汇编,比如写51单片机打开keil4的界面可以看到ARM 8.汇编 C语言 C 之间的关系 发展历程…

Arduino UNO R3自学笔记21 之 Arduino电机的闭环控制

注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。 前言:上篇写了电机速度测定,这篇主要是讲测定出的速度用于反馈,使得实际速度快速响应到需要的速度。 1.控制系统介绍 分2大类&#x…

《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析

目录 一、透视变换 1、什么是透视变换 2、操作步骤 1)选择透视变换的源图像和目标图像 2)确定透视变换所需的关键点 3)计算透视变换的变换矩阵 4)对源图像进行透视变换 5)对变换后的图像进行插值处理 二、轮廓检测…

idea插件市场安装没反应

https://plugins.jetbrains.com/idea重启后还是不行那就

Docker:安装 MongoDB 的详细指南

请关注微信公众号:拾荒的小海螺 博客地址:http://lsk-ww.cn/ 1、简述 MongoDB 是一个流行的 NoSQL 数据库,可以在 Docker 容器中轻松安装和运行。本文将介绍如何在 Docker 中安装 MongoDB,并展示如何在 Java 应用中使用 MongoDB…

kafka发送消费核心参数与设计原理详解

核心参数详解: 发送端参数: 发送方式:默认值一般都是1: 重试参数 : 批量参数: 消费端参数: 自动提交参数: 如果是false,就是说消费完后不提交位移。也就是说比如之前消费的1-5.…

Qt教程(002):Qt项目创建于框架介绍

二、创建Qt项目 2.1 创建项目 【1、New Project】 【2、选择Qt Widgets Application】 【3、设置项目名称和保存路径】 注意,项目名称和路径不要带中文。 【4、选择QWidget】 带菜单栏的窗口QMainWindow空白窗口QWidget对话框窗口QDialog 【5、编译】 2.2 项目框…

前端编程艺术(4)---JavaScript进阶(vue前置知识)

目录 1.变量和常量 2.模版字符串 3.对象 4.解构赋值 1.数组的解构 2.对象的解构 5.箭头函数 6.数组和对象的方法 7.扩展运算符 8.Web存储 9.Promise 10.AsyncAwait 11.模块化 1.变量和常量 JavaScript 中的变量和常量是用于存储数据的标识符。变量可以被重新赋值&am…

基于阻塞队列及环形队列的生产消费模型

目录 条件变量函数 等待条件满足 阻塞队列 升级版 信号量 POSIX信号量 环形队列 条件变量函数 等待条件满足 int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); 参数: cond:要在这个条件变量上等待 mutex…

windows下,在vscode中使用cuda进行c++编程

安装cuda CUDA Toolkit Downloads | NVIDIA Developer 这里网上教程多的是,在这个网址下载安装即可 我这台电脑因为重装过,所以省去了安装步骤,但是要重新配置环境变量。我重新找到了重装之前的CUDA位置(关注这个bin文件夹所在的目录) 在…

微信第三方开放平台接入本地消息事件接口报错问题java.security.InvalidKeyException: Illegal key size

先看报错: java.security.InvalidKeyException: Illegal key sizeat javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)at javax.crypto.Cipher.implInit(Cipher.java:805)at javax.crypto.Cipher.chooseProvider(Cipher.java:864)at javax.crypto.Cipher.in…

九、3 串口发送+printf函数移植+打印汉字

1、接线图 TX与RX交叉连接,TXD接STM32的PA10,RXD接STM32的PA9 VCC与3.3V用跳线帽连接 2、函数介绍 3、代码部分 (1)发送字节的函数(Byte) 可直接发送十六进制数 如0x41,也可直接发送字符 如A …

【重学 MySQL】五十六、位类型

【重学 MySQL】五十六、位类型 定义赋值与使用注意事项应用场景 在MySQL数据库中,位类型(BIT类型)是一种用于存储位字段值的数据类型。 定义 BIT(n)表示n个位字段值,其中n是一个范围从1到64的整数。这意味着你可以存储从1位到64…

【AIGC】AI时代的数据安全:使用ChatGPT时的自查要点

博客主页: [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯法律法规背景中华人民共和国保守秘密法中华人民共和国网络安全法中华人民共和国个人信息保护法遵守法律法规的重要性 💯ChatGPT的数据使用特点ChatGPT数据安全…

YOLOv11 vs YOLOv8:谁才是真正的AI检测之王?

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

Js逆向分析+Python爬虫结合

JS逆向分析Python爬虫结合 特别声明📢:本教程只用于教学,大家在使用爬虫过程中需要遵守相关法律法规,否则后果自负!!! 完整代码地址Github:https://github.com/ziyifast/ziyifast-co…

28 Vue3之搭建公司级项目规范

可以看到保存的时候ref这行被提到了最前面的一行 要求内置库放在组件的前面称为auto fix,数组new arry改成了字面量,这就是我们配置的规范 js规范使用的是airbnb规范模块使用的是antfu 组合prettier&eslint airbnb规范: https://github…

重磅来袭!CMSIS-DAP 脱机烧录器 EasyFlasher 发布~

重磅来袭!CMSIS-DAP 脱机烧录器 EasyFlasher 发布~ 目录 重磅来袭!CMSIS-DAP 脱机烧录器 EasyFlasher 发布~相关文章1、前言1、产品特点2、功能说明3、支持芯片4、关于烧录5、写在最后 某宝店铺:觉皇工作室 购买链接:https://item…