Terrible WiFi performance on new ESP32S3 Feather
I wanted to upgrade my ESP32 NodeMCU network music player (ESP-IDF) to get more flash and access to PSRAM. The Unexpected Maker ESP32S3 Feather (16MB flash, 4MB PSRAM) seems the obvious choice so I bought 4 boards. However I am not having any joy and more testing indicates serious problems with the board. Has anyone else seen this or am I doing something wrong? (this seems unlikely to me given the testing described here).
Firstly (using my software built with ESP-IDF v5.0), the Feather, while it scans networks fine and has 6dB better signal, takes much longer than the NodeMCU running the same code to connect to my AP and is unreliable (code often gives up after 5 retries). Then, loading data from a Western Digital MyCloud NAS using an SMB2 library, the NodeMCU is easily 10 times faster than the Feather. Filling a 16K buffer averages >300ms on the Feather while the NodeMCU averages 30ms. This means that the Feather is not fast enough to play an MP3 file over WiFi.
Then, in case my code or ESP-IDF is at fault, I switched to Arduino IDE v1.8.19 and tried the simple WiFi Scan and WiFi connect (I loaded up-to-date UM Feather S3 board support from GitHub). The same slow / unreliable connect was also there when using the Arduino support.
I then took a step back and flashed UF2 and CircuitPython v8.0.3 back onto the Feather and wrote a simple WiFi TCP server to just read and discard data sent from a Python client on my laptop. WiFi connection to the AP was slow (averaging 4-5s to connect) and data transfer also slow (140-150s to transfer 1MB, usually recv_into() reading 1440 or 2880 bytes per invocation). I flashed the NodeMCU with the DOIT DevKit v1 CircuitPython v8.0.3 and ran the same tests - connection to the AP was normally successful in less than 50ms, and the 1MB transfer time varied from 25s to 75s (I suspect that the Python garbage collector was struggling on the NodeMCU, so the SMB2 test is probably a better measure of the difference).
I then moved the Feather physically closer to AP - this made no difference. Finally in case I just had a bad board (I had bought 4 Feathers) I soldered up the headers on another board and tried that - Performance continued to be terrible with very similar numbers.
Unless I can get a fix for this issue, I will have to abandon the ESP32 Feather and go back to Node MCU (or a Huzzah32 v2 which from brief testing I suspect will be OK). Bit disappointed as I had high expectations… Any suggestions?
I also own the UM Feather S3 but did not test it yet in this respect. But my experience is that both ESP32-S2 and ESP32-C3 have terrible WiFi performance, even something like old as an ESP-01S does much better. I don’t expect the S3 to be better and your results seem to show this as well.
hi Bernhard and interested parties
I’ve now done a lot more experimentation with the UM ESP32S3 Feather using a simple ESP-IDF TCP server as the test harness with a Python client. I can add a few more observations that might be of interest.
It is possible to extract better WiFi performance from the Feather as a TCP server. In fact in my test harness I have seen occasional peaks approaching 2Mbyte/s with sustained data transfer over 500kbyte/s.
This performance is however very variable. Moving the Feather about and changing its orientation or proximity to nearby (metal? conducting?) objects can result in large changes in the observed transfer rate - sometimes down to 30-50kbytes/s or even lower. With the Feather on my testing breadboard I tend to get 60-80kbytes/s, but if I place a finger on the little Ignion antenna this (reproducibly) shoots up to 700kbytes/s!! I seem to work pretty well as a 2.4GHz antenna but how I am going to produce this effect when I move the Feather into a project box, or bolt it to a bit of aluminium, remains to be seen… Giving it an earth connection doesn’t seem to make much difference.
In order to get the best performance from the Feather I needed to make some configuration changes from the defaults generated by ESP-IDF v5.0.1:
- The default CPU frequency is 160MHz for some reason, so this should be changed to 240MHz (although I don’t think that this is the bottleneck in the test harness)
- Set optimisation level to -O2 on the C++ compiler command line or in C++ source modules
- After invocation of esp_wifi_start(), disable WiFi power save with esp_wifi_set_ps(WIFI_PS_NONE)
- In WiFi configuration, increase the maximum number of static RX buffers to 16, maximum number of dynamic RX buffers to 64, increase AMPDU RX BA window size to 32
- in LWIP configuration, increase default receive buffer window size to 16384
I’m not aware of a current mechanism to make equivalent config changes in CircuitPython class Radio or the ESP32 Arduino Core WiFi class; who knows though, maybe it will be possible in future. At the moment (imho) ESP-IDF is the way to go if configurability and performance is a priority. But the main issue remains - to figure out a way of reducing the inconsistency in WiFi behaviour.
Very interesting and thanks for sharing. Is it possible to post your code?
In CP, the IDF-settings are in the file ports/espressif/boards/xxx/sdkconfig. I don’t know if esp_wifi_set_ps() is already part of the CP-api,
These insights might be very valuable for the CP developers and worth an issue in their github-repo.
Tried to post code with cut and paste, but indentation and half the code went missing, sorry. I don’t have GitHub or other server available but I am happy to email code if this works?