SPI

硬件SPI与软件模拟SPI速度区别实测 硬件SPI与软件模拟SPI速度区别实测 目前为了程序移植方便,许多以SPI接口的芯片所提供的参考代码大多都使用的是软件SPI,比如笔者用过的存储芯片W25Q16,SPI接口驱动的OLED显示屏,LORA芯片SX1278等。 最近为了驱动彩色OLED显示屏,为了提高显示刷新率,需要对程序代码进行优化。于是,将相关SPI驱动从软件模拟转换为硬件控制,就势在必行了。 然而,到底软件模拟SPI和硬件SPI有多大的速度区别呢? 1.系统配置 为了测试的公平性,选用同样的ARM(STM32L151C8T6)以及系统时钟 阅读详情

1、什么是SPI?

SPI(Service Provider Interface)是JDK内置的服务发现机制,用在不同模块间通过接口调用服务,避免对具体服务服务接口具体实现类的耦合。比如JDBC的数据库驱动模块,不同数据库连接驱动接口相同但实现类不同,在使用SPI机制以前调用驱动代码需要直接在类里采用Class.forName(具体实现类全名)的方式调用,这样调用方依赖了具体的驱动实现,在替换驱动实现时要修改代码。而采用SPI机制后,在驱动jar包的META-INF/services下面新建一个驱动接口全名的UTF-8编码的文件,里面写上具体实现类的全名,这样调用方通过Java 的ServiceLoad接口动态的去加载接口的实现类,从而达到替换驱动实现不用修改代码的效果,如下代码:

建立四个工程:

spi-interface:

package com.springboot.spi;

public interface IShout {
    void shout();
}

spi-cat:

package com.springboot.spi;

public class Cat implements IShout {
    public void shout() {
        System.out.println("miao miao");
    }
}

com.springboot.spi.IShout:

spi-dog:

package com.springboot.spi;

public class Dog implements IShout {
    public void shout() {
        System.out.println("wang wang");
    }
}

com.springboot.spi.IShout:

spi-core:

package com.springboot.spi;

import java.util.ServiceLoader;

public class SPIMain {
    public static void spiTest(String[] args) {
        ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class);
        for (IShout s : shouts) {
            s.shout();
        }
    }
}

下面建立再建立一个工程进行测试:

spi_test:

引入包:

package com.zy.spitest;

import com.springboot.spi.SPIMain;

public class Test {
    public static void main(String[] args) {
        SPIMain.spiTest(args);
    }
}

输出:

引入全部实现的包:

2、使用场景

  1. JDBC加载不同类型的驱动
  2. SLF4J对log4j/logback的支持
  3. Spring中大量使用了SPI,比如:对servlet3.0规范对ServletContainerInitializer的实现、自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等
  4. Dubbo中也大量使用SPI的方式实现框架的扩展, 不过它对java提供的原生SPI做了封装
  5. 更多应用场景需要大家一起去发现,或者自己使用SPI机制实现代码的解耦

以JDBC为例:

通常各大厂商(如Mysql、Oracle)会根据一个统一的规范(java.sql.Driver)开发各自的驱动实现逻辑。客户端使用jdbc时不需要去改变代码,直接引入不同的spi接口服务即可。
Mysql的则是com.mysql.jdbc.Drive;Oracle则是oracle.jdbc.driver.OracleDriver。

伪代码如下:

	//注:从jdbc4.0之后无需这个操作,spi机制会自动找到相关的驱动实现
	//Class.forName(driver);
	
	//1.getConnection()方法,连接MySQL数据库。有可能注册了多个Driver,这里通过遍历成功连接后返回。
	con = DriverManager.getConnection(mysqlUrl,user,password);
	//2.创建statement类对象,用来执行SQL语句!!
	Statement statement = con.createStatement();
	//3.ResultSet类,用来存放获取的结果集!!
	ResultSet rs = statement.executeQuery(sql);

DriverManager是jdbc里管理和注册不同数据库driver的工具类。针对一个数据库,可能会存在着不同的数据库驱动实现。我们在使用特定的驱动实现时,不希望修改现有的代码,而希望通过一个简单的配置就可以达到效果。 在使用mysql驱动的时候,会有一个疑问,DriverManager是怎么获得某确定驱动类的?我们在运用Class.forName("com.mysql.jdbc.Driver")加载mysql驱动后,就会执行其中的静态代码把driver注册到DriverManager中,以便后续的使用。

