LattePanda Mu X86计算模块套件

最近入手了LattePanda Mu ,这是一款微型 x86 计算模块,模块上带有 Intel N100 四核处理器、8GB LPDDR5 内存和 64GB 存储。搭配基础载板,后可以扩展出来
2个 USB 3.2 10Gbps 接口,1个千兆以太网,2个USB 2.0 ,1个HDMI 2.0,1个PCIEx1 接口。

供电方面可以通过USB Type-C(仅供电) 和12V DC 5.5×2.5mm 进行。

全部配件
全部配件

完整的系统分为2部分:核心板和载板。同样的核心板可以搭配不同的载板实现更强的扩展。

核心板非常迷你,接近信用卡尺寸:

核心板

左上角的芯片是 LPDDR5 内存芯片,下面是 Super Io 芯片,中间是 Intel N100 芯片。

核心板正面
核心板背面
基础载板
完整安装

堆叠安装非常简单,在核心板上安装好风扇后即可插入载板中。

使用载板上的 HDMI 连接显示器

内置的 EMMC 已经预置了 Windows 11,连接好之后就可以开机上电。可以看出我使用笔记本的 TypeC 进行供电。

使用上非常简单,和普通的 X86 没有差别。

下面这个视频测试的是播放视频

https://www.bilibili.com/video/BV1gt421P7dB

这个视频是模拟器运行合金弹头

https://www.bilibili.com/video/BV1mx4y187r2

这款板子在设计上更倾向于开发板,后面会基于这个开发板来完成一些有趣的设计和研究。

C语言内联函数

在阅读代码的过程中,我们有时候会碰到使用 inline 修饰的函数。这是C99 新增的内联函数(inline function)。这种内联函数相当于给编译器一个建议,告诉它将函数的代码插入到调用的地方。编译器可以选择忽略内联函数的建议,继续将函数编译为常规函数。

简单的说,对于常规函数编译器会将它解释成压栈,然后 call 函数名这样的指令;对于内联函数,编译器可以直接在调用处“展开”。这样就避免了压栈和 call 的开销。这样的设计让人很容易联想起来宏定义。

以一个例子来进行说明:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

inline void swapINT1( UINTN *p1, UINTN *p2 )       // 一个内联函数
{
   UINTN tmp = *p1; *p1 = *p2; *p2 = tmp;
}

void swapINT2( UINTN *p1, UINTN *p2 )       // 一个内联函数
{
   UINTN tmp = *p1; *p1 = *p2; *p2 = tmp;
}

INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
  UINTN a=12,b=34;
  swapINT1(&a,&b);
  swapINT2(&a,&b);

  return(0);
}

代码非常简单,定义了一个内联函数 swapINT1() 和一个普通函数swapINT2()。我们在编译种加入 /FAcs 让它生成汇编文件。

ShellAppMain PROC					; COMDAT

; 36   : {

$LN5:
  00000	48 89 54 24 10	 mov	 QWORD PTR [rsp+16], rdx
  00005	48 89 4c 24 08	 mov	 QWORD PTR [rsp+8], rcx
  0000a	48 83 ec 48	 sub	 rsp, 72			; 00000048H

; 37   :   UINTN a=12,b=34;

  0000e	48 c7 44 24 28
	0c 00 00 00	 mov	 QWORD PTR a$[rsp], 12
  00017	48 c7 44 24 20
	22 00 00 00	 mov	 QWORD PTR b$[rsp], 34	; 00000022H

; 14   :    UINTN tmp = *p1; *p1 = *p2; *p2 = tmp;

  00020	48 8b 44 24 28	 mov	 rax, QWORD PTR a$[rsp]
  00025	48 89 44 24 30	 mov	 QWORD PTR tmp$1[rsp], rax
  0002a	48 8b 44 24 20	 mov	 rax, QWORD PTR b$[rsp]
  0002f	48 89 44 24 28	 mov	 QWORD PTR a$[rsp], rax
  00034	48 8b 44 24 30	 mov	 rax, QWORD PTR tmp$1[rsp]
  00039	48 89 44 24 20	 mov	 QWORD PTR b$[rsp], rax

; 38   :   swapINT1(&amp;a,&amp;b);
; 39   :   swapINT2(&amp;a,&amp;b);

  0003e	48 8d 54 24 20	 lea	 rdx, QWORD PTR b$[rsp]
  00043	48 8d 4c 24 28	 lea	 rcx, QWORD PTR a$[rsp]
  00048	e8 00 00 00 00	 call	 swapINT2

; 40   : 
; 41   :   return(0);

  0004d	33 c0		 xor	 eax, eax

; 42   : }

  0004f	48 83 c4 48	 add	 rsp, 72			; 00000048H
  00053	c3		 ret	 0
ShellAppMain ENDP

从上面可以看到 swapINT1() 被“展开”了,swapINT2() 则是正常的通过 call 来调用的。

需要注意的是:内联函数对于编译器来说只是“建议”,编译器完全可以不接受这个建议。例如,r如果函数比较复杂,编译器不会遵从这个建议。

