HaiNguyenEE/axon-c
GitHub: HaiNguyenEE/axon-c
AXON-C 是一款 ESP32-S3 双 USB-C 四层阻抗控制开发板,附带从 Altium 源文件自动生成的完整文档、高速信号完整性分析和板级自检固件。
Stars: 0 | Forks: 0
# AXON-C v1.0
一块带有**两个 USB-C 接口**的 ESP32-S3 开发板 —— 一个直接连接到
芯片的原生 USB 外设,另一个位于 FT231XQ USB 转 UART 桥接器之后 —— 集成在
68.6 × 25.4 mm **4 层阻抗控制 PCB** 上,具有 90 Ω 差分 USB 走线。
**顶层**

**底层** —— 丝印包含 `AXON-C v1.0`, `(C) 2026 HAI NGUYEN`,
`github.com/HaiNguyenEE` 和 `eerfLab.com`,以及两个排针的完整引脚图。

这些都不是截图。这两张图都是由 [`tools/mkboardview.py`](tools/mkboardview.py) 根据
`ESP32wUSB.PcbDoc` 内部的制造几何图形逐像素绘制出来的 ——
铜箔、覆铜、ENIG 焊盘、钻孔和丝印全部提取自二进制 Altium 数据流,
并像板厂那样根据布线的板框进行裁剪。
`esp32-s3` · `usb-c` · `pcb-design` · `high-speed-pcb` · `differential-pair` ·
`signal-integrity` · `controlled-impedance` · `altium-designer` · `hardware-design` ·
`ft231x` · `platformio` · `jlcpcb` · `4-layer-pcb` · `reverse-engineering`
设置两个接口的意义在于你无需再做选择。**ESP** 接口直接通过 GPIO19/20 为你提供
原生 USB(CDC, MSC, HID, TinyUSB)。**UART** 接口为你提供一个
带有硬件 DTR/RTS 自动复位功能的经典 FTDI 控制台,因此 `esptool` 可以
在不触碰任何按钮的情况下将芯片置入下载模式。插入其中任意一个,或同时插入两个,
通过一个 3 针跳线决定由哪个接口为 5 V 电源轨供电。
本代码库中的所有内容 —— 引脚分配表、示意图、固件 ——
均从实际的 PCB 源文件生成,而非手工输入。详见
[本文档是如何生成的](#how-this-documentation-was-produced)。
## 开发板一览
| | |
|---|---|
| **MCU** | ESP32-S3-MINI-1-N8 模块内置 ESP32-S3FN8 — 双核 Xtensa LX7 @ 240 MHz |
| **Flash** | 8 MB,封装内 |
| **PSRAM** | 无 |
| **Radio** | 2.4 GHz Wi-Fi b/g/n + Bluetooth LE 5,PCB 天线 |
| **USB** | 2 × USB-C 母座 (Molex 2171790001),均为仅供电 (5.1 kΩ CC 下拉) |
| **USB-UART** | FTDI FT231XQ,带有 DTR/RTS 自动下载电路 |
| **Regulator** | TI TL1963A-33 — 1.5 A LDO,5 V → 3.3 V |
| **I/O** | 2 个 24 针 2.54 mm 排针 (Molex KK254) 上的 40 个 GPIO |
| **Protection** | 6 × AQ3045-01ETG ESD 抑制器,位于两路 VBUS 和两路 USB 数据对上 |
| **Board** | 68.6 × 25.4 mm (2.700 × 1.000 in),4 层,1.56 mm |
| **Stackup** | 阻抗控制 — 0.0994 mm 半固化片 / 1.265 mm 芯板,外层 1 oz,内层 ½ oz,完整内部 GND 平面 |
| **High speed** | `DIFF90` 类中的 3 个差分对 — 6.03 mil / 8 mil,约 90 Ω 差分阻抗 |
## ⚠ v1.0 存在两个阻碍下单的勘误
**不要直接按照此版本图纸进行制造。** 通过解析 PCB 文件发现 `UART` 路径上
存在两个独立的故障,在 CAD 中均属于双网络修复:
| | 故障 | 影响 |
|---|---|---|
| **[E4](docs/HARDWARE.md#errata-for-v10)** | USB **D+ 和 D− 在 FT231XQ 处接反** — `CON1_USB_P` 连到了引脚 9 (`USBDM`),`CON1_USB_N` 连到了引脚 8 (`USBDP`) | 桥接器无法枚举 — 完全无法识别到串口 |
| **[E1](docs/HARDWARE.md#errata-for-v10)** | UART0 的 **TX 接 TX,RX 接 RX** (通过 R20/R21) | 两个输出相互冲突,两个输入悬空 — 无法传输任何字符 |
**`ESP` 接口不受影响**,开发板完全可通过原生 USB 正常使用。完整的
追踪记录、返工几何图形以及针对这两个问题的 CAD 修复方案均位于
[docs/HARDWARE.md § Errata](docs/HARDWARE.md#errata-for-v10) 中。
## 开发板映射图

| 丝印 | 器件 | 描述 |
|---|---|---|
| `U1` | ESP32-S3-MINI-1-N8 | 模块。PCB 天线悬于右侧边缘。 |
| `U2` | FT231XQ | 用于 **UART** 接口的 USB 转 UART 桥接器 |
| `U3` | TL1963A-33 | 3.3 V LDO |
| `UART` | J3 | 连接到 FT231XQ 的 USB-C 接口 |
| `ESP` | J4 | 连接到芯片原生 USB (GPIO19/20) 的 USB-C 接口 |
| `J1` | 24 针排针 | 顶排 — GPIO0…GPIO18, +3V3, +5V, GND |
| `J2` | 24 针排针 | 底排 — GPIO19…GPIO48, UART0, EN, +3V3, GND |
| `RESET` | SW2 | 拉低 `CHIP_PU` |
| `USER` | SW1 | 拉低 `GPIO0` — 在复位时保持可进入下载模式 |
| `POW` | D1, 绿色 | 硬连接至 +3V3。只要电源轨有电就会亮起。**不可由软件控制。** |
| `USER` | D2, 红色 | 位于 GPIO2,**低电平有效** |
| `REG`/`3V3` | J5 | 2 针跳线:LDO 输出 → 3.3 V 电源轨 |
| `USB1`/`+5V`/`USB2` | J6 | 3 针跳线:决定由哪个 USB-C 接口为 5 V 电源轨供电 |
## 上电前必读
必须正确设置两个跳线,否则将毫无反应。
**J5 (`REG` — `3V3`)** 将 LDO 输出连接到开发板的 3.3 V 电源轨。如果拔下跳线帽,
ESP32-S3 将完全断电。将其保持断开是有意为之:这使得 J5 成为了
整个 3.3 V 电源轨的电流测量点,这正是你在不断开走线的情况下测量 Deep Sleep 电流的方法。在 J5 两端串联一个万用表,你就可以读取
所有下游的电流消耗。
**J6 (`USB1` — `+5V` — `USB2`)** 用于选择由哪个 USB-C 接口提供 5 V 电源。`USB1` 是 **UART**
接口 (J3),`USB2` 是 **ESP** 接口 (J4)。中间的引脚是开发板的 `+5V` 节点,
负责为 LDO 和排针引脚 J1-22 供电。这里没有 ORing 二极管,也没有电源多路复用器 ——
跳线帽是连接两个 VBUS 电源轨的唯一部件,因此**切忌在插有两个充电器的情况下
同时短接两侧。**
只有 UART 接口的 VBUS 受到监控:一个从 `+5V_VBUS1` 引出的 4.7 kΩ / 10 kΩ 分压器
驱动 FT231XQ 的 VBUS 检测输入。ESP 接口的 VBUS 没有检测分压器。
## 引脚分配

完整的引脚表格(包含 PCB 文件中出现的每一个网络名称)位于
**[docs/PINOUT.md](docs/PINOUT.md)** 中。以下是你需要注意的事项简述:
| 引脚 | 为何它不仅仅是一个 GPIO |
|---|---|
| GPIO0 | Strapping(启动模式)。通过 27 Ω 串联电阻连接到 `USER` 按钮,并连接到自动下载晶体管。 |
| GPIO2 | 驱动红色 `USER` LED。可用作 I/O,但会导致 LED 闪烁。 |
| GPIO3, GPIO45, GPIO46 | Strapping 引脚 — JTAG 源、VDD_SPI 电压电平、ROM 启动日志。 |
| GPIO19, GPIO20 | 原生 USB D− / D+。引出至 J2-21 / J2-20,但它们是 `ESP` 接口的数据对。 |
| GPIO43, GPIO44 | UART0 TX / RX,由 FT231XQ 驱动。只有在拔下 UART 接口时才被释放。 |
| GPIO26 | 默认为 `SPICS1`。在此处使用的 **-N8** 模块上可用;在 `-N4R2` 上**不可**用。 |
| GPIO33 – GPIO37 | 在 **-N8** 上可用。在 `-N8R8` 及类似器件上保留给 Octal Flash/PSRAM 使用。 |
ADC1 为 GPIO1–GPIO10,ADC2 为 GPIO11–GPIO20。ADC2 在 Wi-Fi 激活时会停止工作,因此
如果你需要在启用 Wi-Fi 的同时使用模拟输入,请保持在 J1 的引脚 4 至 13 上。
## 烧录代码
**原生 USB(`ESP` 接口,J4)。** 将 J6 设置为 `USB2`,插入 `ESP`,S3 的 USB-serial-JTAG
外设将自动枚举。这是更简单的路径,且无需驱动。
**FTDI(`UART` 接口,J3)。** 将 J6 设置为 `USB1`,插入 `UART`。FT231XQ 的 DTR 和 RTS
信号线驱动两个 SS8050 晶体管控制 `CHIP_PU` 和 `GPIO0`,这是标准的
自动复位方案 —— `esptool` 会翻转 modem 控制线,芯片会自行
进入下载模式。无需按键。
**手动操作**(如果你需要的话):按住 `USER`,轻按 `RESET`,松开 `USER`。
## 固件
[`firmware/`](firmware/) 包含一个专门为该开发板编写的启动和自检应用程序。
它不是一个简单的 blink 测试程序 —— 它是你在一块刚组装好的开发板上运行的程序,
用于测试组装厂是否合格。
开机时,它会打印芯片版本、Flash 大小、MAC 地址和复位原因,然后使
`USER` LED 呈心跳闪烁。通过串行控制台,它为你提供了一个交互式 shell:
```
axon> test run the full self-test
axon> info chip / flash / heap / MAC / reset reason
axon> led blink 100 drive the USER LED (remembering it is active LOW)
axon> btn live state of the USER button
axon> scan drive and read back every free header GPIO
axon> adc 4 sample an ADC pin
axon> i2c 8 9 scan an I2C bus on any two header pins
axon> wifi scan for networks — proves the PCB antenna works
axon> bootloader reboot into ROM download mode
```
提供了两个 PlatformIO 环境,每个 USB 接口各一个:
```
cd firmware
pio run -e axon-c-usb -t upload -t monitor # ESP port, native USB CDC
pio run -e axon-c-uart -t upload -t monitor # UART port, FT231XQ
```
构建和接线详情请见 [firmware/README.md](firmware/README.md);针对全新开发板的启动
流程 —— 在通电 5 V 之前测量什么、按什么顺序测量 ——
请见 [docs/BRINGUP.md](docs/BRINGUP.md)。
## 高速设计
三个 USB 2.0 差分对穿过 4 层阻抗控制叠层。完整的
信号完整性记录 —— 规则、测量的几何尺寸、阻抗以及回流路径分析 ——
位于 **[docs/HIGHSPEED.md](docs/HIGHSPEED.md)** 中。以下是核心数据,全部提取自
PCB 文件而非凭空宣称:
**叠层。** 0.0994 mm PP-006 半固化片 (Dk 4.1) / 1.265 mm FR-4 芯板 / 1 oz 外层铜箔 /
½ oz 内层,总厚度 1.5642 mm。这正是 JLCPCB 的 **JLC04161H-3313** 阻抗控制
叠层。**L3 是一个完整、未被分割的 GND 平面**;较薄的外介质使得
90 Ω 差分对能够以可制造的 6 mil 宽度进行布线。
**`DIFF90` 类。** `ESP_USB`、`CON1_USB` 和 `CON2_USB` 受到
`DiffPairsRouting` 规则约束:**8 mil 间距**,外层 6.03 mil 线宽,中间层 1 为 5.1 mil,
并且**最大非耦合长度为 500 mil** —— 此外还有一个专属的 6 mil 间距覆盖规则,
与开发板通用的 5 mil 间距相比,为差分对提供了与其他网络更大的空间。走线转角
为 45°,过孔直接连接到平面,而非通过散热焊盘连接。
**实际实现情况**,测量自 `Tracks6`/`Arcs6`/`Vias6`:
| 差分对 | 边缘到边缘间距 | 预估 Z_diff | 对内偏差 |
|---|---|---|---|
| `ESP_USB` | **8.00 mil** — 严格符合规则 | 91.8 Ω | **1.4 ps** |
| `CON2_USB` | **8.00 mil** — 严格符合规则 | 90.0 Ω | 9.2 ps\* |
| `FTDI_USB` | 13.68 mil — 超出类规则范围 | 97.1 Ω | 1.2 ps |
\* 连接器侧的网络包含 USB-C A6↔B6 / A7↔B7 翻转支持短截线,因此原始网络
长度超出了实际的电气路径。无短截线的差分对数据才是真实数值。
**回流路径。** 每一段走线的中点都经过了 19 个覆铜区域的测试,
按 `POURINDEX` 顺序进行,因此结果就是实际存在的铜箔。十条引脚走线中的八条
位于 **100% GND** 上方。`CON2_USB` —— 最长的差分对,56–57 mm —— 却并非如此:
每条走线大约有 40% 穿过 L2 层的 `+3V3` 和 `+3V3_REG` 覆铜区域,
每条走线有三个边界交叉点,距离最近的 GND 缝合过孔为 1.9–3.9 mm。在 12 Mbps 下
这是无害的,[文档中也对此直言不讳](docs/HIGHSPEED.md#5-return-paths-and-reference-plane-integrity)
而没有加以掩饰。在 High Speed 下则不然,不过在重新设计中可以轻松修复。
## 图库
| | |
|---|---|
|  |  |
| 顶部,倾斜视角 | 正面,展示两个 USB-C 母座 |
|  |  |
| **第 3 层 —— 内部接地平面。** 黄色部分是覆盖整块开发板的 GND 覆铜;这是内层,不是底层。底层在[本页顶部](#axon-c-v10)。 | 去除阻焊层 —— 裸铜和 ENIG |
|  |  |
| 顶部,从 USB-C 端看去 | 所有层,2D 视图 |
|  |  |
| 底层布线 | 顶层锡膏 / 钢网开窗 |
|  |  |
| 焊盘上带有网络名称的装配图 | 直接从 Altium 导出的顶视图 |
## 仓库布局
```
axon-c/
├── docs/
│ ├── PINOUT.md every pin of J1 and J2, net names verbatim from the PCB
│ ├── HARDWARE.md power tree, auto-program circuit, USB paths, errata, fitted/DNP
│ ├── HIGHSPEED.md differential pairs, stackup, impedance, return-path analysis
│ └── BRINGUP.md first-power-up procedure for a freshly assembled board
├── firmware/
│ ├── platformio.ini
│ ├── README.md
│ └── src/
│ ├── axon_c_board.h pin map, generated from the PCB netlist
│ └── main.cpp bring-up self-test and serial shell
├── hardware/
│ ├── netlist.json component → pin → net, extracted from the PcbDoc
│ ├── NETLIST.md the same thing, readable
│ ├── extract_netlist.py the netlist extractor, so you can re-run it
│ ├── highspeed.json stackup, rules, pair geometry, pours, impedance
│ └── extract_highspeed.py the high-speed extractor
├── tools/
│ ├── mkboardview.py draws board-top.png and board-bottom.png from the PcbDoc
│ └── mkpinout.py draws the pinout diagram from real PCB coordinates
└── images/
```
## 本文档是如何生成的
本仓库中的引脚表并非肉眼对照原理图抄录的。`ESP32wUSB.PcbDoc`
是一个 OLE2 复合文档,其 `Nets6`、`Components6` 和 `Pads6` 数据流被直接解析,
以恢复哪个网络连接到了哪个器件的哪个焊盘上。
[`hardware/extract_netlist.py`](hardware/extract_netlist.py) 就是那个解析器;运行它
处理 PCB 文件,你就能得到 [`hardware/netlist.json`](hardware/netlist.json) 文件。
在进行任何信任之前,解码通过三种方式进行了验证:这 303 条焊盘记录
精确消耗了 82,330 字节中的 82,330 字节,没有任何剩余;扫描到的最高网络索引为
74(对应声明的 75 个网络);最高的器件索引为 65(对应声明的 66 个器件)。
记录布局中的任何一处偏移错误(off-by-one)都会破坏这三项的一致性。
这比听起来更重要。开发板渲染图中的任何内容都无法告诉你
`USER` LED 的朝向,而且输出文件夹中也没有原理图图像。从
PCB 文件中读取给出了答案:电流从 +3V3 流经 R19 进入 D2 然后流向 GPIO2,
因此**当 GPIO2 拉低时 LED 灯亮。** 用常规方式编写的 blink 程序,即使用
`digitalWrite(LED, HIGH)`,将会产生反向逻辑,且短时间内根本没人会察觉。
`images/pinout.svg` 中的示意图是由
`tools/mkpinout.py` 根据相同的提取数据生成的,包括开发板轮廓 —— 模块、按键、LED、跳线和
USB 母座都是根据 PCB 文件中的真实坐标绘制而成的。
本页顶部的两个开发板视图来自 [`tools/mkboardview.py`](tools/mkboardview.py),
它将解码过程推进了一大步:`Regions6` 用于覆铜(每条记录是一个
属性字符串,后跟一个 `u32` 顶点计数以及每个轮廓相应数量的双精度浮点数对,
首先是外边界,然后是孔),`Vias6` 用于 24 mil / 12 mil 的通孔,以及
偏移量 45 处的焊盘孔径记录。丝印是最微妙的部分 —— `Texts6`
为全部 66 个器件各自存储了一个位号和一个注释,无论它们是否被
打印,而且可见性开关根本不在 `Texts6` 中,而是在 `Components6` 中,即
`NAMEON` 和 `COMMENTON`。绘制所有 223 个字符串会使板子变得无法阅读;遵守这
两个标志位会去掉其中的 120 个,留下来的恰好就是板厂丝印的内容。底视图在
X 轴上进行了镜像,这既是你翻转板子时看它的方式,也是为什么
底层丝印 —— 存储时即作镜像以便透过板子阅读 —— 能够清晰可辨的原因。
相同的方法也用于生成高速分析。
[`hardware/extract_highspeed.py`](hardware/extract_highspeed.py) 深入剖析了
格式 —— `Rules6` 记录包含其他数据流所没有的两字节前缀,`Arcs6` 使用了
与 `Tracks6` 不同的记录类型字节,尺寸以带有单位后缀的字符串形式存储
(如 `'1.378mil'`),且必须通过 `LAYER{n}NEXT` 链遍历层叠结构,因为按顺序读取
`LAYER1..LAYER32` 会返回 28 个未使用的 FR-4 默认值。走线、
圆弧和过孔的几何结构随后给出了真实的布线长度、真实的差分对间距和真实的过孔数量;
`Polygons6` 提供了覆铜区域,按 `POURINDEX` 顺序解析它们可以得到每条
走线的实际参考平面。
正是这些将“差分对看起来没问题”转变为了在任何
渲染图中都不可见的两个发现:测得的 8.00 mil 间距精确符合 8 mil 规则,以及 `CON2_USB`
每条走线穿过了三个参考平面边界。这也正是抓出 **E4** 的关键 ——
即 FT231XQ 处接反的 USB 数据对,这种故障在开发板照片上根本看不出来,如果不这么做,
直到付款组装后才会被发现。
## 许可证
固件和文档采用 MIT 许可证 —— 详见 [LICENSE](LICENSE)。
此处不重新分发 PCB 源文件。本代码库中的渲染图和衍生引脚数据
描述的是该开发板的一个实体制造版本。
标签:Altium Designer, ESP32-S3, PCB设计, USB-C, 嵌入式系统, 硬件开发, 逆向工具, 阻抗控制