The ESP32 was released a few years ago, and was immediately touted as an ‘ESP8266 killer’. What happened?
I’ve been using the ESP8285 in my clocks for a while now. It is an ESP8266 with 1M flash built-in. This not only means you have everything you need on one chip, but it also frees up a couple of GPIOs. I’ve been very happy with it and with the Arduino core that is implemented on top of it. It has done everything I have asked of it. I find it odd that it is virtually impossible to find any commercial boards that use it.
So the ESP32, with dual cores, higher speed and more GPIOs should be better right? Well the Espressif code, which is layered on top of FreeRTOS, is still fairly unstable. The Arduino core, just got to 1.0.
However, I figured it was time to seriously start playing with it and I chose the ESP32 Pico dev kit, because, like the ESP8285, it has flash on-chip.
The first thing I did was try and play sounds on it – I wanted to use the I2S interface, which seems like a big distinguishing feature of this chip. After a while I managed to find a good library that works on the Arduino core, and includes support for the ESP32 – ESP8266Audio (by the way, that guy is prolific, check out his other projects). It worked very well.
Next I wanted to add a WiFi Manager to manage setting up a captive portal. It turns out that the one I use on the ESP8285 (AsyncWiFiManager) is also just about the only one that really supports the ESP32.
When I tried to connect my iPhone to the AP, the ESP32 kept crashing. It turns out that this was a problem in esp-idf, which was recently fixed, but the fix wasn’t included in the Arduino core 1.0.1. A few days after I submitted a bug report, it was included in master, so I switched to using master.
Playing sounds is great, but of course, it all starts to fall apart as I try to do more with the platform. I wanted to move beyond just playing sounds so I dove right in and created several FreeRTOS tasks to do things asynchronously.
A quick aside: The arduino core is implemented on top of FreeRTOS tasks. So for example, loop() is in its own task.
Naturally the audio playback instantly started glitching, so I moved everything back into loop() and played around a little. I have a sound effect playing and I have AsyncWifiManager also checking for AP access. As soon as I access the AP, the sound starts to glitch. Basically, the library I am using needs to take over full time to feed I2S.
OK, so we have two cores. By default the arduino core runs on core 1 and the RF stack runs on core 0. So I switch AsyncWifiManager to core 0 and leave the sound player on core 1. But it still glitches whenever I access the AP. Why? Who knows? Probably there are lower-level components that are making assumptions about which core they should be running on.
Now I am sure that I could write a sound library, that has input and output queues, that cause a task to yield if they are full and that are drained under interrupts. Maybe there are even some hardware modules I could use that have built-in queues so I don’t have to worry about timing on the ESP32. But at that point, why bother? I’m not doing this to improve sounds streaming on the ESP32. I just want to play some sounds on my clocks.
Is the ESP32 a case of a solution looking for a problem? Did they just throw everything they thought might be fun at it? Capacitive touch? You got it. I2S? You got it. Dual core? You got it. Why does the software support seem like so much of an afterthought? Kudos to me-no-dev and the Arduino core implemented on top if esp-idf, but Espressif really need to be more on top of this.