CATERR 介绍

CATERR# 是 CPU 上的一个引脚,当CPU 有严重错误发生时,这个引脚会拉低(#表示低有效)。它在所有的Intel CPU 上都有。特别注意:这里是 OD 输出,是没法输出高电平,想要输出高电平,必须外部再接一个上拉电阻(pull-up resistor)。换句话说,如果测量这里为高或者低,务必记得在外面连接一个上拉电阻才能得到正确值【参考3】.

CATERR# 来自【参考1】

Intel 错误分类

首先是两大类:可以检测到的(Detected) 和 不可以检测到的(Undetected)。其中的 Undetected 是非常重要的,因为这种错误无法检测到的错误是没有办法捕捉到和处理的。进一步分为影响不大的 (Benign)和Critical(严重的,这种又被称作 Silent Data Corruption缩写 SDC)。作为系统设计者,必须努力降低这种情况的发生率。

更多的,我们需要关注Detected 这一类。其中又分作可纠正(Corrected)错误(例如,ECC 内存发现了错误,然后可以纠正为正确值)和不可纠正(Uncorrected)错误。例如,我们经常看到的蓝屏就是可以检测不可纠正错误。再进一步,不可纠正(Uncorrected)错误又分作可检测但是不可修正错误(DUE)和可检测不可纠正但可恢复错误(UCR,比如在从U盘Copy 数据到硬盘时,发生了错误,这个错误就是可以检测不可纠正,但是再次尝试读取还可以继续Copy,就是 UCR错误)。

显而易见,我们最大的敌人是DUE。

Intel 内置了 MCA(Machine Check Architecture)来帮助诊断DUE。这也是为什么在碰到稀奇古怪的问题时需要使用 CCA/DCI 的原因:CPU 死翘翘的,只能从不依赖CPU 的路径取得当前的错误。MCA提供了检测和记录:系统总线错误,内存错误,奇偶校验错误,Cache错误和TLB 错误等等。它是通过CPU内部的一组专用的MSR寄存器来实现的。例如:下面就是一组MCA 的 MSR 寄存器:

这里有一个MCA 应用的典型例子【参考4】。当问题发生的时候CATERR#会拉低,进一步检查出现的错误是ROB Timeout(这个有时候也被称作  “three-strike timeout”。3 strike 翻译为“三振出局” ,通常出现问题的时候CPU会进行多次尝试,尝试都失败后就放弃之)。这里提到的 ROB 在前面有介绍过,作用是:“Retirement (Reorder buffer, ROB) ,”主要用于记录μops的状态以及存储EU执行完成后返回的结果,然后按照in-order的顺序把执行结果写回寄存器”。ROB Timeout 的意思是有正在执行的指令超时。所有的指令发送给下一层的 Scheduler 来分配执行的时候会进行记录,如果15秒之后无法得到结果,会报告这个错误。

很明显这样的错误更容易出现在内存读写,IO读写等等和外围设备打交道的情景中。【参考4】提到的错误是发生在内存读写中,发生问题的内存地址是一个 PCIE设备映射的位置,最终配合PCIE 逻辑分析仪找到了原因。

作为BIOS工程师,大部分工作是在诊断定位问题,真正BIOS本身的问题少之又少,类似上面这种问题,如果能确定是某个PICE 的问题,下面直接交给对应工程师或者联系厂商就可以了。

参考:

  1. https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/10th-gen-core-families-datasheet-vol-1-datasheet.pdf
  2. https://www.intel.com/content/dam/www/public/us/en/documents/research/2012-vol16-iss-2-intel-technology-journal.pdf
  3. https://blog.csdn.net/zwl1584671413/article/details/83095044?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163100098916780265447231%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163100098916780265447231&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-1-83095044.pc_v2_rank_blog_default&utm_term=OD&spm=1018.2226.3001.4450 单片机I/O口推挽输出与开漏输出的区别(open-drain与push-pull)
  4. https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/rob-timeout-debug-guide-paper.pdf