参考:

  1. https://www.cnblogs.com/zhuchunlin/p/17756920.html C语言 – 内联函数
  2. https://c.biancheng.net/view/339.html C语言内联函数

CH552 PWM 测试

根据资料,CH552 的PWM 频率是根据 PWM_CK_SE 的分频而来【参考1】。具体的频率计算方法是:

Fsys / 256 / PWM_CK_SE

对应的 DataSheet 描述如下:

为此,编写一段测试代码:

void setup() {
  // put your setup code here, to run once:
  pinMode(15,OUTPUT);
   PIN_FUNC &= ~(bPWM1_PIN_X);
   PWM_CTRL |= bPWM1_OUT_EN;

}

void loop() {
   PWM_CK_SE=1;
   PWM_DATA1 = 127;
   delay(10000);
   PWM_DATA1 = 63;
   delay(10000);
   PWM_CK_SE=16;
   PWM_DATA1 = 127;
   delay(10000);
   PWM_DATA1 = 63;
   delay(10000);
}

当前频率为 16,000,000/256/1=62.5KHz

频率和上面的相同,只是占空比不同。

当前频率为 16,000,000/256/16=3.906KHz

参考:

https://www.wch.cn/bbs/thread-67438-1.html

Step to UEFI (292)Cpp UEFI 008 This 是啥

这一系列文章的目标是让人看懂C++ 代码,因此很多地方知道意思即可。这次介绍的是 “this” 这个关键字。这是一个指向当前对象的 const 指针,通过它可以访问当前对象的所有成员。更简单的描述如下【参考1】:

一.this是什么

this 是 C++ 中的一个关键字

this是一个 const 指针

this 指针是所有成员函数的隐含参数

二、this可以用在哪

this 只能用在类的内部

this可用于调用类的成员函数和成员变量

三、this可以用来做什么

它指向当前对象,通过它可以访问当前对象的所有成员(包括 private、protected、public 属性的成员)

友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。

参考:

1. https://blog.csdn.net/LiuXF93/article/details/121466530

C# 判断字符串是否为空或者空格的函数

在C#中,判断一个字符串是否仅由一个或多个空格组成可以通过String.IsNullOrWhiteSpace方法来实现。这个方法在检查字符串时会考虑空格、制表符、换行符等空白字符,如果字符串为null、空字符串(“”),或者仅包含空白字符,则返回true

using System;

class Program
{
    static void Main()
    {
        // 示例字符串
        string singleSpace = " ";
        string multipleSpaces = "   ";
        string emptyString = "";
        string nullString = null;

        // 判断字符串是否为空或仅包含空白字符
        bool isSingleSpaceEmpty = String.IsNullOrWhiteSpace(singleSpace);
        bool isMultipleSpacesEmpty = String.IsNullOrWhiteSpace(multipleSpaces);
        bool isEmptyStringEmpty = String.IsNullOrWhiteSpace(emptyString);
        bool isNullStringEmpty = String.IsNullOrWhiteSpace(nullString);

        // 输出结果
        Console.WriteLine($"单个空格字符串是否为空或仅包含空白字符: {isSingleSpaceEmpty}");
        Console.WriteLine($"多个空格字符串是否为空或仅包含空白字符: {isMultipleSpacesEmpty}");
        Console.WriteLine($"空字符串是否为空或仅包含空白字符: {isEmptyStringEmpty}");
        Console.WriteLine($"null字符串是否为空或仅包含空白字符: {isNullStringEmpty}");
    }
}

测试0x3F8 串口输出的 UEFI Application

之前的文章【参考1】介绍过,初始化 Legacy COM Port 为 115200 的方法。这次编写一个 UEFI Shell Application,初始化这个 COM port 之后输出 www.lab-z.com字符。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Library/IoLib.h>

