When something does not work, the temptation is to change code blindly. That makes it worse. What really saves time is seeing what is happening. And for that you have the serial monitor and logs.
The serial monitor, properly configured
void setup() {
Serial.begin(115200);
Serial.println("Starting…");
}
Three things almost everyone forgets:
- The baud rate must match (115200 is the standard). If you see
����, it does not. - After
Serial.begin()give it a moment before printing; the first lines are sometimes lost. - The monitor resets the board when it opens in many setups: do not panic if it “boots on its own”.
If you see nothing:
- Is the monitor on the right port?
- Does the board use native USB (S3/C3) and you are watching the wrong port?
- Did you close another program holding the port open?
Leveled logs (if you use ESP-IDF)
Instead of printf everywhere, use levels:
#include "esp_log.h"
static const char *TAG = "app";
ESP_LOGI(TAG, "info");
ESP_LOGW(TAG, "warning");
ESP_LOGE(TAG, "error");
You can raise or lower the level per component from menuconfig, and in
production keep only errors. A printf does not give you that.
The messages that are telling you the problem
On boot, the ESP32 prints a lot of useful information:
rst:0x...→ why it reset: power-on, watchdog, panic, brownout.Brownout detector was triggered→ not enough power. Change the cable, the USB port, or add a capacitor.Guru Meditation Error→ a panic. Below it comes a backtrace with addresses; withidf.py monitorit is translated to function names for you.Task watchdog got triggered→ yourloop()or a task got stuck.
Learning to read those four lines solves half the problems.
Techniques that work
- Bisection: comment out half the code. The problem is in the other half. Repeat.
- Strategic
Serial.println: mark where it passes, not random values. Better[sensor] read: %d. - Status LED: a fast-blinking LED = “I am here”. No monitor needed.
- Multimeter: measure power and levels before blaming the code.
- Logic analyzer (cheap): essential for I2C/SPI. Seeing the bus is another level.
- JTAG (S3/C3): real breakpoints when the bug is slippery.
Typical mistakes
- Changing code at random without watching the monitor.
- Ignoring a brownout thinking it is software.
- Not reading the backtrace (the exact line is there).
- Using
delay()in the loop and hitting the watchdog. - Debugging at 9600 baud and expecting everything to come out.
A loop() that does not block (and does not trip the watchdog)
unsigned long last = 0;
void loop() {
if (millis() - last >= 1000) {
last = millis();
// heavy work here
}
// the rest of the time, breathe
}Summary
- Set the monitor to 115200 and check port and speed.
- Use leveled logs (ESP-IDF) instead of loose
printfs. rst:, brownout, backtrace and watchdog tell you what is wrong; learn them.- Bisection + status LED + multimeter solve most cases.
- For buses (I2C/SPI), a logic analyzer is worth its weight in gold.
- When the bug hides, JTAG (S3/C3).
Next step: with this you close Introduction to the ESP32. From here you can continue to Explore or go back to the series hub.