EDK2 202108 来了

edk2-stable202108 在  https://github.com/tianocore/edk2/releases/tag/edk2-stable202108

下载解压 stable202108.tar.gz 之后,尝试编译自带的模拟环境:

  1. edksetup.bat
  2. build -a X64 -p EmulatorPkg\EmulatorPkg.dsc

会遇到下面的错误

stable202108 报错1

错误的原因是无法找到 Brotli相关的内容。解决方法是下载 submodule-MdeModulePkg-Library-BrotliCustomDecompressLib-brotli.zip 将解压后的内容放到\MdeModulePkg\Library 目录下。

再次编译遇到下面的错误:

        "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\x86_amd64\cl.exe" /showIncludes /nologo /E /TC /DVFRCOMPILE /FIFileExplorerLibStrDefs.h /Ic:\buildbs\stable202108\MdeModulePkg\Library\FileExplorerLib  /Ic:\buildbs\stable202108\Build\EmulatorX64\DEBUG_VS2015x86\X64\MdeModulePkg\Library\FileExplorerLib\FileExplorerLib\DEBUG  /Ic:\buildbs\stable202108\MdePkg  /Ic:\buildbs\stable202108\MdePkg\Include  /Ic:\buildbs\stable202108\MdePkg\Test\UnitTest\Include  /Ic:\buildbs\stable202108\MdePkg\Include\X64  /Ic:\buildbs\stable202108\MdeModulePkg  /Ic:\buildbs\stable202108\MdeModulePkg\Include  /Ic:\buildbs\stable202108\MdeModulePkg\Library\BrotliCustomDecompressLib\brotli\c\include c:\buildbs\stable202108\MdeModulePkg\Library\FileExplorerLib\FileExplorerVfr.vfr > c:\buildbs\stable202108\Build\EmulatorX64\DEBUG_VS2015x86\X64\MdeModulePkg\Library\FileExplorerLib\FileExplorerLib\OUTPUT\FileExplorerVfr.i
BootManagerVfr.Vfr
DeviceManagerVfr.Vfr
'VfrCompile' is not recognized as an internal or external command,
operable program or batch file.

查了一下,这个错误应该是 VfrCompile 这个工具没有编译为 EXE 导致的。所以我们需要先编译准备好 Windows 下的Build工具。命令:

edksetup.bat Rebuild

错误如下:

Microsoft (R) Program Maintenance Utility Version 14.00.24210.0
Copyright (C) Microsoft Corporation.  All rights reserved.

        cl.exe -c  /nologo /Zi /c /O2 /MT /W4 /WX /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /W2 -I .\brotli\c\include  -I . -I C:\BuildBs\stable202108\BaseTools\Source\C\Include -I C:\BuildBs\stable202108\BaseTools\Source\C\Include\Ia32 -I C:\BuildBs\stable202108\BaseTools\Source\C\Common BrotliCompress.c -FoBrotliCompress.obj
cl : Command line warning D9025 : overriding '/W4' with '/W2'
BrotliCompress.c
BrotliCompress.c(20): fatal error C1083: Cannot open include file: './brotli/c/common/constants.h': No such file or directory
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\cl.exe"' : return code '0x2'
Stop.

NMAKE : fatal error U1077: 'if' : return code '0x1'
Stop.
NMAKE : fatal error U1077: 'if' : return code '0x1'
Stop.

应该是缺少BrotliCompress的代码导致的,下载 submodule-BaseTools-Source-C-BrotliCompress-brotli.zip,将内容解压到 \BaseTools\Source\C\BrotliCompress\brotli 中。

再次编译能够正常生成build工具:

stable202108 编译 BaseTools

此外,再次强调必须使用 x86 编译窗口,我是用的是VS2015。

接下来再次编译模拟工具,成功:

stable202108 编译成功

运行  \Build\EmulatorX64\DEBUG_VS2015x86\X64\WinHost.exe

stable202108 模拟器

