MeteorLake-P UART Shell 测试工具

这个工具是用来给 MeteorLake-P Shell 下进行 Uart 测试的工具,它通过 PCH UART输出字符。

在使用之前,请保证:

  1. PCH 对应的 UART 已经 Enable, 在 Shell 下能够看到对应的PCI Controller;
  2. UART 对应的 GPIO 已经设置为 Native UART 功能。

使用方法:

mtlut <UART 编号>

例如, mtlut 0 将会从第一个 PCH UART对应的引脚,以 115200 波特率输出 www.lab-z.com。

程序在这里下载(无源代码)

Sound Wire

SoundWire 是 MIPI 协会推出的关于音频的规范,有时候会被缩写为 SNDW。这个规范定义的总线有如下好处:

  1. 线路简单,一个 Clock 和 一个 Data线即可进行传输,这样能够极大降低产品成本(布线更简单,节省PCB);
  2. 速度快(最高12.288 MHz),使用类似 DDR(Double)的传输方式;
  3. 可以扩展进行  Clock Scaling 或者多个 Data Lane,能够轻松增加带宽;
  4. 单个 master 最多可以支持 11个 Slave;
  5. 支持slave to slave的数据传输方式。

基本拓扑结构是【参考1】:其中的 ADC 可以理解为麦克风,DAC 可以理解为喇叭,下图就是一个 SoundWire Master 连接了2个麦克风和三个喇叭:

复杂一点:Multi Lanes拓扑如下, Clock 提供给 Codec/BT/DSP,然后多个Lane(Data[0]/Data[1]/Data[2]), 这样能够提升一个周期数据的传输数量。

因此,对于 PC 来说,SoundWire 是重新定义了 SoC 或者说南桥对 Codec 的数据传输协议,取代了之前的 HDA 总线。对于软件或者 BIOS 来说应该是透明的。

参考:

  1. https://elinux.org/images/8/80/Introduction-to-SoundWire-Vinod-Koul-Linaro.pdf
  1. https://zhuanlan.zhihu.com/p/535358005
  2. https://bbs.eetop.cn/thread-928626-1-1.html

UEFI TIPS: PciLib

如果你在编写代码时有使用到类似 PciRead8() 这样的函数,那么可以通过在 INF 中加入 PciLib:

[LibraryClasses]
  UefiLib
  ShellCEntryLib
  IoLib
  PciLib

然后在代码中使用 include 调用头文件即可:

 #include <Library/PciLib.h>

具体的 PciLib.h 定义如下:


#define PCI_LIB_ADDRESS(Bus, Device, Function, Register)   \
  (((Register) & 0xfff) | (((Function) & 0x07) << 12) | (((Device) & 0x1f) << 15) | (((Bus) & 0xff) << 20))

RETURN_STATUS
EFIAPI
PciRegisterForRuntimeAccess (
  IN UINTN  Address
  );

UINT8
EFIAPI
PciRead8 (
  IN      UINTN  Address
  );

UINT8
EFIAPI
PciWrite8 (
  IN      UINTN  Address,
  IN      UINT8  Value
  );

UINT8
EFIAPI
PciOr8 (
  IN      UINTN  Address,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
PciAnd8 (
  IN      UINTN  Address,
  IN      UINT8  AndData
  );

UINT8
EFIAPI
PciAndThenOr8 (
  IN      UINTN  Address,
  IN      UINT8  AndData,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
PciBitFieldRead8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT8
EFIAPI
PciBitFieldWrite8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  Value
  );

UINT8
EFIAPI
PciBitFieldOr8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
PciBitFieldAnd8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  AndData
  );

UINT8
EFIAPI
PciBitFieldAndThenOr8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  AndData,
  IN      UINT8  OrData
  );

UINT16
EFIAPI
PciRead16 (
  IN      UINTN  Address
  );

UINT16
EFIAPI
PciWrite16 (
  IN      UINTN   Address,
  IN      UINT16  Value
  );

UINT16
EFIAPI
PciOr16 (
  IN      UINTN   Address,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
PciAnd16 (
  IN      UINTN   Address,
  IN      UINT16  AndData
  );

UINT16
EFIAPI
PciAndThenOr16 (
  IN      UINTN   Address,
  IN      UINT16  AndData,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
PciBitFieldRead16 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT16
EFIAPI
PciBitFieldWrite16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  Value
  );

UINT16
EFIAPI
PciBitFieldOr16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
PciBitFieldAnd16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  AndData
  );

UINT16
EFIAPI
PciBitFieldAndThenOr16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  AndData,
  IN      UINT16  OrData
  );

