ESP32 也能跑 Linux 了

发布于 2026/08/29 07:53 · 更新于 2026/08/29 07:53

ESP32 也能跑 Linux 了

大家好,我是写代码的篮球球痴。

乐鑫最近放了个东西出来,我刷到的时候愣了一下——ESP32 竟然能跑 Linux 了。

那岂不是最便宜的 可量产的Linux系统了?

工程师看到芯片新闻愣住

是乐鑫官方自己出的 BSP,冲着 ESP32-S31 来的,一颗双核 RISC-V 芯片。

——先讲它怎么跑?

ESP32 从 ESP8266 一路迭代到现在,定位一直是 Wi-Fi、蓝牙加 FreeRTOS 的物联网 MCU。控制几个传感器、驱动电机、连个云,好使得很,便宜、省电、上手快。

但你要说跑 Linux,以前基本没戏。

不是芯片性能不够,是差两样东西。

一样是 CPU 架构。

老 ESP32、ESP32-S2、S3 用的都是 Xtensa 核,这个核主线 Linux 不认。

后来乐鑫上了 RISC-V,ESP32-C3、C6、H2 都是 RISC-V 核了,架构这关是过了。

但另一样东西一直没有——MMU,内存管理单元。

Linux 从出生那天起就离不开 MMU。

它要给每个进程一个独立的地址空间,进程 A 以为自己独占整块内存,进程 B 也这么以为,中间靠 MMU 做翻译,把假的虚拟地址映射到真的物理地址上。

这样谁也不能随便踩谁的内存,多进程、多用户、权限隔离才玩得转。

没有 MMU,你就只能跑 µClinux 那种阉割版,能用,但软件生态和开发体验差一大截。

MMU 把虚拟地址翻译成物理地址

MMU 把虚拟地址翻译成物理地址

ESP32-S31 这次把 MMU 加上了,再配 16MB PSRAM,硬件这关才算真正迈过去。

——16MB 内存,怎么把 Linux 塞进去?

你想想,16MB 的 PSRAM,放桌面电脑上屁都不是,装个内核都不够。

正常电脑跑 Linux,是把内核从硬盘加载到 RAM 里解压再执行,树莓派 1GB、2GB 的内存,不在乎这点占用。

但 ESP32-S31 不行。

官方那个完整镜像 s31_full_flash.bin 有 13.8MB,你要是照老办法把内核全搬进 RAM,16MB 扣掉内核,剩一两兆给你跑应用,还玩个毛?

所以乐鑫用了一招:XIP,就地执行(execute in place),这在全志的芯片上也搞过的技术,,,。

一句话,代码不搬进 RAM,留在 Flash 上,CPU 通过 cache 直接去 Flash 里取指令执行。

ESP32 这套机制搞嵌入式的都熟——你平时烧的那几百 KB 固件,很大一部分就是 map 在 Flash 上跑的,不占片内 RAM。

现在把这套思路往上推了一层,推到 Linux 内核头上。

内存划分大概是这么个结构:

位置

放什么

为什么

Flash(16MB)

bootloader、OpenSBI、XIP 内核、cramfs 根文件系统

代码和只读数据就地执行,不占 RAM

PSRAM(16MB)

Linux 运行时内存:页表、堆、栈、可写数据段

可写的东西必须在 RAM

三样大头都是"就地在 Flash 上待着":

是 xipImage,直接在 Flash 上执行,不搬进 PSRAM;

用 cramfs,一种压缩过的只读文件系统,留在 Flash 上,要用哪个文件就读哪个,不整体解压;

也一样,代码留 Flash,只有它那点可写数据(.data/.bss/栈)搬到 PSRAM 顶部。

代码留在 Flash,PSRAM 只放运行时数据

代码留在 Flash,PSRAM 只放运行时数据

这样一来,16MB 的 PSRAM 基本全留给 Linux 当运行时内存了。