之后测试编译支持SecureBoot 的OVMF BIOS:

build -a X64 -p OvmfPkg\OvmfPkgx64.dsc -D SECURE_BOOT_ENABLE=TRUE

收到错误提示如下:

Processing meta-data .
Architecture(s)  = X64
Build target     = DEBUG
Toolchain        = VS2015x86

Active Platform          = c:\buildbs\stable202108\OvmfPkg\OvmfPkgX64.dsc
...

build.py...
c:\buildbs\stable202108\CryptoPkg\Library\OpensslLib\OpensslLibCrypto.inf(26): error 000E: File/directory not found in workspace
        c:\buildbs\stable202108\CryptoPkg\Library\OpensslLib\openssl\e_os.h

和前面的方法一样,补充 submodule-CryptoPkg-Library-OpensslLib-openssl.zip 文件到

\CryptoPkg\Library\OpensslLib\openssl 目录下。,

之后即可正常编译。

本问题到的完整编译环境已经打包,可以在 https://pan.baidu.com/s/1pqD3XYAzrZbExRQALxs4OQ 提取码: tuqy  下载。

寄存器重命名(register renaming)

寄存器重命名是计算机CPU的微体系结构(Microarchitecture)中的一种技术,避免了机器指令或者微指令(μop)不必要的顺序化执行,从而提高了处理器的指令级并行的能力。【参考1】

例如:

mov eax, [mem1]
imul eax, 6
mov [mem2], eax
mov eax, [mem3]
add eax, 2
mov [mem4], eax

这段代码看起来是依赖于 EAX 的计算结果,但是如果将最后三条指令中的 EAX 替换为其他寄存器,就可以清楚的看到代码是在执行两个独立的操作:[MEM1]乘以6结果保存在[MEM2], 以及[MEM3]加上2之后存在[MEM4]中。就是说,这两个操作完全可以并行执行。处理器会自动给最后三条指令分配一个另外的寄存器,这样两个运算可以同时进行。

参考:

1.https://baike.baidu.com/item/%E5%AF%84%E5%AD%98%E5%99%A8%E9%87%8D%E5%91%BD%E5%90%8D/10927257?fr=aladdin

好用的 ESP32 DS1307 库

最近需要实验使用 DS1307 作为 RTC,惊奇的发现很多库都是为标准 Arduino 开发的,因此可能遇到使用 ESP32 不支持的寄存器,或者 TimeLib.h 没有定义的情况。

经过一段时间的探索,找到了来自下面这个网址的库

https://www.elecrow.com/wiki/index.php?title=Tiny_RTC

经过实验(在 DFRobot FireBeetle上),可以正常工作。

代码如下:
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 RTC;

void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
}
void loop () {
    DateTime now = RTC.now(); 
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println(); 
    delay(1000);
}
DS1307 取得时间

有需要的朋友可以在这里:

乱序执行 (out-of-order execution)

乱序执行(out-of-order execution)是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。比方Core乱序执行引擎说程序某一段有7条指令,此时CPU将根据各单元电路的空闲状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路执行。

这好比请A、B、C三个名人为晚会题写横幅“春节联欢晚会”六个大字,每人各写两个字。如果这时在一张大纸上按顺序由A写好”春节”后再交给B写”联欢”,然后再由C写”晚会”,那么这样在A写的时候,B和C必须等待,而在B写的时候C仍然要等待而A已经没事了。但如果采用三个人分别用三张纸同时写的做法, 那么B和C都不必须等待就可以同时各写各的了,甚至C和B还可以比A先写好也没关系(就象乱序执行),但当他们都写完后就必须重新在横幅上(自然可以由别人做,就象CPU中乱序执行后的重新排列单元)按”春节联欢晚会”的顺序排好才能挂出去。【参考1】

从Intel 第六代 CPU(Pentuim Pro) 开始, 引入了乱序执行的功能。通过前面的介绍也可以看出来 CPU 需要确定后面要执行的指令并不依赖于前面的指令。比如:计算 a=1+2, b= a+1, 这种情况是无法先进行 b=a+1 运算的。这种依赖被称作依赖链。