Driver实现:

驱动的类的静态代码块中,调用DriverManager的注册驱动方法new一个自己当参数传给驱动管理器。

package com.mysql.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

Mysql DriverManager实现

    /**
     * Load the initial JDBC drivers by checking the System property
     * jdbc.properties and then use the {@code ServiceLoader} mechanism
     */
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

可以看到其内部的静态代码块中有一个loadInitialDrivers方法,loadInitialDrivers用法用到了上文提到的spi工具类ServiceLoader,完成了引入的数据库驱动的查找及载入:

private static void loadInitialDrivers() {
        String drivers;
        try {
            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    // 使用系统变量方式加载
                    return System.getProperty("jdbc.drivers");
                }
            });
        } catch (Exception ex) {
            drivers = null;
        }
        //如果spi 存在将使用spi方式完成提供的Driver的加载
        // If the driver is packaged as a Service Provider, load it.
        // Get all the drivers through the classloader
        // exposed as a java.sql.Driver.class service.
        // ServiceLoader.load() replaces the sun.misc.Providers()

        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                //查找具体的provider,就是在META-INF/services/***.Driver文件中查找具体的实现。

                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                /* Load these drivers, so that they can be instantiated.
                 * It may be the case that the driver class may not be there
                 * i.e. there may be a packaged driver with the service class
                 * as implementation of java.sql.Driver but the actual class
                 * may be missing. In that case a java.util.ServiceConfigurationError
                 * will be thrown at runtime by the VM trying to locate
                 * and load the service.
                 *
                 * Adding a try catch block to catch those runtime errors
                 * if driver not available in classpath but it's
                 * packaged as service and that service is there in classpath.
                 */
                //查找具体的实现类的全限定名称
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();  // 加载并初始化实现类
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });
    println("DriverManager.initialize: jdbc.drivers = " + drivers);

        if (drivers == null || drivers.equals("")) {
            return;
        }
        String[] driversList = drivers.split(":");
        println("number of Drivers:" + driversList.length);
        for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }

主要看一下核心的代码段:

//java.util.serviceLoader.java

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
  //查找具体的实现类的全限定名称
     while(driversIterator.hasNext()) {
     //加载并初始化实现
         driversIterator.next();
     }
 } catch(Throwable t) {
 // Do nothing
 }

主要是通过ServiceLoader来完成的,我们按照执行顺序来看看ServiceLoader实现:

//初始化一个ServiceLoader,load参数分别是需要加载的接口class对象,当前类加载器
    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }
    public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader)
    {
        return new ServiceLoader<>(service, loader);
    }

遍历所有存在的service实现(ServiceLoader中)

public boolean hasNext() {
    if (acc == null) {
        return hasNextService();
    } else {
        PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
            public Boolean run() { return hasNextService(); }
        };
        return AccessController.doPrivileged(action, acc);
    }
}
	//写死的一个目录
       private static final String PREFIX = "META-INF/services/";

       private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    String fullName = PREFIX + service.getName();
                    //通过相对路径读取classpath中META-INF目录的文件,也就是读取服务提供者的实现类全限定名
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            //判断是否读取到实现类全限定名,比如mysql的“com.mysql.jdbc.Driver
”
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                pending = parse(service, configs.nextElement());
            }
            nextName = pending.next();//nextName保存,后续初始化实现类使用
            return true;//查到了 返回true,接着调用next()
        }

可以看到加载META-INF/services/ 文件夹下类名为文件名(这里相当于Driver.class.getName())的资源,然后将其加载到虚拟机。

