最近偶然看到这本书,大概浏览了一下,非常适合初学者阅读。
从零开始的UEFI裸机编程
フルスクラッチで作る!UEFIベアメタルプログラミング
大神 祐真 著, 神楽坂琴梨 译

本书的目录:
- 从零开始的UEFI裸机编程
- 译者的话
- 1. 第一部分
- 2. 第二部分
- 关于本书
中译本在 https://kagurazakakotori.github.io/ubmp-cn/index.html 可以看到,有兴趣的朋友可以查看。
最近偶然看到这本书,大概浏览了一下,非常适合初学者阅读。
从零开始的UEFI裸机编程
フルスクラッチで作る!UEFIベアメタルプログラミング
大神 祐真 著, 神楽坂琴梨 译
本书的目录:
中译本在 https://kagurazakakotori.github.io/ubmp-cn/index.html 可以看到,有兴趣的朋友可以查看。
前面介绍了 Shell 下的 IoApic 的读写,这次研究一下 Windows 下面的。在 Windows 下面,我们可以直接使用 RW_Everything 来进行读取,设定如下:
读取结果如下:
我们特别关注 0x12 偏移处的值为 0x980 (这台机器和之前的 WinDBG 调试的不是同一个机器,IoApic 不同)。我猜测这里是PS/2 keyboard 的 IRQ0。参照资料修改 Bit16 (Interrupt Mask),设置为1会 Disable 这个中断。于是 x012 会被写为 0x0001 0980,这时候我发现键盘无法工作了。
测试的这个机器是笔记本,键盘是挂在EC 下面的,EC汇报给系统的是PS/2键盘。
于是,通过这样的方式我阻止了 IRQ1 的产生,因此按键会无效。接下来,再将这个恢复为之前的 0x980,但是笔记本键盘是不工作的。我猜测应该有可能是按键堵住了 Buffer,所以再使用 RW 读取 0x60 IO port(就是打开 0x60 IO Port 页面看一下),键盘即恢复了工作。有兴趣的朋友可以自行尝试,记得需要连接一个 USB 键盘。
结论:我们现在谈论的IRQ 只的是针对 IOAPIC的Number, 比如,IRQ1 位于 I/O Redirection Table Register 1 的位置,同时这个 Register 会给出对应的 Vector。当中断发生时,CPU 会根据 Vector 找到 IDT 中给出来的ISR (Interrupt Service Routine)。
额外的实验,我们可以编写一个 Python Script 来配合 Dbc实现 IoApic 的读取,代码如下:
def Test():
def get_APIC_DAT(index):
_base.mem(0xfec00000 , 1, index)
return _base.mem(0xfec00010, 4)
import common.baseaccess as _baseaccess
_base = _baseaccess.getglobalbase()
print("Script from www.lab-z.com")
for i in range(0,0x77):
print("%02x:%08X %08X" %(i,get_APIC_DAT(0x10+i*2),get_APIC_DAT(0x10+i*2+1)))
上述代码命名为 myscript.py, 运行结果如下:
20220114 RW_Everything 访问 0x60 port 的方法如下:
最近在编写一个Shell 下读取 IoApic 的工具,首先实验直接调用 IoApicLib来实现,为此,在 AppPkg.dsc 中加入下面三个 Lib:
IoApicLib|PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
之后在自己的App 中引用IoApicLib。但是这样编译出来的EFI 在运行期会死机,甚至没有运行到 Application第一行就会死机。经过研究发现在 DxeAcpiTimerLib.inf 中有如下设定:
CONSTRUCTOR = DxeAcpiTimerLibConstructor
因此,DxeAcpiTimerLibConstructor会先于我们的Application入口执行,其中的代码会导致运行时死机(但是具体原因我没有分析)。
所以,需要手工编写一个读取的工具。
首先,研究一下读取的方法,根据【参考1】给出的指引,在内存中有暴露出2个内存地址作为 Index 和Data,在目前我们的电脑上都是 0xFEC0 0000h
和0xFEC 0010h. 具体的读取操作是在 Index 给出的内存地址写入要访问的寄存器索引,之后 Data 给出的内存位置就是这个寄存器的值。
具体的寄存器分布如下:
上面的 01h(IOAPICVER) 中会给出来 Redirection Table 的实际数量,Spec 中给出只有24个,但是现在通常会多于这个数量。
最终的代码如下(其中的 IoApicLib.h 等代码也都是直接从 ED2 代码中提取组合而成):
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/IoLib.h>
#include <Library/ShellLib.h>
#include "IoApicLib.h"
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
IO_APIC_VERSION_REGISTER Version;
IO_APIC_REDIRECTION_TABLE_ENTRY Entry;
UINTN Irq;
ShellSetPageBreakMode(TRUE);
Version.Uint32 = IoApicRead (IO_APIC_VERSION_REGISTER_INDEX);
Print(L"Version : %X \n",Version.Bits.Version);
Print(L"Max Entry: %X \n",Version.Bits.MaximumRedirectionEntry);
for (Irq=0;Irq<Version.Bits.MaximumRedirectionEntry; Irq++) {
Entry.Uint32.Low = IoApicRead (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2);
Entry.Uint32.High = IoApicRead(IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2+1);
Print(L"Int%02X: %08X %08X \n",Irq,Entry.Uint32.Low,Entry.Uint32.High);
}
return EFI_SUCCESS;
}
运行结果:
如果觉得上面的读取方式过于复杂,还可以直接使用 MMIO 的方式来访问,通过调用 IoLib 的方式实现 MmIo 的访问代码非常简单:
for (Irq=0;Irq<Version.Bits.MaximumRedirectionEntry; Irq++) {
MmioWrite8 (0xFEC00000, IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX+(UINT8)Irq*2);
Entry.Uint32.Low=MmioRead32 (0xFEC00000+0x10);
MmioWrite8 (0xFEC00000, IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX+(UINT8)Irq*2+1);
Entry.Uint32.High=MmioRead32 (0xFEC00000+0x10);
Print(L"%08X %08X \n",Entry.Uint32.Low,Entry.Uint32.High);
}
在实体机上这两种方法没有差别,结果是相同的。完整代码和 X64 EFI 可以在这里下载:
最近研究了一下旋转编码器的使用。入手的是 ALPS EC11系列的:
为了让它工作,自己做了电路板电阻配合【参考1】。电路图和 PCB 设计如下:
工程可以在这里下载:
软件方面使用了ai-esp32-rotary-encoder 库,下面是一个同时使用2个旋转编码器的例子(特特别注意:不是任何的GPIO 都能选择成为和旋转编码器连接的引脚,某些连接之后会导致无法启动,有可能是因为部分ESP32在启动时会选做接口VSPI,如果你了解原因不妨在评论中指出。谢谢! ):
#include "AiEsp32RotaryEncoder.h"
#include "Arduino.h"
/*
connecting Rotary encoder
CLK (A pin) - to any microcontroler intput pin with interrupt -> in this example pin 32
DT (B pin) - to any microcontroler intput pin with interrupt -> in this example pin 21
SW (button pin) - to any microcontroler intput pin -> in this example pin 25
VCC - to microcontroler VCC (then set ROTARY_ENCODER_VCC_PIN -1) or in this example pin 25
GND - to microcontroler GND
*/
#define ROTARY_ENCODER1_A_PIN 4
#define ROTARY_ENCODER1_B_PIN 16
#define ROTARY_ENCODER1_BUTTON_PIN 2
AiEsp32RotaryEncoder rotaryEncoder1 = AiEsp32RotaryEncoder(ROTARY_ENCODER1_A_PIN, ROTARY_ENCODER1_B_PIN, ROTARY_ENCODER1_BUTTON_PIN, -1);
void rotary1_onButtonClick() {
Serial.println("Button1 Pressed!");
}
void rotary1_loop() {
//first lets handle rotary encoder button click
if (rotaryEncoder1.currentButtonState() == BUT_RELEASED) {
//we can process it here or call separate function like:
rotary1_onButtonClick();
}
//lets see if anything changed
int16_t encoderDelta = rotaryEncoder1.encoderChanged();
//for some cases we only want to know if value is increased or decreased (typically for menu items)
if (encoderDelta>0) Serial.print("+");
if (encoderDelta<0) Serial.print("-");
//for other cases we want to know what is current value. Additionally often we only want if something changed
//example: when using rotary encoder to set termostat temperature, or sound volume etc
//if value is changed compared to our last read
if (encoderDelta!=0) {
//now we need current value
int16_t encoderValue = rotaryEncoder1.readEncoder();
//process new value. Here is simple output.
Serial.print("Rot 1 value: ");
Serial.println(encoderValue);
}
}
#define ROTARY_ENCODER2_A_PIN 26
#define ROTARY_ENCODER2_B_PIN 27
#define ROTARY_ENCODER2_BUTTON_PIN 14
AiEsp32RotaryEncoder rotaryEncoder2 = AiEsp32RotaryEncoder(ROTARY_ENCODER2_A_PIN, ROTARY_ENCODER2_B_PIN, ROTARY_ENCODER2_BUTTON_PIN, -1);
void rotary2_onButtonClick() {
Serial.println("Button2 Pressed!");
}
void rotary2_loop() {
//first lets handle rotary encoder button click
if (rotaryEncoder2.currentButtonState() == BUT_RELEASED) {
//we can process it here or call separate function like:
rotary2_onButtonClick();
}
//lets see if anything changed
int16_t encoderDelta = rotaryEncoder2.encoderChanged();
//for some cases we only want to know if value is increased or decreased (typically for menu items)
if (encoderDelta>0) Serial.print("+");
if (encoderDelta<0) Serial.print("-");
//for other cases we want to know what is current value. Additionally often we only want if something changed
//example: when using rotary encoder to set termostat temperature, or sound volume etc
//if value is changed compared to our last read
if (encoderDelta!=0) {
//now we need current value
int16_t encoderValue = rotaryEncoder2.readEncoder();
//process new value. Here is simple output.
Serial.print("Rot 2 value: ");
Serial.println(encoderValue);
}
}
void setup() {
Serial.begin(115200);
Serial.println("Starttesting");
//we must initialize rorary encoder
rotaryEncoder1.begin();
rotaryEncoder1.setup([]{rotaryEncoder1.readEncoder_ISR();});
//optionally we can set boundaries and if values should cycle or not
rotaryEncoder1.setBoundaries(0, 10, true); //minValue, maxValue, cycle values (when max go to min and vice versa)
//we must initialize rorary encoder
rotaryEncoder2.begin();
rotaryEncoder2.setup([]{rotaryEncoder2.readEncoder_ISR();});
//optionally we can set boundaries and if values should cycle or not
rotaryEncoder2.setBoundaries(0, 10, true); //minValue, maxValue, cycle values (when max go to min and vice versa)
}
void loop() {
//in loop call your custom function which will process rotary encoder values
rotary1_loop();
rotary2_loop();
delay(50);
}
上述测试代码:
库可以在这里下载:
测试的照片:
参考:
1.
之前在 Teensy上使用过 ILI9341 的屏幕【参考1】,这次在 FireBeelte(ESP32)上使用这个屏幕,相比之下 ESP32 可以很轻松的使用 40Mhz的SPI 频率。
连接如下:
ILI9341屏幕 | GND | VCC | CLK | MOS | RES | DC | BLK | MIS |
FireBeelte | GND | VCC (推荐) 3.3V也可以 | SCK/IO18 | MOSI/IO23 | D2/IO25 | D9/IO2 | NA | MISO/IO19 |
在程序开头有2种定义方式:
1.类似 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 这种是指定使用硬件 SPI,速度快(我看资料理论可以达到 80Mhz, 实际测试 40Mhz 完全没问题)
2.类似 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); 这种定义是 SW SPI 最高在 1.2Mhz 左右
测试代码是 Adafruit_GFX_Library的例子 mock_ili9341.ino, 有修过如下:
/***************************************************
This is our GFX example for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
// For the Adafruit shield, these are the default.
//#define TFT_DC 9
//#define TFT_CS 10
// For the Adafruit shield, these are the default.
//#define TFT_DC D9
#define TFT_DC 21
#define TFT_CS D8
#define TFT_MOSI MOSI
#define TFT_CLK SCK
//#define TFT_RST D2
#define TFT_RST 22
#define TFT_MISO MISO
// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
void setup() {
Serial.begin(9600);
Serial.println("ILI9341 Test!");
tft.begin(2000000UL);
// read diagnostics (optional but can help debug problems)
uint8_t x = tft.readcommand8(ILI9341_RDMODE);
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDMADCTL);
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDPIXFMT);
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDIMGFMT);
Serial.print("Image Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDSELFDIAG);
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
Serial.println(F("Benchmark Time (microseconds)"));
delay(10);
Serial.print(F("Screen fill "));
Serial.println(testFillScreen());
delay(500);
Serial.print(F("Text "));
Serial.println(testText());
delay(3000);
Serial.print(F("Lines "));
Serial.println(testLines(ILI9341_CYAN));
delay(500);
Serial.print(F("Horiz/Vert Lines "));
Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
delay(500);
Serial.print(F("Rectangles (outline) "));
Serial.println(testRects(ILI9341_GREEN));
delay(500);
Serial.print(F("Rectangles (filled) "));
Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
delay(500);
Serial.print(F("Circles (filled) "));
Serial.println(testFilledCircles(10, ILI9341_MAGENTA));
Serial.print(F("Circles (outline) "));
Serial.println(testCircles(10, ILI9341_WHITE));
delay(500);
Serial.print(F("Triangles (outline) "));
Serial.println(testTriangles());
delay(500);
Serial.print(F("Triangles (filled) "));
Serial.println(testFilledTriangles());
delay(500);
Serial.print(F("Rounded rects (outline) "));
Serial.println(testRoundRects());
delay(500);
Serial.print(F("Rounded rects (filled) "));
Serial.println(testFilledRoundRects());
delay(500);
Serial.println(F("Done!"));
}
void loop(void) {
for(uint8_t rotation=0; rotation<4; rotation++) {
tft.setRotation(rotation);
testText();
delay(1000);
}
}
unsigned long testFillScreen() {
unsigned long start = micros();
tft.fillScreen(ILI9341_BLACK);
yield();
tft.fillScreen(ILI9341_RED);
yield();
tft.fillScreen(ILI9341_GREEN);
yield();
tft.fillScreen(ILI9341_BLUE);
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
return micros() - start;
}
unsigned long testText() {
tft.fillScreen(ILI9341_BLACK);
unsigned long start = micros();
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
tft.println(1234.56);
tft.setTextColor(ILI9341_RED); tft.setTextSize(3);
tft.println(0xDEADBEEF, HEX);
tft.println();
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(5);
tft.println("Groop");
tft.setTextSize(2);
tft.println("I implore thee,");
tft.setTextSize(1);
tft.println("my foonting turlingdromes.");
tft.println("And hooptiously drangle me");
tft.println("with crinkly bindlewurdles,");
tft.println("Or I will rend thee");
tft.println("in the gobberwarts");
tft.println("with my blurglecruncheon,");
tft.println("see if I don't!");
return micros() - start;
}
unsigned long testLines(uint16_t color) {
unsigned long start, t;
int x1, y1, x2, y2,
w = tft.width(),
h = tft.height();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = y1 = 0;
y2 = h - 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t = micros() - start; // fillScreen doesn't count against timing
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = w - 1;
y1 = 0;
y2 = h - 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = 0;
y1 = h - 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = w - 1;
y1 = h - 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
yield();
return micros() - start;
}
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height();
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
return micros() - start;
}
unsigned long testRects(uint16_t color) {
unsigned long start;
int n, i, i2,
cx = tft.width() / 2,
cy = tft.height() / 2;
tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height());
start = micros();
for(i=2; i<n; i+=6) {
i2 = i / 2;
tft.drawRect(cx-i2, cy-i2, i, i, color);
}
return micros() - start;
}
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
unsigned long start, t = 0;
int n, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height());
for(i=n; i>0; i-=6) {
i2 = i / 2;
start = micros();
tft.fillRect(cx-i2, cy-i2, i, i, color1);
t += micros() - start;
// Outlines are not included in timing results
tft.drawRect(cx-i2, cy-i2, i, i, color2);
yield();
}
return t;
}
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(x=radius; x<w; x+=r2) {
for(y=radius; y<h; y+=r2) {
tft.fillCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, r2 = radius * 2,
w = tft.width() + radius,
h = tft.height() + radius;
// Screen is not cleared for this one -- this is
// intentional and does not affect the reported time.
start = micros();
for(x=0; x<w; x+=r2) {
for(y=0; y<h; y+=r2) {
tft.drawCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testTriangles() {
unsigned long start;
int n, i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
n = min(cx, cy);
start = micros();
for(i=0; i<n; i+=5) {
tft.drawTriangle(
cx , cy - i, // peak
cx - i, cy + i, // bottom left
cx + i, cy + i, // bottom right
tft.color565(i, i, i));
}
return micros() - start;
}
unsigned long testFilledTriangles() {
unsigned long start, t = 0;
int i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(i=min(cx,cy); i>10; i-=5) {
start = micros();
tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(0, i*10, i*10));
t += micros() - start;
tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(i*10, i*10, 0));
yield();
}
return t;
}
unsigned long testRoundRects() {
unsigned long start;
int w, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
w = min(tft.width(), tft.height());
start = micros();
for(i=0; i<w; i+=6) {
i2 = i / 2;
tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
}
return micros() - start;
}
unsigned long testFilledRoundRects() {
unsigned long start;
int i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(i=min(tft.width(), tft.height()); i>20; i-=6) {
i2 = i / 2;
tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
yield();
}
return micros() - start;
}
这里是上述三个库:
参考:
1. http://www.lab-z.com/teensyucglib/
2022年7月17日 我又一次尝试使用这个屏幕,但是惊奇的发现无法点亮,最终研究得出了如下结论:
屏幕引脚分别是GND/VCC/CLK/MOSI/RES/DC/BLK/MISO
首先是 VCC, 经过实验最好使用5V供电,否则会概率性无法显示(屏幕是白色无内容);其中CLK 和 MOIS 需要连接到你板子上的 SPI 上;RES 是 RESET 引脚,并不是CS (卖家说的 CS 可能指的是整体省电),因此你可以将RES直接接到3.3V上(注意不要接5V),这是是最大的坑;BLK和MISO 可以悬空不接。
// Ili9341 LCD panel
#define TFT_DC 21
#define TFT_CS -1
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
我在 FireBeetle板子上运行示例代码\libraries\Adafruit_ILI9341\examples\graphicstest.ino 头部做如下声明即可:
// Ili9341 LCD panel
#define TFT_DC 21
#define TFT_CS -1
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
连接方式:
ILI9341屏幕 | GND | VCC | CLK | MOS | RES | DC | BLK | MIS |
FireBeelte | GND | VCC 5V | SCK/IO18 | MOSI/IO23 | 3.3V | 21 | N/A | N/A |
此外Adafruit_BusIO 在编译时有一点小问题,我修改了一下,有需要的可以试试:
同样的连接,在 ESP32 WROOM 上也可以正常工作:
最近看到 Github 上的Intel Hao Wu 提供了一个读取“EFI Partition Infomation Protocol”的工具,在 https://github.com/hwu25/edk2/tree/partition_info_test/MdeModulePkg/Application/DumpPartInfo 可以看到(https://github.com/hwu25/edk2 branch:partition_info_test)。于是进行了一番研究。
首先对于 Partition Information Protocol 可以在 UEFI Spec 2.7 中的 13.18 章节看到,通过它可以获得当前系统中的分区信息:
DumpPartInfo代码不复杂,放到 \MdeModulePkg\Application中,然后修改MdeModulePkg.dsc 即可正常编译。但是在实体机上运行的时候没有任何输出。转过头查看 DumpPartInfo.c代码发现其中使用 DEBUG() 宏作为输出。对于DEBUG这个宏,在之前的文章【参考1】中有过研究。这个宏在 \MdePkg\Include\Library\DebugLib.h 中有定义,所有的调用都是相同的头文件,但是在链接的时候会使用不同的文件作为实现。
为了确定具体实现的文件,查看Build 过程中生成的Makefile 在\Build\MdeModule\DEBUG_VS2015x86\X64\MdeModulePkg\Application\DumpPartInfo\DumpPartInfo\Makefile 可以看到,链接过程中使用了 UefiDebugLibStdErr ,因此我们需要查看 \MdePkg\Library\UefiDebugLibStdErr\DebugLib.c 才能看到具体的实现:
1.DebugPrintEnabled()函数,代码如下:
/**
Returns TRUE if DEBUG() macros are enabled.
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
PcdDebugProperyMask is set. Otherwise FALSE is returned.
@retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
@retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
**/
BOOLEAN
EFIAPI
DebugPrintEnabled (
VOID
)
{
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
}
这里提示我们需要在 MdeModulePkg.dsc 打开下面的开关:
第一部分:
[Defines]
PLATFORM_NAME = MdeModule
PLATFORM_GUID = 587CE499-6CBE-43cd-94E2-186218569478
PLATFORM_VERSION = 0.98
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/MdeModule
SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC|ARM|AARCH64
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
SKUID_IDENTIFIER = DEFAULT
#LABZ_Debug_Start
#
# Debug output control
#
DEFINE DEBUG_ENABLE_OUTPUT = TRUE # Set to TRUE to enable debug output
DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000040 # Flags to control amount of debug output
DEFINE DEBUG_PROPERTY_MASK = 2
#LABZ_Debug_End
[LibraryClasses]
第二部分:
2.实现上面的代码后,在 NT32Pkg 虚拟机中我们可以看到 DEBUG()能够实现在屏幕上的输出了,但实体机上仍然无输出。继续研究,输出的具体代码在UefiDebugLibStdErr\DebugLib.c 中下面这个函数:
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
CHAR16 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
VA_LIST Marker;
//
// If Format is NULL, then ASSERT().
//
ASSERT (Format != NULL);
//
// Check driver debug mask value and global mask
//
if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
return;
}
//
// Convert the DEBUG() message to a Unicode String
//
VA_START (Marker, Format);
UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, Marker);
VA_END (Marker);
//
// Send the print string to the Standard Error device
//
if ((gST != NULL) && (gST->StdErr != NULL)) {
gST->StdErr->OutputString (gST->StdErr, Buffer);
}
}
追踪显示 gST-> StdErr 并不是 NULL,但有可能是定义为串口。对于我们来说最简单的办法是将 StdErr 赋值为 StdOut 。修改DumpPartInfo.c代码如下:
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE *Handles;
UINTN HandleCount;
UINTN HandleIndex;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
CHAR16 *DPText;
EFI_PARTITION_INFO_PROTOCOL *PartInfo;
gST->StdErr=gST->ConOut;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiPartitionInfoProtocolGuid,
NULL,
&HandleCount,
&Handles
);
之后,实体机中工作正常了:
完整代码和 X64 EFI 文件下载:
参考:
1. http://www.lab-z.com/stu170dbg/ Application 中使用 DEBUG 宏
本文介绍如何使用USB 键盘在 Windows 下生成一个 Dump 文件,然后通过工具进行分析。
在【参考1】,微软提供了一个使用键盘触发蓝屏生成 Dump 文件的方法。具体操作是:
1.对于 USB 键盘,需要在注册表:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\kbdhid\Parameters 下面创建 CrashOnCtrlScroll 类型为 REG_DWORD ,值为0x01:
2.重启之后可以通过按下右侧 ctrl 然后快速按下2次 Scroll 键实现蓝屏:
3.重启后在被测机的 Windows 目录下查找 *.dmp 文件:
4.可以使用nirsoft的 BlueScreenView v1.55 【参考2】,进行简单的分析,使用方法很简单:打开文件然后将 Dump 文件放进去。从下面可以看到,蓝屏是 kbdhid.sys 文件导致的:
5.正规的方法是使用 WinDBG,在下面的位置打开 dump 文件
运行结果:
Executable search path is:
Windows 10 Kernel Version 18362 MP (12 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 18362.1.amd64fre.19h1_release.190318-1202
Machine Name:
Kernel base = 0xfffff806`0e200000 PsLoadedModuleList = 0xfffff806`0e648210
Debug session time: Tue Sep 15 12:19:54.203 2020 (UTC + 8:00)
System Uptime: 0 days 0:00:13.012
Loading Kernel Symbols
...............................................................
................................................................
................................
Loading User Symbols
Loading unloaded module list
......
For analysis of this file, run !analyze -v
nt!KeBugCheckEx:
fffff806`0e3c1220 48894c2408 mov qword ptr [rsp+8],rcx ss:0018:fffff806`1309acc0=00000000000000e2
之后运行 !analyze -v 命令
0: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
MANUALLY_INITIATED_CRASH (e2)
The user manually initiated this crash dump.
Arguments:
Arg1: 0000000000000000
Arg2: 0000000000000000
Arg3: 0000000000000000
Arg4: 0000000000000000
Debugging Details:
------------------
BLACKBOXWINLOGON: 1
CUSTOMER_CRASH_COUNT: 1
PROCESS_NAME: System
STACK_TEXT:
fffff806`1309acb8 fffff806`15764170 : 00000000`000000e2 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KeBugCheckEx
fffff806`1309acc0 fffff806`15763a7f : ffffa80e`a2d0d602 fffff806`11c1208d ffffa80e`a2d321d0 00000000`000000c0 : kbdhid!KbdHidProcessCrashDump+0x1f0
fffff806`1309ad00 fffff806`15064d99 : ffffa80e`a2d0d6a0 ffffa80e`a2e6ac4c ffffa80e`00000000 fffff806`15068110 : kbdhid!KbdHid_InsertCodesIntoQueue+0xbf
fffff806`1309ad60 fffff806`15064f09 : ffffa80e`000000c6 fffff806`0e231f39 ffffa80e`a2c51470 00000000`00000001 : HIDPARSE!HidP_KbdPutKey+0x45
fffff806`1309ad90 fffff806`15065084 : ffffa80e`a2e6ac4c 00000000`0000000e ffffa80e`a2d30010 fffff806`15001a27 : HIDPARSE!HidP_ModifierCode+0xa9
fffff806`1309adc0 fffff806`15065173 : ffffa80e`a2e6ad18 ffffa80e`a2d2c6d0 ffffa80e`a2d2c6d0 fffff806`15063e9a : HIDPARSE!HidP_TranslateUsage+0x8c
fffff806`1309ae10 fffff806`157637b5 : 00000000`00000000 ffffa80e`a2d2c6d0 ffffa80e`a2d0d6a0 ffffa80e`a28fe300 : HIDPARSE!HidP_TranslateUsageAndPagesToI8042ScanCodes+0xb3
fffff806`1309ae80 fffff806`0e32b136 : 00000000`00000000 ffffa80e`a77aff02 ffffa80e`00000000 00000000`0007fe01 : kbdhid!KbdHid_ReadComplete+0x445
fffff806`1309af10 fffff806`0e247799 : ffffa80e`a2d2c6d0 fffff806`1309afe9 00000000`00000000 ffffa80e`a2d2cc6b : nt!IopUnloadSafeCompletion+0x56
fffff806`1309af40 fffff806`0e247667 : ffffa80e`a28fe310 00000000`00000006 00000000`00000000 ffffa80e`a2da21d0 : nt!IopfCompleteRequest+0x119
fffff806`1309b050 fffff806`1502acb1 : ffffa80e`a28fe300 ffffa80e`a28fe302 fffff806`1309b0f1 00000000`00000009 : nt!IofCompleteRequest+0x17
fffff806`1309b080 fffff806`1502a7ba : ffffa80e`a2da21d0 ffffa80e`a2da2102 ffffa80e`a290d730 00000000`00000009 : HIDCLASS!HidpDistributeInterruptReport+0x25d
fffff806`1309b150 fffff806`0e247799 : ffffa80e`a2d2f9a0 ffffa80e`a2d2f9a0 fffff806`1309b201 ffffa80e`a2d2fe1b : HIDCLASS!HidpInterruptReadComplete+0x34a
fffff806`1309b1f0 fffff806`0e247667 : ffffa80e`a2bc99b0 fffff806`14c48f00 00000000`00000001 00000000`00000001 : nt!IopfCompleteRequest+0x119
fffff806`1309b300 fffff806`11b383fd : 00000000`00000000 ffffa80e`a2bc89c0 00000000`00000002 fffff806`14c39700 : nt!IofCompleteRequest+0x17
fffff806`1309b330 fffff806`11b37ecb : ffffa80e`a2bc8b02 fffff806`1309b451 ffffa80e`a2d2f9a0 00000000`00000000 : Wdf01000!FxRequest::CompleteInternal+0x22d [minkernel\wdf\framework\shared\core\fxrequest.cpp @ 869]
fffff806`1309b3c0 fffff806`14c47e80 : 00000000`ffffff02 ffffa80e`a2bc89c0 ffffa80e`a2c28400 ffffa80e`a2c28400 : Wdf01000!imp_WdfRequestComplete+0x8b [minkernel\wdf\framework\shared\core\fxrequestapi.cpp @ 436]
fffff806`1309b420 fffff806`14c45cf4 : ffffa80e`a2bc8b60 ffffa80e`a2c28460 ffffa80e`a2bc8bf0 fffff806`1309b6f8 : USBXHCI!Bulk_Transfer_CompleteCancelable+0x19c
fffff806`1309b480 fffff806`14c44460 : ffffa80e`a25c97e0 00000000`00000003 00000000`00000000 fffff806`11c1208d : USBXHCI!Bulk_ProcessTransferEventWithED1+0x464
fffff806`1309b540 fffff806`14c398d3 : ffffa80e`a107e901 fffff806`14df8301 00000000`02400280 fffff806`1309b670 : USBXHCI!Bulk_EP_TransferEventHandler+0x10
fffff806`1309b570 fffff806`14c2ba4f : 00000000`0000002b fffff806`1309b661 ffffa80e`a2af58a0 fffff806`14c134b9 : USBXHCI!TR_TransferEventHandler+0x17
fffff806`1309b5a0 fffff806`14c4c2be : fffff806`1309b6f8 fffff806`1309b6c8 00000000`00000000 fffff806`1309b6d0 : USBXHCI!Endpoint_TransferEventHandler+0x167
fffff806`1309b620 fffff806`14c2ea3c : ffffa80e`a2969ab0 fffff806`1309b719 00000000`00000000 ffffa80e`a2b35510 : USBXHCI!UsbDevice_TransferEventHandler+0xa6
fffff806`1309b680 fffff806`14c2f55c : 00000000`00000000 00000000`00000001 00000000`00000000 ffffa80e`a29698b0 : USBXHCI!Interrupter_DeferredWorkProcessor+0x578
fffff806`1309b780 fffff806`11b326ad : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : USBXHCI!Interrupter_WdfEvtInterruptDpc+0xc
fffff806`1309b7b0 fffff806`0e26ae85 : fffff806`0bb04180 00000000`00000001 fffff806`1309b7a8 00000000`00000000 : Wdf01000!FxInterrupt::_InterruptDpcThunk+0x9d [minkernel\wdf\framework\shared\irphandlers\pnp\km\interruptobjectkm.cpp @ 410]
fffff806`1309b7f0 fffff806`0e26a4df : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiExecuteAllDpcs+0x305
fffff806`1309b930 fffff806`0e3c4d64 : 00000000`00000000 fffff806`0bb04180 fffff806`0e791400 ffffa80e`a6adf040 : nt!KiRetireDpcList+0x1ef
fffff806`1309bb60 00000000`00000000 : fffff806`1309c000 fffff806`13095000 00000000`00000000 00000000`00000000 : nt!KiIdleLoop+0x84
SYMBOL_NAME: kbdhid!KbdHidProcessCrashDump+1f0
MODULE_NAME: kbdhid
IMAGE_NAME: kbdhid.sys
IMAGE_VERSION: 10.0.18362.418
STACK_COMMAND: .thread ; .cxr ; kb
BUCKET_ID_FUNC_OFFSET: 1f0
FAILURE_BUCKET_ID: MANUALLY_INITIATED_CRASH_kbdhid!KbdHidProcessCrashDump
OS_VERSION: 10.0.18362.1
BUILDLAB_STR: 19h1_release
OSPLATFORM_TYPE: x64
OSNAME: Windows 10
FAILURE_ID_HASH: {a90fbd35-7a19-bced-0f76-fa89d249d332}
Followup: MachineOwner
---------
同样的,蓝屏原因指向 KBDHID.sys
参考:
检查 PEP Table 是Modern Standby 调试过程中必不可少的一环。通常的做法是运行 PEPChecker 这个工具,然后根据结果修改 PEPD 设定。此外还可以使用RW 或者其他工具读取 ACPI DSDT ,但是这样的做法看到的是静态的信息并没有办法得知运行期的值。这次介绍使用 WinDBG 查看测试机的 PEPD 设定,本质上是 WinDDBG ACPI Debug,在 RS2/3 上进行 ACPI Debug 会比较麻烦【参考1】,但是从 Win 10 1803 开始,MS 修改了Windows,不再需要替换文件(“For Windows* 10 version lower than 1803, checked builds of the Windows* ACPI driver (Acpi.sys) are used. Starting from version 1803, checked builds are no longer required for using Microsoft* AMLI Debugger” )。
首先,被测机MSConfig 设定 USB Debug 名称是 labz:
接下来,主机端设定 WinDBG, Target name 为 labz:
将两台机器用 USB Debug Cable连接起来即可。
8: kd> !amli find PEPD
\_SB.PEPD
8: kd> !amli find devy
\_SB.PEPD.DEVY
8: kd> !amli dns /v \_SB.PEPD.DEVY
ACPI Name Space: \_SB.PEPD.DEVY (ffff8e0ac79f8cf0)
Package(DEVY:NumElements=71){
| Package(:NumElements=3){
| | String(:Str="\_SB.PR00")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR01")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR02")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR03")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR04")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR05")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR06")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR07")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.GFX0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.UA00")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.UA01")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C1")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.XHC")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.HDAS")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.PEMC")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.PSDC")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C2")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C3")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For UART2 D3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SPI0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SPI1")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP01.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP02.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP03.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP04.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP05.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP06.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP07.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP08.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP09.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP10.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP11.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP12.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP13.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP14.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP15.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP16.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP17.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP18.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP19.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP20.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.VOL0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR08")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR09")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR10")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR11")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR12")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR13")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR14")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR15")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.IPU0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.HECI")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.GLAN")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.PEG0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="USB\VID_8087&PID_0AC9&MI*")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000002[2])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT1")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT2")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT4")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT5")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For TBT RP0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For TBT RP1")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR16")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR17")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR18")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR19")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For WWAN D3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For DG1 D3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
}
从上面可以看到 DEVY 的结构以及数值。
参考:
昨天在编译 EDK2 的代码时,忽然遇到无法 Link 到 GDI32.LIB 的情况。百思不得其解中回想了一下,最近重装了 SDK,并且编译的目标是 NT32Pkg,它需要Window32 API, 所以问题应该出现在 SDK 上。
最终经过研究,原来是我在安装最新的 10.0.19041.0 时,没有选择 X64 的Library:
如果你也遇到类似问题,不妨检查一下 \Windows Kits\10\Lib\10.0.19041.0\um\x64 下面是否有 GDI32.LIB, 如果没有的话,请再检查当前系统中的 SDK安装情况。
当我们谈论 ESP32 支持USB 时,谈论的并不是最常见的ESP32而是乐鑫信息科技(上海)股份有限公司(ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD.)新出品的一个型号:ESP32 S2。具体的比对可以从下图看到。主要的变化是变成单核(对 Arduino玩家几乎没有影响),去掉了蓝牙功能,另外就是增加了USB OTG 的功能。这意味着可以用 S2 方便的实现USB Device或者 Host 功能(目前还没有看到 Arduino 版本的 USB Host支持):
为了进行实验,需要入手一个开发板,在【参考2】可以目前的模块有如下四种:
ESP32-S2-WROOM
ESP32-S2-WROOM-I
ESP32-S2-WROVER
ESP32-S2-WROVER-I
其中 WROOM 和 WROVER 的差别在于 PRAM 大小的差别,有 -I 和没有的在于天线是否存在于模组之上。最终选择的是 ESP32-S2-Saola-1开发板,直接在taobao 上的 乐鑫科技 Espressif Online 买了一块 ESP32-S2-Saola-1R (这个应该算是官方正版了)。相比之下,这个板子价格要比普通的贵上很多,达到48元/块。
接下来就是软件的问题了,ESP32 S2 并不能用普通的 Arduino 支持的 ESP32 环境进行编译,更准确的说是不能用他来完成 USB Device的支持。具体的支持方法可以在【参考4】看到。这里简单说一下我实验成功的方法。
1. 如果你当前Arduino 安装过 ESP32 的支持,请在 Board manager 中卸载之;
2.安装 Git,然后创建一个目录用于存放编译工具;
3.进入这个目录使用 Git Bash Here打开窗口输入下面的命令
4.git clone https://github.com/espressif/arduino-esp32.git -b esp32s2
(有可能会很慢,从我的经验上来看,用手机热点会快很多)
5.上述结束之后运行 tools 下面的get.exe
6. 安装 USBTiny , 在 https://github.com/chegewara/EspTinyUSB 其中硬件方面,按照如下设定【参考5】
7.安装 USBTiny , 在 https://github.com/chegewara/EspTinyUSB
硬件方面,按照如下连接【参考5】
参考:
1. https://blog.csdn.net/toopoo/article/details/104299011
2. https://www.espressif.com/zh-hans/node/4458
3. https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-22443450244.11.741d27e6IeGkuO&id=612711016956