首先,处理器将指令转为微指令(μop)。比如: ADD EAX,EBX 这样的只对应一个μop;但是像 ADD EAX,[MEM1] 会生成2个μop:一条指令是从内存读取数值到寄存器,另外一条是将保存内存值的寄存器和 EAX 相加;再例如 ADD [MEM1],EAX 会生成3个μop:第一个是从内存取值,一个是进行相加,最后一个是将结果传输到内存中。这样做的好处是,拆分之后的μop可以进行乱序执行:

例如:

mov eax,[mem1]
imul eax,5
add eax[mem2]
mov [mem3],eax

这里 ADD EAX,[MEM2] 拆分为2条μop。这样计算 imul eax, 5 的时候可以同时到内存中读取[MEM2]。如果Cache 中没有数据,那么处理器读取[MEM1]之后会马上进行读取[MEM2]的操作。

再比如堆栈操作指令拆分为μop之后运行会更有效率。例如:

push eax
call func

如果没有将 PUSH 拆分为2条μop的话,因为 CALL 操作需要依赖于 ESP ,所以 CALL 需要等待 PUSH EAX 之后才能执行。如果将 PUSH eax 指令拆分为2个μop: SUB ESP,4 和 MOV [ESP],EAX。 那么 SUB ESP,4 可以在 EAX 还没有赋值之前执行。这样就解除了CALL 指令的路径依赖。可见在μop的帮助下,堆栈的操作能够节省时间。【参考2】

参考:

1.https://baike.baidu.com/item/%E4%B9%B1%E5%BA%8F%E6%89%A7%E8%A1%8C/4944129?fr=aladdin

2.https://www.agner.org/optimize/microarchitecture.pdf

CISC 和 RISC

计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。指令集,就是CPU中用来计算和控制计算机系统的一套指令的集合,而每一种新型的CPU在设计时就规定了一系列与其他硬件电路相配合的指令系统。比如:日常生活中,“去吃饭”这样的命令可以看作是简单的指令。根据我的观察,男人和女人在指令集上是存在差别的。男人理解的指令集通常只是女人指令集的子集。譬如说,女人对于“洗衣服”指令的理解是包括“将衣物放入洗衣机启动洗涤”,“洗衣完成后晾衣服”以及“晾干后收起来”;但是对于男人来说“洗衣服”指令只是 “将衣物放入洗衣机启动洗涤” 的含义。

指令集的先进与否,也关系到CPU的性能发挥,它也是CPU性能体现的一个重要标志。每款CPU在设计时就规定了一系列与其硬件电路相配合的指令系统。指令的强弱也是CPU的重要指标,指令集是提高微处理器效率的最有效的工具之一。从现阶段的主流体系结构讲,指令集可分为CISC和RISC两种。

CISC是“复杂指令集计算机”的缩写:Complex Instruction Set Computer。我们日常使用的 X86 就是 CISC 的典型代表。

计算机处理器包含有实现各种功能的指令或微指令,指令集越丰富,为微处理器编写程序就越容易,但是丰富的微指令集会影响其性能。复杂指令集计算机(CISC)体系结构的设计策略是使用大量的指令,包括复杂指令。与其他设计相比,在CISC中进行程序设计要比在其他设计中容易,因为每一项简单或复杂的任务都有一条对应的指令。程序设计者不需要写一大堆指令去完成一项复杂的任务。 但指令集的复杂性使得CPU和控制单元的电路非常复杂。[1]

RISC是“精简指令集计算机”的缩写:Reduced Instruction Set Computing RISC)。RISC的指令系统相对简单,它只要求硬件执行很有限且最常用的那部分指令,大部分复杂的操作则使用成熟的编译技术,由简单指令合成。RISC结构采用精简的,长短划一的指令集,使大多数的操作获得了尽可能高的效率。某些在传统结构中要用多周期指令实现的操作,在RISC结构中,通过机器语言编程,就代之以多条单周期指令了。【参考1】

