ESP8266连接AWS MQTT服务器崩溃问题排查求助
问题
在Arduino IDE中开发ESP8266项目,使用PubSubClient库连接AWS MQTT服务器。执行pubsubClient.connect(config.mqtt.id, config.mqtt.username, config.mqtt.password)后设备崩溃,崩溃日志如下:
:ref 1 _iobuf_in: 0x3fff5ebc _iobuf_out: 0x3fff3f94 _iobuf_in_size: 16709 _iobuf_out_size: 597 --------------- CUT HERE FOR EXCEPTION DECODER --------------- Exception (28): epc1=0x4021f88f epc2=0x00000000 epc3=0x00000000 excvaddr=0x00003a98 depc=0x00000000 >>>stack>>> ctx: cont sp: 3fff0bc0 end: 3fff0fd0 offset: 0150 3fff0d10: 00000000 2c9f0300 4000050c 3fffc278 3fff0d20: 00000000 00000000 00000022 40234a30 ...
已设置最高日志级别开启调试,但调试串口未捕获到额外信息。Exception decoder解码结果如下:
Exception 9: LoadStoreAlignmentCause: Load or store to an unaligned address PC: 0x4024232d: br_x509_minimal_run at src/x509\x509_minimal.c:1203 EXCVADDR: 0x0000252d Decoding stack results 0x4023cdb4: br_ssl_hs_client_run at src/ssl\ssl_hs_client.c:1877 0x4023af50: jump_handshake at src\inner.h:2211 0x4023b33d: br_ssl_engine_sendrec_ack at src/ssl\ssl_engine.c:1168 0x4021552e: is in BearSSL::WiFiClientSecureCtx::_run_until(unsigned int, bool) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\src\WiFiClientSecureBearSSL.cpp:586). 0x4023af50: jump_handshake at src\inner.h:2211 0x4023c0a8: br_ssl_hs_client_run at src/ssl\ssl_hs_client.c:960 0x40215588: BearSSL::WiFiClientSecureCtx::_wait_for_handshake() at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\src\WiFiClientSecureBearSSL.cpp:609 0x4021585b: is in BearSSL::WiFiClientSecureCtx::_connectSSL(char const*) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\src\WiFiClientSecureBearSSL.cpp:1194). 0x40101218: umm_malloc(size_t) at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:912 0x402354e8: ip4_output_if_opt at core/ipv4\ip4.c:1572 0x4022cd75: mem_malloc at core\mem.c:210 0x4023550e: ip4_output_if at core/ipv4\ip4.c:1549 0x40236467: ip_chksum_pseudo at core\inet_chksum.c:392 0x4021d70c: __esp_suspend() at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_features.h:64 0x4021d85d: is in __esp_delay(unsigned long) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:161). 0x4021d8d2: is in esp_try_delay(unsigned int, unsigned int, unsigned int) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:182). 0x4021d8d2: is in esp_try_delay(unsigned int, unsigned int, unsigned int) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:182). 0x40214306: is in WiFiClient::connect(IPAddress, unsigned short) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266/coredecls.h:69). 0x402354b2: ip4_output_if_src at core/ipv4\ip4.c:1589 0x4021593b: is in BearSSL::WiFiClientSecureCtx::connect(char const*, unsigned short) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\src\WiFiClientSecureBearSSL.cpp:228). 0x40218a84: is in PubSubClient::connect(char const*, char const*, char const*, char const*, unsigned char, bool, char const*, bool) (c:\ArduinoTest\libraries\PubSubClient\src\PubSubClient.cpp:196). 0x40231bd8: udp_sendto_if at core\udp.c:692 0x4021d7ba: __yield() at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_features.h:64 0x40218c6c: is in PubSubClient::connect(char const*, char const*, char const*) (c:\ArduinoTest\libraries\PubSubClient\src\PubSubClient.cpp:170). 0x40206ef1: is in sendMQTT(unsigned long, String, String) (C:\ArduinoTest\vtsistema/vtsistema.ino:172). 0x4021c375: is in String::copy(char const*, unsigned int) (C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\WString.cpp:274). 0x402084ff: loop() at C:\ArduinoTest\vtsistema\vtsistema.ino:599 0x402177c0: fs::FS::_defaultTimeCB() at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\FS.h:260 0x401011d6: umm_free(void*) at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:688 0x402177c0: fs::FS::_defaultTimeCB() at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\FS.h:260 0x4021d944: loop_wrapper() at C:\Users\g\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:258
排查步骤
从解码日志看,崩溃是Exception 9: LoadStoreAlignmentCause(加载/存储未对齐地址),发生在BearSSL的x509证书解析阶段,按以下步骤排查:
检查证书/密钥的格式与内存对齐
- AWS MQTT连接需要根CA证书、设备证书和私钥,确保这些文件内容无格式错误,比如多余空格、换行,或复制时遗漏
-----BEGIN CERTIFICATE-----/-----END CERTIFICATE-----头尾部。 - 避免直接将证书内容作为字符串常量硬编码,尤其是字符串长度非4的倍数时,易引发内存未对齐。建议用
PROGMEM存储证书,或把证书文件放入SPIFFS读取,保证内存地址对齐。
- AWS MQTT连接需要根CA证书、设备证书和私钥,确保这些文件内容无格式错误,比如多余空格、换行,或复制时遗漏
升级ESP8266核心库版本
当前使用的ESP8266核心版本为3.1.2,该版本的BearSSL实现可能存在未对齐内存访问的bug。升级到最新稳定版(如3.1.3及以上),新版本通常会修复这类底层内存问题。检查PubSubClient与WiFiClientSecure的配置
- 确保PubSubClient使用
WiFiClientSecure实例而非普通WiFiClient,AWS MQTT要求SSL/TLS连接。 - 手动设置WiFiClientSecure的CA证书,不要依赖自动加载:
WiFiClientSecure espClient; void setup() { // 加载根CA证书 espClient.setCACert(rootCA); PubSubClient client(espClient); client.setServer(MQTT_SERVER, 8883); } - 验证MQTT连接参数:clientId、username、password是否正确,AWS IoT的username通常为空,password是签名后的令牌,不要传入错误格式的字符串。
- 确保PubSubClient使用
排查内存分配问题
日志中出现umm_malloc/umm_free调用,说明可能存在内存碎片化或分配失败:- 减少全局变量使用,尤其是大字符串(如证书)。
- 连接MQTT前,调用
ESP.getFreeHeap()打印剩余内存,若剩余内存不足5KB,可能导致内存分配错误,进而引发未对齐访问。 - 避免频繁创建String对象,改用
char[]数组,减少内存碎片。
测试最小化连接代码
编写仅包含WiFi连接、MQTT连接的最小测试程序,排除其他代码干扰:#include <ESP8266WiFi.h> #include <PubSubClient.h> const char* ssid = "YOUR_SSID"; const char* password = "YOUR_WIFI_PASS"; const char* mqttServer = "AWS_MQTT_ENDPOINT"; const int mqttPort = 8883; const char* mqttClientId = "YOUR_CLIENT_ID"; const char* mqttUsername = ""; // AWS IoT通常留空 const char* mqttPassword = "YOUR_SIGNED_TOKEN"; const char* rootCA = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"; WiFiClientSecure espClient; PubSubClient client(espClient); void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("WiFi connected"); espClient.setCACert(rootCA); client.setServer(mqttServer, mqttPort); if (client.connect(mqttClientId, mqttUsername, mqttPassword)) { Serial.println("MQTT connected"); } else { Serial.print("MQTT connect failed, rc="); Serial.println(client.state()); } } void loop() { client.loop(); }如果这个最小程序能正常连接,说明问题出在原项目的其他代码中,逐步添加原代码模块排查。
检查编译器优化选项
Arduino IDE中,ESP8266的编译器优化等级如果设置过高(如-O2),可能导致内存对齐问题。尝试将优化等级改为“-Os”(默认)或“-O1”,可在IDE的编译选项菜单调整,或修改ESP8266核心的platform.txt文件。
内容的提问来源于stack exchange,提问作者vico

