Lost tens of hours of my life trying to bring a new ESP32-based board up. Debugging code, cutting traces and soldering bridge wires, buying and using a logic analyzer.
Turns out:
Some of the pins on the ESP32
a) Are strapping pins (configure stuff like what voltage to talk to FLASH). Luckily there's a few fuses you can blow to hardcode some of the settings the strapping pins are reading, so they ignore logic level on boot,
b) Default back to JTAG pins. For example, you have to explicitly reset GPIO12 - gpio_reset_pin(GPIO12) to use it as an I/O pin again (this burnt a day of my life).
Lesson learnt, if something weird is happening with your micro, check for strapping and / or default pin behavior.
Same deal with Kinetis and ST micros - there are a few BOOT pins which can really ruin your day! They are documented but it isn't super obvious. I found that it is important to check a few parts of the datasheet/reference manual before using any part and designing a circuit:
- What are the default states of every pin on start up?
- What is the boot sequence? Is there a pin or setting to switch the boot between Flash, RAM, bootloader, etc?
- Is there any built-in bootloader? How is it triggered?
Ye pins on those are used for many different things. Really annoying. I had the same one-day-issue. "Solved" it by quickly removing the programmer after booting and connect my uart device ...
It's genuinely interesting that he says that the USB flashing can't be relied on: we've been using the S3 at work for... gosh, 12 months? Longer? And it's been perfectly reliable for us -- and that's despite us flashing it via OpenOCD inside a Docker container, inside WSL2 with usbipd!
Espressif dev here. I usually advise people to break out GPIO0 (or GPIO9 for the ESP32Cx series) because 1. if you somehow write firmware that reconfigures the USB pins, there's no way to get the USB connection going via which you can reset the ESP into download mode, and 2. if somehow a firmware upload aborts halfway, the ESP32 can go into a bootloop with the USB device periodically disappearing. In the 2nd scenario, it's not impossible to time your flash so it goes through, but simply pulling GPIO0 low is easier. I don't think having an actual button is needed, but I'd certainly have a test point or another way you can ground that pin when you get yourself in a pickle.
Oh, we absolutely have on our boards. It's just we've had to use it to recover from a borked flash maybe twice, total? We don't have a button, just have to bridge some pads.
ESP-IDF devcontainer + vscode and the ESP-IDF plugin? Maybe it's worth me seeing if work will let me publish our docs around it, but it was pretty much as simple as following the ESP-IDF plugin's own documentation:
I'm interested in what other people are doing with esphome. I am using pretty cheap 8266es to do distributed sensing around the house, but what are you doing that requires the S3? It was my impression that it was decently more expensive?
The one thing the S3 has that others don't is the LX7 micro, and it's vector extensions. This can be used to speed up computer vision tasks if you're using presence detection... but really theres better choices for that haha
I have found the ESP32-C3 pretty frustrating in terms of occupied pins, once you eliminate all the strapping pins etc. there aren't all that many remaining.
By default, on bootup, an ESP32 uses the value of pin IO12 to determine SPI Flash chip voltage. It has an internal pull-down so defaults to low (3.3V flash chip). If held high during bootup, then ESP32 treats Flash Chip voltage as 1.8V.
If you an input (say DIP switches) with pull-ups on IO12 and the dip switch is "off", i.e. disconnecting the ground circuit / pulled-up. Then, at boot, the ESP32 thinks it need to use 1.8V to talk with the flash chip, instantly crashing boot.
The use-case is to signal to the chip (since it's going to be booting off flash) what voltage to use (if you're using a 1.8V logic chip).
Luckily (on the ESP32 at least) there's a bunch of internal fuses you can blow to stop it from sampling certain strapping pins at boot, and hard coding certain settings (in a irreversible way).
In software, you pass configuration on the command line or in environment variables.
In hardware, you "strap" pins to a particular value when the chip powers on. You can strap them high (tie them to the power source), strap them low (tie them to GND), or sometimes they do something fancier and tie them high or low via a particular resistor (for more fine-grained configurations like timing patterns, power selection, or I2C address selection in pin-constrained environments).
Usually you can reuse the pins for something else after power on. Often there are efuse bits you can blow after manufacture in order to override the strapping values and use the pins as normal IOs.
Strapping in circuits is figuratively tying a thing by strings so it stays in vicinity of voltage/current/circuit constants. In this case, the chip has pins that can be used to change operating modes by strapping high or low, called strapping pins. Similar to but slightly different from pull-up/pull-down.
Boot strapping in circuits usually refers to passive parts that provide power needed locally for switching parts.
Strapping pins internally have a pullup or pulldown resistor. At startup these control what state some part of the system is in, (like the example mentioned elsewhere, flash voltage). These are controllable by applying your own resistor at startup, like a normal i/o pin would be. The difference is that these pins are multipurpose. At power-on, the early bios reads the bootstrapping pins, sets its state, and then releases them to the actual OS, so that they can be used for other things (sometimes).
As useful as they are, imo they are a bit problematic, because of that mixed-use state. You have to be able to setup that pin for your hardware configuration, and then during operation use it for your needs.
Most of these also have an internal fuse you can burn to force the state permanently, which is where the "slightly different" comes in. The fuse sets the permanent internal pull state, so you dont have to deal with the setup phase, except, that you need to make sure anything you use that pin for in your application defaults to the state you want, as you can still externally modify that pin at power-on.
The information is in the data sheets for the chips, the data sheets for the modules and the technical reference manuals - but it’s spread over multiple sections. Bringing everything together into one quick and easy reference is very useful.
I highly recommend using Forth for interactive exploration of hardware. In my opinion, C-Forth and uEForth are particularly well-suited for the ESP32. Even when I choose to develop C-based Baremetal solutions for the ESP32, Forth proves incredibly useful for quickly testing and validating my ideas. This is especially true for verifying physical wiring, as it significantly reduces the time spent troubleshooting potential errors, whether in my own work or when examining a pre-made board.
I know that it is substantially supported on the ESP32, which is great, but I’m not sure if it’s able to give you the HW access that Forth has, you can extend and build your own drivers on the Forth system, which is my main use case. I like to do things as bare to the metal as possible and C and forth give me that, it’s the same reason I never used the arduino framework.
Lost tens of hours of my life trying to bring a new ESP32-based board up. Debugging code, cutting traces and soldering bridge wires, buying and using a logic analyzer.
Turns out:
Some of the pins on the ESP32
Lesson learnt, if something weird is happening with your micro, check for strapping and / or default pin behavior.