接下来用一个例子来说明二者的区别。

假设我们有一个这样的计算机:内存是一个 6×4 的数组, 有A-F 6个寄存器。

对于 CISC 来说,如果想完成内存中2个数值的相乘的操作,可以直接使用下面的指令:

MULT 2:3,5:2

这里的 MULT 就是一个“复杂指令”。 进一步,如果设定变量 x 为内存 2:3 中的值。 y 为内存 5:2 的值,上面的指令就可以理解为C语言的 x=x*y。

如果用 RISC 来完成,那么需要写成如下的指令:

LOAD A, 2:3
LOAD B, 5:2
PROD A, B
STORE 2:3, A

从这个结果上来看,RISC 效率更低,因为需要执行更多的代码,使用更多的内存。但是实际上 RISC 的指令通常只需要1个机器周期来完成,所以整体上消耗时间和CISC 的 MULT 指令相同,另外因为 RISC 机器码指令长度相同,执行时只需要一个机器周期所以更适合流水线方式执行(我的理解是方便硬件预读取和判断)。【参考2】

虽然 Intel X86 CPU 是 CISC 的典型代表,但是它的内部也存在RISC 的设计概念。所有的操作都会被分解为微指令再执行。微指令是典型的 CISC 的指令。

微指令(英语:microcode,μop),还有翻译为微码或者微操作,为了避免歧义,后面全部使用 μop,是在CISC结构下,运行一些功能复杂的指令时,所分解一系列相对简单的指令。相关的概念最早在1947年开始出现。
微指令的作用是将机器指令与相关的电路实现分离,这样一来机器指令可以更自由的进行设计与修改,而不用考虑到实际的电路架构。与其他方式比较起来,使用微指令架构可以在降低电路复杂度的同时,建构出复杂的多步骤机器指令。撰写微指令一般称为微程序设计(microprogramming),而特定架构下的处理器实做中微指令有时会称为微程序(microprogram)。


现代的微指令通常由CPU工程师在设计阶段编写,并且存储在只读内存(ROM, read-only-memory)或可编程逻辑数组(PLA, programmable logic array)中。然而有些机器会将微指令存储在静态随机存取内存(SRAM)或是闪存(flash memory)中。它通常对普通程序员甚至是汇编语言程序员来说是不可见的,也是无法修改的。与机器指令不同的是,机器指令必须在一系列不同的处理器之间维持兼容性,而微指令只设计成在特定的电路架构下运行,成为特定处理器设计的一部分。【参考3】

参考:
1.https://baike.baidu.com/item/%E7%B2%BE%E7%AE%80%E6%8C%87%E4%BB%A4%E9%9B%86%E8%AE%A1%E7%AE%97%E6%9C%BA/661859?fromtitle=risc&fromid=62696#viewPageContent

2.https://cs.stanford.edu/people/eroberts/courses/soco/projects/risc/risccisc/

3.https://baike.baidu.com/item/%E5%BE%AE%E7%A0%81/10708310?fr=aladdin

3.http://www.enroo.com/support/category1/dpjrmzs/78378500.html 什么是RISC架构?RISC架构的优点与缺点

4.http://www.enroo.com/support/category1/dpjrmzs/38700314.html 什么是CISC体系结构?CISC架构的优点与缺点

5.https://teachcomputerscience.com/risc-and-cisc-processors/ RISC and CISC Processors

6.https://www.zhihu.com/question/404743266/answer/1321179351 这里还有一个 X86 为什么选择 CISC 的历史。

CISC诞生的原因也很简单,第一,当时的主流看法是设计硬件比设计编译器简单;第二,而且当时的内存很贵,以8086开始设计的1976年来看,当时4KB内存需要159美元,8KB内存需要250美元;第三,当时的内存速度很慢,而寄存器价格上天,8086只有约20000个晶体管,而寄存器为了存储16bit数据就花费了至少256个晶体管。