UINT32
EFIAPI
PciRead32 (
  IN      UINTN  Address
  );

UINT32
EFIAPI
PciWrite32 (
  IN      UINTN   Address,
  IN      UINT32  Value
  );

UINT32
EFIAPI
PciOr32 (
  IN      UINTN   Address,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
PciAnd32 (
  IN      UINTN   Address,
  IN      UINT32  AndData
  );

UINT32
EFIAPI
PciAndThenOr32 (
  IN      UINTN   Address,
  IN      UINT32  AndData,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
PciBitFieldRead32 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT32
EFIAPI
PciBitFieldWrite32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  Value
  );

UINT32
EFIAPI
PciBitFieldOr32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
PciBitFieldAnd32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  AndData
  );

UINT32
EFIAPI
PciBitFieldAndThenOr32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  AndData,
  IN      UINT32  OrData
  );

UINTN
EFIAPI
PciReadBuffer (
  IN      UINTN  StartAddress,
  IN      UINTN  Size,
  OUT     VOID   *Buffer
  );

UINTN
EFIAPI
PciWriteBuffer (
  IN      UINTN  StartAddress,
  IN      UINTN  Size,
  IN      VOID   *Buffer
  );

MCP4922 SPI DAC 在 FireBeetle ESP32 上的测试

之前有介绍过,ESP32 没有 DAC 引脚,但是可以通过 PWM 来进行模拟,这次入手了 MCP4922 这款双通道 DAC 芯片。它使用 SPI 接口,提供12Bit 的输出精度。芯片引脚定义如下:

引脚编号名称介绍
1Vdd供电 2.7-5.5V
2NC
3CS#SPI CS 引脚
4SCKSPI Clock
5SDISPI MOSI
6NC
7NC
8LDAC#锁存,只有为低时,芯片才会从 Vouta和Voutb 输出电压
9SHDN#关闭,为低芯片停止工作
10Voutb输出B电压引脚
11Vrefb输出B 的参考电压,可以接入Vss到Vdd 以内的电压.这次测试接入了Vdd(3.3V)
12Vss
13Vrefa输出A 的参考电压,,可以接入Vss到Vdd 以内的电压.这次测试接入了Vdd(3.3V)
14Vouta输出A的电压引脚

这次测试基于 https://github.com/michd/Arduino-MCP492X 提供的库文件,代码如下:

#include <MCP492X.h> // Include the library

#define PIN_SPI_CHIP_SELECT_DAC 25 // Or any pin you'd like to use

MCP492X myDac(PIN_SPI_CHIP_SELECT_DAC);

void setup() {
  // put your setup code here, to run once:
  myDac.begin();
}