void init_serial(UINTN Port) {
	IoWrite8(Port + 1, 0x00); // Disable all interrupts
	IoWrite8(Port + 3, 0x80); // Enable DLAB (set baud rate divisor)
	IoWrite8(Port + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
	IoWrite8(Port + 1, 0x00); // (hi byte)
	IoWrite8(Port + 3, 0x03); // 8 bits, no parity, one stop bit
	IoWrite8(Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
	IoWrite8(Port + 4, 0x0B); // IRQs enabled, RTS/DSR set
}

INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
	CHAR8 TestString[]="www.lab-z.com";
	init_serial(0x3F8);
	for (UINTN i=0;i<sizeof(TestString);i++) {
		IoWrite8(0x3F8,TestString[i]);
	}
	return(0);
}

虽然有很多BIOS 的调试方法,但是BIOS 工程师最常见的方法仍然是串口输出 Log,唯一的原因是:足够简单和直接。用户无需为了调试BIOS而去调试工具。

源代码和编译后的 EFI Application:

参考:

1. https://www.lab-z.com/ocuart/

推荐一个开源的HTTP Server

有些时候我们需要进行一些带有JavaScript的网页测试,为了保证能够可靠的运行,推荐架设一个的 HTTP Server 然后通过浏览器进行测试。这推荐一个开源简单的命令行 HTTP Server:simple-http-server,项目地址是https://github.com/TheWaWaR/simple-http-server/

项目支持多种 OS:

对于我们来说,最简单的是 Windows 版本的。

具体的命令行参数如下:

Simple HTTP(s) Server 0.6.8

USAGE:
    x86_64-pc-windows-msvc-simple-http-server.exe [FLAGS] [OPTIONS] [--] [root]

FLAGS:
        --coep       Add "Cross-Origin-Embedder-Policy" HTTP header and set it to "require-corp"
        --coop       Add "Cross-Origin-Opener-Policy" HTTP header and set it to "same-origin"
        --cors       Enable CORS via the "Access-Control-Allow-Origin" header
    -h, --help       Prints help information
    -i, --index      Enable automatic render index page [index.html, index.htm]
        --nocache    Disable http cache
        --norange    Disable header::Range support (partial request)
        --nosort     Disable directory entries sort (by: name, modified, size)
    -o, --open       Open the page in the default browser
    -s, --silent     Disable all outputs
    -u, --upload     Enable upload files. (multiple select) (CSRF token required)
    -V, --version    Prints version information

OPTIONS:
    -a, --auth &lt;auth>                HTTP Basic Auth (username:password)
        --cert &lt;cert>                TLS/SSL certificate (pkcs#12 format)
        --certpass &lt;certpass>        TLS/SSL certificate password
    -c, --compress &lt;compress>...     Enable file compression: gzip/deflate
                                         Example: -c=js,d.ts
                                         Note: disabled on partial request!
        --ip &lt;ip>                    IP address to bind [default: 0.0.0.0]
    -p, --port &lt;port>                Port number [default: 8000]
        --redirect &lt;redirect>        takes a URL to redirect to using HTTP 301 Moved Permanently
    -t, --threads &lt;threads>          How many worker threads [default: 3]
        --try-file &lt;PATH>            serve this file (server root relative) in place of missing files (useful for single
                                     page apps) [aliases: try-file-404]
    -l, --upload-size-limit &lt;NUM>    Upload file size limit [bytes] [default: 8000000]

ARGS:
&lt;root>    Root directory

比较常用的参数有如下几个:

–ip :指定绑定的IP 地址

-p : 指定绑定的端口号

例如:首先使用 ipconfig 查看你当前的 ip,接下来指定绑定信息

然后通过浏览器直接访问这个IP 即可(80 Port是 HTTP 默认端口,如果指定其他端口,访问时还需要写成  IP:端口 的形式)

如果你需要打开后直接访问 index.html文件还可以使用 -i 参数打开 index。推荐有需要的朋友直接去项目地址下载。如果无法访问可以直接使用下面这个版本:

修改 Win11 鼠标右键菜单的方法

Windows 11 中修改了鼠标右键菜单,我们经常需要选择“Show more options”才能找到我们需要的功能。本文介绍如何修改为之前的菜单。

管理员权限使用如下命令即可修改为老式右键菜单风格:

reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve

之后还可以使用如下命令恢复:

reg.exe delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f

修改之后需要重启才能生效,或者使用如下命令重启Explorer:

taskkill /f /im explorer.exe &amp; start explorer.exe

编写两个批处理方便使用(密码 labz):

参考:

1.https://answers.microsoft.com/en-us/windows/forum/all/restore-old-right-click-context-menu-in-windows-11/a62e797c-eaf3-411b-aeec-e460e6e5a82a

2.有没有什么办法可以让win11右键默认显示更多选项? – 知乎 (zhihu.com)

一种 WinDBG 无法使用的解决方法

之前偶然发现很多机器无法使用 WinDBG + USB 3.0 Cable 进行调试。最近花了一点时间仔细研究这个问题。

我遇到的现象是:USB 3.0 调试线连接之后设备管理器中有时候没有新设备出现,有时候出现Yellow Bang ,提示 Port Reset 失败。

经过研究这个问题是我的被调试系统(DUT)中存在多个 XHCI,解决方法是需要指定一个 XHCI 作为被调试目标。在 DUT 中管理员权限打开一个 CMD 窗口,然后输入如下命令:

bcdedit /set “{dbgsettings}” busparams 0.20.0

其中 0.20.0 是Bus:0 Device:20 Func:0 的意思,Intel 芯片组上对应着 XHCI 控制器。解析来工作机上的设备管理器中就会出现 “USB Debug Connection Device”,接下来就可以使用 WinDBG 进行工作了。

参考:

1.https://zhuanlan.zhihu.com/p/405683773 用USB 3.0 + WinDbg开始你的调试之旅

2.https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit–dbgsettings BCDEdit /dbgsettings

=============================================

2025年3月 有兴趣的朋友可以查看这篇文章《Windows Hypervisor&内核调试的几种常见/不常见方法》 https://research.qianxin.com/archives/1876