diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index ca70127565f..b1d7f815822 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -848,6 +848,9 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) endif SDKCONFIGS := esp-idf-config/sdkconfig.defaults;$(DEBUG_SDKCONFIG);$(FLASH_SIZE_SDKCONFIG);$(FLASH_MODE_SDKCONFIG);$(FLASH_SPEED_SDKCONFIG);$(PSRAM_SDKCONFIG);$(PSRAM_SIZE_SDKCONFIG);$(PSRAM_MODE_SDKCONFIG);$(PSRAM_SPEED_SDKCONFIG);$(BLE_SDKCONFIG);$(TARGET_SDKCONFIG);boards/$(BOARD)/sdkconfig +ifneq ($(EXTRA_SDKCONFIG),) # CP-WIFI-DEBUG + SDKCONFIGS := $(SDKCONFIGS);$(EXTRA_SDKCONFIG) +endif # create the config headers .PHONY: do-sdkconfig diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index eb3b57174a3..2d4099d4eed 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -19,6 +19,10 @@ #include "esp_now.h" #include "mphalport.h" +#include "esp_wifi.h" /* CP-WIFI-DEBUG */ +#include "esp_log.h" /* CP-WIFI-DEBUG */ +#include "esp_heap_caps.h" /* CP-WIFI-DEBUG */ +static const char *TAG = "CP espnow"; /* CP-WIFI-DEBUG */ #include "esp_now.h" @@ -120,7 +124,18 @@ void common_hal_espnow_init(espnow_obj_t *self) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); } - CHECK_ESP_RESULT(esp_now_init()); + { /* CP-WIFI-DEBUG */ + wifi_mode_t m = 0; uint8_t ch = 0; wifi_second_chan_t sc = 0; + esp_wifi_get_mode(&m); esp_wifi_get_channel(&ch, &sc); + ESP_LOGW(TAG, "esp_now_init: before mode=%d ch=%d/%d", m, ch, sc); + } + esp_err_t now_res = esp_now_init(); + { + wifi_mode_t m = 0; uint8_t ch = 0; wifi_second_chan_t sc = 0; + esp_wifi_get_mode(&m); esp_wifi_get_channel(&ch, &sc); + ESP_LOGW(TAG, "esp_now_init -> 0x%x: after mode=%d ch=%d/%d", now_res, m, ch, sc); + } + CHECK_ESP_RESULT(now_res); // esp_now_set_peer_rate_config() is poorly documented, and we haven't figured out // what the esp_now_rate_config_t settings should be. For now, just ignore phy_rate. @@ -178,6 +193,10 @@ mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const mp_buffer_info_t *mess (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { RUN_BACKGROUND_TASKS; } + { /* CP-WIFI-DEBUG */ + ESP_LOGW(TAG, "esp_now_send len=%u -> 0x%x (waited %lu ms) idf_free=%u largest=%u internal_free=%u", (unsigned)message->len, err, (unsigned long)(mp_hal_ticks_ms() - start), + (unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT), (unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT), (unsigned)heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + } CHECK_ESP_RESULT(err); return mp_const_none; diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index 51d4913926f..2752f1f994d 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -25,6 +25,8 @@ #include "components/esp_netif/include/esp_netif_net_stack.h" #include "components/esp_wifi/include/esp_wifi.h" +#include "components/log/include/esp_log.h" /* CP-WIFI-DEBUG */ +static const char *TAG = "CP wifi"; /* CP-WIFI-DEBUG */ #include "components/lwip/include/apps/ping/ping_sock.h" #include "lwip/sockets.h" @@ -269,7 +271,13 @@ void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_ config->ap.max_connection = max_connections; - esp_wifi_set_config(WIFI_IF_AP, config); + esp_err_t cfg_res = esp_wifi_set_config(WIFI_IF_AP, config); /* CP-WIFI-DEBUG */ + { + wifi_mode_t m = 0; uint8_t ch = 0; wifi_second_chan_t sc = 0; + esp_wifi_get_mode(&m); esp_wifi_get_channel(&ch, &sc); + ESP_LOGW(TAG, "start_ap ssid='%s' req_ch=%d auth=%d maxconn=%d -> set_config=0x%x mode=%d cur_ch=%d/%d", + (char *)config->ap.ssid, channel, esp_authmode, max_connections, cfg_res, m, ch, sc); + } // Wait a few ms for the AP to start. Empirically, this takes < 3ms on ESP32, and < 1ms on other chips. for (size_t ms = 0; ms < 10; ms++) { if (common_hal_wifi_radio_get_ap_active(self)) { @@ -277,6 +285,7 @@ void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_ } mp_hal_delay_ms(1); } + ESP_LOGW(TAG, "start_ap done: ap_active=%d netif_up=%d", common_hal_wifi_radio_get_ap_active(self), esp_netif_is_netif_up(self->ap_netif)); /* CP-WIFI-DEBUG */ } bool common_hal_wifi_radio_get_ap_active(wifi_radio_obj_t *self) { @@ -614,11 +623,14 @@ void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) { } void common_hal_wifi_radio_start_dhcp_server(wifi_radio_obj_t *self) { - esp_netif_dhcps_start(self->ap_netif); + esp_err_t r = esp_netif_dhcps_start(self->ap_netif); /* CP-WIFI-DEBUG */ + esp_netif_dhcp_status_t st = 0; esp_netif_dhcps_get_status(self->ap_netif, &st); + ESP_LOGW(TAG, "dhcps_start -> 0x%x status=%d", r, st); } void common_hal_wifi_radio_stop_dhcp_server(wifi_radio_obj_t *self) { - esp_netif_dhcps_stop(self->ap_netif); + esp_err_t r = esp_netif_dhcps_stop(self->ap_netif); /* CP-WIFI-DEBUG */ + ESP_LOGW(TAG, "dhcps_stop -> 0x%x", r); } void common_hal_wifi_radio_set_ipv4_address(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway, mp_obj_t ipv4_dns) { diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 7a9aea3b5e0..c0faef87bc2 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -24,6 +24,7 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "components/log/include/esp_log.h" +#include "esp_mac.h" /* CP-WIFI-DEBUG */ #include "supervisor/port.h" #include "supervisor/workflow.h" @@ -75,10 +76,16 @@ static void event_handler(void *arg, esp_event_base_t event_base, case WIFI_EVENT_AP_STOP: ESP_LOGW(TAG, "ap stop"); break; - case WIFI_EVENT_AP_STACONNECTED: + case WIFI_EVENT_AP_STACONNECTED: { /* CP-WIFI-DEBUG */ + wifi_event_ap_staconnected_t *e = (wifi_event_ap_staconnected_t *)event_data; + ESP_LOGW(TAG, "ap sta connected " MACSTR " aid=%d idf_free=%u largest=%u", MAC2STR(e->mac), e->aid, (unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT), (unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); break; - case WIFI_EVENT_AP_STADISCONNECTED: + } + case WIFI_EVENT_AP_STADISCONNECTED: { /* CP-WIFI-DEBUG */ + wifi_event_ap_stadisconnected_t *e = (wifi_event_ap_stadisconnected_t *)event_data; + ESP_LOGW(TAG, "ap sta disconnected " MACSTR " aid=%d reason=%d", MAC2STR(e->mac), e->aid, e->reason); break; + } case WIFI_EVENT_STA_START: ESP_LOGW(TAG, "sta start"); break; diff --git a/ports/espressif/esp-idf-config/partitions-8MB-no-ota-no-uf2.csv b/ports/espressif/esp-idf-config/partitions-8MB-no-ota-no-uf2.csv new file mode 100644 index 00000000000..32a9aa50e27 --- /dev/null +++ b/ports/espressif/esp-idf-config/partitions-8MB-no-ota-no-uf2.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size +# bootloader, app, boot, 0x1000/0x0, 28/32K +# partition_table, data, table, 0x8000, 4K +nvs, data, nvs, 0x9000, 20K +otadata, data, ota, 0xe000, 8K +ota_0, app, ota_0, 0x10000, 4032K +user_fs, data, fat, 0x400000, 4096K diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-8MB-no-ota-no-uf2.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-8MB-no-ota-no-uf2.defaults new file mode 100644 index 00000000000..8424fe275c3 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-8MB-no-ota-no-uf2.defaults @@ -0,0 +1,4 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="8MB" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-8MB-no-ota-no-uf2.csv" +CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-8MB-no-ota-no-uf2.csv" diff --git a/ports/espressif/esp-idf-config/sdkconfig-wifidebug-opt.defaults b/ports/espressif/esp-idf-config/sdkconfig-wifidebug-opt.defaults new file mode 100755 index 00000000000..635ff110e33 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-wifidebug-opt.defaults @@ -0,0 +1,17 @@ +# +# CP-WIFI-DEBUG (release-optimised variant): keep the opt build's RAM/flash profile but +# route ESP_LOGW/ESP_LOGE + DHCPS_DEBUG printf to the UART0 console (devkit UART bridge). +# Use with: make BOARD=... EXTRA_SDKCONFIG=esp-idf-config/sdkconfig-wifidebug-opt.defaults +# +# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +CONFIG_ESP_CONSOLE_SECONDARY_NONE=y +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +CONFIG_LOG_DEFAULT_LEVEL_WARN=y +CONFIG_LOG_MAXIMUM_LEVEL_WARN=y +# TLS server: a 3.7KB Let's Encrypt chain must fit one outgoing handshake record +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=4096 +CONFIG_MBEDTLS_DYNAMIC_BUFFER=y +CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y +CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y diff --git a/ports/espressif/esp-idf-config/sdkconfig-wifidebug.defaults b/ports/espressif/esp-idf-config/sdkconfig-wifidebug.defaults new file mode 100644 index 00000000000..d23f7d7877e --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-wifidebug.defaults @@ -0,0 +1,9 @@ +# +# CP-WIFI-DEBUG: extra logging for softAP / DHCP / BLE coexistence investigation. +# Use with: make BOARD=... DEBUG=1 EXTRA_SDKCONFIG=esp-idf-config/sdkconfig-wifidebug.defaults +# +# (LWIP_DEBUG / LOG_MAXIMUM_LEVEL_DEBUG / dynamic log control overflow the C6's 2MB +# firmware partition by ~186KB -- DHCP server logging comes from DHCPS_DEBUG=1 instead) +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set +CONFIG_BT_NIMBLE_LOG_LEVEL_INFO=y diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 34cfba32b7e..317ed0683d0 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -32,6 +32,8 @@ #include "common-hal/watchdog/WatchDogTimer.h" #include "common-hal/socketpool/Socket.h" #include "common-hal/wifi/__init__.h" +#include "shared-bindings/wifi/__init__.h" +#include "shared-bindings/wifi/Radio.h" #include "supervisor/background_callback.h" #include "supervisor/shared/tick.h" #include "shared-bindings/microcontroller/__init__.h" @@ -50,6 +52,7 @@ #if CIRCUITPY_BLEIO_NATIVE #include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" #endif #if CIRCUITPY_ESPCAMERA @@ -342,9 +345,34 @@ void *port_realloc(void *ptr, size_t size, bool dma_capable) { return heap_caps_realloc(ptr, size, caps); } +// Headroom kept in the IDF heap when the Python heap grows while a radio is +// enabled. The wifi driver, lwIP and NimBLE allocate at runtime (TX buffers, +// station association, DHCP replies, ESP-NOW frames); without this the GC heap +// absorbs the whole system heap and those allocations fail silently +// (ESP_ERR_ESPNOW_NO_MEM, stations that associate and drop, hard faults). +#ifndef CIRCUITPY_ESP_RADIO_HEAP_RESERVE +#define CIRCUITPY_ESP_RADIO_HEAP_RESERVE (40 * 1024) +#endif + size_t port_heap_get_largest_free_size(void) { - size_t free_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); - return free_size; + size_t largest = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + size_t reserve = 0; + #if CIRCUITPY_WIFI + if (common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + reserve = CIRCUITPY_ESP_RADIO_HEAP_RESERVE; + } + #endif + #if CIRCUITPY_BLEIO_NATIVE + if (common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + reserve = CIRCUITPY_ESP_RADIO_HEAP_RESERVE; + } + #endif + if (reserve == 0) { + return largest; + } + size_t total = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t allowed = total > reserve ? total - reserve : 0; + return MIN(largest, allowed); } void reset_port_early(void) {