void loop() {
  for (int i=0;i<4096;i++) {
      myDac.analogWrite(0, i);
      myDac.analogWrite(1, 4095-i);
      delay(1);
}

代码运行后使用示波器进行测试,结果如下:

修改代码,loop如下:

void loop() {
   myDac.analogWrite(0, 0); 
   myDac.analogWrite(0, 4095);
}

可以看到波形如下:

参考:

  1. https://www.microchip.com/en-us/product/MCP4922#
  2. https://ua726.co.uk/2012/12/22/testing-the-mcp4922-with-an-arduino/

本文使用的库:

MCP492X Datasheet

Ch32v305 上手指南

最近拿到一块 Ch32V305 的 EVT 板子,芯片的具体型号是CH32V305FBP6 ,它使用TSSOP20 封装,对于DIY 非常友好。这里介绍如何烧录和运行一个 USB KBMS 的代码。

代码来自官方的 EVT Package: CH32V307EVT\EVT\EXAM\USB\USBHS\DEVICE\CompositeKM

特别注意:和其他芯片不同,这款芯片必须使用 WCK LinkE 进行烧录。

MounRiver Studio 自带的烧录软件

需要特别注意的是在《CH32V30x 评估板说明及应用参考》上有提到还可以使用WCH-LinkUtility.exe 进行下载,但是实验中我发现这个会和 MounRiver Studio 自带的烧录软件冲突。打开WCH-LinkUtility后会提示你需要升级 WCH LinkE ,否则不能进行烧录,升级之后再使用MounRiver Studio ,它又会提示需要升级WCH LinkE ,否则不能进行烧录。

最后放上一个独立版本的键盘鼠标代码。

目录比较差异提取工具

起因:每次维护网站都需要进行全站备份,目前使用压缩后下载全部文件的方法。但是这样每次都要下载很大的文件,费时费力。因此需要一种方法能够让我只下载有差异的部分。为此编写了一个目录比较并且提取差异的工具,例如:我基于 edk2202308 修改出来了 edk2202308modified ,然后用工具进行比较,比较后的差别会自动提取到 100916 目录下。

需要注意有如下几点:

  1. 文件只是比较大小,并没有对内容进行比较;
  2. 比较后放置差异的目录是根据当前时间生成的,每次运行目录不同;
  3. 工具不是很完善,没有处理文件被删除掉的情况
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace ComparePatch
{
    class Program
    {
        static void Printusage()
        {
            Console.WriteLine("Directory compare and patch utility");
            Console.WriteLine("Usage:");
            Console.WriteLine("cap Latest LastBackup PatchDir");
            Console.WriteLine("");
        }

        static void CopyFileTo(String Filename, String TargetDir)
        {

        }

        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Printusage();
                Environment.Exit(0);
            }
            // 指定要枚举的目录
            string Latest, LastBackup, PatchDir;
            Latest = args[0];
            LastBackup = args[1];
            if (Latest[Latest.Length - 1] != '\\')
            {
                Latest = Latest + '\\';
            }
            if (LastBackup[LastBackup.Length - 1] != '\\')
            {
                LastBackup = LastBackup + '\\';
            }
            PatchDir = Directory.GetCurrentDirectory() + "\\" + DateTime.Now.ToString("HHmmss") + "\\";
            Console.WriteLine("Compare " + LastBackup + " with " + Latest);
            Console.WriteLine("And put files into " + PatchDir);

            try
            {
                // 使用Directory类的GetFiles方法获取所有文件,包括所有子目录
                string[] filesInLastBackup = Directory.GetFiles(LastBackup, "*", SearchOption.AllDirectories);
                Console.WriteLine("Files in " + LastBackup + " and all subdirectories:");

                // 遍历所有文件并打印
                foreach (string file in filesInLastBackup)
                {
                    // 情况1
                    if (File.Exists(file.Replace(LastBackup, Latest)))
                    {
                        // 新目录下存在该文件
                        // 创建一个FileInfo对象
                        FileInfo NewFileInfo = new FileInfo(file);
                        FileInfo OldFileInfo = new FileInfo(file.Replace(LastBackup, Latest));
                        String PatchFileName = file.Replace(LastBackup, PatchDir);
                        if (NewFileInfo.Length != OldFileInfo.Length)
                        {
                            // 文件大小不同,判定为不同
                            Console.WriteLine("=========================");
                            Console.Write("New file would be copy to");
                            Console.WriteLine(PatchFileName);
                            if (!Directory.Exists(Path.GetDirectoryName(PatchFileName))) {
                                Directory.CreateDirectory(Path.GetDirectoryName(PatchFileName));
                            }
                            File.Copy(file, PatchFileName); 
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("The process failed: {0}", e.ToString());
            }

            // Console.ReadKey();
        }
    }
}

可执行文件:

如果你有更专业的需求,可以考虑直接使用 GIT 这种来进行维护。

Intel: PPAM

众所周知,进入 SMM 后,对于系统的资源有着至高无上的访问权限。因此,一旦 SMM 被攻破会出现不可预料的效果。针对这个问题,Intel 不断对 SMM 进行加固。PPAM全称是“Platform Properties AssessmentModule”。它的作用就是提升 SMM 安全性,如果你想在 SMM中访问某个IO Port 或者某个 MSR 寄存器,那么必须在 BIOS 代码中声明需要使用的这些 IO 或者 MSR,否则会阻止SMM 代码中对于这些资源的访问。

例外一个角度:如果你发现你的代码在 SMM 中有 halt的问题,不妨检查是否 Enable 了 PPAM,可以 Disable 之后再尝试。

参考:

1.https://www.intel.com/content/dam/www/central-libraries/us/en/documents/drtm-based-computing-whitepaper.pdf

PWRTest

PwrTest 是一款微软提供的用于Power Loop 测试的工具【参考1】,可以用于 ModernStandby或者 S3/S4 循环测试。它位于 WDK中,安装后可以在C:\Program Files (x86) \Windows Kits\ 目录中找到(建议在这这个目录下直接搜索)。

用法非常简单:

  1. 使用管理员权限打开 cmd 窗口
  2. Pwrtest + 参数即可

例如:测试S4睡眠并且唤醒 100次

pwrtest /sleep  /s:4 /c:100  

下面是运行 pwrtest /? 得到的帮助信息:

Usage: pwrtest /scenario [/scenario_options] [/common_options]

scenario
  Name                Description                                     Min OS Req
  ------------------------------------------------------------------------------
  sleep               run sleep/resume transitions                    Win7
  battery             battery information and monitoring              Win7
  info                system power information                        Win7
  es                  thread execution state monitoring               Win7
  idle                power idle monitoring                           Win7
  ppm                 processor power management monitoring           Win7
  timer               system timer resolution monitoring              Win7
  disk                disk idle monitoring                            Win7
  device              device idle monitoring                          Win7
  monitor             monitor dim/blank monitoring (user idle)        Win7
  requests            power request monitoring                        Win7
  thermal             ACPI thermal zone monitoring                    Win7
  processidle         monitor and force idle/background tasks to run  Win7
  cs                  run connected standby transitions               Win8
  platidle            platform idle statistics monitoring             Win8
  ppmidlecontrol      veto/un-veto processor idle states              Win10 RS5
  platformidlecontrol veto/un-veto platform idle states               Win10 RS5
  directedfx          run Directed FX tests on a device               Win10 19H1

scenario_options
  To see available scenario options type: pwrtest.exe /scenario /?
  Example: pwrtest.exe /sleep /?

common_options
  /lf:folder          folder for the log files
                      For example, c:\myfolder or \\server\share
                      Default log location is the same folder as pwrtest.exe
  /ln:name            name for the log files and the ETW trace session name.
                      Log file extensions added automatically (.wtl, .xml, etc.)
                      Default name is pwrtestlog.
  /etwbuffersize:n    n indicates ETW buffer size in KB if larger than default.
                      Default is current page size or 256KB (whichever is
                      greater).
  /etwminbuffers:n    n indicates the minimum number of buffers allocated for
                      the ETW session if larger than the minimum of 2 per
                      logical processor.
                      Default is 2 per logical processor
  /etwmaxbuffers:n    n indicates the maximum number of buffers allocated for
                      the ETW session if larger than the minimum of 2 per
                      logical processor and larger than etwminbuffers.
                      Default is etwminbuffers + 20.
  /delaywrite         when specified, log data is buffered in memory to reduce
                      disk writes.  Affects all log types including ETL.


Execution Requirements:
  -must run from an administrator/elevated command prompt in order to support
   ETW tracing
  -must run natively (WoW64 not supported) in order to support ETW tracing
  -group policy settings put in place by your system administrator may
   interfere with some scenarios that need to temporarily modify power
   setting values (such as the sleep scenario)

这是 10.0.22621.1 WDK 自带的pwrtest。

有需要测试 S3 S4 MS Loop的朋友可以考虑使用这款工具进行测试。

参考:

1. https://learn.microsoft.com/zh-cn/windows-hardware/drivers/devtest/pwrtest

ESP32 S3 I2C 从机测试

测试了 ESP32 S3 的 I2C 从机功能, 使用的是ESP32 S3 DevKitC-1 如下:

C:\Users\YOUNAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.4\libraries\Wire\examples\WireSlave
#include "Wire.h"

#define I2C_DEV_ADDR 0x55

uint32_t i = 0;

void onRequest(){
  Wire.print(i++);
  Wire.print(" Packets.");
  Serial.println("onRequest");
}

void onReceive(int len){
  Serial.printf("onReceive[%d]: ", len);
  while(Wire.available()){
    Serial.write(Wire.read());
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Wire.onReceive(onReceive);
  Wire.onRequest(onRequest);
  Wire.begin((uint8_t)I2C_DEV_ADDR);

#if CONFIG_IDF_TARGET_ESP32
  char message[64];
  snprintf(message, 64, "%u Packets.", i++);
  Wire.slaveWrite((uint8_t *)message, strlen(message));
#endif
}

void loop() {

}

打开 Debug 开关,运行之后提示:

Attempting to boot anyway...
entry 0x403c98d8
[   104][I][esp32-hal-i2c-slave.c:234] i2cSlaveInit(): Initialising I2C Slave: sda=8 scl=9 freq=100000, addr=0x55
[   104][D][esp32-hal-i2c-slave.c:486] i2c_slave_set_frequency(): Fifo thresholds: rx_fifo_full = 28, tx_fifo_empty = 4

就是说:SDA 是8 Pin, SCL 是9 Pin,特别注意默认频率是 100K.

之后 I2C 工具设置如下:

设置发送数据  aa(地址) 31 32 33 34 35 36 37

ESP32 端收到的数据为

onReceive[7]: 1234567

测试使用的工具是志明电子出品的 USB 转SPI/I2C 调试工具。