这类现象在 ESP32/ESP32-S3 上很常见:只要固件里"启用过 BLE(NimBLE/Controller)",哪怕你在 OTA 前调用了 exit,HTTP OTA 仍可能明显变慢。通常是下面两类原因叠加造成的(你对比"直接注释蓝牙功能的固件"更快,这个对比非常关键)。
1)根因 A:BLE 让 Wi-Fi 走"共存"时隙,吞吐必然掉
Wi-Fi 和 BLE 共用同一个 2.4G 射频前端,打开 BLE 后会进入 RF coexist(时分复用)。
尤其当 BLE 在扫描/连接/较短 interval 广播时,会频繁抢占射频,Wi-Fi 可用 airtime 下降,HTTP 下载速度就会掉。
但你说"已经 exit 了还慢",这说明 不止是射频时隙,还有根因 B。
2)根因 B:即使 BLE "退出",Controller 预留内存/任务/共存状态没彻底释放
很多项目里 nimble_port_deinit() + esp_bt_controller_deinit() 之后,BT controller 的内存并不会自动回收到 heap ,而"未启用蓝牙的固件"天然没有这部分常驻占用,所以 OTA 的 lwIP / TCP / esp_http_client 可用的 内部内存更大、更连续,吞吐更高。
你截图里的 hal_eb_ble_exit() 里虽然做了 stop/deinit/controller_disable/deinit,但缺少最关键的一步:mem_release(以及某些 IDF 版本推荐的 controller deinit API)。
✅建议你按下面做(优先级从高到低)
✅1)在 OTA 前彻底关闭 BLE,并释放 BT Controller 内存(最关键)
把 exit 做成"完整关停 + 释放内存"的版本(注意顺序):
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_log.h"
void hal_eb_ble_exit_for_ota(void)
{
// 1) 先停止所有 BLE 行为(广告/扫描/连接)
// 视你的代码情况调用:ble_gap_adv_stop(), ble_gap_disc_cancel(), 断开连接等
// 2) 停 NimBLE host task
nimble_port_stop();
vTaskDelay(pdMS_TO_TICKS(200));
nimble_port_deinit();
// 3) 关 controller(不同 IDF 可能有更推荐的 API)
esp_bt_controller_disable();
esp_bt_controller_deinit();
// 4) ★释放 controller 占用的内存给系统(没有这步,和"注释蓝牙"差距会很大)
esp_err_t err = esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
ESP_LOGI("BLE", "mem_release BLE ret=%d", err);
// 如果你工程里从来不用经典蓝牙,也可以在启动时就释放 CLASSIC 内存:
// esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
}
你现在测到"编译时注释 BLE 更快",极大概率就是因为这一块 controller 常驻内存没回收,导致 OTA 期间 lwIP/TLS/HTTP 缓冲不足、碎片化更严重。
验证方法:在 OTA 开始前后打印内部 heap 和最大连续块:
ESP_LOGI("MEM", "internal free=%u, largest=%u",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
如果加了 mem_release() 后这两个数明显上涨,基本就坐实了。
✅2)如果 OTA 时仍需要 BLE 常开:降低 BLE 对 Wi-Fi 的"射频打扰"
如果你的业务要求 BLE 不能完全关(比如给小程序持续广播),那就只能"让 BLE 更温柔":
-
停止扫描(scan 对 coexist 影响最大)
-
广播间隔拉大(比如 100ms→500ms/1000ms)
-
若连接态:conn interval 拉大(如 30ms→60~120ms),并减少 notify 频率
-
OTA 期间直接 暂停 notify/广播,OTA 完再恢复(最有效)
✅3)把 NimBLE host task 放到另外一个核/降低优先级(减少 CPU 抢占)
Wi-Fi/LwIP 在某些场景对 CPU 调度很敏感。nimble_port_freertos_init() 默认创建 host task,你可以:
-
把 BLE host task pin 到 core1(Wi-Fi 通常在 core0 更重)
-
降低 BLE host task priority(不要高过 tcpip、http、ota 相关任务)
(不同 IDF/NimBLE glue 方式不一样,你当前是 nimble_port_freertos_init(ble_host_task),如果你的 ble_host_task 是自己创建的任务,可在创建时 pin/priority。)
✅4)Wi-Fi 侧配置:关省电、提高吞吐稳定性
在 menuconfig 或运行时确保:
-
Wi-Fi power save 关闭(modem sleep 会让吞吐更抖)
esp_wifi_set_ps(WIFI_PS_NONE);
-
信号弱时 BLE coexist 更明显:尽量在 OTA 时保证 RSSI 好一点(>-60dBm)
一句话结论
你现在"exit 了还慢",最像的是:蓝牙 controller 内存没有释放(mem_release 缺失) + coexist 机制/任务调度带来的残余影响 。
先把 esp_bt_controller_mem_release(ESP_BT_MODE_BLE) 加上再测,通常就能把"和注释蓝牙固件的差距"拉回去一大截。
如果你愿意,把你 OTA 开始前后打印的:
-
internal free / largest block
-
OTA 下载速度(KB/s)
-
你 BLE 是否处于扫描/连接/仅广播(以及 interval)