1. 项目概述:为什么S3到手先改Flash和PSRAM配置
ESP32-S3这颗芯片最近两年在智能硬件圈子里是真的火,尤其是带8MB Octal PSRAM的N16R8模组,跑LVGL界面、做边缘视觉、挂摄像头,内存不够用的焦虑一下缓解了不少。但很多朋友拿到板子的第一反应是:明明买的是16MB Flash版本,为什么编译完固件才几百KB,上传之后还动不动提示空间不足?查一下ESP.getFlashChipSize(),返回的却是4MB,甚至PSRAM直接就是0。问题出在哪儿?十有八九是PlatformIO和Arduino框架的默认配置压根没有按你的硬件来。
这篇文章我直接把日常折腾S3的配置方案摊开讲:从VS Code里搭建PlatformIO环境,到platformio.ini里逐行解释Flash和PSRAM的关键参数,再到自定义分区表、启用Octal PSRAM、验证硬件是否真正生效,最后附上我踩过的几个比较隐蔽的坑。无论你是刚入手S3开发板的新手,还是从Arduino IDE转过来的老玩家,这篇文章都能帮你少走不少冤枉路。
我默认你手里的板子是基于ESP32-S3-WROOM-1模组的开发板,Flash为16MB(Quad SPI),PSRAM为8MB(Octal SPI),也就是常说的N16R8版本。其他容量组合的配置思路完全一致,只是参数值不同,文末的部分我会顺带说明。
动手之前,先快速过一遍需要用到的工具链。PlatformIO本质是一个跨平台的嵌入式构建系统,底层调用的是乐鑫官方的ESP-IDF工具链,只是在这个基础上又套了一层更友好的工程管理外壳。VS Code里安装PlatformIO IDE插件后,你不需要单独装ESP-IDF、不需要手动配环境变量、不需要关心编译链版本冲突,插件会自动拉取对应版本的编译工具。这也是我建议直接用PlatformIO而不是原生ESP-IDF来跑Arduino框架的原因:省事,可复现,换台电脑也不用重新折腾半天。
注意:PlatformIO会从GitHub下载工具链和框架源码。如果网络条件不好,下载经常中断,建议配置好代理或者提前下载好PlatformIO核心工具包放到指定目录,否则很容易卡在
tool-esptoolpy或framework-arduinoespressif32的下载步骤上。
2. 从零搭建PlatformIO工程:开发环境准备全流程
2.1 安装PlatformIO IDE插件与创建项目
打开VS Code,在扩展商店里搜索PlatformIO IDE,认准作者是PlatformIO官方那个,安装量几百万的,点击Install等待完成。装完之后左侧栏会多出一个PlatformIO的小图标,工具栏也会出现对应的入口。
创建项目有两种方式。第一种是点击PlatformIO图标,选择PIO Home->Open->New Project,在弹窗里设置项目名称、选择开发板型号。第二种是直接用命令行,在终端里执行pio project init,适合已经建好文件夹的场景。我个人更习惯第一种,省事。
在板子型号下拉框里输入esp32-s3,会看到若干个选项,包括esp32-s3-devkitc-1、esp32-s3-devkitm-1、esp32-s3-fh4r2等。这里需要注意,PlatformIO的板级定义文件(boards/esp32-s3-devkitc-1.json)里默认配置的Flash大小是8MB,PSRAM是2MB。这个默认值和你实际手上的16MB Flash、8MB PSRAM并不一致,所以即便你选对了开发板型号,如果不在platformio.ini里做进一步的覆盖,最终编译出来的固件也只会按8MB Flash和2MB PSRAM来处理。
创建完成后,PlatformIO会自动生成一个最小工程目录:
my_s3_project/ ├── .pio/ ├── include/ ├── lib/ ├── src/ │ └── main.cpp ├── test/ ├── platformio.ini └── .gitignoresrc/main.cpp是Arduino工程的入口文件,.pio目录存放编译缓存、依赖包和生成固件,platformio.ini是核心配置文件,接下来我们需要重点操作的就是它。
2.2 platformio.ini里最关键的三行配置
打开platformio.ini,默认内容大致长这样:
[env:esp32-s3-devkitc-1] platform = espressif32 board = esp32-s3-devkitc-1 framework = arduino这三行代表的意思分别是:使用espressif32平台(包含ESP-IDF和工具链)、以esp32-s3-devkitc-1的板级配置为准、使用Arduino框架。在此基础上,我们要追加几行关键配置,让它与我们手头的N16R8硬件完全匹配。
[env:esp32-s3-devkitc-1] platform = espressif32 board = esp32-s3-devkitc-1 framework = arduino board_build.flash_size = 16MB board_build.psram_size = 8MB board_upload.flash_size = 16MB board_build.partitions = default_16MB.csv board_build.arduino.memory_type = qio_qspi逐行解释一下:
board_build.flash_size:告诉编译器和链接器,Flash总容量是16MB。这个值会影响链接脚本里各种段的布局,不设置正确的话,即便分区表写对了,地址偏移也可能算错。board_build.psram_size:声明PSRAM容量为8MB。Arduino框架编译时会根据这个值决定相关宏定义。board_upload.flash_size:这个参数传给esptool烧录工具。烧录时esptool会根据Flash大小来计算擦除范围、校验地址参数。board_build.partitions:指定分区表文件。PlatformIO内置了default_16MB.csv,对应的就是16MB Flash的分区布局。board_build.arduino.memory_type:指定Flash和PSRAM的连接方式。qio_qspi表示Flash使用QIO模式、PSRAM使用QSPI模式。但这里有个非常关键的坑:N16R8模组的8MB PSRAM是Octal模式,不是QSPI。所以如果你用的是N16R8,这一行应该设置为qio_opi。
board_build.arduino.memory_type = qio_opiqio_opi的具体含义是:Flash走Quad I/O,PSRAM走Octal I/O。如果这里搞错了,最典型的症状就是上电后串口日志里反复打印PSRAM not found或PSRAM ID read error,因为芯片根本没法用QSPI协议和一颗Octal PSRAM正常通信。
2.3 分区表的作用与自定义分区表
分区表的角色相当于硬盘的分区布局,它规定了固件、文件系统、NVFS、OTA等区域各占多大空间、位于什么偏移地址。PlatformIO自带的default_16MB.csv已经能覆盖绝大多数场景,布局大致如下:
# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x700000, app1, app, ota_1, 0x710000, 0x700000, spiffs, data, spiffs, 0xe10000, 0x1E0000,这个布局的特点是:两个OTA分区各占7MB,SPIFFS文件系统占约1.875MB,总共使用约16MB。对于大部分应用来说,一个固件7MB的空间绰绰有余。如果你不需要OTA功能,希望把更多空间留给文件系统,完全可以自定义分区表。
自定义分区表的步骤很简单:在项目根目录下新建一个partitions_custom.csv,内容按需编辑,然后在platformio.ini里把分区表指向它:
board_build.partitions = partitions_custom.csv这里我给一个不带OTA、追求固件区和文件系统均衡的16MB分区表示例:
# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x800000, spiffs, data, spiffs, 0x810000, 0x7F0000,这样固件区占8MB,文件系统占约7.94MB。如果你的应用要存大量图片、音频、日志文件,这种布局会舒服很多。注意,自定义分区表里的每个分区大小必须按照Flash的扇区大小(4KB)对齐,偏移地址也得对齐,否则esptool会报错。
3. 核心细节解析:Flash与PSRAM配置背后的原理
3.1 Flash容量如果设错会发生什么
经常有人问:我不设置board_build.flash_size,直接把固件烧进去,好像也能跑,有什么区别?
区别非常大。先看编译环节:Arduino框架在编译时,会根据Flash大小生成对应的esp32_arduino.ld链接脚本。这个脚本里定义了FLASH段的起始地址和长度。如果你不指定,默认可能按4MB或者8MB来处理,那么生成的固件二进制文件里的地址信息、.flash.rodata段长度等参数都会按小容量来计算。这通常不会导致编译失败,但会带来两个隐患:一是实际上你用不满16MB空间,二是分区表偏移和固件地址可能出现错位。
再看烧录环节:esptool在烧录时,固件里如果带有Flash参数信息(默认会烧录一个包含flash mode、flash size、flash freq的头部数据),当板子的实际Flash大小与这些参数不匹配时,芯片启动时bootloader会尝试重新初始化Flash,过程可能出现问题。最典型的现象是:程序能烧进去,但上电后串口疯狂重启,日志里反复出现Flash size error或者invalid segment count。
简单说,Flash大小不对,编译不一定报错,但运行一定会出问题。这个问题有时候很隐蔽,因为它不是必现的。所以拿到新板子,第一步就是把Flash大小写对。
3.2 Octal PSRAM为什么不能按QSPI来配
ESP32-S3的PSRAM有一个比较特殊的地方:它既支持Quad PSRAM(通过QSPI接口),也支持Octal PSRAM(通过OPI接口)。而8MB容量的PSRAM,绝大多数型号都是Octal的。市面上常见的8MB PSRAM芯片,例如 APS6408、ESP-PSRAM64H,工作模式都是OPI。
Octal和Quad的区别主要在于数据线数量:Quad使用4根数据线(D0-D3),Octal使用8根数据线(D0-D7)。虽然8MB PSRAM也有少数QSPI型号,但极少见,基本可以忽略。也因此,在配置memory_type时,qio_qspi只能驱动Quad PSRAM,对于8MB的Octal PSRAM必须设置成qio_opi。
配置成qio_opi后,ESP32-S3会自动使用对应的GPIO矩阵来初始化PSRAM,包括发送ID读取命令、设置延时等。如果在启动日志里能够看到类似:
PSRAM: ID = 0x0d 0x5d PSRAM: Manufacturer ID = 0x0d PSRAM: Type = 0x5d PSRAM: Size = 8MB说明PSRAM初始化成功。如果看到的是PSRAM not found或者PSRAM ID read error,第一优先检查的就是memory_type是否设置正确。
3.3 Arduino框架下如何启用PSRAM的堆内存
即使PSRAM初始化成功,默认情况下Arduino框架并不会把所有内存分配都迁移到PSRAM。默认的malloc、new、String等操作仍然使用内部SRAM,容量大约512KB。内部SRAM对于简单程序够了,但如果你要跑LVGL、OpenMV这种吃内存大户,512KB很容易爆。
Arduino框架提供两种方式使用PSRAM:
第一种是显式调用PSRAM分配函数:
void *buf = ps_malloc(1024 * 1024); // 分配1MB内存 if (buf != NULL) { // 使用这块内存 free(buf); }ps_malloc与标准malloc的区别在于,它优先从PSRAM分配,如果PSRAM不足或者未启用,会回退到内部SRAM。也有heap_caps_malloc(size, MALLOC_CAP_SPIRAM)可以精确指定从PSRAM分配,不过对于大多数场景,ps_malloc已经够用。
第二种是全局启用PSRAM作为堆内存的一部分。在platformio.ini中,通过build_flags添加如下宏:
build_flags = -DBOARD_HAS_PSRAM -DCONFIG_SPIRAM_SUPPORT=y -DCONFIG_SPIRAM_MODE_OCT=y添加之后,重新编译烧录。框架会尽可能把堆分配放到PSRAM中,但这并不意味着所有malloc都会自动走PSRAM,内部SRAM仍然有优先分配权。实际使用中,如果遇到内存不足,建议关键的大块内存还是显式用ps_malloc来分配,这样更可控。
提示:
ps_malloc分配的内存只能通过free释放,不能通过delete释放。如果你在C++代码里用ps_malloc配合new使用,记得自己管理生命周期,避免内存泄漏。
4. 实操过程:从配置到验证Flash和PSRAM生效
4.1 完整可复现的platformio.ini示例
直接给一份我日常使用的、经过验证的完整配置:
[env:esp32-s3-devkitc-1] platform = espressif32 board = espressif32:esp32-s3-devkitc-1 framework = arduino ; Flash和PSRAM容量 board_build.flash_size = 16MB board_build.psram_size = 8MB ; 分区表 board_build.partitions = default_16MB.csv ; Flash和PSRAM连接方式(N16R8这里必须用qio_opi) board_build.arduino.memory_type = qio_opi ; 启用PSRAM和Octal模式 build_flags = -DBOARD_HAS_PSRAM -DCONFIG_SPIRAM_SUPPORT=y -DCONFIG_SPIRAM_MODE_OCT=y ; 烧录相关 upload_speed = 921600 monitor_speed = 115200注意board那一行,我在前面加上了espressif32:前缀。这是为了避免和PlatformIO内置的其他厂商板级定义冲突,尤其当你安装过多个开发平台时,显式指定平台名能减少很多莫名其妙的报错。
如果你使用的是带UART的经典S3开发板,直接烧录即可。如果你用的是仅带USB的S3板子(比如某些核心板只有一个USB-C口,没有额外串口芯片),需要在platformio.ini中加一行:
upload_port = /dev/cu.usbmodem* ; macOS路径示例,Windows下类似COM3或者是通过board_upload.use_1200bps_touch = yes、board_upload.wait_for_upload_port = yes配合串口监视器实现一键烧录。这部分配置因板而异,不展开。
4.2 用一段验证代码确认Flash和PSRAM真实状态
配置完成后,不要急着写业务逻辑。先烧一段验证代码,确保硬件层面的配置真正生效。
#include <Arduino.h> void setup() { Serial.begin(115200); delay(2000); // 等待串口监视器连接 Serial.println("\n===== ESP32-S3 Hardware Info ====="); // Flash信息 Serial.printf("Flash Chip Size: %u bytes (%.2f MB)\n", ESP.getFlashChipSize(), ESP.getFlashChipSize() / 1024.0 / 1024.0); Serial.printf("Flash Speed: %u Hz\n", ESP.getFlashChipSpeed()); // PSRAM信息 Serial.printf("PSRAM Size: %u bytes (%.2f MB)\n", ESP.getPsramSize(), ESP.getPsramSize() / 1024.0 / 1024.0); Serial.printf("Free PSRAM: %u bytes\n", ESP.getFreePsram()); // 测试PSRAM读写 size_t testSize = 2 * 1024 * 1024; // 2MB uint8_t *buf = (uint8_t *)ps_malloc(testSize); if (buf != NULL) { Serial.printf("ps_malloc(%u) OK\n", testSize); // 写入测试数据 for (size_t i = 0; i < testSize; i++) { buf[i] = (uint8_t)(i & 0xFF); } // 校验 bool ok = true; for (size_t i = 0; i < testSize; i++) { if (buf[i] != (uint8_t)(i & 0xFF)) { ok = false; Serial.printf("Data mismatch at %u\n", i); break; } } Serial.printf("PSRAM Read/Write Test: %s\n", ok ? "PASS" : "FAIL"); free(buf); } else { Serial.println("ps_malloc FAILED"); } // 测试Flash读取 Serial.printf("Flash Chip ID: 0x%08X\n", ESP.getFlashChipId()); Serial.println("================================="); } void loop() { delay(10000); }这段代码做的事情很简单:打印Flash总容量、PSRAM总容量、可用PSRAM,然后分配2MB的PSRAM内存做一次完整的写入和回读校验。如果打印结果中Flash是16777216 bytes (16.00 MB),PSRAM是8388608 bytes (8.00 MB),并且读写测试显示PASS,说明整个配置链是通的。
特别说明一下ps_malloc分配2MB的意义。如果你遇到分配失败,说明PSRAM没有真正启用,或者build_flags里的宏没有生效。有一种情况是编译时启用了PSRAM,但启动初始化失败,此时ESP.getPsramSize()会返回0,ps_malloc也会返回NULL。这时建议先用串口监视器把启动日志完整抓下来,观察PSRAM初始化的具体报错信息。
4.3 烧录过程中常见日志与正常现象
烧录过程中,esptool的输出信息非常关键。正常的烧录日志大致长这样:
Serial port COM5 Chip is ESP32-S3 Features: WiFi, BLE, Embedded Flash 16MB (XMC) Crystal is 40MHz MAC: 7c:df:a1:xx:xx:xx Uploading stub... Running stub... Stub running... Changing baud rate to 921600 Configuring flash size... Flash will be erased from 0x00000000 to 0x0000ffff... Flash will be erased from 0x00010000 to 0x0080ffff... Compressed 26144 bytes... Writing at 0x00000000... Compressed 629584 bytes... Writing at 0x00010000...注意看Embedded Flash 16MB (XMC)这一行,它表示esptool正确识别了你板子上的Flash容量。如果这里显示的是8MB或4MB,那么即便你代码里配置了16MB,烧录阶段也会出问题。
还有一个细节:esptool在烧录完成后会打印:
Hash of data verified.说明数据校验通过,烧录没有出错。如果等一会儿却看不到这个信息,而是出现Hash mismatch、A fatal error occurred之类的字样,多半是Flash型号识别错误、烧录速度过快导致不稳定,或者串口线质量不佳。把upload_speed调低到460800甚至230400再试,常见问题基本能解决。
5. 常见问题与排查技巧实录
5.1 配置后烧录正常但PSRAM始终为0
我遇到过不少次,配置看起来全对,编译烧录都正常,但跑起来ESP.getPsramSize()就是返回0。排查思路按优先级排序:
第一,确认memory_type是不是qio_opi。如果你用的是8MB Octal PSRAM,这里写错等于白搭。怎么确认自己的PSRAM是Octal还是Quad?最直接的方法是看板子或模组的丝印。N16R8里的R8就代表8MB Octal PSRAM,R2是2MB Quad PSRAM,R8J是8MB Quad PSRAM(这个比较少见)。大部分情况下,8MB的PSRAM都是Octal。
第二,确认board_build.psram_size = 8MB有没有写对。有些朋友把psram_size和flash_size写反了,或者漏掉了一个,导致Arduino框架拿到的PSRAM参数错误。
第三,检查启动日志。把波特率设为115200,上电后立刻按住复位键,查看serial monitor中的完整日志。正常的PSRAM初始化日志如下:
I (299) spiram: Found 8MB PSRAM device, let's initialize it I (299) spiram: Enabling QUAD (0x0) mode I (305) spiram: SPIRAM mode: QUAD I (311) psram: PSRAM initialized, size: 8MB如果你的日志里出现:
E (299) spiram: PSRAM ID read error: 0x00ffffff那么问题100%出在硬件连接或者memory_type上。先检查memory_type,再检查开发板是否是N16R8版本,如果你的板子其实是8MB Flash + 2MB PSRAM的N8R2,那么qio_qspi才是正确的。
5.2 编译报错“No such file or directory”或链接脚本冲突
这种情况多发生在修改了Flash大小或者分区表之后,PlatformIO的编译缓存没有完全刷新。解决方案也比较粗暴:
pio run -t clean pio run如果还不行,直接把.pio目录删除,重新编译。.pio里缓存了旧的分区表、链接脚本和编译产物,不清理干净的话,新参数可能不会被正确应用。
另一种报错情况是使用了自定义分区表,但CSV文件本身的格式有问题。检查CSV文件的换行符,在Windows下记事本编辑可能导致CRLF换行问题,esptool在解析时偶尔会报错。推荐用VS Code编辑,保存格式保持UTF-8无BOM。
5.3 OTA分区相关的问题
配置16MB Flash后,很多人会开启OTA功能。OTA本身不复杂,但要特别注意分区表里必须预留两个app分区。如果分区表里只有一个app分区,启用OTA后,新固件没有地方放,OTA会直接失败。
常见设置为app0和app1各占7MB,但这会压缩文件系统空间。对于16MB Flash和8MB PSRAM的配置,如果项目比较大,建议把文件系统空间控制在1~2MB以内,把更多空间留给两个OTA固件。否则,未来固件超过分区大小,OTA会报Not enough space for new partition。
5.4 USB CDC串口无法打印日志
S3开发板有两种调试方式:一种是板载UART转USB芯片,比如CP2102或CH340,这种最省心,直接认串口;另一种是原生USB CDC,即S3芯片的USB接口直接连电脑。后者需要正确配置才能输出日志。
如果是原生USB CDC,Arduino框架下需要在platformio.ini中加入:
build_flags = -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1然后在代码里使用Serial.begin(115200)后,日志会通过USB CDC输出。IDE里选择对应的串口号,波特率设置为115200即可。
但需要注意,USB CDC模式下,如果你同时启用了monitor_speed = 115200,在PlatformIO的Serial Monitor中需要选择正确的端口,并且确保没有其他程序占用该串口。
6. 进阶扩展:几个值得留意的方向
6.1 从Arduino框架切换到ESP-IDF需要注意什么
如果有一天你觉得Arduino框架的封装太厚,想玩ESP-IDF原生开发,配置会有些不同。ESP-IDF可以使用idf.py set-target esp32s3以及idf.py menuconfig来配置Flash大小、PSRAM模式、分区表等。但这套流程和PlatformIO的platformio.ini配置体系是两套逻辑,不能简单混用。
在PlatformIO里切换到ESP-IDF框架,只需要改一行:
framework = espidf但ESP-IDF下的配置是通过sdkconfig文件实现的,PlatformIO会在第一次编译时根据板级定义自动生成一个默认的sdkconfig,之后你再通过build_flags添加-DCONFIG_XXX来覆盖。很多从Arduino转过来的朋友在切换之后,容易忽略ESP-IDF严格的分区表校验和线程模型,导致代码跑飞。建议在真正需要底层控制时再做切换,否则Arduino框架足够用了。
6.2 PSRAM性能优化:缓存与DMA的权衡
PSRAM的带宽远低于内部SRAM。实测下来,PSRAM的读取速度大约是内部SRAM的一半到三分之一。所以在使用PSRAM时,需要权衡:
- 对于高频访问的变量,比如循环计数、状态标志,放到内部SRAM。
- 对于大块数据,比如图像帧缓冲、音频样本、字体缓存,放到PSRAM。
- DMA外设(如I2S、SDMMC)如果要访问PSRAM,部分外设不支持直接访问PSRAM,需要经过内部SRAM中转。
经验法则是:80%的大块数据放PSRAM,20%的高频小变量放SRAM。LVGL等GUI库的帧缓冲放PSRAM完全没问题,但触摸坐标这类高频读写的数据,最好留在SRAM里。
6.3 如何用PlatformIO的Monitor实时查看内存信息
PlatformIO内置的Serial Monitor虽然简单,但调试内存信息非常方便。可以在代码里定时打印ESP.getFreeHeap()和ESP.getFreePsram(),然后在Serial Monitor里观察变化趋势。这个习惯能帮你快速定位内存泄漏和过度分配问题。
Serial.printf("Free Heap: %u, Free PSRAM: %u\n", ESP.getFreeHeap(), ESP.getFreePsram());我在调优LVGL界面时,就是靠这两行日志定位到了字体缓冲分配过大导致的卡顿问题。
6.4 16MB Flash下如何合理规划文件系统
如果你的应用要存大量静态资源,可以考虑把SPIFFS换成LittleFS。LittleFS在断电恢复、写性能方面比SPIFFS好不少,而且Arduino框架对它的支持也比较成熟。在platformio.ini中通过board_build.filesystem = littlefs来指定文件系统类型。
如果你的分区表里给SPIFFS/LittleFS分了较大的空间,还需要在烧录时顺带烧入文件系统镜像。PlatformIO的做法是先在项目根目录下创建data文件夹,放入需要打包的静态资源,然后执行:
pio run -t uploadfs这样文件系统镜像就会按照分区表偏移烧录到对应区域。注意,uploadfs会擦除整个文件系统分区,如果分区表配置不当或者偏移错误,可能会覆盖到固件区,导致系统无法启动。文件系统分区建议和app分区之间留出足够间隔,至少在CSV文件中让spiffs的偏移不要紧跟业务固件尾部,给自己留点缓冲空间。
7. 给同样在折腾S3的玩家几句掏心窝的话
文章写到这里,该说的技术细节基本都覆盖了。最后回归到实际体验层面,聊几句题外话。
我在拿到第一块N16R8开发板的时候,也曾经被Flash和PSRAM配置折磨过一整天,卡在PSRAM始终识别不出来这个坎上。后来一步步排查,最后发现就是memory_type少写了一个字节的事。从那之后我养成一个习惯:所有新板子到手,第一件是永远是跑硬件信息验证代码,而不是急着写业务逻辑。这个习惯帮我在后续几个项目里省了大量排查时间。
还有一点想说的是,PlatformIO的配置看起来简单,但背后的platformio.ini本质上是一个构建系统的入口,很多看起来无关紧要的选项,实际关联着链接脚本、编译宏、烧录参数等多个环节。遇到问题的时候,不要急着换芯片换板子,先把配置逐行过一遍,把编译日志和启动日志抓完整,大部分问题都能在日志里找到答案。
希望这篇文章能帮你少走弯路。如果你在配置过程中遇到其他离谱的问题,欢迎在评论区交流。不同厂家的S3板子虽然硬件差异不大,但细节调教上确实有一些不一样的门道,互相分享一下经验,大家都省心。