public S next() {
            if (acc == null) {//用来判断serviceLoader对象是否完成初始化
                return nextService();
            } else {
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
                    public S run() { return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }
      private S nextService() {
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;//上一步找到的服务实现者全限定名
            nextName = null;
            Class<?> c = null;
            try {
            //加载字节码返回class对象.但并不去初始化(换句话就是说不去执行这个类中的static块与static变量初始化)
            //
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
                fail(service,
                     "Provider " + cn + " not found");
            }
            if (!service.isAssignableFrom(c)) {
                fail(service,
                     "Provider " + cn  + " not a subtype");
            }
            try {
	            //初始化这个实现类.将会通过static块的方式触发实现类注册到DriverManager(其中组合了一个CopyOnWriteArrayList的registeredDrivers成员变量)中
                S p = service.cast(c.newInstance());
                providers.put(cn, p);//本地缓存 (全限定名,实现类对象)
                return p;
            } catch (Throwable x) {
                fail(service,
                     "Provider " + cn + " could not be instantiated",
                     x);
            }
            throw new Error();          // This cannot happen
        }

上一步中,Sp = service.cast(c.newInstance()) 将会导致具体实现者的初始化,比如mysqlJDBC,会触发如下代码:

//com.mysql.jdbc.Driver.java
......
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
......

    static {
        try {
		     //并发安全的想一个copyOnWriteList中方
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

 

/**
     * Registers the given driver with the {@code DriverManager}.
     * A newly-loaded driver class should call
     * the method {@code registerDriver} to make itself
     * known to the {@code DriverManager}. If the driver is currently
     * registered, no action is taken.
     *
     * @param driver the new JDBC Driver that is to be registered with the
     *               {@code DriverManager}
     * @param da     the {@code DriverAction} implementation to be used when
     *               {@code DriverManager#deregisterDriver} is called
     * @exception SQLException if a database access error occurs
     * @exception NullPointerException if {@code driver} is null
     * @since 1.8
     */
    public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

    }

将自己注册到驱动管理器的驱动列表中

public class DriverManager {


    // List of registered JDBC drivers
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();

 

 

 

 

 

 

组件化框架设计之Java SPI机制(三) 11/12号文档资料已全面更新!;《【阿里P7】移动互联网架构师高级教程+BAT面试题》,点击下方链接前往领取: 【阿里P7】移动互联网架构师进阶高级教程+BAT面试题 本篇文章将从深入理解java SPI机制来介绍组件化框架设计: 一、SPI机制定义 SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework,参... 阅读详情

相关推荐

SPI通信协议(软件SPI和硬件SPI)

当准备发数据时,如果检测到TXE=1(TDR为空),则软件写入数据(0xF1),此时TDR为0xF1,TXE则变为0,如果移位寄存器为空,则数据(0xF1)转入移位寄存器里,然后移位寄存器就将数据发送出去了,接着等待RXNE为1,即接收到数据,此时可以读取RDR里的数据,然后将下个数据(0xF2)写入TDR,接着重复以上过程,循环八次即可交换一个字节。当发送完一个数据时,此时移位寄存器中也接收到了来自从机发送过来的数据,接着将数据转入接受数据寄存器RDR中,并置RXNE标志位(RDR非空标志位)

2301_81374681的博客 4377

源码级深度理解 Java SPI

本文从源码入手分析,深入探讨 Java SPI 的特性、原理,以及在一些比较经典领域的应用。

vivo互联网技术 709

硬件SPI与软件模拟SPI速率对比

​ 1、前言 本文使用AT32F425驱动RC522来测试SPI1的速率,关于RC522的详细代码操作可查帖子【GD32L233C-START评测】7、硬件SPI1驱动RC522。 2、关于AT32F425的SPI AT32F425系列最多有3个spi,本文使用SPI1。 3、SPI1的最大速率 SPI1挂在APB2总线上,APB2总线的最大速率是96MHz; SPI的最大速率为fPCLK/2,即48Mhz。 4、代码实现 /*SPI1 : PA4/CS PA5/SCK

freemote的博客 1万+

结合实战和源码来聊聊Java中的SPI机制?

JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

2401_83916283的博客 656

STM32F103 SPI DMA收发(SPI2发送 SPI1接收)

目录 STM32 SPI DMA收发 GPIO初始化 SPI初始化 DMA初始化 问题记录 STM32F103 SPI DMA收发 GPIO初始化 void my_spi_init(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphCloc...

REALIOT'S BLOG 9899

ESP32 SPI 接口的应用

乐鑫 ESP-LCD 多媒体智能控制方案” 视频介绍乐鑫 ESP-LCD 多媒体智能控制方案优势。

2401_87225473的博客 1548

【转】SPI服务加载机制注册驱动原理分析、线程上下文类加载器、违反双亲委派模型

转自:双亲委派模型与线程上下文类加载器 https://blog.youkuaiyun.com/justloveyou_/article/details/72231425 摘要: SPI机制是什么,有哪些应用场景,又带来了哪些问题? 双亲委派模型是Java推荐的类加载模型,但违背该模型的案例有哪些?为什么会违背,又是怎么解决这种case的? JDBC驱动加载的案例有哪些,SPI机制为它带来了哪些方便? 线程上下文类加载器的作用与应用场景? 一、引子 SPI机制简介 SPI的全名为Service Prov

Sid小杰的博客 868

(5)SPI应用设计及仿真验证3 —— 验证代码实现

激动人心的测试环节啦?你是否有好好的梳理过tb文件到底怎么写?

CAUC_learner的博客 1614

SPI协议详解(Standard SPI、Dual SPI和Queued SPI)

(1)通常我们说的SPI就是Standard SPI,有4根信号线,分别为CLK、CS、MOSI和MISO,也就是上面介绍的SPI协议;(2)Dual SPI:只是针对SPI Flash而言,不是针对所有SPI外设。对于SPI Flash,全双工并不常用,因此扩展了mosi和miso的用法,让它们工作在半双工,用以加倍数据传输。

weixin_42031299的博客 4万+

PDPS16.0单机版与SPLMLicenseServer授权避坑指南:从安装到冲突解决

本文详细解析了PDPS16.0单机版的安装与授权流程,重点阐述了如何正确配置SPLMLicenseServer本地许可证服务器以实现软件激活。针对安装过程中常见的许可证冲突问题,提供了清晰的排查思路和解决方案,并介绍了通过设置环境变量等替代授权方法,帮助用户高效避坑,确保Tecnomatix Process Simulate顺利运行。

weixin_29231221的博客 564

Altera USB-Blaster在Win10/Win11的驱动兼容性处理

解决Altera USB-Blaster在Windows 10和Windows 11系统下的驱动兼容性问题,详细演示如何手动安装与更新altera usb-blaster驱动安装,确保下载电缆正常识别,提升开发调试效率。

weixin_42284380的博客 1290

GD32F303调试小记(二)之SPI(软件SPI、硬件SPI、硬件SPI+DMA)

前言 目前有一个项目中用到了TFT-LCD,其驱动芯片为ILI9341。为更好的达到显示效果,在最终的代码中我们会使用单片机自带的硬件SPI+DMA模块,以尽可能的减轻CPU的负荷,不过在调试过程中,我们会使用到软件模拟SPI以及单独的硬件SPI。由于我们只是使用SPI与屏显的驱动芯片通信,所以只使用SPI的发送,在接下来的代码演示中,不包含SPI接收。以后如果有机会用到SPI通信的FLASH存储芯片或其他,会再出一个调试文章。 ...

欢喜6666的博客 3万+

Blender.粒子效果

Blender.粒子效果 ✦ shift+A新建一个棱角球,细分(之后要分解成许多小颗粒) ✦ 给球添加粒子系统,这时播放粒子会向下掉,力场权重☛重力☛0后,粒子会在球体周围运动 ✦ shift+A添加一个力场,调整力场强度 ✦如果粒子运动太快,我们可以在输出属性中调整时间重映射的原始值 ✦想让粒子在球周围运动而不是发散出去,在物理属性找到力场设置,调整流的大小 ✦S键将球形缩小到看不见 ✦给粒子变添加立方体的形状,在粒子属性里找到渲染选项,将“光晕”改为“物体”,在实例物体中选择新建的立方

weixin_46385629的博客 6669

SPI控制器(spi_master)、SPI设备、SPI总线(spi_device与spi_driver的匹配机制)、SPI万能驱动`spidev.c`

spidev.c各SPI设备通过SPI总线来使用SPI控制器的传输能力,关于这一点具体解释如下:由于SPI设备比I2C设备复杂,比如每个SPI设备有自己的片选控制引脚、有自己的最大时钟值、有自己的传输方式(任意时刻是只读或只写还是既读又写),所以SPI设备们直接使用SPI控制器的驱动是很困难的。要想使用一个SPI设备,通常都不是直接去使用SPI控制器的驱动来操作SPI设备,而是通过SPI总线来为具体的SPI设备提供驱动。

昊虹AI笔记 1666

【数据集6】全球人工不透水面积GAIA(清华数据)

全球人工不透水面GAIA简介及其应用

WW、forever的博客 3803

Android软键盘系统深度解析:架构、原理与实现

Android软键盘系统深度解析:架构与实现原理 本文系统剖析了Android软键盘的核心工作机制。作为系统级输入服务,软键盘具有双重属性:既是可安装的独立应用,又深度集成于系统框架中。文章详细解读了软键盘的系统架构,包括其与InputMethodManagerService(IMMS)和WindowManagerService(WMS)的交互机制,以及通过InputConnection实现的跨进程通信流程。同时分析了输入法窗口的特殊管理策略、布局调整模式,并深入探讨了输入预测引擎的实现原理,包括词典加载、

保持专注,保持热爱 115

SPI时序简单理解(SPI0、SPI1、SPI2、SPI3)

基本概念: CPOL CPOL:Clock Polarity,时钟的极性。 时钟的极性是什么概念呢? 通信的整个过程分为空闲时刻和通信时刻; 如果SCLK在数据发送之前和之后的空闲状态是高电平,那么就是CPOL=1; 如果空闲状态SCLK是低电平,那么就是 CPOL=0。 CPHA CPHA:Clock Phase,时钟的相位。 CPHA=1,表示一个时钟周期的第一个沿上是输出。 CPHA=0,表示一个时钟周期的第一个沿上是采样。那输出就是第二个沿。 至于这个沿是上升还是下降要视CPOL的值而定,CPOL=

allenallate的博客 1万+

全志V3S嵌入式驱动开发(解决kernel 5.2.y wifi驱动问题)

​【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 wifi模块,之前测试的时候,开发板上用的是esp8089,当时内核时4.14.y,测试也是通过的。链接地址在这里, https://blog.youkuaiyun.com/feixiaoxing/article/details/131178420?spm=1001.2014.3001.5501 那个时候测试的时候,我们就说过,wifi驱动可能是除了镜像制作之外,最复杂的一个

嵌入式-老费,一个分享专业嵌入式知识的blog 1158

【SPI】SPI学习之SPI驱动相关

spi驱动框架 目录:linux/driver/spi/ <从设备驱动层>  spidev.c                             自己编写 <核 心 层>  spi.c                             内核提供 <控 制 器 层>  spi-xxx.c(瑞芯微:spi-rockchip.c  全志:spi-sunxi.c)     原厂提供 ...

诸葛一帆丶的博客 3693

UG NX二次开发(C++)-NX2406系列二次开发编程模板配置

前面已经写了有关UG NX二次开发编程模板配置的文章,但是由于NX2406/2412系列的版本中,在UGOpen文件夹中没有了vs_files文件夹了,而是采用了VSIX Project的方式配置(其适用于VS2019),在VS2022中不能正确的配置。我结合以前配置模板的经验和现在的配置方式讲一下NX2406系列二次开发编程模板的配置。我把相应的编程模板放在资源文件UG NX二次开发编程模板(基于NX2406版本制作)中,方便大家下载使用。

GimiGimmy 2640

解锁RK3588:内核模块签名与安全启动配置全攻略

RK3588作为一款高性能嵌入式SoC芯片,其内核模块签名与安全启动配置是保障系统安全的核心机制。本文详细介绍了RK3588的芯片特性,重点阐述了安全启动的硬件信任链原理和内核模块签名的实现方法。通过具体步骤演示了从密钥生成、模块签名到验证加载的完整流程,并深入解析了安全启动配置的硬件连接、软件工具准备、密钥烧录等关键环节。此外,还提出了防御旁路攻击和动态信任链扩展等高级安全策略,为RK3588在工业控制、智能安防等高安全要求场景中的应用提供了全面的安全解决方案。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 347

标准SPI、DUAL SPI、Quad SPI

1. 标准SPI 标准SPI通常就称SPI,它是一种串行外设接口规范,有4根引脚信号:clk , cs, mosi, miso 2. Dual SPI 它只是针对SPI Flash而言,不是针对所有SPI外设。对于SPI Flash,全双工并不常用,因此扩展了mosi和miso的用法,让它们工作在半双工,用以加倍数据传输。也就是对于Dual SPI Flash,可以发送一个命令字节进入dua...

芒果爱火锅的博客 1万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【SPI】SPI学习之SPI调试相关

spi调试方法 uboot下调试SPI 在uboot下,有spi的调试命令“sspi”,代码在:uboot/cmd/spi.c 具体用法如下:

诸葛一帆丶的博客 6467

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【MCAL】SPI模块详解

AUTOSAR架构下SPI模块详解

qq_36056498的博客 6428

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

SPI协议

EEPROM

Kudo_chitose的博客 7519
上一篇: 分布式事务
下一篇: 设计模式之模板方法模式
给自己加加油
博客等级 码龄8年 302粉丝 110原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值