diff --git a/drivers/wifi/CMakeLists.txt b/drivers/wifi/CMakeLists.txt index 27775027b11..72c4d30b57b 100644 --- a/drivers/wifi/CMakeLists.txt +++ b/drivers/wifi/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory_ifdef(CONFIG_WIFI_WINC1500 winc1500) add_subdirectory_ifdef(CONFIG_WIFI_SIMPLELINK simplelink) add_subdirectory_ifdef(CONFIG_WIFI_ESWIFI eswifi) add_subdirectory_ifdef(CONFIG_WIFI_ESP esp) +add_subdirectory_ifdef(CONFIG_WIFI_ESP32 esp32) diff --git a/drivers/wifi/Kconfig b/drivers/wifi/Kconfig index 59cde5e827f..3f368922318 100644 --- a/drivers/wifi/Kconfig +++ b/drivers/wifi/Kconfig @@ -33,5 +33,6 @@ source "drivers/wifi/winc1500/Kconfig.winc1500" source "drivers/wifi/simplelink/Kconfig.simplelink" source "drivers/wifi/eswifi/Kconfig.eswifi" source "drivers/wifi/esp/Kconfig.esp" +source "drivers/wifi/esp32/Kconfig.esp32" endif # WIFI diff --git a/drivers/wifi/esp32/CMakeLists.txt b/drivers/wifi/esp32/CMakeLists.txt new file mode 100644 index 00000000000..ec9074698c6 --- /dev/null +++ b/drivers/wifi/esp32/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_WIFI_ESP32 + src/esp_wifi_drv.c + ) diff --git a/drivers/wifi/esp32/Kconfig.esp32 b/drivers/wifi/esp32/Kconfig.esp32 new file mode 100644 index 00000000000..b8503fb3063 --- /dev/null +++ b/drivers/wifi/esp32/Kconfig.esp32 @@ -0,0 +1,232 @@ +# Copyright 2020 Espressif Systems (Shanghai) PTE LTD + +menuconfig WIFI_ESP32 + bool "ESP32 SoC WiFi support" + select POSIX_API + select THREAD_CUSTOM_DATA + select DYNAMIC_INTERRUPTS + help + Enable ESP32 SoC WiFi support. + + Note: POSIX_API is required by Wifi library. It shall be removed + once NEWLIB gets supported. + +if WIFI_ESP32 + +config ESP32_WIFI_SSID + string "SSID of WiFi network" + help + SSID (network name) for the application to connect to. + +config ESP32_WIFI_PASSWORD + string "Password (WPA or WPA2) of WiFi network" + help + WiFi password (WPA or WPA2) for the example to use. + +config ESP32_WIFI_STA_AUTO + bool "Automatically connect to configured WiFi SSID" + help + WiFi driver will automatically connect to SSID. + +config ESP32_WIFI_STA_RECONNECT + bool "WiFi connection retry" + default y + help + Set auto WiFI reconnection when disconnected. + +config ESP32_WIFI_EVENT_TASK_STACK_SIZE + int "Event Task Stack Size" + default 4096 + +config ESP32_WIFI_EVENT_TASK_PRIO + int "Event Task Priority" + default 4 + +config ESP32_WIFI_STATIC_RX_BUFFER_NUM + int "Max number of WiFi static RX buffers" + range 2 25 + default 10 + help + Set the number of WiFi static RX buffers. Each buffer takes approximately + 1.6KB of RAM. The static rx buffers are allocated when esp_wifi_init is + called, they are not freed until esp_wifi_deinit is called. + + WiFi hardware use these buffers to receive all 802.11 frames. A higher + number may allow higher throughput but increases memory use. + If ESP32_WIFI_AMPDU_RX_ENABLED is enabled, this value is recommended to + set equal or bigger than ESP32_WIFI_RX_BA_WIN in order to achieve better + throughput and compatibility with both stations and APs. + +config ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM + int "Max number of WiFi dynamic RX buffers" + range 0 128 + default 32 + help + Set the number of WiFi dynamic RX buffers, 0 means unlimited RX buffers + will be allocated (provided sufficient free RAM). The size of each dynamic + RX buffer depends on the size of the received data frame. + + For each received data frame, the WiFi driver makes a copy to an RX buffer + and then delivers it to the high layer TCP/IP stack. The dynamic RX buffer + is freed after the higher layer has successfully received the data frame. + + For some applications, WiFi data frames may be received faster than the + application can process them. In these cases we may run out of memory if + RX buffer number is unlimited (0). If a dynamic RX buffer limit is set, + it should be at least the number of static RX buffers. + +choice ESP32_WIFI_TX_BUFFER + prompt "Type of WiFi TX buffers" + default ESP32_WIFI_DYNAMIC_TX_BUFFER + help + Select type of WiFi TX buffers: + + If "Static" is selected, WiFi TX buffers are allocated when WiFi is + initialized and released when WiFi is de-initialized. The size of each + static TX buffer is fixed to about 1.6KB. + + If "Dynamic" is selected, each WiFi TX buffer is allocated as needed + when a data frame is delivered to the Wifi driver from the TCP/IP stack. + The buffer is freed after the data frame has been sent by the WiFi driver. + The size of each dynamic TX buffer depends on the length of each data + frame sent by the TCP/IP layer. + + If PSRAM is enabled, "Static" should be selected to guarantee enough + WiFi TX buffers. If PSRAM is disabled, "Dynamic" should be selected + to improve the utilization of RAM. + + config ESP32_WIFI_STATIC_TX_BUFFER + bool "Static" + config ESP32_WIFI_DYNAMIC_TX_BUFFER + bool "Dynamic" +endchoice + +config ESP32_WIFI_TX_BUFFER_TYPE + int + default 0 if ESP32_WIFI_STATIC_TX_BUFFER + default 1 if ESP32_WIFI_DYNAMIC_TX_BUFFER + +config ESP32_WIFI_STATIC_TX_BUFFER_NUM + int "Max number of WiFi static TX buffers" + depends on ESP32_WIFI_STATIC_TX_BUFFER + range 1 64 + default 16 + help + Set the number of WiFi static TX buffers. Each buffer takes approximately + 1.6KB of RAM. The static RX buffers are allocated when esp_wifi_init() is + called, they are not released until esp_wifi_deinit() is called. + + For each transmitted data frame from the higher layer TCP/IP stack, + the WiFi driver makes a copy of it in a TX buffer. For some applications + especially UDP applications, the upper layer can deliver frames faster + than WiFi layer can transmit. + In these cases, we may run out of TX buffers. + +config ESP32_WIFI_CACHE_TX_BUFFER_NUM + int "Max number of WiFi cache TX buffers" + range 16 128 + default 32 + help + Set the number of WiFi cache TX buffer number. + + For each TX packet from uplayer, such as LWIP etc, WiFi driver needs to + allocate a static TX buffer and makes a copy of uplayer packet. If WiFi + driver fails to allocate the static TX buffer, it caches the uplayer + packets to a dedicated buffer queue, this option is used to configure the + size of the cached TX queue. + +config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM + int "Max number of WiFi dynamic TX buffers" + depends on ESP32_WIFI_DYNAMIC_TX_BUFFER + range 1 128 + default 32 + help + Set the number of WiFi dynamic TX buffers. The size of each + dynamic TXbuffer is not fixed, it depends on the size of each + transmitted data frame. + + For each transmitted frame from the higher layer TCP/IP stack, + the WiFi driver makes a copy of it in a TX buffer. For some applications, + especially UDP applications, the upper layer can deliver frames faster + than WiFi layer can transmit. In these cases, we may run out of TX + buffers. + +config ESP32_WIFI_CSI_ENABLED + bool "WiFi CSI(Channel State Information)" + help + Select this option to enable CSI(Channel State Information) feature. + CSI takes about CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM KB of RAM. + If CSI is not used, it is better to disable this feature in order + to save memory. + +config ESP32_WIFI_AMPDU_TX_ENABLED + bool "WiFi AMPDU TX" + default y + help + Select this option to enable AMPDU TX feature. It improves transmission + error checking and overall network performance with the cost of processing + speed. Helpful when the device is operating in crowded wireless area. + +config ESP32_WIFI_TX_BA_WIN + int "WiFi AMPDU TX BA window size" + depends on ESP32_WIFI_AMPDU_TX_ENABLED + range 2 32 + default 6 + help + Set the size of WiFi Block Ack TX window. Generally a bigger value means + higher throughput but more memory. Most of time we should NOT change the + default value unless special reason, e.g. test the maximum + UDP TX throughput with iperf etc. For iperf test in shieldbox, + the recommended value is 9~12. + +config ESP32_WIFI_AMPDU_RX_ENABLED + bool "WiFi AMPDU RX" + default y + help + Select this option to enable AMPDU RX feature. It improves transmission + error checking and overall network performance with the cost of processing + speed. Helpful when the device is operating in crowded wireless area. + +config ESP32_WIFI_RX_BA_WIN + int "WiFi AMPDU RX BA window size" + depends on ESP32_WIFI_AMPDU_RX_ENABLED + range 2 32 + default 6 + help + Set the size of WiFi Block Ack RX window. Generally a bigger value means + higher throughput and better compatibility but more memory. Most of time + we should NOT change the default value unless special reason, + e.g. test the maximum UDP RX throughput with iperf etc. For iperf test in + shieldbox, the recommended value is 9~12. If PSRAM is used and WiFi memory + is preferred to allocat in PSRAM first, the default and minimum value + should be 16 to achieve better throughput and compatibility with both + stations and APs. + +choice ESP32_WIFI_TASK_CORE_ID + prompt "WiFi Task Core ID" + default ESP32_WIFI_TASK_PINNED_TO_CORE_0 + help + Pinned WiFi task to core 0 (core 1 not supported yet) + + config ESP32_WIFI_TASK_PINNED_TO_CORE_0 + bool "Core 0" +endchoice + +config ESP32_PHY_MAX_WIFI_TX_POWER + int "Max WiFi TX power (dBm)" + range 10 20 + default 20 + help + Set maximum transmit power for WiFi radio. Actual transmit power for high + data rates may be lower than this setting. + +config ESP32_PHY_MAX_TX_POWER + int + default ESP32_PHY_MAX_WIFI_TX_POWER + +config ESP32_WIFI_SW_COEXIST_ENABLE + bool + help + Software controls WiFi/Bluetooth coexistence. Not supported yet. + +endif # WIFI_ESP32 diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c new file mode 100644 index 00000000000..85018e086ee --- /dev/null +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_wifi + +#include +LOG_MODULE_REGISTER(esp32_wifi, CONFIG_WIFI_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include "esp_networking_priv.h" +#include "esp_private/wifi.h" +#include "esp_event.h" +#include "esp_timer.h" +#include "esp_wifi_system.h" +#include "esp_wpa.h" + +#define DEV_DATA(dev) \ + ((struct esp32_wifi_runtime *)(dev)->data) + +/* use global iface pointer to support any ethernet driver */ +/* necessary for wifi callback functions */ +static struct net_if *esp32_wifi_iface; + +struct esp32_wifi_runtime { + struct net_if *iface; + uint8_t mac_addr[6]; + bool tx_err; + uint32_t tx_word; + int tx_pos; + uint8_t frame_buf[NET_ETH_MAX_FRAME_SIZE]; +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + struct net_stats_eth stats; +#endif +}; + +static int eth_esp32_send(const struct device *dev, struct net_pkt *pkt) +{ + const int pkt_len = net_pkt_get_len(pkt); + + /* Read the packet payload */ + if (net_pkt_read(pkt, DEV_DATA(dev)->frame_buf, pkt_len) < 0) { + return -EIO; + } + + /* Enqueue packet for transmission */ + esp_wifi_internal_tx(ESP_IF_WIFI_STA, (void *)DEV_DATA(dev)->frame_buf, pkt_len); + + LOG_DBG("pkt sent %p len %d", pkt, pkt_len); + + return 0; +} + +static esp_err_t eth_esp32_rx(void *buffer, uint16_t len, void *eb) +{ + struct net_pkt *pkt; + + if (esp32_wifi_iface == NULL) { + LOG_ERR("network interface unavailable"); + return ESP_FAIL; + } + + pkt = net_pkt_rx_alloc_with_buffer(esp32_wifi_iface, len, + AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_ERR("Failed to get net buffer"); + return ESP_FAIL; + } + + if (net_pkt_write(pkt, buffer, len) < 0) { + LOG_ERR("Failed to write pkt"); + goto pkt_unref; + } + + if (net_recv_data(esp32_wifi_iface, pkt) < 0) { + LOG_ERR("Failed to push received data"); + goto pkt_unref; + } + + esp_wifi_internal_free_rx_buffer(eb); + return ESP_OK; + +pkt_unref: + net_pkt_unref(pkt); + return ESP_FAIL; +} + +/* internally used by wifi hal layer */ +void esp_wifi_set_net_state(bool state) +{ + if (esp32_wifi_iface == NULL) { + LOG_ERR("network interface unavailable"); + return; + } + + if (state) { + net_if_up(esp32_wifi_iface); + } else { + net_if_down(esp32_wifi_iface); + } +} + +static void eth_esp32_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct esp32_wifi_runtime *dev_data = DEV_DATA(dev); + + dev_data->iface = iface; + esp32_wifi_iface = iface; + + /* Start interface when we are actually connected with WiFi network */ + net_if_flag_set(iface, NET_IF_NO_AUTO_START); + esp_read_mac(dev_data->mac_addr, ESP_MAC_WIFI_STA); + + /* Assign link local address. */ + net_if_set_link_addr(iface, + dev_data->mac_addr, 6, NET_LINK_ETHERNET); + + ethernet_init(iface); + + esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, eth_esp32_rx); +} + +#if defined(CONFIG_NET_STATISTICS_ETHERNET) +static struct net_stats_eth *eth_esp32_stats(const struct device *dev) +{ + return &(DEV_DATA(dev)->stats); +} +#endif + +static int eth_esp32_dev_init(const struct device *dev) +{ + esp_timer_init(); + esp_event_init(); + + wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); + esp_err_t ret = esp_wifi_init(&config); + + ret |= esp_supplicant_init(); + ret |= esp_wifi_start(); + + if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO)) { + wifi_config_t wifi_config = { + .sta = { + .ssid = CONFIG_ESP32_WIFI_SSID, + .password = CONFIG_ESP32_WIFI_PASSWORD, + }, + }; + + ret = esp_wifi_set_mode(WIFI_MODE_STA); + ret |= esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); + ret |= esp_wifi_connect(); + } + + if (ret != ESP_OK) { + LOG_ERR("Connect failed"); + } + + return ret; +} + + +static struct esp32_wifi_runtime eth_data; + +static const struct ethernet_api eth_esp32_apis = { + .iface_api.init = eth_esp32_init, + .send = eth_esp32_send, +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + .get_stats = eth_esp32_stats, +#endif +}; + +NET_DEVICE_DT_INST_DEFINE(0, + eth_esp32_dev_init, device_pm_control_nop, + ð_data, NULL, CONFIG_ETH_INIT_PRIORITY, + ð_esp32_apis, ETHERNET_L2, + NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU); diff --git a/dts/xtensa/espressif/esp32.dtsi b/dts/xtensa/espressif/esp32.dtsi index ad86144c571..ce38eafe5a0 100644 --- a/dts/xtensa/espressif/esp32.dtsi +++ b/dts/xtensa/espressif/esp32.dtsi @@ -50,6 +50,11 @@ status = "ok"; }; + wifi: wifi { + compatible = "espressif,esp32-wifi"; + status = "disabled"; + }; + uart0: uart@3ff40000 { compatible = "espressif,esp32-uart"; reg = <0x3ff40000 0x400>; @@ -161,5 +166,7 @@ clocks = <&rtc ESP32_SPI3_MODULE>; status = "disabled"; }; + }; + }; diff --git a/soc/xtensa/esp32/linker.ld b/soc/xtensa/esp32/linker.ld index b70bc607652..a4f3169ab00 100644 --- a/soc/xtensa/esp32/linker.ld +++ b/soc/xtensa/esp32/linker.ld @@ -39,6 +39,7 @@ PROVIDE ( crc32_le = 0x4005cfec ); PROVIDE ( Cache_Read_Disable_rom = 0x40009ab8 ); PROVIDE ( Cache_Read_Enable_rom = 0x40009a84 ); PROVIDE ( Cache_Read_Init_rom = 0x40009950 ); +PROVIDE ( phy_get_romfuncs = 0x40004100 ); PROVIDE ( SPI1 = 0x3ff42fff ); PROVIDE ( SPI2 = 0x3ff64fff ); PROVIDE ( SPI3 = 0x3ff65fff );