启动日志里 free -h 一跑,看到的是 13.6M total,剩下那点被 OpenSBI 的可写段和预留区吃掉了。

这就是为什么一颗只有 16MB PSRAM 的芯片,能把一整条 Linux 启动链跑起来——核心不是内存够大,是代码压根不占内存。

——两颗核,还分工

这里还有个窍门,不搞嵌入式的不容易注意到。

ESP32-S31 是双核,但跑 Linux 的时候,它没做成 SMP(对称多处理,两颗核一起跑 Linux),而是一个核一个活:

为啥不两颗核一起跑 Linux?

原因是——乐鑫那套射频固件是闭源的,只能跑在 FreeRTOS 框架里,你没法把它搬到 Linux 下去驱动。所以干脆让 Hart 0 守着老本行干无线,Linux 占 Hart 1。

但这也埋了个雷——Wi-Fi 恰恰成了现在最悬的外设。

射频在 Hart 0,Linux 在 Hart 1,中间隔着核,数据得通过共享内存和中断门铃来回搬。这套跨核通信的驱动,官方文档到现在没给个准话。

这也是为什么说,别急着拿它做产品。

Hart 0 管无线,Hart 1 跑 Linux

——官方 BSP 

乐鑫这次放出来的东西挺全乎,不是丢给你一个内核让你自己点。

镜像布局和打包在 esp-linux-bsp 这个仓库

github.com/espressif/esp-linux-bsp

最后生成一个 s31_full_flash.bin,直接烧进去就能跑。

真正的 Buildroot 配置在 esp-buildroot-external 仓库

github.com/espressif/esp-buildroot-external

基于 Buildroot 2025.02,32 位 RISC-V musl 工具链。里面这几个组件:

——启动链是

SPL → OpenSBI → U-Boot → Linux 内核 → 根文件系统 → root shell。

这不是单独把内核"点亮"给你看个 logo,这是一整条完整的 Linux 启动链,从 bootloader 一路跑到能登录。

——编译烧录走一遍

光看 BSP 列表还是虚的。我顺着 CNX Software 那篇实测往下撸了一遍流程,把关键步骤拎出来。

CNX 作者自己没板子,只跑了到生成镜像这一步,但编译链路是通的,烧录到板子上命令也是同一套。

第一步,esptool 升版本。这是个坑——ESP32-S31 要求 esptool 5.3.0 以上,老版本会直接报错。Ubuntu 自带的多半是 4.x,得手动装:

sudo apt purge esptool sudo apt install pipx pipx ensurepath pipx install esptool esptool version

跑完应该看到 esptool v5.3.1。

第二步,拉代码。Buildroot 主线和乐鑫的外部配置各一个仓库,分开拉:

git clone --branch 2025.02 --depth 1 https://gitlab.com/buildroot.org/buildroot.git esp-buildroot

注意 esp-linux-bsp 这个镜像打包仓库不用单独拉,Buildroot 会自动拽下来。

第三步,配 defconfig。乐鑫给了一个默认配置,省事:

make -C esp-buildroot \   BR2_EXTERNAL=~/edev/sandbox/esp-buildroot-external \   O=~/edev/sandbox/esp32-s31-linux \   espressif_esp32s31_function_core_board_nor_defconfig

看到 configuration written to .../.config 就说明配置成功了。

第四步,开编。这步最熬人,CNX 实测一个多小时:

ESP_ESPTOOL=$(which esptool)

编完到 images/ 目录下看一眼,关键产物是这些:

$ ls esp32-s31-linux/images/

s31_full_flash.bin 就是最后要烧的那个总镜像,13.8MB,把 bootloader、OpenSBI、U-Boot、内核、根文件系统全打包好了。

xipImage 是裸内核镜像,rootfs.cramfs 是只读根文件系统,前面那套 XIP 内存划分就是靠这两个货实现的。

第五步,烧录。接上板子,确认串口号,然后:

esptool --chip esp32s31 --port <serial-port> --baud 1152000 write-flash 0x0 <path-to-output-directory>/images/s31_full_flash.bin

波特率用的是 1.5M,115200 是烧完后看 Linux 串口控制台用的。

整条链路就这五步。

Buildroot 第一次编要把 32 位 RISC-V musl 工具链、各种依赖全下载下来,等于从头搭一套小 Linux 发行版,所以慢。

第二次编就快了,增量编译。

——但是,先别急着拿它做产品

我得泼盆冷水。

这次发的是 Developer Preview,开发者预览版,不是稳定版。乐鑫自己在项目说明里写得很实在:

再叠上前面的 Wi-Fi 悬案,现在最适合干的,是拿块板子体验下启动流程,看看外设支持到什么程度,评估下 Linux 在 16MB 内存里到底能跑成啥样。

真要往量产方案里写,还早着了。。。。。。

——那 ESP32 跑 Linux,到底有啥用?

这问题得说清楚。

如果你就是控制几个传感器、驱动电机、定时传点数据,FreeRTOS 更省资源、启动更快,硬上 Linux 纯属自找麻烦。

但换个场景就反过来了。比如你要用现成的网络工具、文件系统、Shell 脚本、一堆开源程序,Linux 生态里现成的东西一大把,你在 FreeRTOS 里得一个驱动一个驱动地抠。

再比如你团队本来就熟 Linux 开发,招人、交接、维护都顺。

ESP32-S31 可能就此站到一个以前够不着的位置:比普通 MCU 更接近通用操作系统,又比传统 Linux SoC 更轻、更便宜。

现在说它要改变哪个市场,还太早。

更实在的问题是,乐鑫接下来能不能把无线和常用外设的驱动补齐,能不能让这个 BSP 稳定地维护下去。等这些都有了,ESP32-S31 才算真正迈过 Linux 设备的门槛。

——

还有个背景值得一提。

官方 BSP 出来之前,社区已经抢跑了。

早就有大佬在给 ESP32-S31-Korvo-1 开发板移植 Linux,有的基于 Linux 6.12(github.com/GrieferPig/esp32-s31-linux),能稳定跑 Buildroot 根文件系统和重启,但关机还没做,Wi-Fi、蓝牙双模、双核支持都是实验状态;还有的在试 Linux 7.1 和 OpenSBI 1.9(github.com/annoyedmilk/esp32-s31-linux),基础启动成了,但 LCD、microSD、USB Host、WLAN Modem 这些外设都还没启用。

直接看 GrieferPig 那边跑出来的实际启动日志——Linux 6.12 内核,Buildroot 根文件系统,登录 root,跑个 CoreMark 测了下性能(1083 iterations/sec),然后 free -h 一看,16MB PSRAM 跑起来后剩 13.6M total:

GrieferPig 在 ESP32-S31 上跑 Linux 6.12 的实际启动日志

GrieferPig 在 ESP32-S31 上跑 Linux 6.12 的实际启动日志

注意一行 Starting network: Cannot find device "eth0" FAIL,网络驱动还没接上,这跟官方 BSP 的 Wi-Fi 悬案是一个问题:射频基带锁在 FreeRTOS 那颗核上,Linux 核暂时够不着。

这说明两件事:

一是 ESP32-S31 的硬件确实扛得住 Linux,

二是驱动和外设适配才是后面最磨人的部分。内核能启动,只是第一关。

这篇文章先写到这。

乐鑫还是有点东西,我挺期待他们把 Wi-Fi 驱动补齐的那天。

到那时候,可能很多以前得用 A 系列芯片干的活,一颗几块钱的 ESP32 就能接了。

那画面,想想挺爽,全志,瑞芯微的不知道会不会发抖,,。

---

参考:


原文地址:https://mp.weixin.qq.com/s/AGv0u_onAEG6P77Jw-k6qw