8086的祖宗8008只有3500个晶体管,配合0.5Mhz的时钟频率,连寄存器-寄存器的复制都需要20us,更别说当时的内存速度了。

8008时期的DRAM每字节高达2.52美元,实现一个完整的系统就需要几千字节,基于各种原因,微架构工程师只能让处理器在使用同样的资源下尽可能的多干一些活,让一个指令干完全部工作,在RISC出来之后这种方式就被叫做复杂指令集了(CISC)

在70年代后期,随着编译器的普及和汇编的减少,正交寻址几乎被程序员忽略,虽然当时的编译器不能完全利用CISC处理器的优势,但是显然历史的车轮是不会停下的,于是乎正交寻址变得更加没用了。

实际上随着集成电路的发展,一些复杂指令集相比一系列简单的指令集更慢,因为芯片越来越复杂,但是设计者显然没有时间针对几百条指令的每一条都进行优化。几乎就在同时,得益于半导体工艺的进步,微处理器的运行速度变得比内存更快,而且可以预见的是在未来这个差距会变得越来越大,因此就需要腾出空间去安排更多的寄存器和缓存。

FireBeetle USB KB/MS Shield

USB 键盘鼠标是最常见的输入设备了,之前如果想在 Arduino 上使用这两种设备,一个可行的方法是使用 USB Host Shield。这种方法的缺点是:成本比较高(MAX3421E芯片贵),操作复杂(SPI接口),资料少。因为这样缺点的存在,USB Host Shield 在使用上存在诸多不便。偶然间看到USB键鼠转串口通讯控制芯片CH9350(南京沁恒,WCH,阅读过我文章的朋友都知道CH340 也是他们家的产品)。这款能够将 USB 键盘鼠标的有效信息转为串口数据。芯片特点如下:

  • 支持12Mbps全速USB传输和1.5Mbps低速USB传输,兼容USB V2.0。
  • 上位机端USB端口符合标准HID类协议,不需要额外安装驱动程序,支持内置HID类设备驱动的Windows、Linux、MAC等操作系统。
  • 同一芯片可配置为上位机模式和下位机模式,分别连接USB-Host主机和USB键盘、鼠标。
  • 支持USB键盘鼠标在BIOS界面使用,支持多媒体功能键,支持不同分辨率USB鼠标。
  • 支持各种品牌的USB键盘鼠标、USB无线键盘鼠标、USB转PS2线等。
  • 上位机端和下位机端支持热插拔。
  • 提供发送状态引脚,支持485通讯。
  • 串口支持115200/57600/38400串口通信波特率。
  • 内置晶振和上电复位电路,外围电路简单。
  • 支持5V、3.3V电源电压。
  • 提供LQFP-48无铅封装,兼容RoHS。

于是尝试给 ESP32 FireBeetle 绘制一个  USB Keyboard/Mouse Shield,让 ESP32 能够轻松的获得 USB 键盘鼠标数据。

第一步,设计电路。核心是 CH9350芯片,它能够一次性支持2个 USB Host接口,下图中的 USB1 和 USB2。LED1 和 LED2 是通讯指示灯,对应的 USB1 和 USB2 如果有正常的通讯,对应的 LED会熄灭。此外,还有一个USB_Power 是USB公头,用于从外部取电,避免 FireBeetle 供电不足的情况。

CH9350L 最小系统

PCB 设计如下:

CH9350L PCB

3D 预览如下:

做出来就是这样(美中不足的因为2个USB 母头的存在,这个板子稍微大一些。另外,这个芯片引脚比较密集,焊接费了一些功夫,如果你对自己焊接技术不放心,推荐直接 SMT 避免手工焊接):

因为芯片使用串口输出,所以很容易就能够获得数据。数据格式在 Data Sheet 上有描述:

CH9350L 输出数据格式

解析数据会出现在 FireBeetle Serial2上。

电路图是立创 EDA设计的,如下:

对应的 CH9350L Datasheet

再读 eSPI

5年前,我给出过如果有可能尽量不要在设计上使用 eSPI 接口,时至今日,至少在平板和笔记本上 eSPI 已经完全取代了 LPC 接口, 我们需要对此有所了解。

首先 eSPI 相比之前的 LPC 总线,有着速度更快的优势。最新的 ADL-P 平台上,eSPI 可达50Mhz (最多支持4个数据线,一次性可以传输 4Bits).

此外,还提供了虚拟信号的功能,比如,可以从eSPI上发送 SMI# 信号,这样无需外部有SMI# 的引线即可让 EC 发送 SMI# 请求。从另外的角度来说,使用 eSPI 之后可以简化布线节省 PCB 空间。

再有就是提供通过 PECI 读取CPU /PCH 温度这样的功能,便于 EC 进行温度方面的控制。这样可以实现更好的散热功能。

传统的设计上, BIOS 和 EC 的 Firemware 是分别存储在两个 SPI NOR 中的:

使用 eSPI 之后可以共享。共享方式有如下两种:

第一种:挂接在 PCH 上,EC 访问需要通过 PCH 的 eSPI Master, 称作 Master Attached Flash Sharing (简称 MAFS,或者 MAF),这种模式下 EC 通过PCH 中的SPI Master 来访问存放在 SPI Nor 中的 EC Firmware。

MAFS

特别注意的是,还有一种 MAFS 的变种 G3 Flash Sharing,特别之处在于 EC 和 PCH 都是直连 SPI Nor。在PCH Reset 之前,EC 作为 SPI master 需要完成读取 Firmware 的动作。PCH Reset 之后,PCH 作为 SPI Master 来和 SPI Nor 进行通讯。G3 Flash Sharing 的设定和CSME以及BIOS 无关,完全是硬件动作,所以你也无法在 FIT 中找到设定的选项(个人非常不建议用这个模式,因为出现问题不容易判断产生错误的原因,可能是硬件也可能是 EC Firmare) 随着时代的进步,G3 Sharing 已经成为主流,现在建议跟随 Intel 参考设计进行:

第二种,SPI 挂在 EC 下面,PCH 访问需要透过EC, 这种称作 Slave Attached Flash Sharing(简称 SAFS,或者 SAF)

SAFS

个人建议:尽量不要使用共享模式,虽然能帮老板省一点钱,但是可能会有未知的问题。或者说参考板用哪种,尽量用哪种。特别是新的 Chipset ,理论上全部都可以支持,但是很可能非参考板的设计目前尚未验证过,如果想让它正常工作还需要特别的PMC 之类的设定。

参考:

1.https://blog.csdn.net/gkcywbcbjpvel404/article/details/107401736

2.Intel: Enhanced SPI (eSPI) Platform Enabling and Debug Guide

ESP32 的 Software Serial 库

ESP32 支持3个串口,ESP32 S2支持2个串口。但是,你终究会遇到需求比硬件支持多一个的情况。这种情况下就需要使用软串口。

这里推荐一个 ESP32 SoftSerial ,经过我的测试可以在ESP32 S2 上正常使用。

示例代码如下,使用 GPIO12 发送,未使用接收功能,比如,我们需要多出来的串口输出调试信息:
#include <SoftwareSerial.h>
                   // RX TX
SoftwareSerial swSer(SW_SERIAL_UNUSED_PIN, 12, false, 256);

void setup() {
  Serial.begin(115200);
  swSer.begin(115200);

  Serial.println("\nSoftware serial test started");

  for (char ch = ' '; ch <= 'z'; ch++) {
    swSer.write(ch);
  }
  swSer.println("");

}

void loop() {
  while (swSer.available() > 0) {
    Serial.write(swSer.read());
  }
  while (Serial.available() > 0) {
    swSer.write(Serial.read());
  }

}

库文件:

来自:https://github.com/akshaybaweja/SoftwareSerial