物联网网关的老问题

做过物联网网关的开发者都知道一个痛点:一个网关里塞了好几颗芯片。Wi-Fi用一颗ESP32,Zigbee挂一个CC2530,以太网再外挂一个W5500,蓝牙音频可能还得加一颗。PCB面积大、BOM成本高、多芯片之间的数据搬运全靠串口或SPI,延迟和功耗都降不下来。2026年3月,乐鑫发布了ESP32-S31。这颗芯片把Wi-Fi 6、蓝牙5.4(含经典蓝牙)、Thread/Zigbee/Matter和千兆以太网MAC全塞进了一颗QFN80封装的MCU里。我们团队在沧州虎王科技做过不少ESP32网关项目,看到S31的规格书时第一反应是:以前的很多多芯片方案,可能真的要过时了。这篇文章不念参数表,聊聊从网关设计角度,S31到底改变了什么,以及实际落地时要注意什么。## S31的核心能力速览先把跟网关设计直接相关的几个能力列出来:| 能力 | 规格 | 网关意义 ||—|—|—|| CPU | 双核RISC-V 320MHz | 协议栈并行运行不卡 || Wi-Fi | Wi-Fi 6 (2.4GHz) | OFDMA多设备不拥堵 || 蓝牙 | BT 5.4 LE + BR/EDR | 能对接传统蓝牙设备 || 802.15.4 | Thread/Zigbee/Matter | 单芯片全协议网关 || 以太网 | 千兆MAC | 工业有线回传 || GPIO | 60个 | 不用IO扩展芯片 || PSRAM | 封装内16/32MB DDR | 多连接缓冲不溢出 || USB | 2.0高速480Mbps | 调试和U盘存储 |重点说三个:千兆以太网MAC、802.15.4全协议、Wi-Fi 6的TWT。千兆以太网MAC是ESP32系列头一回集成。以前做工业网关,有线回传得外挂W5500或LAN8720,最高只到100Mbps。S31原生支持千兆,配合外部PHY就能跑,板面积和成本都省了。802.15.4意味着Thread、Zigbee 3.0和Matter协议都能在一颗芯片上跑。以前做Matter网关,通常需要一颗Wi-Fi芯片加一颗802.15.4射频芯片,两颗芯片之间通过UART或SPI通信。现在S31单芯片就能完成"Wi-Fi回传 + Matter转发",这是Matter生态里BOM成本最低的方案之一。Wi-Fi 6的TWT(Target Wake Time)对电池供电的传感器节点特别有用。传统Wi-Fi设备保持连接时射频模块得持续监听信标帧,功耗在毫安级。TWT让设备和路由器协商好"什么时候醒",其余时间深度睡眠,联网待机功耗能压到微安级。## 传统方案 vs 单芯片方案拿我们团队做过的一个智慧工厂项目举例。原来的网关架构:- ESP32(Wi-Fi回传 + MQTT上报)- MAX485 + 外挂串口转Modbus TCP- CC2530(Zigbee采集)- W5500(以太网备链路)四颗主要芯片,PCB是四层板,BOM成本在80元左右。多芯片之间的数据通过ESP32的UART和SPI汇总,串口带宽成了瓶颈,Modbus轮询30个设备时要2秒以上。如果换成S31单芯片方案:- S31直接跑Wi-Fi 6 + 千兆以太网双链路- 802.15.4跑Zigbee,和Wi-Fi共享同一颗芯片- Modbus RTU走S31的UART,TCP走片上协议栈- 外挂一颗RS485收发器即可BOM降到30元出头(S31芯片+外围),PCB可以做到两层板,Modbus轮询延迟降一半以上,因为数据不再经过多芯片间的串口搬运。当然这是理论推演,实际项目还要考虑S31生态成熟度的问题,后面会说。## 多协议并行架构怎么设计S31最吸引人的是"同时"跑多种协议。但"同时"不意味着没有资源竞争,架构设计上要注意几点。### 协议栈的CPU亲和性S31是双核,建议按以下方式分配:c// Core 0: Wi-Fi + BLE + 网络协议栈// Core 1: 802.15.4 + 应用逻辑 + Modbus轮询//// FreeRTOS任务绑定核心示例void app_main(void) { // Wi-Fi和TCP/IP协议栈默认跑在Core 0 // 不需要手动绑定 // 802.15.4/Matter任务绑定到Core 1 xTaskCreatePinnedToCore( zigbee_task, "zigbee", 8192, NULL, 5, NULL, 1); // Modbus轮询也放Core 1 xTaskCreatePinnedToCore( modbus_poll_task, "modbus", 4096, NULL, 4, NULL, 1); // 应用主任务在Core 0 xTaskCreatePinnedToCore( app_main_task, "app", 8192, NULL, 3, NULL, 0);}Wi-Fi和蓝牙控制器固件默认在Core 0运行,网络协议栈也在Core 0。把802.15.4和业务逻辑放Core 1,减少和Wi-Fi中断的竞争。### 内存分配策略多协议并行时,连接缓冲区是内存大户。S31有16/32MB封装内PSRAM,但SRAM只有512KB。高频访问的数据放SRAM,大块数据缓冲放PSRAM:c// 高频访问的控制结构体放内部SRAM// 通过MALLOC_CAP_INTERNAL确保分配到片内modbus_ctx_t *ctx = heap_caps_malloc( sizeof(modbus_ctx_t), MALLOC_CAP_INTERNAL);// 大块接收缓冲放PSRAM// MALLOC_CAP_SPIRAM分配到外部PSRAMuint8_t *rx_buf = heap_caps_malloc( 4096, MALLOC_CAP_SPIRAM);### 802.15.4和Wi-Fi共存S31的Wi-Fi和802.15.4都工作在2.4GHz频段,虽然有硬件级的共存管理,但在Wi-Fi大数据传输时,Zigbee信道仍可能被挤压。实际测试中,Wi-Fi持续高吞吐时Zigbee丢包率会上升。缓解办法是在Zigbee设备密集的场景下,把Wi-Fi回传放到5GHz路由器的2.4GHz兼容模式之外(如果有的话),或者在应用层做Zigbee重传机制。Matter over Thread协议本身有重传设计,问题相对小一些。## 千兆以太网实战要点千兆以太网MAC是S31在网关场景的核心卖点之一。实际使用时注意几点。PHY选型方面,S31提供的是MAC层,需要外部PHY芯片完成物理层。千兆PHY常用RTL8211或类似芯片,通过RGMII接口连接。Function-CoreBoard-1开发板已经板载了PHY和RJ45,可以直接参考其原理图。引脚占用方面,RGMII接口要占掉13个左右的GPIO。如果同时还要用DVP摄像头和24位RGB LCD,引脚会非常紧张。网关场景一般不需要摄像头和屏,问题不大。ESP-IDF配置如下:bash# menuconfig中配置以太网# Ethernet → MAC type: ESP32-S31 EMAC# Ethernet → PHY address: 查看原理图(通常为0或1)# Ethernet → PHY reset GPIO: 查看原理图# Ethertype → RGMII TX/RX delay: 按PHY datasheet调实测带宽方面,千兆MAC的理论峰值是1000Mbps,实际在ESP32-S31上能跑到多少取决于CPU处理能力。我们的测试中,TCP吞吐在200-400Mbps区间,UDP稍高。对于物联网网关来说已经绰绰有余,以前100Mbps的W5500已经是行业标配了。## 开发环境搭建S31目前只支持ESP-IDF的master分支,而且是preview状态。这意味着Arduino暂时不能用,必须走ESP-IDF。bash# 克隆master分支git clone --recursive https://github.com/espressif/esp-idf.gitcd esp-idf./install.sh. ./export.sh# 新建项目,注意--preview参数idf.py create-project s31_gateway && cd s31_gatewayidf.py --preview set-target esp32s31# 配置组件依赖idf.py add-dependency "espressif/esp_zigbee"idf.py add-dependency "espressif/esp_modbus"# 编译烧录idf.py buildidf.py flash monitor三个容易踩的坑:1. 忘了加--previewset-target直接报unknown target2. 用了release/v5.x分支,里面没有esp32s31目标3. master分支更新频繁,pull之后要重新跑install.sh同步工具链## Wi-Fi 6与千兆以太网双链路代码网关场景经常需要双链路冗余,Wi-Fi做主链路,以太网做备份。S31可以同时激活两个网络接口,通过FreeRTOS事件组管理链路状态:c#include "freertos/FreeRTOS.h"#include "freertos/event_groups.h"#include "esp_wifi.h"#include "esp_eth.h"#include "esp_netif.h"#define LINK_WIFI_OK (1 << 0)#define LINK_ETH_OK (1 << 1)#define LINK_ALL_OK (LINK_WIFI_OK | LINK_ETH_OK)static EventGroupHandle_t s_link_event;// Wi-Fi事件回调static void wifi_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) { if (id == WIFI_EVENT_STA_CONNECTED) { xEventGroupSetBits(s_link_event, LINK_WIFI_OK); } else if (id == WIFI_EVENT_STA_DISCONNECTED) { xEventGroupClearBits(s_link_event, LINK_WIFI_OK); esp_wifi_connect(); // 自动重连 }}// 以太网事件回调static void eth_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) { if (id == ETHERNET_EVENT_CONNECTED) { xEventGroupSetBits(s_link_event, LINK_ETH_OK); } else if (id == ETHERNET_EVENT_DISCONNECTED) { xEventGroupClearBits(s_link_event, LINK_ETH_OK); }}void app_main(void) { s_link_event = xEventGroupCreate(); // 初始化TCP/IP协议栈 ESP_ERROR_CHECK(esp_netif_init()); // 创建默认事件循环 esp_event_loop_create_default(); // 创建Wi-Fi和以太网netif esp_netif_create_default_wifi_sta(); esp_netif_config_t eth_cfg = ESP_NETIF_DEFAULT_ETH(); esp_netif_t *eth_netif = esp_netif_new(&eth_cfg); // 初始化Wi-Fi wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&cfg); esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL); esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL); // 配置Wi-Fi 6 wifi_config_t wifi_cfg = { .sta = { .ssid = "factory_ap", .password = "your_password", }, }; esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg); esp_wifi_start(); // 初始化以太网(千兆MAC + 外部PHY) eth_mac_config_t mac_cfg = ETH_MAC_DEFAULT_CONFIG(); eth_esp32_emac_config_t esp32_emac_cfg = ETH_ESP32_EMAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_cfg, &esp32_emac_cfg); eth_phy_config_t phy_cfg = ETH_PHY_DEFAULT_CONFIG(); esp_eth_phy_t *phy = esp_eth_phy_new_rtl8211(&phy_cfg); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle; esp_eth_driver_install(&eth_config, &eth_handle); esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL); esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); esp_eth_start(eth_handle); // 主循环:监控双链路状态 while (1) { EventBits_t bits = xEventGroupWaitBits( s_link_event, LINK_ALL_OK, pdFALSE, pdFALSE, pdMS_TO_TICKS(1000)); if (bits & LINK_ETH_OK) { // 以太网优先,作为主链路 } else if (bits & LINK_WIFI_OK) { // 以太网断了,切Wi-Fi } else { // 两个都断了,触发告警 } }}这段代码实现了双链路冗余的基本框架。实际项目中还需要加MQTT断线重连、数据缓冲重发等逻辑。## 从虎王科技的实践看S31落地我们在沧州虎王科技过去三年做了不少ESP32网关项目,包括Modbus网关、LoRaWAN网关、多协议协议网关。之前用ESP32做协议网关时,最大的限制是"一颗芯片跑不了所有协议",所以不得不做多芯片拼接。S31解决的核心问题是"单芯片全协议"。以前我们的ESP32协议网关需要外挂Zigbee模块、外挂以太网芯片,现在理论上一颗S31就能搞定。在我们开源的ESP32工具箱(heicat.com上有介绍)中,固件烧录和串口调试的硬件调试能力已经能直接支持S31的烧录和配置。但也要说实话:S31现在处于生态早期,ESP-IDF的S31支持还在master分支preview阶段,Arduino不支持,社区项目稀少。如果你的项目要赶工期、需要大量参考代码,S3目前仍然是更安全的选择。S31更适合新立项的产品和想抢生态先发的团队。## 选型建议| 场景 | 推荐 | 原因 ||—|—|—|| 复刻开源项目学习 | S3 | 生态成熟,教程多 || 新立项Matter网关 | S31 | 单芯片全协议 || 工业有线网关 | S31 | 千兆以太网MAC || 蓝牙音频设备 | S31 | 支持经典蓝牙BR/EDR || 视频流/摄像头 | S31 | 硬件JPEG+大PSRAM || 低成本传感器节点 | C3/C6 | 性价比高 |S31不是万能的,但在网关这个场景下,它确实是ESP32系列里第一次"一颗芯片够用"的选择。以前我们做网关设计花在多芯片互联上的时间,现在可以花在业务逻辑上。## 写在最后ESP32-S3用了五年时间证明了平价芯片加开源社区能做出什么样的产品。S31把Wi-Fi 6、全协议连接、千兆以太网和企业级安全一次性摆上了牌桌。对于做物联网网关的工程师来说,这颗芯片值得认真评估。不过现在还是早期阶段。官方文档在完善中,社区项目刚起步。第一批在S31上做出开源网关方案的团队,有机会定义这个生态的玩法。我们虎王科技会持续跟进S31的实际项目落地,后续会分享更多实战经验。ESP32工具箱已支持S31烧录调试,欢迎到heicat.com了解更多。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