<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>TunaTek ESP32</title>
    <subtitle>Hands-on ESP32 tutorials, projects and engineering notes: GPIO, Wi-Fi, BLE, MQTT, power and more.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://esp32.tunatek.tech/en/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-10-07T00:00:00+00:00</updated>
    <id>https://esp32.tunatek.tech/en/atom.xml</id>
    <entry xml:lang="en">
        <title>Serial monitor and debugging on the ESP32: stop guessing</title>
        <published>2026-10-07T00:00:00+00:00</published>
        <updated>2026-10-07T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/monitor-serie-depuracion-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/monitor-serie-depuracion-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/monitor-serie-depuracion-esp32/">&lt;p&gt;When something does not work, the temptation is to change code blindly. That
makes it worse. What really saves time is &lt;strong&gt;seeing what is happening&lt;/strong&gt;. And for
that you have the serial monitor and logs.&lt;/p&gt;
&lt;h2 id=&quot;the-serial-monitor-properly-configured&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-serial-monitor-properly-configured&quot; aria-label=&quot;Anchor link for: the-serial-monitor-properly-configured&quot;&gt;The serial monitor, properly configured&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;115200&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;Starting…&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things almost everyone forgets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The baud rate must match&lt;/strong&gt; (115200 is the standard). If you see &lt;code&gt;����&lt;/code&gt;, it
does not.&lt;/li&gt;
&lt;li&gt;After &lt;code&gt;Serial.begin()&lt;/code&gt; give it a moment before printing; the first lines are
sometimes lost.&lt;/li&gt;
&lt;li&gt;The monitor &lt;strong&gt;resets the board&lt;/strong&gt; when it opens in many setups: do not panic if
it “boots on its own”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you see nothing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is the monitor on the &lt;strong&gt;right port&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Does the board use &lt;strong&gt;native USB&lt;/strong&gt; (S3/C3) and you are watching the wrong
port?&lt;/li&gt;
&lt;li&gt;Did you close another program holding the port open?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;leveled-logs-if-you-use-esp-idf&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#leveled-logs-if-you-use-esp-idf&quot; aria-label=&quot;Anchor link for: leveled-logs-if-you-use-esp-idf&quot;&gt;Leveled logs (if you use ESP-IDF)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Instead of &lt;code&gt;printf&lt;/code&gt; everywhere, use levels:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;esp_log.h&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; *&lt;/span&gt;&lt;span&gt;TAG &lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;ESP_LOGI&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TAG&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;ESP_LOGW&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TAG&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;warning&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;ESP_LOGE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TAG&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can raise or lower the level &lt;strong&gt;per component&lt;/strong&gt; from &lt;code&gt;menuconfig&lt;/code&gt;, and in
production keep only errors. A &lt;code&gt;printf&lt;/code&gt; does not give you that.&lt;/p&gt;
&lt;h2 id=&quot;the-messages-that-are-telling-you-the-problem&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-messages-that-are-telling-you-the-problem&quot; aria-label=&quot;Anchor link for: the-messages-that-are-telling-you-the-problem&quot;&gt;The messages that are telling you the problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On boot, the ESP32 prints a lot of useful information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rst:0x...&lt;/code&gt;&lt;/strong&gt; → why it reset: power-on, watchdog, panic, brownout.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Brownout detector was triggered&lt;/code&gt;&lt;/strong&gt; → &lt;strong&gt;not enough power&lt;/strong&gt;. Change the
cable, the USB port, or add a capacitor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Guru Meditation Error&lt;/code&gt;&lt;/strong&gt; → a &lt;em&gt;panic&lt;/em&gt;. Below it comes a &lt;strong&gt;backtrace&lt;/strong&gt; with
addresses; with &lt;code&gt;idf.py monitor&lt;/code&gt; it is translated to function names for you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Task watchdog got triggered&lt;/code&gt;&lt;/strong&gt; → your &lt;code&gt;loop()&lt;/code&gt; or a task got stuck.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Learning to read &lt;strong&gt;those four lines&lt;/strong&gt; solves half the problems.&lt;/p&gt;
&lt;h2 id=&quot;techniques-that-work&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#techniques-that-work&quot; aria-label=&quot;Anchor link for: techniques-that-work&quot;&gt;Techniques that work&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bisection&lt;/strong&gt;: comment out half the code. The problem is in the other half.
Repeat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strategic &lt;code&gt;Serial.println&lt;/code&gt;&lt;/strong&gt;: mark where it passes, not random values.
Better &lt;code&gt;[sensor] read: %d&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Status LED&lt;/strong&gt;: a fast-blinking LED = “I am here”. No monitor needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multimeter&lt;/strong&gt;: measure power and levels before blaming the code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logic analyzer&lt;/strong&gt; (cheap): essential for I2C/SPI. Seeing the bus is another
level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JTAG&lt;/strong&gt; (S3/C3): real breakpoints when the bug is slippery.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Changing code at random&lt;/strong&gt; without watching the monitor.&lt;/li&gt;
&lt;li&gt;Ignoring a &lt;strong&gt;brownout&lt;/strong&gt; thinking it is software.&lt;/li&gt;
&lt;li&gt;Not reading the &lt;strong&gt;backtrace&lt;/strong&gt; (the exact line is there).&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;delay()&lt;/code&gt; in the loop and hitting the &lt;strong&gt;watchdog&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Debugging at 9600 baud and expecting everything to come out.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;a-loop-that-does-not-block-and-does-not-trip-the-watchdog&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-loop-that-does-not-block-and-does-not-trip-the-watchdog&quot; aria-label=&quot;Anchor link for: a-loop-that-does-not-block-and-does-not-trip-the-watchdog&quot;&gt;A &lt;code&gt;loop()&lt;/code&gt; that does not block (and does not trip the watchdog)&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; -&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;    //&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; heavy work here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;  //&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; the rest of the time, breathe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Set the &lt;strong&gt;monitor to 115200&lt;/strong&gt; and check port and speed.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;leveled logs&lt;/strong&gt; (ESP-IDF) instead of loose &lt;code&gt;printf&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rst:&lt;/code&gt;, brownout, backtrace and watchdog&lt;/strong&gt; tell you what is wrong; learn
them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bisection + status LED + multimeter&lt;/strong&gt; solve most cases.&lt;/li&gt;
&lt;li&gt;For buses (I2C/SPI), a &lt;strong&gt;logic analyzer&lt;/strong&gt; is worth its weight in gold.&lt;/li&gt;
&lt;li&gt;When the bug hides, &lt;strong&gt;JTAG&lt;/strong&gt; (S3/C3).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; with this you close &lt;em&gt;Introduction to the ESP32&lt;/em&gt;. From here you can
continue to &lt;a href=&quot;https://esp32.tunatek.tech/explorar/&quot;&gt;Explore&lt;/a&gt; or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Reading a push button properly: pull-up, debounce and interrupts</title>
        <published>2026-10-06T00:00:00+00:00</published>
        <updated>2026-10-06T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/pulsador-antirrebote-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/pulsador-antirrebote-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/pulsador-antirrebote-esp32/">&lt;p&gt;Reading a button sounds like the easiest thing in the world: &lt;code&gt;digitalRead()&lt;/code&gt; and
done. Then the usual happens: one press counts as five, or the pin reads random
noise while nobody is touching it. Both have an explanation and a fix.&lt;/p&gt;
&lt;h2 id=&quot;first-never-leave-a-pin-floating&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#first-never-leave-a-pin-floating&quot; aria-label=&quot;Anchor link for: first-never-leave-a-pin-floating&quot;&gt;First: never leave a pin “floating”&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you wire a button between the pin and &lt;code&gt;3V3&lt;/code&gt; with nothing else, when it is
&lt;strong&gt;not&lt;/strong&gt; pressed the pin floats and reads garbage. You need a resistor to pull it
to a known level:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull-up&lt;/strong&gt;: the pin is &lt;code&gt;HIGH&lt;/code&gt; at rest; pressing pulls it to &lt;code&gt;GND&lt;/code&gt;. &lt;strong&gt;What I
use almost always.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull-down&lt;/strong&gt;: the pin is &lt;code&gt;LOW&lt;/code&gt; at rest; pressing pulls it to &lt;code&gt;3V3&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ESP32 has an &lt;strong&gt;internal pull-up&lt;/strong&gt;, so you usually do not need a resistor:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;constexpr&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; int&lt;/span&gt;&lt;span&gt; BTN&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;115200&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  pinMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BTN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; INPUT_PULLUP&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;   //&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; rest = HIGH, pressed = LOW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;digitalRead&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BTN&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; ==&lt;/span&gt;&lt;span&gt; LOW&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;pressed&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Careful: &lt;strong&gt;GPIO34–39 have no internal pull-up&lt;/strong&gt; (input only). If you use one of
those, you need an external resistor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;why-it-bounces-and-why-you-see-5-presses&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-it-bounces-and-why-you-see-5-presses&quot; aria-label=&quot;Anchor link for: why-it-bounces-and-why-you-see-5-presses&quot;&gt;Why it “bounces” (and why you see 5 presses)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A button does &lt;strong&gt;not&lt;/strong&gt; go cleanly from &lt;code&gt;HIGH&lt;/code&gt; to &lt;code&gt;LOW&lt;/code&gt;. For a few milliseconds it
makes and breaks contact several times. The ESP32, running at 240 MHz, &lt;strong&gt;sees it
all&lt;/strong&gt;. That is &lt;em&gt;bounce&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;software-debounce-my-favourite&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#software-debounce-my-favourite&quot; aria-label=&quot;Anchor link for: software-debounce-my-favourite&quot;&gt;Software debounce (my favourite)&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;constexpr&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; int&lt;/span&gt;&lt;span&gt; BTN&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;constexpr&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; DEBOUNCE_MS&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 30&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;bool&lt;/span&gt;&lt;span&gt; stable&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span&gt; HIGH&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;bool&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span&gt; HIGH&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; change&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  bool&lt;/span&gt;&lt;span&gt; reading&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; digitalRead&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BTN&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;reading&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; !=&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    change&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span&gt; reading&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; -&lt;/span&gt;&lt;span&gt; change&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span&gt; DEBOUNCE_MS&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; reading&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; !=&lt;/span&gt;&lt;span&gt; stable&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    stable&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span&gt; reading&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;stable&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; ==&lt;/span&gt;&lt;span&gt; LOW&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;valid press&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The idea: you only accept a change if it stays &lt;strong&gt;stable&lt;/strong&gt; for 30 ms. That is
enough for 99 % of buttons.&lt;/p&gt;
&lt;h2 id=&quot;hardware-debounce&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hardware-debounce&quot; aria-label=&quot;Anchor link for: hardware-debounce&quot;&gt;Hardware debounce&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the button is critical or noisy, an &lt;strong&gt;RC&lt;/strong&gt; (10 kΩ + 100 nF) and, if needed, a
&lt;strong&gt;Schmitt trigger&lt;/strong&gt; (74HC14) fix it. More parts, but zero code.&lt;/p&gt;
&lt;h2 id=&quot;interrupts-powerful-and-dangerous&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#interrupts-powerful-and-dangerous&quot; aria-label=&quot;Anchor link for: interrupts-powerful-and-dangerous&quot;&gt;Interrupts: powerful and dangerous&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With &lt;code&gt;attachInterrupt()&lt;/code&gt; the ESP32 runs your function instantly. Great for not
missing presses, but it has rules:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;volatile&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; bool&lt;/span&gt;&lt;span&gt; pressed&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; IRAM_ATTR&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; onPress&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;   //&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; IRAM_ATTR: it must live in IRAM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  pressed&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  pinMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BTN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; INPUT_PULLUP&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  attachInterrupt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;digitalPinToInterrupt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BTN&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; onPress&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; FALLING&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;pressed&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pressed&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Golden rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The shared variable must be &lt;strong&gt;&lt;code&gt;volatile&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The function must be &lt;strong&gt;&lt;code&gt;IRAM_ATTR&lt;/code&gt;&lt;/strong&gt; (otherwise it can fail with Wi-Fi).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do not do heavy work inside the ISR&lt;/strong&gt;: set a flag and handle it in &lt;code&gt;loop()&lt;/code&gt;.
No &lt;code&gt;Serial.print&lt;/code&gt; or &lt;code&gt;delay&lt;/code&gt; in there.&lt;/li&gt;
&lt;li&gt;Even with an interrupt, &lt;strong&gt;bounce still exists&lt;/strong&gt;: debounce anyway.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;A button with no pull-up and pins reading noise → you think the ESP32 is
broken.&lt;/li&gt;
&lt;li&gt;Using &lt;strong&gt;GPIO34–39&lt;/strong&gt; for a button and discovering there is no internal pull-up.&lt;/li&gt;
&lt;li&gt;Putting &lt;code&gt;Serial.println&lt;/code&gt; inside the ISR → random hangs.&lt;/li&gt;
&lt;li&gt;Forgetting &lt;code&gt;volatile&lt;/code&gt; → the compiler “optimizes” and the flag never changes.&lt;/li&gt;
&lt;li&gt;No debounce and counting 5 presses per press.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never&lt;/strong&gt; leave an input pin floating: use &lt;strong&gt;&lt;code&gt;INPUT_PULLUP&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Buttons &lt;strong&gt;bounce&lt;/strong&gt;; 30 ms of debounce fixes it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interrupts&lt;/strong&gt;: &lt;code&gt;volatile&lt;/code&gt;, &lt;code&gt;IRAM_ATTR&lt;/code&gt;, minimal work and debounce too.&lt;/li&gt;
&lt;li&gt;GPIO34–39 have no pull-up: external resistor required.&lt;/li&gt;
&lt;li&gt;With hardware (RC + Schmitt) you save code if the noise is serious.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;serial monitor and basic debugging&lt;/a&gt;, to
stop guessing why it is not working. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Getting started with ESP32: blink an LED</title>
        <published>2026-10-05T00:00:00+00:00</published>
        <updated>2026-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/primeros-pasos-esp32-blink/"/>
        <id>https://esp32.tunatek.tech/en/blog/primeros-pasos-esp32-blink/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/primeros-pasos-esp32-blink/">&lt;p&gt;The hardware &lt;em&gt;Hello World&lt;/em&gt; is blinking an LED. It is a simple ritual, but it
touches every important part of a new board: &lt;strong&gt;power&lt;/strong&gt;, &lt;strong&gt;toolchain&lt;/strong&gt;, &lt;strong&gt;GPIO&lt;/strong&gt;
and &lt;strong&gt;flashing&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-you-need&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-you-need&quot; aria-label=&quot;Anchor link for: what-you-need&quot;&gt;What you need&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;Detail&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Board&lt;/td&gt;&lt;td&gt;ESP32 DevKitC, ESP32-WROOM-32 or similar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LED&lt;/td&gt;&lt;td&gt;Any color, ~2 V forward drop&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resistor&lt;/td&gt;&lt;td&gt;220 Ω to 330 Ω&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Software&lt;/td&gt;&lt;td&gt;PlatformIO (recommended) or Arduino IDE 2.x&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; many DevKits already ship an LED on &lt;code&gt;GPIO2&lt;/code&gt;. You can use it to test
without wiring anything, though it is usually inverted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-pinout-in-two-minutes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-pinout-in-two-minutes&quot; aria-label=&quot;Anchor link for: the-pinout-in-two-minutes&quot;&gt;The pinout in two minutes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ESP32 has GPIOs numbered 0 to 39, but &lt;strong&gt;not all are usable&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GPIO6&lt;/code&gt;–&lt;code&gt;GPIO11&lt;/code&gt; are wired to the SPI flash. &lt;strong&gt;Do not touch them.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GPIO34&lt;/code&gt;–&lt;code&gt;GPIO39&lt;/code&gt; are &lt;strong&gt;input only&lt;/strong&gt; (no internal pull-up).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GPIO1&lt;/code&gt; (&lt;code&gt;TX0&lt;/code&gt;) and &lt;code&gt;GPIO3&lt;/code&gt; (&lt;code&gt;RX0&lt;/code&gt;) are used by the serial port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GPIO0&lt;/code&gt; selects the boot mode; avoid using it as an output.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For an LED, any output GPIO works. We will use &lt;code&gt;GPIO2&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;arduino-code&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#arduino-code&quot; aria-label=&quot;Anchor link for: arduino-code&quot;&gt;Arduino code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Arduino &lt;em&gt;core&lt;/em&gt; makes startup trivial:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;Arduino.h&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;constexpr&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; int&lt;/span&gt;&lt;span&gt; LED_PIN&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  pinMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LED_PIN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; OUTPUT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  digitalWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LED_PIN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; HIGH&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  delay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  digitalWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LED_PIN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; LOW&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  delay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;delay-blocks-and-sometimes-that-matters&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#delay-blocks-and-sometimes-that-matters&quot; aria-label=&quot;Anchor link for: delay-blocks-and-sometimes-that-matters&quot;&gt;&lt;code&gt;delay()&lt;/code&gt; blocks (and sometimes that matters)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;delay()&lt;/code&gt; halts the whole CPU. For a blink it is fine, but as soon as you add
Wi-Fi or several sensors you will want &lt;code&gt;millis()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;constexpr&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; INTERVAL&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 1000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; -&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span&gt; INTERVAL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    digitalWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LED_PIN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;digitalRead&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LED_PIN&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;the-same-in-esp-idf-rust&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-same-in-esp-idf-rust&quot; aria-label=&quot;Anchor link for: the-same-in-esp-idf-rust&quot;&gt;The same in ESP-IDF (Rust)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you prefer &lt;strong&gt;Rust&lt;/strong&gt;, the &lt;code&gt;esp-idf-hal&lt;/code&gt; crate offers a typed API. A &lt;em&gt;blink&lt;/em&gt;
with &lt;code&gt;esp-idf-svc&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;hal&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;FreeRtos&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;hal&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;gpio&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;PinDriver&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;hal&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;Peripherals&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; anyhow&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;Result&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;sys&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;link_patches&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    let&lt;/span&gt;&lt;span&gt; peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; Peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;take&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; mut&lt;/span&gt;&lt;span&gt; led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; PinDriver&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;output&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span&gt;pins&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span&gt;gpio2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    loop&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;set_high&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        FreeRtos&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;delay_ms&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;set_low&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        FreeRtos&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;delay_ms&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The big difference: in Rust the compiler &lt;strong&gt;forces&lt;/strong&gt; you to declare the pin as an
output before writing to it. Many hardware mistakes vanish at compile time.&lt;/p&gt;
&lt;h2 id=&quot;platformio-setup&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#platformio-setup&quot; aria-label=&quot;Anchor link for: platformio-setup&quot;&gt;PlatformIO setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A minimal &lt;code&gt;platformio.ini&lt;/code&gt; for the Arduino &lt;em&gt;core&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;env:esp32dev&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;platform&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espressif32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;board&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp32dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;framework&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arduino&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;monitor_speed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And for Rust with &lt;code&gt;esp-idf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;env:esp32dev&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;platform&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espressif32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;board&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp32dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;framework&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espidf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;monitor_speed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;troubleshooting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#troubleshooting&quot; aria-label=&quot;Anchor link for: troubleshooting&quot;&gt;Troubleshooting&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;It will not flash / board not found.&lt;/strong&gt; Install the &lt;code&gt;cp210x&lt;/code&gt; or &lt;code&gt;ch34x&lt;/code&gt;
drivers matching your board’s USB chip.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It flashes but does not blink.&lt;/strong&gt; Check the LED polarity and the resistor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It reboots in a loop.&lt;/strong&gt; Usually a power issue: use a USB port that can
deliver at least 500 mA.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;next-step&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#next-step&quot; aria-label=&quot;Anchor link for: next-step&quot;&gt;Next step&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With GPIO under control you have the essentials. The natural next jump is
connectivity (Wi-Fi, MQTT), which we will cover on the blog. For now you can move
on to &lt;a href=&quot;https://esp32.tunatek.tech/en/blog/monitor-serie-depuracion-esp32/&quot;&gt;serial monitor and debugging&lt;/a&gt;
or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>VS Code + ESP-IDF: the official environment with JTAG included</title>
        <published>2026-10-04T00:00:00+00:00</published>
        <updated>2026-10-04T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/vscode-esp-idf/"/>
        <id>https://esp32.tunatek.tech/en/blog/vscode-esp-idf/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/vscode-esp-idf/">&lt;p&gt;If you have decided to use &lt;strong&gt;ESP-IDF&lt;/strong&gt;, the official VS Code extension gives you
the best of both worlds: a modern editor and &lt;strong&gt;real JTAG debugging&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;installation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot;&gt;Installation&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;In VS Code, install the &lt;strong&gt;ESP-IDF&lt;/strong&gt; extension (by Espressif).&lt;/li&gt;
&lt;li&gt;Run the &lt;em&gt;setup wizard&lt;/em&gt; (ESP-IDF icon → &lt;strong&gt;Setup&lt;/strong&gt;). The extension downloads
ESP-IDF, the &lt;em&gt;toolchain&lt;/em&gt; and Python.&lt;/li&gt;
&lt;li&gt;Pick the version: today &lt;strong&gt;ESP-IDF 6.1&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It takes a while because it downloads everything (ESP-IDF is big). That is
normal.&lt;/p&gt;
&lt;h2 id=&quot;create-a-project&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#create-a-project&quot; aria-label=&quot;Anchor link for: create-a-project&quot;&gt;Create a project&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;ESP-IDF: New Project&lt;/em&gt; → template (&lt;code&gt;sample_project&lt;/code&gt;, &lt;code&gt;blink&lt;/code&gt;…), name and chip.
The layout is ESP-IDF’s:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;my-project/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── CMakeLists.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── sdkconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── main/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── CMakeLists.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── main.c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;menuconfig-from-vs-code&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#menuconfig-from-vs-code&quot; aria-label=&quot;Anchor link for: menuconfig-from-vs-code&quot;&gt;&lt;code&gt;menuconfig&lt;/code&gt; from VS Code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;ESP-IDF: SDK Configuration Editor&lt;/em&gt; opens &lt;code&gt;menuconfig&lt;/code&gt; in an integrated web
view: change options, search by text and it saves &lt;code&gt;sdkconfig&lt;/code&gt;. Much nicer than
the terminal.&lt;/p&gt;
&lt;h2 id=&quot;build-flash-and-monitor&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#build-flash-and-monitor&quot; aria-label=&quot;Anchor link for: build-flash-and-monitor&quot;&gt;Build, flash and monitor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The bottom bar has the buttons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build&lt;/strong&gt;, &lt;strong&gt;Flash&lt;/strong&gt;, &lt;strong&gt;Monitor&lt;/strong&gt; and &lt;strong&gt;Build + Flash + Monitor&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serial port&lt;/strong&gt; and &lt;strong&gt;monitor speed&lt;/strong&gt; selection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt; selection (&lt;code&gt;esp32&lt;/code&gt;, &lt;code&gt;esp32s3&lt;/code&gt;, &lt;code&gt;esp32c3&lt;/code&gt;…).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is equivalent to:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;idf.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;idf.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; /dev/ttyUSB0&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; flash&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; monitor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jtag-debugging&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jtag-debugging&quot; aria-label=&quot;Anchor link for: jtag-debugging&quot;&gt;JTAG debugging&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the gem. With an ESP32-S3/C3 board (and its native USB) or an external
probe, you get &lt;strong&gt;breakpoints&lt;/strong&gt;, &lt;em&gt;step over&lt;/em&gt;, variable inspection and call
stacks — no &lt;code&gt;printf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In ESP-IDF it is set up with &lt;code&gt;idf.py openocd&lt;/code&gt;, and the extension integrates it.
This is one of the biggest time savers when a bug refuses to show itself.&lt;/p&gt;
&lt;h2 id=&quot;extensions-that-pair-well&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#extensions-that-pair-well&quot; aria-label=&quot;Anchor link for: extensions-that-pair-well&quot;&gt;Extensions that pair well&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;C/C++&lt;/strong&gt; (IntelliSense) — the extension configures it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;clang-format&lt;/strong&gt; — automatic formatting on save.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Lens&lt;/strong&gt; — errors inline, without opening the console.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;when-to-choose-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-choose-it&quot; aria-label=&quot;Anchor link for: when-to-choose-it&quot;&gt;When to choose it&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Yes&lt;/strong&gt;: you are serious about ESP-IDF, want a comfortable &lt;code&gt;menuconfig&lt;/code&gt; and
JTAG debugging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No&lt;/strong&gt;: if you use Arduino or MicroPython (not applicable) or the command line
is enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;ESP-IDF&lt;/strong&gt; extension installs the SDK and the &lt;em&gt;toolchain&lt;/em&gt; for you.&lt;/li&gt;
&lt;li&gt;Integrated &lt;strong&gt;&lt;code&gt;menuconfig&lt;/code&gt;&lt;/strong&gt;, with search.&lt;/li&gt;
&lt;li&gt;Build/flash/monitor buttons and chip/port selection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JTAG&lt;/strong&gt; for real debugging (S3/C3 or an external probe).&lt;/li&gt;
&lt;li&gt;Current ESP-IDF version: &lt;strong&gt;6.1&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; the hands-on block:
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;blink an LED&lt;/a&gt; with what you already have set up. Or go
back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>VS Code + PlatformIO for ESP32: the environment I use every day</title>
        <published>2026-10-03T00:00:00+00:00</published>
        <updated>2026-10-03T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/vscode-platformio-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/vscode-platformio-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/vscode-platformio-esp32/">&lt;p&gt;If I had to keep just one environment for the ESP32, it would be this one.
PlatformIO turns VS Code into a real IDE: &lt;strong&gt;build, upload, monitor and
debugging&lt;/strong&gt;, with the project config in a text file.&lt;/p&gt;
&lt;h2 id=&quot;installation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot;&gt;Installation&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;strong&gt;VS Code&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;Extensions&lt;/em&gt;, search &lt;strong&gt;PlatformIO IDE&lt;/strong&gt; and install it.&lt;/li&gt;
&lt;li&gt;Wait for it to prepare the &lt;em&gt;toolchain&lt;/em&gt; the first time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That is it. PlatformIO downloads compilers and tools for you.&lt;/p&gt;
&lt;h2 id=&quot;create-a-project&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#create-a-project&quot; aria-label=&quot;Anchor link for: create-a-project&quot;&gt;Create a project&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;PlatformIO Home → New Project&lt;/em&gt;: name, board (&lt;code&gt;Espressif ESP32 Dev Module&lt;/code&gt;) and
framework (&lt;code&gt;Arduino&lt;/code&gt; or &lt;code&gt;ESP-IDF&lt;/code&gt;). The structure it generates:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;my-project/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── platformio.ini     # configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/main.cpp       # your code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── lib/               # your own libraries&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;platformio-ini-the-heart&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#platformio-ini-the-heart&quot; aria-label=&quot;Anchor link for: platformio-ini-the-heart&quot;&gt;&lt;code&gt;platformio.ini&lt;/code&gt;: the heart&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;env:esp32dev&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;platform&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espressif32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;board&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp32dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;framework&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arduino&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;monitor_speed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;upload_speed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 921600&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Switching board is changing &lt;strong&gt;one line&lt;/strong&gt;. This is gold when you have several
projects:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;env:s3&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;platform&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espressif32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;board&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp32-s3-devkitc-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;framework&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arduino&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;monitor_speed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;env:c3&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;platform&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espressif32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;board&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp32-c3-devkitm-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;framework&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arduino&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pick the environment in the bottom bar and upload.&lt;/p&gt;
&lt;h2 id=&quot;upload-and-monitor&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#upload-and-monitor&quot; aria-label=&quot;Anchor link for: upload-and-monitor&quot;&gt;Upload and monitor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the status bar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;✓ Build&lt;/strong&gt; — compile.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;→ Upload&lt;/strong&gt; — compile and flash.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;🔌 Serial Monitor&lt;/strong&gt; — open the monitor at your configured baud.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Or from the terminal:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;pio&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; upload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;pio&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; device&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; monitor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;per-project-libraries&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#per-project-libraries&quot; aria-label=&quot;Anchor link for: per-project-libraries&quot;&gt;Per-project libraries&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Instead of installing them globally, you declare them:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;lib_deps&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    adafruit/Adafruit BME280 Library@^2.2.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    knolleary/PubSubClient@^2.8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Huge advantage: &lt;strong&gt;the project carries its own versions&lt;/strong&gt;. If a library breaks
tomorrow, your code stays the same.&lt;/p&gt;
&lt;h2 id=&quot;debugging&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#debugging&quot; aria-label=&quot;Anchor link for: debugging&quot;&gt;Debugging&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With a board that supports it (ESP32-S3/C3) and a JTAG probe:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;debug_tool&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp-builtin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you get &lt;strong&gt;real breakpoints&lt;/strong&gt;, not &lt;code&gt;printf&lt;/code&gt;. It is the quality jump once the
project grows.&lt;/p&gt;
&lt;h2 id=&quot;what-i-like-and-what-i-do-not&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-i-like-and-what-i-do-not&quot; aria-label=&quot;Anchor link for: what-i-like-and-what-i-do-not&quot;&gt;What I like (and what I do not)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; one environment for almost everything, versionable config, per-project
dependencies, real debugging, cross-platform.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; the first build downloads a lot; and if you are new, there are more
concepts than in the Arduino IDE.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;strong&gt;PlatformIO IDE&lt;/strong&gt; in VS Code and forget the rest.&lt;/li&gt;
&lt;li&gt;All configuration lives in &lt;strong&gt;&lt;code&gt;platformio.ini&lt;/code&gt;&lt;/strong&gt; (versionable).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lib_deps&lt;/code&gt;&lt;/strong&gt; pins libraries &lt;strong&gt;per project&lt;/strong&gt;, not globally.&lt;/li&gt;
&lt;li&gt;Switching board is one line: great for one &lt;code&gt;env&lt;/code&gt; per variant.&lt;/li&gt;
&lt;li&gt;With JTAG you get &lt;strong&gt;real debugging&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;VS Code + ESP-IDF&lt;/a&gt; if you go deep with
the official SDK. Or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Arduino IDE 2.x for ESP32: step-by-step setup (and the usual errors)</title>
        <published>2026-10-02T00:00:00+00:00</published>
        <updated>2026-10-02T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/arduino-ide-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/arduino-ide-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/arduino-ide-esp32/">&lt;p&gt;Arduino IDE 2.x is the fastest way to get an LED blinking. It has known friction
(boards, drivers, port), so here is the guide with the usual stumbles already
solved.&lt;/p&gt;
&lt;h2 id=&quot;1-install-the-ide&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-install-the-ide&quot; aria-label=&quot;Anchor link for: 1-install-the-ide&quot;&gt;1. Install the IDE&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Download it from arduino.cc (2.x). It includes the editor, library manager,
serial monitor and board manager.&lt;/p&gt;
&lt;h2 id=&quot;2-add-esp32-support&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-add-esp32-support&quot; aria-label=&quot;Anchor link for: 2-add-esp32-support&quot;&gt;2. Add ESP32 support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In &lt;em&gt;File → Preferences → Additional boards manager URLs&lt;/em&gt;, paste:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://espressif.github.io/arduino-esp32/package_esp32_index.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then go to &lt;em&gt;Boards Manager&lt;/em&gt;, search &lt;strong&gt;esp32&lt;/strong&gt; and install &lt;strong&gt;esp32 by Espressif
Systems&lt;/strong&gt;. It takes a while: hundreds of MB.&lt;/p&gt;
&lt;h2 id=&quot;3-pick-the-right-board&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-pick-the-right-board&quot; aria-label=&quot;Anchor link for: 3-pick-the-right-board&quot;&gt;3. Pick the right board&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In &lt;em&gt;Tools → Board&lt;/em&gt;, choose yours:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32 Dev Module&lt;/strong&gt; → the classic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32S3 Dev Module&lt;/strong&gt;, &lt;strong&gt;ESP32C3 Dev Module&lt;/strong&gt;, etc. → the variant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-WROVER&lt;/strong&gt; only if the module has PSRAM.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Pick the wrong board and it usually compiles and uploads, but &lt;strong&gt;does not run&lt;/strong&gt;
or boot-loops. It is the number one mistake.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;4-the-serial-port-and-the-drivers&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-the-serial-port-and-the-drivers&quot; aria-label=&quot;Anchor link for: 4-the-serial-port-and-the-drivers&quot;&gt;4. The serial port and the drivers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is where 90 % of the problems live. Check which USB-serial chip your board
uses:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Chip&lt;/th&gt;&lt;th&gt;Driver&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CP2102&lt;/strong&gt; (Silicon Labs)&lt;/td&gt;&lt;td&gt;CP210x VCP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CH340 / CH341&lt;/strong&gt; (WCH)&lt;/td&gt;&lt;td&gt;CH341SER&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Native USB&lt;/strong&gt; (S3/C3/C6)&lt;/td&gt;&lt;td&gt;no driver needed&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;If the port does not show in &lt;em&gt;Tools → Port&lt;/em&gt;, it is the driver. On Linux you may
also need to be in the &lt;code&gt;dialout&lt;/code&gt; group.&lt;/p&gt;
&lt;h2 id=&quot;5-upload-the-first-program&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-upload-the-first-program&quot; aria-label=&quot;Anchor link for: 5-upload-the-first-program&quot;&gt;5. Upload the first program&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;115200&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  pinMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; OUTPUT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  digitalWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;digitalRead&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  delay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;500&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;println&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;blink&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hit &lt;strong&gt;Upload&lt;/strong&gt;. If it hangs at &lt;code&gt;Connecting...&lt;/code&gt;, hold &lt;strong&gt;BOOT&lt;/strong&gt; for a couple of
seconds; that is the classic trick.&lt;/p&gt;
&lt;h2 id=&quot;6-the-serial-monitor&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-the-serial-monitor&quot; aria-label=&quot;Anchor link for: 6-the-serial-monitor&quot;&gt;6. The serial monitor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open it with the magnifier icon and set &lt;strong&gt;115200 baud&lt;/strong&gt;. If you see garbage
(“����”), the speed does not match.&lt;/p&gt;
&lt;h2 id=&quot;typical-errors-and-their-cause&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-errors-and-their-cause&quot; aria-label=&quot;Anchor link for: typical-errors-and-their-cause&quot;&gt;Typical errors and their cause&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Symptom&lt;/th&gt;&lt;th&gt;Usual cause&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;“No such file” or missing port&lt;/td&gt;&lt;td&gt;USB-serial driver&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Endless &lt;code&gt;Connecting........&lt;/code&gt;&lt;/td&gt;&lt;td&gt;BOOT button, bad cable or wrong board&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Uploads but does nothing&lt;/td&gt;&lt;td&gt;Wrong board (variant)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Boot loop&lt;/td&gt;&lt;td&gt;Not enough power or &lt;code&gt;GPIO12&lt;/code&gt; held high&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Garbage in the monitor&lt;/td&gt;&lt;td&gt;Baud rate not 115200&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;settings-that-save-time&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#settings-that-save-time&quot; aria-label=&quot;Anchor link for: settings-that-save-time&quot;&gt;Settings that save time&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Enable &lt;strong&gt;“Show verbose output during: upload”&lt;/strong&gt; when something fails: it tells
the truth.&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;fixed port name&lt;/strong&gt; if you have several boards.&lt;/li&gt;
&lt;li&gt;Save your favourite boards so you do not pick each time.&lt;/li&gt;
&lt;li&gt;For big projects, move to &lt;strong&gt;VS Code + PlatformIO&lt;/strong&gt;: the Arduino IDE falls short.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Install the IDE and add Espressif’s board URL.&lt;/li&gt;
&lt;li&gt;Install “esp32 by Espressif” from the &lt;strong&gt;Boards Manager&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Pick the &lt;strong&gt;right board&lt;/strong&gt; (this breaks more projects than code).&lt;/li&gt;
&lt;li&gt;Solve the USB-serial chip &lt;strong&gt;driver&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Upload, open the &lt;strong&gt;monitor at 115200&lt;/strong&gt; and enjoy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;VS Code + PlatformIO&lt;/a&gt; when the project
grows. Or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Which IDE should you use for the ESP32? Arduino IDE, VS Code and friends</title>
        <published>2026-10-01T00:00:00+00:00</published>
        <updated>2026-10-01T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/ide-esp32-comparativa/"/>
        <id>https://esp32.tunatek.tech/en/blog/ide-esp32-comparativa/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/ide-esp32-comparativa/">&lt;p&gt;Choosing an IDE looks like a small decision and it is not: it is where you will
spend &lt;strong&gt;hundreds of hours&lt;/strong&gt;. The good news is that the choice depends almost
entirely on the framework you picked.&lt;/p&gt;
&lt;h2 id=&quot;the-table&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-table&quot; aria-label=&quot;Anchor link for: the-table&quot;&gt;The table&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;IDE&lt;/th&gt;&lt;th&gt;Ideal framework&lt;/th&gt;&lt;th&gt;Pros&lt;/th&gt;&lt;th&gt;Cons&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Arduino IDE 2.x&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Arduino&lt;/td&gt;&lt;td&gt;Simple, all included&lt;/td&gt;&lt;td&gt;Limited, no real debugging&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;VS Code + PlatformIO&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Arduino, ESP-IDF, Rust, MicroPython&lt;/td&gt;&lt;td&gt;Powerful, multi-board, debugging&lt;/td&gt;&lt;td&gt;More setup&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;VS Code + ESP-IDF&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ESP-IDF&lt;/td&gt;&lt;td&gt;Official, JTAG, &lt;em&gt;menuconfig&lt;/em&gt;&lt;/td&gt;&lt;td&gt;ESP-IDF only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Thonny&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;MicroPython&lt;/td&gt;&lt;td&gt;Great to start&lt;/td&gt;&lt;td&gt;MicroPython only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CLion / RustRover&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Rust&lt;/td&gt;&lt;td&gt;Top refactor and debugging&lt;/td&gt;&lt;td&gt;Commercial / heavy&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;arduino-ide-2-x&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#arduino-ide-2-x&quot; aria-label=&quot;Anchor link for: arduino-ide-2-x&quot;&gt;Arduino IDE 2.x&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is the “open and it works” option. Add the board URL, pick the board, hit
upload. Done.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; zero friction, built-in library manager.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; weak editor, no serious &lt;em&gt;IntelliSense&lt;/em&gt;, no JTAG debugging, and it
struggles with large projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt; learning, small sketches, workshops.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;vs-code-platformio&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#vs-code-platformio&quot; aria-label=&quot;Anchor link for: vs-code-platformio&quot;&gt;VS Code + PlatformIO&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My general recommendation. PlatformIO turns VS Code into a real IDE:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One environment&lt;/strong&gt; for Arduino, ESP-IDF, Rust or MicroPython, with the same
flow (build / upload / monitor).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;platformio.ini&lt;/code&gt;&lt;/strong&gt;: the project config is text, versionable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-platform&lt;/strong&gt; and multi-board: switch from ESP32 to ESP8266, STM32 or
RP2040.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging&lt;/strong&gt; with &lt;code&gt;debug_tool&lt;/code&gt; and the right hardware.&lt;/li&gt;
&lt;li&gt;Per-project dependency management (not global).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt; almost everything, especially if you will have several projects.&lt;/p&gt;
&lt;h2 id=&quot;vs-code-the-esp-idf-extension&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#vs-code-the-esp-idf-extension&quot; aria-label=&quot;Anchor link for: vs-code-the-esp-idf-extension&quot;&gt;VS Code + the ESP-IDF extension&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you pick &lt;strong&gt;ESP-IDF&lt;/strong&gt;, this is the official option: it integrates &lt;code&gt;idf.py&lt;/code&gt;,
&lt;code&gt;menuconfig&lt;/code&gt;, the serial monitor and &lt;strong&gt;JTAG debugging&lt;/strong&gt; inside VS Code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; official, real JTAG, Kconfig one click away.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; it is meant &lt;em&gt;only&lt;/em&gt; for ESP-IDF; the flow differs a bit from
PlatformIO.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt; serious ESP-IDF projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;thonny-micropython&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#thonny-micropython&quot; aria-label=&quot;Anchor link for: thonny-micropython&quot;&gt;Thonny (MicroPython)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For MicroPython, Thonny is the friendliest thing around: one button to flash the
firmware, a built-in REPL and a file browser for the board.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt; teaching, learning, quick prototypes.&lt;/p&gt;
&lt;h2 id=&quot;clion-rustrover-vs-code-rust&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#clion-rustrover-vs-code-rust&quot; aria-label=&quot;Anchor link for: clion-rustrover-vs-code-rust&quot;&gt;CLion / RustRover / VS Code (Rust)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you program in &lt;strong&gt;Rust&lt;/strong&gt;, the flow is &lt;code&gt;cargo&lt;/code&gt; + &lt;code&gt;espflash&lt;/code&gt;, so almost any editor
works. VS Code with &lt;code&gt;rust-analyzer&lt;/code&gt; is enough; CLion adds better refactoring and
debugging.&lt;/p&gt;
&lt;h2 id=&quot;how-to-choose-without-getting-it-wrong&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-choose-without-getting-it-wrong&quot; aria-label=&quot;Anchor link for: how-to-choose-without-getting-it-wrong&quot;&gt;How to choose (without getting it wrong)&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;If you use…&lt;/th&gt;&lt;th&gt;Use…&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Arduino core&lt;/td&gt;&lt;td&gt;&lt;strong&gt;VS Code + PlatformIO&lt;/strong&gt; (or Arduino IDE to start)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP-IDF&lt;/td&gt;&lt;td&gt;&lt;strong&gt;VS Code + ESP-IDF&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MicroPython&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Thonny&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust&lt;/td&gt;&lt;td&gt;&lt;strong&gt;VS Code&lt;/strong&gt; + &lt;code&gt;rust-analyzer&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Several frameworks&lt;/td&gt;&lt;td&gt;&lt;strong&gt;VS Code + PlatformIO&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;You do not have to decide forever: VS Code + PlatformIO covers almost every
framework, so you can start there and add the ESP-IDF extension when you need
it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;extras-that-make-a-difference&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#extras-that-make-a-difference&quot; aria-label=&quot;Anchor link for: extras-that-make-a-difference&quot;&gt;Extras that make a difference&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Serial monitor with colors and timestamps&lt;/strong&gt;: that is 30 % of your working time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JTAG debugging&lt;/strong&gt; (ESP32-S3/C3): real breakpoints, not &lt;code&gt;printf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic formatting&lt;/strong&gt; (&lt;code&gt;clang-format&lt;/code&gt;) and linting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrated Git&lt;/strong&gt;: firmware deserves version control too.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arduino IDE 2.x&lt;/strong&gt;: start fast. &lt;strong&gt;PlatformIO&lt;/strong&gt;: the most complete and
versatile. &lt;strong&gt;VS Code + ESP-IDF&lt;/strong&gt;: the official one for ESP-IDF. &lt;strong&gt;Thonny&lt;/strong&gt;:
MicroPython.&lt;/li&gt;
&lt;li&gt;Choose based on your &lt;strong&gt;framework&lt;/strong&gt;, not habit.&lt;/li&gt;
&lt;li&gt;PlatformIO is the safest bet if you will touch several frameworks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JTAG debugging&lt;/strong&gt; is the quality jump once the project grows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;Arduino IDE 2.x step by step&lt;/a&gt; or
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;VS Code + PlatformIO&lt;/a&gt;. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rust on the ESP32: esp-idf-hal, esp-hal and embassy without drama</title>
        <published>2026-09-30T00:00:00+00:00</published>
        <updated>2026-09-30T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/rust-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/rust-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/rust-esp32/">&lt;p&gt;Rust on the ESP32 stopped being an experiment a while ago. Today the &lt;code&gt;esp-rs&lt;/code&gt;
ecosystem is &lt;strong&gt;stable and surprisingly pleasant&lt;/strong&gt;, with one huge advantage: the
compiler saves you from memory and concurrency bugs that cost you an afternoon of
debugging in C.&lt;/p&gt;
&lt;p&gt;The trade-off: you have to learn Rust and set up a separate toolchain.&lt;/p&gt;
&lt;h2 id=&quot;two-paths-not-one&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#two-paths-not-one&quot; aria-label=&quot;Anchor link for: two-paths-not-one&quot;&gt;Two paths, not one&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Path&lt;/th&gt;&lt;th&gt;What it is&lt;/th&gt;&lt;th&gt;Best for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;esp-idf-hal&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Rust on top of ESP-IDF, with &lt;strong&gt;&lt;code&gt;std&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Reusing ESP-IDF, Wi-Fi, larger projects&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;esp-hal&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;no_std&lt;/code&gt;&lt;/strong&gt;, without ESP-IDF&lt;/td&gt;&lt;td&gt;Total control, small binaries, async&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;embassy&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Async&lt;/strong&gt; framework on &lt;code&gt;esp-hal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Elegant concurrent tasks&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The rule: if you want easy Wi-Fi and Espressif APIs, &lt;strong&gt;&lt;code&gt;esp-idf-hal&lt;/code&gt;&lt;/strong&gt;. If you want
to squeeze everything and do not mind &lt;code&gt;no_std&lt;/code&gt;, &lt;strong&gt;&lt;code&gt;esp-hal&lt;/code&gt; + &lt;code&gt;embassy&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;toolchain&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#toolchain&quot; aria-label=&quot;Anchor link for: toolchain&quot;&gt;Toolchain&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The official installer is &lt;code&gt;espup&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;cargo&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; espup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;espup&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;          #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; installs Xtensa and RISC-V targets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;.&lt;/span&gt;&lt;span&gt; $&lt;/span&gt;&lt;span&gt;HOME&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;/export-esp.sh&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;  #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; or the script it generates&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And to flash, &lt;code&gt;cargo-espflash&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;cargo&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; cargo-espflash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;cargo&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; espflash&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; flash&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;-monitor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Current HAL version: &lt;strong&gt;&lt;code&gt;esp-hal&lt;/code&gt; 1.2.0&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;example-blink-with-esp-idf-hal-with-std&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#example-blink-with-esp-idf-hal-with-std&quot; aria-label=&quot;Anchor link for: example-blink-with-esp-idf-hal-with-std&quot;&gt;Example: blink with &lt;code&gt;esp-idf-hal&lt;/code&gt; (with &lt;code&gt;std&lt;/code&gt;)&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;hal&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;FreeRtos&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;hal&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;gpio&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;PinDriver&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;hal&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;Peripherals&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; anyhow&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;Result&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    esp_idf_svc&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;sys&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;link_patches&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    let&lt;/span&gt;&lt;span&gt; peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; Peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;take&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; mut&lt;/span&gt;&lt;span&gt; led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; PinDriver&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;output&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;peripherals&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span&gt;pins&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span&gt;gpio2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    loop&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;set_high&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        FreeRtos&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;delay_ms&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;set_low&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        FreeRtos&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;delay_ms&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the detail: &lt;strong&gt;the compiler forces you&lt;/strong&gt; to declare the pin as an output
before writing. In C, a forgotten &lt;code&gt;pinMode&lt;/code&gt; is a silent bug; here it does not
compile.&lt;/p&gt;
&lt;h2 id=&quot;async-with-embassy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#async-with-embassy&quot; aria-label=&quot;Anchor link for: async-with-embassy&quot;&gt;Async with &lt;code&gt;embassy&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The best part of the &lt;code&gt;no_std&lt;/code&gt; path is &lt;code&gt;embassy&lt;/code&gt;: real asynchronous tasks, with no
&lt;code&gt;loop()&lt;/code&gt; and no hand-written state machines.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;embassy_executor&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; blink&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;mut&lt;/span&gt;&lt;span&gt; led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; Output&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;static&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; Gpio2&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    loop&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;toggle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        Timer&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;after_millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;500&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;await&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two tasks “sleeping” at the same time without blocking each other: that is the
modern way to write concurrent firmware.&lt;/p&gt;
&lt;h2 id=&quot;real-advantages&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#real-advantages&quot; aria-label=&quot;Anchor link for: real-advantages&quot;&gt;Real advantages&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Safety&lt;/strong&gt;: no &lt;em&gt;use-after-free&lt;/em&gt;, no data races, no &lt;em&gt;null&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Honest concurrency&lt;/strong&gt;: if it compiles, it usually does not stomp memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Small binaries&lt;/strong&gt; in &lt;code&gt;no_std&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cargo&lt;/code&gt;&lt;/strong&gt;: dependencies, tests and docs in one place.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;downsides&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#downsides&quot; aria-label=&quot;Anchor link for: downsides&quot;&gt;Downsides&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learning curve&lt;/strong&gt; for Rust (borrows, &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;no_std&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Younger ecosystem&lt;/strong&gt; than Arduino: fewer ready-made libraries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Separate toolchain&lt;/strong&gt;: &lt;code&gt;espup&lt;/code&gt;, targets, a specific Rust version.&lt;/li&gt;
&lt;li&gt;Fewer examples and tutorials than in C/C++.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;when-to-choose-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-choose-it&quot; aria-label=&quot;Anchor link for: when-to-choose-it&quot;&gt;When to choose it?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You care about &lt;strong&gt;reliability&lt;/strong&gt; and want fewer weird bugs.&lt;/li&gt;
&lt;li&gt;You already know Rust (or want to learn it properly).&lt;/li&gt;
&lt;li&gt;You need real &lt;strong&gt;async&lt;/strong&gt; or very small binaries.&lt;/li&gt;
&lt;li&gt;It is a long-term project where maintenance matters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;No:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is your first contact with microcontrollers: start with Arduino or
MicroPython.&lt;/li&gt;
&lt;li&gt;You need a specific library that only exists in C++.&lt;/li&gt;
&lt;li&gt;You are in a hurry.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Two paths: &lt;strong&gt;&lt;code&gt;esp-idf-hal&lt;/code&gt;&lt;/strong&gt; (with &lt;code&gt;std&lt;/code&gt;, on ESP-IDF) and &lt;strong&gt;&lt;code&gt;esp-hal&lt;/code&gt;&lt;/strong&gt;
(&lt;em&gt;no_std&lt;/em&gt;), plus &lt;strong&gt;&lt;code&gt;embassy&lt;/code&gt;&lt;/strong&gt; for async.&lt;/li&gt;
&lt;li&gt;Toolchain with &lt;strong&gt;&lt;code&gt;espup&lt;/code&gt;&lt;/strong&gt; and flashing with &lt;strong&gt;&lt;code&gt;cargo-espflash&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The compiler &lt;strong&gt;prevents errors&lt;/strong&gt; that are silent in C.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;esp-hal&lt;/code&gt; is on &lt;strong&gt;1.2.0&lt;/strong&gt; and the ecosystem is now mature.&lt;/li&gt;
&lt;li&gt;It is worth it if you care about maintenance and safety.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; a change of scene with the &lt;strong&gt;IDEs&lt;/strong&gt;:
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;which one to use and why&lt;/a&gt;. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>MicroPython and Lua on the ESP32: programming without compiling</title>
        <published>2026-09-29T00:00:00+00:00</published>
        <updated>2026-09-29T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/micropython-lua-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/micropython-lua-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/micropython-lua-esp32/">&lt;p&gt;There is a way to program the ESP32 where you &lt;strong&gt;compile nothing&lt;/strong&gt;: you flash a
firmware, open a console and type Python. In five minutes you have an LED
blinking. It is called &lt;strong&gt;MicroPython&lt;/strong&gt; and it is the best on-ramp there is.&lt;/p&gt;
&lt;p&gt;The other side: it is slower and not everything is covered. Let’s be honest about
it.&lt;/p&gt;
&lt;h2 id=&quot;what-micropython-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-micropython-is&quot; aria-label=&quot;Anchor link for: what-micropython-is&quot;&gt;What MicroPython is&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is a Python 3 implementation &lt;strong&gt;made for microcontrollers&lt;/strong&gt;. It is small, fits
on the ESP32 and gives you a &lt;strong&gt;REPL&lt;/strong&gt; (interactive console) over USB or Wi-Fi.&lt;/p&gt;
&lt;h2 id=&quot;flash-and-connect&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#flash-and-connect&quot; aria-label=&quot;Anchor link for: flash-and-connect&quot;&gt;Flash and connect&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Install it with &lt;code&gt;esptool&lt;/code&gt; (the firmware is published by micropython.org):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;esptool.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;-chip&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; esp32&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; /dev/ttyUSB0&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; erase_flash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;esptool.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;-chip&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; esp32&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; /dev/ttyUSB0&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; write_flash&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 0x1000&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; esp32-&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;.bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And to talk to the board, &lt;code&gt;mpremote&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;mpremote&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; connect&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; /dev/ttyUSB0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; machine,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; led&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; machine.Pin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;2,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; machine.Pin.OUT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;u&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;     led.value&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; led.value&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; time.sleep(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is it. No compiling, no &lt;code&gt;setup()&lt;/code&gt;, no &lt;code&gt;loop()&lt;/code&gt;. Perfect for learning.&lt;/p&gt;
&lt;h2 id=&quot;upload-your-code&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#upload-your-code&quot; aria-label=&quot;Anchor link for: upload-your-code&quot;&gt;Upload your code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ESP32 shows up as a &lt;strong&gt;file system&lt;/strong&gt; (with &lt;code&gt;boot.py&lt;/code&gt; and &lt;code&gt;main.py&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;mpremote&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; main.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; :main.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;     #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; copy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;mpremote&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; main.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;             #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; run without copying&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main.py&lt;/code&gt; runs automatically on boot.&lt;/p&gt;
&lt;h2 id=&quot;the-good&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-good&quot; aria-label=&quot;Anchor link for: the-good&quot;&gt;The good&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Minimal curve&lt;/strong&gt; if you know Python (or if you do not).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instant iteration&lt;/strong&gt;: try a line and see the result.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Great for teaching&lt;/strong&gt; and for workshops.&lt;/li&gt;
&lt;li&gt;Good modules: &lt;code&gt;machine&lt;/code&gt;, &lt;code&gt;network&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;socket&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-bad-important&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-bad-important&quot; aria-label=&quot;Anchor link for: the-bad-important&quot;&gt;The bad (important)&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Speed&lt;/strong&gt;: it is interpreted, so forget fine &lt;em&gt;timing&lt;/em&gt; or audio/video
processing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt;: the interpreter takes part of the RAM; PSRAM helps, but it is not
C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peripherals&lt;/strong&gt;: not every ESP32 feature is exposed. If one is missing, you
usually drop to C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real time&lt;/strong&gt;: no real priority tasks like in FreeRTOS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production&lt;/strong&gt;: for a serious product, you almost always end up in C/C++ or
Rust.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;and-lua-nodemcu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#and-lua-nodemcu&quot; aria-label=&quot;Anchor link for: and-lua-nodemcu&quot;&gt;And Lua (NodeMCU)?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was popular with the ESP8266. Today it is largely parked: less support, fewer
libraries, and MicroPython is nicer and more alive. &lt;strong&gt;For new projects, I do not
recommend it.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;quick-comparison&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#quick-comparison&quot; aria-label=&quot;Anchor link for: quick-comparison&quot;&gt;Quick comparison&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;MicroPython&lt;/th&gt;&lt;th&gt;Arduino&lt;/th&gt;&lt;th&gt;ESP-IDF&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Compile&lt;/td&gt;&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Speed&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Available RAM&lt;/td&gt;&lt;td&gt;Less&lt;/td&gt;&lt;td&gt;Lots&lt;/td&gt;&lt;td&gt;Lots&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tasks&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;1 loop&lt;/td&gt;&lt;td&gt;&lt;strong&gt;N tasks&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Curve&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Very low&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Best for&lt;/td&gt;&lt;td&gt;Learning, prototypes&lt;/td&gt;&lt;td&gt;Everything&lt;/td&gt;&lt;td&gt;Products&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;when-to-use-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-use-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-use-it-and-when-not-to&quot;&gt;When to use it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are learning or teaching.&lt;/li&gt;
&lt;li&gt;You want to try an idea in 10 minutes.&lt;/li&gt;
&lt;li&gt;The project is a sensor that publishes and does not need speed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;No:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need precise &lt;em&gt;timing&lt;/em&gt; or DSP.&lt;/li&gt;
&lt;li&gt;You are going to production with memory or power constraints.&lt;/li&gt;
&lt;li&gt;You need a peripheral that is not exposed in Python.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MicroPython&lt;/strong&gt;: Python on the ESP32, no compiling, with a REPL and a file
system. Current version: &lt;strong&gt;1.29&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;the best way to start&lt;/strong&gt; and to prototype fast.&lt;/li&gt;
&lt;li&gt;It is slower and uses more RAM: it does not fit everything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lua/NodeMCU&lt;/strong&gt; is no longer worth it for new projects.&lt;/li&gt;
&lt;li&gt;You can start in MicroPython and drop to C/Rust when the project demands it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;Rust on the ESP32&lt;/a&gt;, the other extreme:
maximum safety and control. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP-IDF in depth: projects, tasks, logs and partitions</title>
        <published>2026-09-28T00:00:00+00:00</published>
        <updated>2026-09-28T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp-idf-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp-idf-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp-idf-a-fondo/">&lt;p&gt;If the Arduino core hides the ESP32, &lt;strong&gt;ESP-IDF shows you everything&lt;/strong&gt;. It is
Espressif’s official SDK and the base everything else is built on. It has a
steeper curve, yes, but it also gives you the control a product needs.&lt;/p&gt;
&lt;p&gt;Let’s cover what matters without drowning in docs.&lt;/p&gt;
&lt;h2 id=&quot;project-layout&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#project-layout&quot; aria-label=&quot;Anchor link for: project-layout&quot;&gt;Project layout&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;my-project/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── CMakeLists.txt          # project (almost always the same)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── sdkconfig               # generated configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── main/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── CMakeLists.txt      # registers main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── main.c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The root &lt;code&gt;CMakeLists.txt&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cmake&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;cmake_minimum_required&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;VERSION&lt;/span&gt;&lt;span&gt; 3.16)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;$ENV{IDF_PATH}&lt;/span&gt;&lt;span&gt;/tools/cmake/project.cmake)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;project&lt;/span&gt;&lt;span&gt;(my-project)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the one in &lt;code&gt;main/&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cmake&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;idf_component_register(SRCS &lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;main.c&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       INCLUDE_DIRS &lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;the-commands-you-will-use&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-commands-you-will-use&quot; aria-label=&quot;Anchor link for: the-commands-you-will-use&quot;&gt;The commands you will use&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;idf.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; set-target&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; esp32s3&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;   #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; pick the chip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;idf.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; menuconfig&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;           #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; configure (Kconfig)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;idf.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; build&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;                #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; compile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;idf.py&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; flash&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; monitor&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;        #&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; flash and open the monitor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;menuconfig&lt;/code&gt; is one of the best things in ESP-IDF: you change options (Wi-Fi,
logs, partitions, PSRAM) without touching code, and they are stored in
&lt;code&gt;sdkconfig&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hello-world-with-logs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hello-world-with-logs&quot; aria-label=&quot;Anchor link for: hello-world-with-logs&quot;&gt;Hello world with logs&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;esp_log.h&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; *&lt;/span&gt;&lt;span&gt;TAG &lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; app_main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    ESP_LOGI&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TAG&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;Starting…&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    ESP_LOGW&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TAG&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;This is a warning&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    ESP_LOGE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TAG&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;And this an error&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No &lt;code&gt;printf&lt;/code&gt;: use &lt;strong&gt;log levels&lt;/strong&gt;. You can raise or lower the level per component
from &lt;code&gt;menuconfig&lt;/code&gt;, and turn almost all of them off in production.&lt;/p&gt;
&lt;h2 id=&quot;tasks-the-heart-of-esp-idf&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#tasks-the-heart-of-esp-idf&quot; aria-label=&quot;Anchor link for: tasks-the-heart-of-esp-idf&quot;&gt;Tasks: the heart of ESP-IDF&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the big difference from Arduino. Instead of a &lt;code&gt;loop()&lt;/code&gt;, you create
FreeRTOS &lt;strong&gt;tasks&lt;/strong&gt; with their own priority and stack size:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; sensor_task&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: light-dark(#E36209, #FFAB70);&quot;&gt;arg&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        read_sensor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;        vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; app_main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    xTaskCreate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sensor_task&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;sensor&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 4096&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Real benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;True parallelism&lt;/strong&gt;: one task measures, another publishes over MQTT.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;vTaskDelay&lt;/code&gt; does not block&lt;/strong&gt; the rest of the system.&lt;/li&gt;
&lt;li&gt;You control &lt;strong&gt;stack&lt;/strong&gt; and &lt;strong&gt;priority&lt;/strong&gt;, which is what prevents weird reboots.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;partitions-and-ota&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#partitions-and-ota&quot; aria-label=&quot;Anchor link for: partitions-and-ota&quot;&gt;Partitions and OTA&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Flash is not a single block: it is &lt;strong&gt;partitioned&lt;/strong&gt; (a &lt;code&gt;partitions.csv&lt;/code&gt; table). By
default there are two application slots (&lt;code&gt;app0&lt;/code&gt; and &lt;code&gt;app1&lt;/code&gt;) so you can do &lt;strong&gt;OTA&lt;/strong&gt;
(Wi-Fi updates) with &lt;em&gt;rollback&lt;/em&gt; if something fails.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;csv&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Name,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;   Type,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; SubType,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; Offset,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;  Size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvs,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;      data,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; nvs,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;     0x9000,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;  0x4000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;factory,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  app,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  factory,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt; 0x10000,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; 1M&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An OTA-style partition table:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;csv&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Name,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;   Type,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; SubType,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;  Size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvs,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;      data,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; nvs,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;      0x4000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;otadata,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  data,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; ota,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;      0x2000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;phy_init,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; data,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; phy,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;      0x1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;factory,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  app,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  factory,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;  1M&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ota_0,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    app,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  ota_0,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;    1M&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ota_1,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    app,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  ota_1,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6A737D, #6A737D);&quot;&gt;    1M&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wiring-arduino-or-esp-idf&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wiring-arduino-or-esp-idf&quot; aria-label=&quot;Anchor link for: wiring-arduino-or-esp-idf&quot;&gt;Wiring: Arduino or ESP-IDF?&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Arduino core&lt;/th&gt;&lt;th&gt;ESP-IDF&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Curve&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Control&lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tasks&lt;/td&gt;&lt;td&gt;1 &lt;em&gt;loop&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;N tasks&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Memory&lt;/td&gt;&lt;td&gt;Automatic&lt;/td&gt;&lt;td&gt;&lt;strong&gt;You decide&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OTA&lt;/td&gt;&lt;td&gt;Easy&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Complete&lt;/strong&gt; (rollback)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Logs&lt;/td&gt;&lt;td&gt;&lt;code&gt;Serial&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Per-component levels&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;when-it-is-worth-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-it-is-worth-it&quot; aria-label=&quot;Anchor link for: when-it-is-worth-it&quot;&gt;When it is worth it&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Yes&lt;/strong&gt;: products, battery, fine &lt;em&gt;timing&lt;/em&gt;, serious OTA, many peripherals.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No&lt;/strong&gt;: if you just want to read a sensor and publish, Arduino gets you there
in an afternoon and is more than enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: you can mix them. The Arduino core &lt;strong&gt;is&lt;/strong&gt; ESP-IDF underneath, so from a
sketch you can call ESP-IDF APIs when you need them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ESP-IDF is the official SDK: &lt;strong&gt;CMake + &lt;code&gt;idf.py&lt;/code&gt; + &lt;code&gt;menuconfig&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use FreeRTOS &lt;strong&gt;tasks&lt;/strong&gt;, not a &lt;code&gt;loop()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log levels&lt;/strong&gt; with &lt;code&gt;ESP_LOGx&lt;/code&gt; instead of &lt;code&gt;printf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Flash is &lt;strong&gt;partitioned&lt;/strong&gt;; OTA with &lt;em&gt;rollback&lt;/em&gt; comes almost for free.&lt;/li&gt;
&lt;li&gt;Current version: &lt;strong&gt;6.1&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;MicroPython and Lua&lt;/a&gt; for the opposite
extreme: zero compiling. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Arduino core for ESP32 in depth: install it, understand it, stop fighting it</title>
        <published>2026-09-27T00:00:00+00:00</published>
        <updated>2026-09-27T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/arduino-core-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/arduino-core-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/arduino-core-esp32/">&lt;p&gt;The “Arduino core for ESP32” is why half the world uses this chip. It lets you
write &lt;code&gt;pinMode()&lt;/code&gt; and &lt;code&gt;digitalWrite()&lt;/code&gt; like on an Arduino UNO, but underneath
there is an &lt;strong&gt;ESP32 running FreeRTOS&lt;/strong&gt;. Understanding that layer is the difference
between copying examples and knowing what you are doing.&lt;/p&gt;
&lt;h2 id=&quot;what-it-actually-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-actually-is&quot; aria-label=&quot;Anchor link for: what-it-actually-is&quot;&gt;What it actually is&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is not an emulated Arduino. Since version 3.x, the core is a &lt;strong&gt;wrapper over
ESP-IDF&lt;/strong&gt;: your &lt;code&gt;setup()&lt;/code&gt; and &lt;code&gt;loop()&lt;/code&gt; run inside a real &lt;strong&gt;FreeRTOS task&lt;/strong&gt; (called
&lt;em&gt;loopTask&lt;/em&gt;), on &lt;strong&gt;core 1&lt;/strong&gt;, with 8 KB of stack by default.&lt;/p&gt;
&lt;p&gt;That explains two very typical things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If your &lt;code&gt;loop()&lt;/code&gt; hangs, the &lt;strong&gt;watchdog&lt;/strong&gt; fires and the board reboots.&lt;/li&gt;
&lt;li&gt;If the project grows, you can &lt;strong&gt;create tasks&lt;/strong&gt; with &lt;code&gt;xTaskCreatePinnedToCore()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;installation-two-ways&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation-two-ways&quot; aria-label=&quot;Anchor link for: installation-two-ways&quot;&gt;Installation (two ways)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Arduino IDE&lt;/strong&gt; — add the board URL in &lt;em&gt;Preferences&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https://espressif.github.io/arduino-esp32/package_esp32_index.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then install “esp32 by Espressif” from the &lt;strong&gt;Boards Manager&lt;/strong&gt; and pick your board.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PlatformIO&lt;/strong&gt; (my recommendation) — &lt;code&gt;platformio.ini&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;env:esp32dev&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;platform&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; espressif32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;board&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; esp32dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;framework&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arduino&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;monitor_speed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;setup-and-loop-under-the-hood&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#setup-and-loop-under-the-hood&quot; aria-label=&quot;Anchor link for: setup-and-loop-under-the-hood&quot;&gt;&lt;code&gt;setup()&lt;/code&gt; and &lt;code&gt;loop()&lt;/code&gt; under the hood&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Serial&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;115200&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  pinMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; OUTPUT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  digitalWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;digitalRead&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;  delay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works, but keep in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;delay()&lt;/code&gt; &lt;strong&gt;blocks&lt;/strong&gt; the task. With Wi-Fi or several sensors, use &lt;code&gt;millis()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setup()&lt;/code&gt; runs &lt;strong&gt;once&lt;/strong&gt;; if you want parallel work, create tasks there.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;watchdog&lt;/strong&gt; watches the loop: take too long and it reboots.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anti-blocking version:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;constexpr&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; unsigned&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; long&lt;/span&gt;&lt;span&gt; INTERVAL&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 1000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; -&lt;/span&gt;&lt;span&gt; last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span&gt; INTERVAL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    last&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; millis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    digitalWrite&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;digitalRead&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;libraries-not-all-of-them-work&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#libraries-not-all-of-them-work&quot; aria-label=&quot;Anchor link for: libraries-not-all-of-them-work&quot;&gt;Libraries: not all of them work&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Generic Arduino&lt;/strong&gt; libraries usually work if they do not touch AVR registers.&lt;/li&gt;
&lt;li&gt;Those using &lt;strong&gt;timers&lt;/strong&gt; or specific interrupts may fail.&lt;/li&gt;
&lt;li&gt;For sensors, look for the “ESP32” version or use the vendor library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Wire&lt;/code&gt;&lt;/strong&gt; (I2C) and &lt;strong&gt;&lt;code&gt;SPI&lt;/code&gt;&lt;/strong&gt; exist, but you can choose the pins.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;differences-from-an-arduino-uno&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#differences-from-an-arduino-uno&quot; aria-label=&quot;Anchor link for: differences-from-an-arduino-uno&quot;&gt;Differences from an Arduino UNO&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Arduino UNO&lt;/th&gt;&lt;th&gt;ESP32&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Voltage&lt;/td&gt;&lt;td&gt;5 V&lt;/td&gt;&lt;td&gt;&lt;strong&gt;3.3 V&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bits&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;&lt;strong&gt;32&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;EEPROM&lt;/td&gt;&lt;td&gt;1 KB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt; (use &lt;code&gt;Preferences&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;10-bit&lt;/td&gt;&lt;td&gt;&lt;strong&gt;12-bit&lt;/strong&gt; (and ADC2 with Wi-Fi, careful)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cores&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Saving something in the ESP32 “EEPROM” is done like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;Preferences.h&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Preferences&lt;/span&gt;&lt;span&gt; prefs&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  prefs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;my-app&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;  int&lt;/span&gt;&lt;span&gt; boots&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; =&lt;/span&gt;&lt;span&gt; prefs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;getInt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  prefs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;putInt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; boots&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  prefs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;end&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;good-practices&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#good-practices&quot; aria-label=&quot;Anchor link for: good-practices&quot;&gt;Good practices&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Do not block the loop&lt;/strong&gt;: use &lt;code&gt;millis()&lt;/code&gt;, tasks or &lt;code&gt;vTaskDelay&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serial at 115200&lt;/strong&gt;, and wait a moment after &lt;code&gt;begin()&lt;/code&gt; if needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do not abuse &lt;code&gt;String&lt;/code&gt;&lt;/strong&gt;: it fragments memory. Use &lt;code&gt;char[]&lt;/code&gt; and &lt;code&gt;snprintf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Split your code&lt;/strong&gt; into files; a 2000-line &lt;code&gt;.ino&lt;/code&gt; is painful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debug with logs&lt;/strong&gt;, not &lt;code&gt;Serial.println&lt;/code&gt; everywhere.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;when-to-move-to-esp-idf&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-move-to-esp-idf&quot; aria-label=&quot;Anchor link for: when-to-move-to-esp-idf&quot;&gt;When to move to ESP-IDF&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you need fine control over tasks and memory, precise &lt;em&gt;timing&lt;/em&gt;, serious OTA
partitions, or to squeeze power. The Arduino core hides a lot, and sometimes that
is fine… until it is not.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It is a &lt;strong&gt;wrapper over ESP-IDF&lt;/strong&gt;; your &lt;code&gt;setup&lt;/code&gt;/&lt;code&gt;loop&lt;/code&gt; are a FreeRTOS task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;delay()&lt;/code&gt; blocks&lt;/strong&gt;; learn &lt;code&gt;millis()&lt;/code&gt; from day one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3.3 V&lt;/strong&gt;, no EEPROM (use &lt;strong&gt;NVS/Preferences&lt;/strong&gt;), 12-bit ADC.&lt;/li&gt;
&lt;li&gt;Not every Arduino library compiles: check compatibility.&lt;/li&gt;
&lt;li&gt;Current core version: &lt;strong&gt;3.3.11&lt;/strong&gt; (on ESP-IDF 5.5.5).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP-IDF in depth&lt;/a&gt; for when you need total
control. Or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Which framework should you use on the ESP32? Arduino, ESP-IDF, MicroPython or Rust</title>
        <published>2026-09-26T00:00:00+00:00</published>
        <updated>2026-09-26T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/framework-esp32-comparativa/"/>
        <id>https://esp32.tunatek.tech/en/blog/framework-esp32-comparativa/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/framework-esp32-comparativa/">&lt;p&gt;Here comes the most repeated question: &lt;strong&gt;what do I program the ESP32 with?&lt;/strong&gt; The
short answer is “it depends”, and the useful answer is this table. Pick based on
where you stand and what you want to achieve.&lt;/p&gt;
&lt;h2 id=&quot;the-five-paths&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-five-paths&quot; aria-label=&quot;Anchor link for: the-five-paths&quot;&gt;The five paths&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Framework&lt;/th&gt;&lt;th&gt;Language&lt;/th&gt;&lt;th&gt;Curve&lt;/th&gt;&lt;th&gt;Control&lt;/th&gt;&lt;th&gt;Best for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Arduino core&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;Very low&lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;td&gt;Starting, prototypes, sensors&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ESP-IDF&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;C (C++)&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Products, RTOS, performance&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;MicroPython&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Python&lt;/td&gt;&lt;td&gt;Very low&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Learning, quick tests&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Rust&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Rust&lt;/td&gt;&lt;td&gt;Medium-high&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;td&gt;Robustness, safety, &lt;em&gt;no_std&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Lua (NodeMCU)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Lua&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Legacy, very simple scripts&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Let us be clear: there is &lt;strong&gt;no best one&lt;/strong&gt;, there is a better one &lt;em&gt;for you right
now&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;arduino-core-where-almost-everyone-starts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#arduino-core-where-almost-everyone-starts&quot; aria-label=&quot;Anchor link for: arduino-core-where-almost-everyone-starts&quot;&gt;Arduino core: where almost everyone starts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You write &lt;code&gt;setup()&lt;/code&gt; and &lt;code&gt;loop()&lt;/code&gt;, call &lt;code&gt;pinMode()&lt;/code&gt;, &lt;code&gt;digitalWrite()&lt;/code&gt;, and that is
it. Thousands of libraries and examples.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; you start in an afternoon, huge community, everyone can help you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; it hides things (tasks, memory, partitions), and when something weird
happens, you do not know where to look.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Current version:&lt;/strong&gt; &lt;strong&gt;3.3.11&lt;/strong&gt; (built on ESP-IDF 5.5.5).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Use it if&lt;/strong&gt; you are starting, building a prototype, or coming from Arduino.&lt;/p&gt;
&lt;h2 id=&quot;esp-idf-the-real-one&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp-idf-the-real-one&quot; aria-label=&quot;Anchor link for: esp-idf-the-real-one&quot;&gt;ESP-IDF: the “real” one&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is Espressif’s official SDK. Here you control everything: &lt;strong&gt;FreeRTOS&lt;/strong&gt;, tasks,
queues, partitions, &lt;em&gt;menuconfig&lt;/em&gt;, logs, power, security.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; total control, better performance, fully documented by the vendor, the
base of everything else.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; more concepts to learn and more code for the same thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Current version:&lt;/strong&gt; &lt;strong&gt;6.1&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Use it if&lt;/strong&gt; you are going to production, need fine &lt;em&gt;timing&lt;/em&gt;, or want to squeeze
the hardware.&lt;/p&gt;
&lt;h2 id=&quot;micropython-understand-it-in-5-minutes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#micropython-understand-it-in-5-minutes&quot; aria-label=&quot;Anchor link for: micropython-understand-it-in-5-minutes&quot;&gt;MicroPython: understand it in 5 minutes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Flash the firmware, open a REPL and write Python. Perfect to learn and to tinker
without compiling.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; immediate, fun, great for teaching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; slower, more RAM, and not every peripheral is covered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Current version:&lt;/strong&gt; &lt;strong&gt;1.29&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Use it if&lt;/strong&gt; you want results now, or you come from Python.&lt;/p&gt;
&lt;h2 id=&quot;rust-power-with-a-safety-net&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rust-power-with-a-safety-net&quot; aria-label=&quot;Anchor link for: rust-power-with-a-safety-net&quot;&gt;Rust: power with a safety net&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;esp-rs&lt;/code&gt; ecosystem gives you two paths: &lt;strong&gt;&lt;code&gt;esp-idf-hal&lt;/code&gt;&lt;/strong&gt; (on top of ESP-IDF,
with &lt;code&gt;std&lt;/code&gt;) and &lt;strong&gt;&lt;code&gt;esp-hal&lt;/code&gt; / &lt;code&gt;embassy&lt;/code&gt;&lt;/strong&gt; (&lt;em&gt;no_std&lt;/em&gt;, lighter and async).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; the compiler prevents memory and concurrency bugs, very robust code,
real async with &lt;code&gt;embassy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; learning curve, separate toolchain (&lt;code&gt;espup&lt;/code&gt;), younger ecosystem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Current version:&lt;/strong&gt; &lt;code&gt;esp-hal&lt;/code&gt; &lt;strong&gt;1.2.0&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Use it if&lt;/strong&gt; you care about reliability, come from Rust, or want to learn
something serious.&lt;/p&gt;
&lt;h2 id=&quot;lua-nodemcu-the-past&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lua-nodemcu-the-past&quot; aria-label=&quot;Anchor link for: lua-nodemcu-the-past&quot;&gt;Lua (NodeMCU): the past&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was popular with the ESP8266. Today it is largely abandoned next to
MicroPython. It only makes sense to maintain old projects.&lt;/p&gt;
&lt;h2 id=&quot;the-decision-in-20-seconds&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-decision-in-20-seconds&quot; aria-label=&quot;Anchor link for: the-decision-in-20-seconds&quot;&gt;The decision, in 20 seconds&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Your situation&lt;/th&gt;&lt;th&gt;Start with&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;It is my first microcontroller&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Arduino core&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;I can program, but not C/C++&lt;/td&gt;&lt;td&gt;&lt;strong&gt;MicroPython&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;I need control and performance&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP-IDF&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;I want safety and robustness&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Rust (&lt;code&gt;esp-idf-hal&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;I am building a battery product&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP-IDF&lt;/strong&gt; (or Rust)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;I want to teach someone&lt;/td&gt;&lt;td&gt;&lt;strong&gt;MicroPython&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; you do not have to choose forever. Many people start with Arduino and
jump to ESP-IDF when the project demands it. The concepts (GPIO, I2C, tasks)
carry over.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;what-matters-more-than-the-framework&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-matters-more-than-the-framework&quot; aria-label=&quot;Anchor link for: what-matters-more-than-the-framework&quot;&gt;What matters more than the framework&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Understanding the hardware&lt;/strong&gt;: ADC, reserved pins, power.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Knowing how to debug&lt;/strong&gt;: logs, &lt;code&gt;printf&lt;/code&gt;, measuring signals.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading the datasheet&lt;/strong&gt; when something does not add up.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With that, switching frameworks is a weekend. Without it, none of them saves you.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arduino&lt;/strong&gt;: start fast. &lt;strong&gt;ESP-IDF&lt;/strong&gt;: control and production.
&lt;strong&gt;MicroPython&lt;/strong&gt;: learn and prototype. &lt;strong&gt;Rust&lt;/strong&gt;: robustness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lua&lt;/strong&gt; is no longer worth it for new projects.&lt;/li&gt;
&lt;li&gt;The current version of each is in the table above.&lt;/li&gt;
&lt;li&gt;Choose by your &lt;strong&gt;experience&lt;/strong&gt; and your &lt;strong&gt;goal&lt;/strong&gt;, not by fashion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; let’s go into detail with the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;Arduino core&lt;/a&gt;, the most used one. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP8266 vs ESP32: when the little one is (not) worth it</title>
        <published>2026-09-25T00:00:00+00:00</published>
        <updated>2026-09-25T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp8266-vs-esp32/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp8266-vs-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp8266-vs-esp32/">&lt;p&gt;The ESP8266 put cheap Wi-Fi in everyone’s hands. It was the chip that turned
makers into people able to run a web server in their living room for two dollars.
It still sells, it still gets used, and it still has an audience.&lt;/p&gt;
&lt;p&gt;The honest question is: &lt;strong&gt;does it make sense to buy one today?&lt;/strong&gt; Almost always
no, and here is why.&lt;/p&gt;
&lt;h2 id=&quot;the-differences-that-matter&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-differences-that-matter&quot; aria-label=&quot;Anchor link for: the-differences-that-matter&quot;&gt;The differences that matter&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;ESP8266&lt;/th&gt;&lt;th&gt;ESP32 (classic)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Cores&lt;/td&gt;&lt;td&gt;1 × Xtensa L106 @ 160 MHz&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2 × LX6 @ 240 MHz&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Usable RAM&lt;/td&gt;&lt;td&gt;~50 KB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;~320 KB&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;Wi-Fi 4&lt;/td&gt;&lt;td&gt;Wi-Fi 4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;&lt;strong&gt;BT 4.2 + BLE&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Usable GPIOs&lt;/td&gt;&lt;td&gt;~11&lt;/td&gt;&lt;td&gt;~25&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;1 channel, 10-bit&lt;/td&gt;&lt;td&gt;18 channels, 12-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DAC&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Native USB&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;It is not just “less powerful”: there is &lt;strong&gt;10× less memory&lt;/strong&gt; and very few pins.
That constrains everything you can do.&lt;/p&gt;
&lt;h2 id=&quot;where-the-esp8266-still-shines&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-the-esp8266-still-shines&quot; aria-label=&quot;Anchor link for: where-the-esp8266-still-shines&quot;&gt;Where the ESP8266 still shines&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pure price&lt;/strong&gt;: under $2 on AliExpress.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: to read a sensor and publish over Wi-Fi to one &lt;em&gt;endpoint&lt;/em&gt;, it
is plenty.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Legacy&lt;/strong&gt;: tons of working code and tutorials.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Very low&lt;/strong&gt; &lt;em&gt;deep sleep&lt;/em&gt; current if the project is simple.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;where-it-falls-short-and-it-hurts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-it-falls-short-and-it-hurts&quot; aria-label=&quot;Anchor link for: where-it-falls-short-and-it-hurts&quot;&gt;Where it falls short (and it hurts)&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt;: a big JSON parser or TLS leaves you out of RAM and with random
reboots.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single core&lt;/strong&gt;: Wi-Fi and your code share the CPU, so any long task triggers
&lt;em&gt;watchdog resets&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pins&lt;/strong&gt;: with the ADC and the flash, you are left with very few GPIOs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS&lt;/strong&gt;: modern &lt;em&gt;handshakes&lt;/em&gt; are expensive for this chip.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relevance&lt;/strong&gt;: the ecosystem is now centred on the ESP32.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-comparison-that-actually-matters-today&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-comparison-that-actually-matters-today&quot; aria-label=&quot;Anchor link for: the-comparison-that-actually-matters-today&quot;&gt;The comparison that actually matters today&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the ESP8266 tempts you on price, &lt;strong&gt;compare it with the ESP32-C3&lt;/strong&gt;, not the
classic:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;ESP8266&lt;/th&gt;&lt;th&gt;&lt;strong&gt;ESP32-C3&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Price&lt;/td&gt;&lt;td&gt;~$1.5&lt;/td&gt;&lt;td&gt;~$2–3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Core&lt;/td&gt;&lt;td&gt;Xtensa&lt;/td&gt;&lt;td&gt;&lt;strong&gt;RISC-V @ 160 MHz&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;RAM&lt;/td&gt;&lt;td&gt;~50 KB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;400 KB&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;&lt;strong&gt;BLE 5&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Native USB&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Yes (Serial/JTAG)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;10-bit&lt;/td&gt;&lt;td&gt;&lt;strong&gt;12-bit&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The price gap is &lt;strong&gt;a few cents&lt;/strong&gt; and the C3 is better at everything. That is why
I recommend forgetting the 8266 for a new project.&lt;/p&gt;
&lt;h2 id=&quot;when-to-use-each&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-use-each&quot; aria-label=&quot;Anchor link for: when-to-use-each&quot;&gt;When to use each&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Use the ESP8266 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Price is &lt;em&gt;the only&lt;/em&gt; thing that matters (volume production, toys).&lt;/li&gt;
&lt;li&gt;You have old working code and do not want to touch it.&lt;/li&gt;
&lt;li&gt;The project is a minimal sensor that will never grow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Use an ESP32 (C3) if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need &lt;strong&gt;BLE&lt;/strong&gt;, &lt;strong&gt;more pins&lt;/strong&gt; or &lt;strong&gt;more memory&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You are doing TLS, OTA or non-trivial logic.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;native USB&lt;/strong&gt; and decent debugging.&lt;/li&gt;
&lt;li&gt;You think the project might &lt;strong&gt;grow&lt;/strong&gt; (and it always does).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;migrating-from-the-8266-to-the-esp32-c3&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#migrating-from-the-8266-to-the-esp32-c3&quot; aria-label=&quot;Anchor link for: migrating-from-the-8266-to-the-esp32-c3&quot;&gt;Migrating from the 8266 to the ESP32-C3&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are coming from the 8266 and jumping to the C3, watch out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ESP8266WiFi.h&lt;/code&gt; becomes &lt;code&gt;WiFi.h&lt;/code&gt;&lt;/strong&gt; (and some APIs get renamed).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;ADC is different&lt;/strong&gt;: on the 8266 it is &lt;code&gt;A0&lt;/code&gt; (10-bit); on the C3 you use
ADC1 with 12 bits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deep sleep&lt;/strong&gt; is more flexible: specific GPIOs can wake it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Libraries&lt;/strong&gt; for the 8266 do not always compile: look for the ESP32
equivalent.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;pin mapping&lt;/strong&gt; is nothing alike: do not copy the wiring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The ESP8266 was revolutionary, but &lt;strong&gt;today it is dated&lt;/strong&gt; next to the C3.&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;~50 KB RAM, one core and few pins&lt;/strong&gt;: it runs out of room quickly.&lt;/li&gt;
&lt;li&gt;It only wins when &lt;strong&gt;price&lt;/strong&gt; is everything or the code is inherited.&lt;/li&gt;
&lt;li&gt;For new projects, an &lt;strong&gt;ESP32-C3&lt;/strong&gt; costs about the same and is far superior.&lt;/li&gt;
&lt;li&gt;If you migrate, expect changes in Wi-Fi, ADC and pins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; that closes the variants. Now it is time to
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;choose a framework&lt;/a&gt;: Arduino, ESP-IDF, MicroPython or
Rust. Or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP32-P4 in depth: the radio-less ESP32 for displays and high performance</title>
        <published>2026-09-24T00:00:00+00:00</published>
        <updated>2026-09-24T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-p4-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-p4-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-p4-a-fondo/">&lt;p&gt;The ESP32-P4 breaks the family mould: it has &lt;strong&gt;no Wi-Fi, no Bluetooth, no
802.15.4&lt;/strong&gt;. No radios at all. In exchange, it is the most powerful ESP32 ever made
and the first one designed as an &lt;strong&gt;application processor&lt;/strong&gt;: displays, interfaces,
light video and compute.&lt;/p&gt;
&lt;p&gt;It sounds odd for an ESP32… until you get the trick: &lt;strong&gt;you choose the radio&lt;/strong&gt;. Put
a &lt;strong&gt;C6&lt;/strong&gt; next to it and you get the best of both worlds.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-is&quot; aria-label=&quot;Anchor link for: what-it-is&quot;&gt;What it is&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Cores&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2 × RISC-V @ 400 MHz&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;&lt;strong&gt;768 KB&lt;/strong&gt; on-chip (+ 8 KB TCM)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Radio&lt;/td&gt;&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt; (Wi-Fi/BT via a separate chip)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;OTG 2.0 high-speed&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Others&lt;/td&gt;&lt;td&gt;&lt;strong&gt;MIPI-CSI/DSI&lt;/strong&gt;, Ethernet, SDIO, CAN&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;AI&lt;/td&gt;&lt;td&gt;AI extensions + FPU&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two details set it apart: &lt;strong&gt;MIPI-CSI/DSI&lt;/strong&gt; (real camera and display interfaces,
not SPI) and &lt;strong&gt;high-speed USB&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;you-add-the-radio-yourself&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#you-add-the-radio-yourself&quot; aria-label=&quot;Anchor link for: you-add-the-radio-yourself&quot;&gt;You add the radio yourself&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The P4 deliberately ships no connectivity. The usual setup pairs it with a &lt;strong&gt;C6&lt;/strong&gt;
(which has Wi-Fi 6, BLE and 802.15.4) and splits the work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;P4&lt;/strong&gt; handles the display, the camera and the logic.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;C6&lt;/strong&gt; handles talking to the world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is why the official kit, the &lt;strong&gt;ESP32-P4-Function-EV-Board&lt;/strong&gt;, already includes
a C6.&lt;/p&gt;
&lt;h2 id=&quot;pins-plenty&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pins-plenty&quot; aria-label=&quot;Anchor link for: pins-plenty&quot;&gt;Pins: plenty&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With &lt;strong&gt;55 programmable GPIOs&lt;/strong&gt;, this chip does not have the pin shortage of its
smaller siblings. It also brings blocks for SPI, I2C, I2S, UART, CAN, SDIO,
Ethernet (RMII) and the MIPI interfaces. For the exact mapping, the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.espressif.com/&quot;&gt;Espressif datasheet&lt;/a&gt; is the reference.&lt;/p&gt;
&lt;p&gt;One important note: it &lt;strong&gt;does have an ADC&lt;/strong&gt;, but forget the Wi-Fi that broke ADC2
on other models — there is no radio here to interfere.&lt;/p&gt;
&lt;h2 id=&quot;boards&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#boards&quot; aria-label=&quot;Anchor link for: boards&quot;&gt;Boards&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-P4-Function-EV-Board&lt;/strong&gt; — evaluation board with an &lt;strong&gt;integrated C6&lt;/strong&gt;, a
MIPI display and a camera. The easiest way to start.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-P4-Module&lt;/strong&gt; — for your own PCBs.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/familia-esp32.svg&quot; alt=&quot;The ESP32 family with the P4 at the end&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;The P4 (2024) closes the line: no radio, but as an application processor. Own illustration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-to-pick-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-it-and-when-not-to&quot;&gt;When to pick it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the P4 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are driving &lt;strong&gt;large or touch displays&lt;/strong&gt; (MIPI, not slow SPI).&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;real camera&lt;/strong&gt;, with MIPI-CSI.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;high-speed USB&lt;/strong&gt;, Ethernet or heavy compute.&lt;/li&gt;
&lt;li&gt;You split the project into &lt;strong&gt;processor + radio&lt;/strong&gt; (P4 + C6).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Do not pick it if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You want something &lt;strong&gt;simple with Wi-Fi&lt;/strong&gt;: a &lt;strong&gt;C3&lt;/strong&gt; or &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You want the &lt;strong&gt;cheapest&lt;/strong&gt;: the P4 is not it.&lt;/li&gt;
&lt;li&gt;You do not need a display or heavy compute: you would be overpaying.&lt;/li&gt;
&lt;li&gt;You expect &lt;strong&gt;on-board connectivity&lt;/strong&gt;: it has none (and that surprises people).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Buying it expecting &lt;strong&gt;built-in Wi-Fi&lt;/strong&gt; (it has none; you need the C6).&lt;/li&gt;
&lt;li&gt;Driving a serious display over &lt;strong&gt;SPI&lt;/strong&gt; when you have MIPI-DSI available.&lt;/li&gt;
&lt;li&gt;Forgetting it is a &lt;strong&gt;new chip&lt;/strong&gt;: it needs a recent toolchain (ESP-IDF 5.3+,
today &lt;strong&gt;6.1&lt;/strong&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Two RISC-V cores at 400 MHz&lt;/strong&gt;, &lt;strong&gt;768 KB SRAM&lt;/strong&gt; and &lt;strong&gt;55 GPIOs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MIPI-CSI/DSI&lt;/strong&gt;, USB 2.0 HS and Ethernet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No radio&lt;/strong&gt;: pair it with a &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It is the chip for &lt;strong&gt;HMI, displays and high performance&lt;/strong&gt;, not a dumb sensor.&lt;/li&gt;
&lt;li&gt;If you are torn between P4 and S3: the S3 is cheaper and already has radios; the
P4 is for when you need a real display.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; we close the variants block with
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP8266 vs ESP32&lt;/a&gt; and then move on to &lt;strong&gt;frameworks&lt;/strong&gt;. Or
go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP32-H2 in depth: the Wi-Fi-less ESP32 for battery Matter nodes</title>
        <published>2026-09-23T00:00:00+00:00</published>
        <updated>2026-09-23T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-h2-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-h2-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-h2-a-fondo/">&lt;p&gt;It sounds like a joke: an ESP32 &lt;strong&gt;without Wi-Fi&lt;/strong&gt;. But think about it twice and it
makes perfect sense. The H2 is built for &lt;strong&gt;low-power home automation&lt;/strong&gt;: sensors,
switches and &lt;strong&gt;Matter/Thread&lt;/strong&gt; nodes that have to last months on a battery.&lt;/p&gt;
&lt;p&gt;Fewer radios on = less battery. And if you already have a &lt;em&gt;border router&lt;/em&gt; at home,
a device does not need its own Wi-Fi.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-is&quot; aria-label=&quot;Anchor link for: what-it-is&quot;&gt;What it is&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is a &lt;strong&gt;single-core RISC-V&lt;/strong&gt; SoC focused on low-power wireless, with the flash
&lt;strong&gt;inside the chip itself&lt;/strong&gt; (2 or 4 MB), which simplifies the design a lot.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Core&lt;/td&gt;&lt;td&gt;1 × low-power RISC-V&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;&lt;strong&gt;320 KB&lt;/strong&gt; (+ 4 KB LP memory)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ROM&lt;/td&gt;&lt;td&gt;128 KB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;&lt;strong&gt;BLE 5&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;802.15.4&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Thread / Zigbee / Matter&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;&lt;strong&gt;19&lt;/strong&gt; programmable, with &lt;strong&gt;ADC&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;native Serial/JTAG&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Flash&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2 or 4 MB integrated (SiP)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;why-no-wi-fi-and-why-that-is-fine&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-no-wi-fi-and-why-that-is-fine&quot; aria-label=&quot;Anchor link for: why-no-wi-fi-and-why-that-is-fine&quot;&gt;Why no Wi-Fi (and why that is fine)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The H2 is a &lt;strong&gt;node&lt;/strong&gt; chip, not a gateway. In a &lt;strong&gt;Thread&lt;/strong&gt; network all devices talk
to each other and &lt;strong&gt;only one&lt;/strong&gt; (the &lt;em&gt;border router&lt;/em&gt;) needs Internet access. The
rest can spend their energy on what matters: measuring and sleeping.&lt;/p&gt;
&lt;p&gt;Result: a well-slept H2 uses far less than a C6 with Wi-Fi on. And it does not
compete for spectrum with your home Wi-Fi.&lt;/p&gt;
&lt;h2 id=&quot;pins-what-you-should-know&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pins-what-you-should-know&quot; aria-label=&quot;Anchor link for: pins-what-you-should-know&quot;&gt;Pins: what you should know&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The H2 brings &lt;strong&gt;19 programmable GPIOs&lt;/strong&gt; with &lt;strong&gt;ADC&lt;/strong&gt;, SPI, UART, I2C, I2S, RMT,
GDMA and PWM support. The exact mapping depends on the module, so for fine detail
check the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.espressif.com/&quot;&gt;datasheet&lt;/a&gt;. What is worth keeping clear:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One block of pins acts as &lt;strong&gt;ADC&lt;/strong&gt;; use it for analog sensors.&lt;/li&gt;
&lt;li&gt;There are &lt;em&gt;&lt;strong&gt;strapping&lt;/strong&gt;&lt;/em&gt; pins and pins taken by the &lt;strong&gt;internal flash&lt;/strong&gt;: do not
use them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USB Serial/JTAG&lt;/strong&gt; to flash and debug with no external chip.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;boards-and-modules&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#boards-and-modules&quot; aria-label=&quot;Anchor link for: boards-and-modules&quot;&gt;Boards and modules&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-H2-MINI-1&lt;/strong&gt; — the small module (the usual one, with integrated flash).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-H2-DevKitM-1&lt;/strong&gt; — the development board.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-H2-WROOM-1&lt;/strong&gt; — the classic module.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-h2.svg&quot; alt=&quot;Illustration of the ESP32-H2 and its features&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-H2: BLE 5 + Zigbee/Thread, no Wi-Fi. Own illustration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-to-pick-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-it-and-when-not-to&quot;&gt;When to pick it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the H2 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are doing &lt;strong&gt;Matter/Thread/Zigbee&lt;/strong&gt; automation and want &lt;strong&gt;maximum runtime&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;small, cheap node&lt;/strong&gt; that only speaks 802.15.4/BLE.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;integrated flash&lt;/strong&gt; to reduce parts on your PCB.&lt;/li&gt;
&lt;li&gt;You already have a &lt;em&gt;border router&lt;/em&gt; and do not need Wi-Fi on the node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Do not pick it if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The device needs to &lt;strong&gt;reach the Internet on its own&lt;/strong&gt; → &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You are doing plain Wi-Fi → &lt;strong&gt;C3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;camera, audio or AI&lt;/strong&gt; → &lt;strong&gt;S3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;lots of GPIOs&lt;/strong&gt; → &lt;strong&gt;S3&lt;/strong&gt; or &lt;strong&gt;P4&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Buying it assuming it &lt;strong&gt;has Wi-Fi&lt;/strong&gt; (it does not, and no firmware fixes that).&lt;/li&gt;
&lt;li&gt;Trying to use it as a &lt;strong&gt;gateway&lt;/strong&gt;: for that you need a &lt;strong&gt;C6&lt;/strong&gt; (or a C6 + H2).&lt;/li&gt;
&lt;li&gt;Forgetting that its whole point is &lt;strong&gt;sleeping&lt;/strong&gt;: keep it awake all the time and
you lose the advantage.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single low-power RISC-V&lt;/strong&gt;, &lt;strong&gt;320 KB SRAM&lt;/strong&gt; and &lt;strong&gt;integrated flash&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BLE 5 + 802.15.4&lt;/strong&gt; (Thread/Zigbee/Matter) and &lt;strong&gt;no Wi-Fi&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;19 GPIOs with ADC&lt;/strong&gt; and USB Serial/JTAG.&lt;/li&gt;
&lt;li&gt;It is the ideal chip for &lt;strong&gt;battery Matter nodes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For a gateway or Wi-Fi, prefer a &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP32-P4&lt;/a&gt;, the new radio-less chip
for displays and high performance. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP32-C6 in depth: Wi-Fi 6, Matter and Thread in one chip</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-c6-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-c6-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-c6-a-fondo/">&lt;p&gt;The ESP32-C6 is the chip of &lt;strong&gt;modern home automation&lt;/strong&gt;. Not because it is the most
powerful, but because it brings something none of its siblings have: an
&lt;strong&gt;802.15.4 radio&lt;/strong&gt;, the foundation of &lt;strong&gt;Thread, Zigbee and Matter&lt;/strong&gt;. And on top of
that, it ships &lt;strong&gt;Wi-Fi 6&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you are building a genuinely connected home (one that talks to Apple Home,
Google Home or Home Assistant without hacks), this is the chip.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-is&quot; aria-label=&quot;Anchor link for: what-it-is&quot;&gt;What it is&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The C6 uses &lt;strong&gt;two RISC-V cores&lt;/strong&gt;: a high-performance one (HP, 160 MHz) and a
low-power one (LP, 20 MHz) that can keep watching sensors while the rest sleeps.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Cores&lt;/td&gt;&lt;td&gt;RISC-V HP 160 MHz + LP 20 MHz&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;512 KB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Wi-Fi 6 (802.11ax, 2.4 GHz)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;&lt;strong&gt;BLE 5&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;802.15.4&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Thread / Zigbee / Matter&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;native Serial/JTAG&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;what-makes-it-unique-802-15-4-wi-fi-6&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-makes-it-unique-802-15-4-wi-fi-6&quot; aria-label=&quot;Anchor link for: what-makes-it-unique-802-15-4-wi-fi-6&quot;&gt;What makes it unique: 802.15.4 + Wi-Fi 6&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;802.15.4&lt;/strong&gt; is the radio behind &lt;strong&gt;Matter, Thread and Zigbee&lt;/strong&gt;. Without it, your
device cannot speak the language of the modern connected home.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wi-Fi 6&lt;/strong&gt; is not marketing: it plays nicer with crowded networks and adds
&lt;strong&gt;TWT&lt;/strong&gt; (&lt;em&gt;Target Wake Time&lt;/em&gt;), letting the device negotiate with the router when
to wake up. Translation: &lt;strong&gt;less power&lt;/strong&gt; for the same Wi-Fi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And it can use Wi-Fi and 802.15.4 at the same time, so you can build a Thread
&lt;strong&gt;border router&lt;/strong&gt;… or simply be a Matter device that reaches the Internet over
Wi-Fi.&lt;/p&gt;
&lt;h2 id=&quot;pinout-the-essentials&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pinout-the-essentials&quot; aria-label=&quot;Anchor link for: pinout-the-essentials&quot;&gt;Pinout: the essentials&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pin(s)&lt;/th&gt;&lt;th&gt;What for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO12 / GPIO13&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;USB D− / D+&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO0–6&lt;/td&gt;&lt;td&gt;ADC1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO8, GPIO9, GPIO15&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;Strapping&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO24–30&lt;/td&gt;&lt;td&gt;Internal flash (do not use)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO5 / GPIO6&lt;/td&gt;&lt;td&gt;usual UART (RX / TX)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;As across the family: &lt;strong&gt;no DAC&lt;/strong&gt;, &lt;strong&gt;no touch&lt;/strong&gt;, and &lt;strong&gt;ADC2 does not work with
Wi-Fi&lt;/strong&gt; (here, use ADC1).&lt;/p&gt;
&lt;h2 id=&quot;boards-and-modules&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#boards-and-modules&quot; aria-label=&quot;Anchor link for: boards-and-modules&quot;&gt;Boards and modules&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C6-WROOM-1&lt;/strong&gt; — standard module.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C6-MINI-1&lt;/strong&gt; — small version.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C6-DevKitC-1&lt;/strong&gt; — development board.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C6-DevKitM-1&lt;/strong&gt; — the reduced one.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-c6.jpg&quot; alt=&quot;ESP32-C6 development board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-C6: Wi-Fi 6 + BLE 5 + 802.15.4 (Thread/Zigbee/Matter). Photo: Popolon (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-to-pick-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-it-and-when-not-to&quot;&gt;When to pick it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the C6 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are doing &lt;strong&gt;Matter, Thread or Zigbee&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;Wi-Fi 6&lt;/strong&gt; and good power behaviour with TWT.&lt;/li&gt;
&lt;li&gt;You need a device compatible with modern home ecosystems.&lt;/li&gt;
&lt;li&gt;You want to build a Thread &lt;strong&gt;border router&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Do not pick it if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You only do plain, cheap Wi-Fi: a &lt;strong&gt;C3&lt;/strong&gt; costs less.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;camera, audio or AI&lt;/strong&gt;: that is the &lt;strong&gt;S3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;classic Bluetooth&lt;/strong&gt; or a &lt;strong&gt;DAC&lt;/strong&gt;: the &lt;strong&gt;classic&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You do not need Wi-Fi: the &lt;strong&gt;H2&lt;/strong&gt; is cheaper for an 802.15.4/BLE node.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Buying a C6 “to try” without a recent toolchain: Matter needs &lt;strong&gt;ESP-IDF 5.1+&lt;/strong&gt;
(today we are on &lt;strong&gt;6.1&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Expecting a &lt;strong&gt;DAC&lt;/strong&gt; or &lt;strong&gt;touch&lt;/strong&gt; that do not exist.&lt;/li&gt;
&lt;li&gt;Confusing Matter (application protocol) with Thread (network): the C6 has the
radio for both.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dual RISC-V&lt;/strong&gt; (HP + LP), 512 KB SRAM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wi-Fi 6 + BLE 5 + 802.15.4&lt;/strong&gt;: the only one in the family with hardware Matter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;30 GPIOs&lt;/strong&gt; and USB Serial/JTAG.&lt;/li&gt;
&lt;li&gt;It is the choice for &lt;strong&gt;modern home automation&lt;/strong&gt;; for everything else, C3 or S3.&lt;/li&gt;
&lt;li&gt;It needs an up-to-date toolchain (ESP-IDF 5.1+, ideally 6.x).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP32-H2&lt;/a&gt;, its Wi-Fi-less sibling for
battery Matter nodes. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP32-C3 in depth: the one I recommend to start with (and why)</title>
        <published>2026-09-21T00:00:00+00:00</published>
        <updated>2026-09-21T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-c3-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-c3-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-c3-a-fondo/">&lt;p&gt;If you ask me “which ESP32 should I buy to start?”, the short answer is
&lt;strong&gt;ESP32-C3&lt;/strong&gt;. It is modern, cheap, has Bluetooth 5 and native USB, and for 90 % of
sensor and home-automation projects it is &lt;strong&gt;more than enough&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It is not perfect: it has &lt;strong&gt;few pins&lt;/strong&gt; and is missing a few things. Let’s see
exactly what you get and what you do not.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-is&quot; aria-label=&quot;Anchor link for: what-it-is&quot;&gt;What it is&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The C3 is the “next generation” ESP32: instead of the usual Xtensa cores, it uses
&lt;strong&gt;RISC-V&lt;/strong&gt;, the open architecture Espressif adopted for its newest chips.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Core&lt;/td&gt;&lt;td&gt;1 × RISC-V @ 160 MHz&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;400 KB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;802.11 b/g/n (2.4 GHz)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;&lt;strong&gt;BLE 5&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;&lt;strong&gt;22&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;2 × 12-bit (6 channels)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DAC&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Touch&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;native Serial/JTAG&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;the-good&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-good&quot; aria-label=&quot;Anchor link for: the-good&quot;&gt;The good&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cheap&lt;/strong&gt;: it usually costs the same as an ESP8266 and beats it at everything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BLE 5&lt;/strong&gt;: great for talking to a phone (no classic Bluetooth).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native USB&lt;/strong&gt;: forget the CH340 and enjoy &lt;strong&gt;built-in JTAG&lt;/strong&gt;, which means
breakpoint debugging with no extra hardware.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low power&lt;/strong&gt;: in &lt;em&gt;deep sleep&lt;/em&gt; it stays below the classic, ideal for
battery-powered nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RISC-V&lt;/strong&gt;: modern toolchain and first-class support in ESP-IDF, Arduino and
Rust.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-bad&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-bad&quot; aria-label=&quot;Anchor link for: the-bad&quot;&gt;The bad&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Only 22 GPIOs&lt;/strong&gt;, and you have to subtract the flash pins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No DAC&lt;/strong&gt; and &lt;strong&gt;no touch&lt;/strong&gt;: if you need real analog output or capacitive
buttons, go back to the classic or the S2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single core&lt;/strong&gt;: you cannot split work across two CPUs.&lt;/li&gt;
&lt;li&gt;Bluetooth is &lt;strong&gt;BLE only&lt;/strong&gt;, no classic.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pinout-the-essentials&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pinout-the-essentials&quot; aria-label=&quot;Anchor link for: pinout-the-essentials&quot;&gt;Pinout: the essentials&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pin(s)&lt;/th&gt;&lt;th&gt;What for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO18 / GPIO19&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;USB D− / D+&lt;/strong&gt; (USB Serial/JTAG)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO0–4&lt;/td&gt;&lt;td&gt;ADC1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO5&lt;/td&gt;&lt;td&gt;ADC2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO2, GPIO8, GPIO9&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;Strapping&lt;/em&gt; (careful with 9: it is the BOOT button)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO11–17&lt;/td&gt;&lt;td&gt;Internal flash (do not use)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO20 / GPIO21&lt;/td&gt;&lt;td&gt;UART (RX / TX)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;As always: &lt;strong&gt;ADC2 does not work with Wi-Fi on&lt;/strong&gt;, so for sensors use &lt;strong&gt;ADC1
(GPIO0–4)&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/pinout-esp32-c3.png&quot; alt=&quot;ESP32-C3 pinout&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-C3 pinout. Source: Wikimedia Commons, CC BY-SA 4.0.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;boards-and-modules&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#boards-and-modules&quot; aria-label=&quot;Anchor link for: boards-and-modules&quot;&gt;Boards and modules&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C3-WROOM-02&lt;/strong&gt; — the standard module.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C3-MINI-1&lt;/strong&gt; — small, for your own PCB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C3-DevKitM-1&lt;/strong&gt; — the small, stick-like board.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-C3-DevKitC-02&lt;/strong&gt; — with more pins and buttons.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-c3.jpg&quot; alt=&quot;ESP32-C3 NodeMCU-style board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;An ESP32-C3 NodeMCU board: small, cheap and USB-C. Photo: Popolon (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-to-pick-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-it-and-when-not-to&quot;&gt;When to pick it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the C3 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are &lt;strong&gt;getting started&lt;/strong&gt; and do not want to overspend.&lt;/li&gt;
&lt;li&gt;You are building &lt;strong&gt;home automation&lt;/strong&gt;, sensors or relays with Wi-Fi and BLE.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;native USB&lt;/strong&gt; and &lt;strong&gt;JTAG&lt;/strong&gt; with no extra chip.&lt;/li&gt;
&lt;li&gt;You want a &lt;strong&gt;battery&lt;/strong&gt; node with good &lt;em&gt;deep sleep&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Do not pick it if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need &lt;strong&gt;classic Bluetooth&lt;/strong&gt; → classic ESP32.&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;DAC&lt;/strong&gt; or &lt;strong&gt;touch&lt;/strong&gt; → classic or S2.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;lots of GPIOs&lt;/strong&gt; → S2 or S3.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;camera, audio or AI&lt;/strong&gt; → S3.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;Matter/Thread/Zigbee&lt;/strong&gt; → C6 or H2.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Counting on &lt;strong&gt;22 GPIOs&lt;/strong&gt; and forgetting that &lt;strong&gt;GPIO11–17&lt;/strong&gt; are the flash.&lt;/li&gt;
&lt;li&gt;Putting the &lt;strong&gt;BOOT button on GPIO9&lt;/strong&gt; and having the chip boot into download
mode.&lt;/li&gt;
&lt;li&gt;Looking for the &lt;strong&gt;DAC&lt;/strong&gt; or &lt;strong&gt;touch&lt;/strong&gt; in the C3 docs (they do not exist).&lt;/li&gt;
&lt;li&gt;Reading sensors on &lt;strong&gt;ADC2&lt;/strong&gt; with Wi-Fi connected.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 × RISC-V core&lt;/strong&gt; at 160 MHz, 400 KB SRAM, &lt;strong&gt;Wi-Fi 4 + BLE 5&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native USB Serial/JTAG&lt;/strong&gt; and good &lt;em&gt;deep sleep&lt;/em&gt; current.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;22 GPIOs&lt;/strong&gt;, no DAC and no touch.&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;the best starter buy&lt;/strong&gt; in 2026: cheap, modern and well supported.&lt;/li&gt;
&lt;li&gt;If you need more muscle or pins, jump to the &lt;strong&gt;S3&lt;/strong&gt; or &lt;strong&gt;S2&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP32-C6&lt;/a&gt;, with Wi-Fi 6 and a radio
for &lt;strong&gt;Matter&lt;/strong&gt;. Or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP32-S3 in depth: cores, PSRAM, AI and USB for serious projects</title>
        <published>2026-09-20T00:00:00+00:00</published>
        <updated>2026-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-s3-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-s3-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-s3-a-fondo/">&lt;p&gt;If the S2 was the experiment, the &lt;strong&gt;ESP32-S3&lt;/strong&gt; is the one that worked out: &lt;strong&gt;two
cores&lt;/strong&gt;, Bluetooth, native USB and, on top of that, &lt;strong&gt;vector instructions&lt;/strong&gt; that
speed up AI. It is the chip inside camera boards, voice assistants and almost any
“big” ESP32 project.&lt;/p&gt;
&lt;p&gt;That said: it is the most expensive of the family and, if you are not going to use
what it brings, you are overpaying.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-is&quot; aria-label=&quot;Anchor link for: what-it-is&quot;&gt;What it is&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Cores&lt;/td&gt;&lt;td&gt;2 × Xtensa LX7 @ 240 MHz&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;512 KB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;802.11 b/g/n (2.4 GHz)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;&lt;strong&gt;BLE 5&lt;/strong&gt; (no classic Bluetooth)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;&lt;strong&gt;up to 45&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;20 channels, 12-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Touch&lt;/td&gt;&lt;td&gt;14 channels&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;native OTG&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PSRAM&lt;/td&gt;&lt;td&gt;up to 8 MB (module dependent)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Notice two things: it has &lt;strong&gt;no DAC&lt;/strong&gt; (unlike the classic and the S2) and its
Bluetooth is &lt;strong&gt;BLE only&lt;/strong&gt;, just like the C3.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-it-special-vector-instructions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-makes-it-special-vector-instructions&quot; aria-label=&quot;Anchor link for: what-makes-it-special-vector-instructions&quot;&gt;What makes it special: vector instructions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The S3 adds &lt;strong&gt;128-bit SIMD&lt;/strong&gt; aimed at neural networks. In practice that means a
small voice or gesture model runs &lt;strong&gt;several times faster&lt;/strong&gt; than on a classic, with
no GPU or external accelerator.&lt;/p&gt;
&lt;p&gt;That is why camera boards and home “assistants” use an S3 instead of a C3.&lt;/p&gt;
&lt;h2 id=&quot;psram-quad-vs-octal-and-the-price-in-pins&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#psram-quad-vs-octal-and-the-price-in-pins&quot; aria-label=&quot;Anchor link for: psram-quad-vs-octal-and-the-price-in-pins&quot;&gt;PSRAM: quad vs octal (and the price in pins)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is a trap here that bites many people. S3 modules come in several combos,
for example &lt;strong&gt;N8R2&lt;/strong&gt; (8 MB flash + 2 MB PSRAM) or &lt;strong&gt;N8R8&lt;/strong&gt; (8 MB + 8 MB), and the
PSRAM can be &lt;strong&gt;quad&lt;/strong&gt; or &lt;strong&gt;octal&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quad PSRAM&lt;/strong&gt; — uses fewer pins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Octal PSRAM&lt;/strong&gt; — faster, but it &lt;strong&gt;eats GPIO33–GPIO37&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And in any configuration, &lt;strong&gt;GPIO26–GPIO32&lt;/strong&gt; are taken by the flash (and by the
PSRAM when present). Translation: do not count on 45 GPIOs if the module has
memory. Always check the specific module datasheet.&lt;/p&gt;
&lt;h2 id=&quot;pinout-the-essentials&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pinout-the-essentials&quot; aria-label=&quot;Anchor link for: pinout-the-essentials&quot;&gt;Pinout: the essentials&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pin(s)&lt;/th&gt;&lt;th&gt;What for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO19 / GPIO20&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;USB D− / D+&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO1–10&lt;/td&gt;&lt;td&gt;ADC1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO11–20&lt;/td&gt;&lt;td&gt;ADC2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO1–14&lt;/td&gt;&lt;td&gt;Touch&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO0, 3, 45, 46&lt;/td&gt;&lt;td&gt;&lt;em&gt;Strapping&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO26–32&lt;/td&gt;&lt;td&gt;Flash/PSRAM (do not use)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO33–37&lt;/td&gt;&lt;td&gt;&lt;strong&gt;extra&lt;/strong&gt; if the module has &lt;strong&gt;octal PSRAM&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The usual peripherals are still there (SPI, I2C, I2S, UART, PWM, RMT) plus a
&lt;strong&gt;camera interface&lt;/strong&gt; (LCD_CAM) able to move video.&lt;/p&gt;
&lt;h2 id=&quot;boards-and-modules&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#boards-and-modules&quot; aria-label=&quot;Anchor link for: boards-and-modules&quot;&gt;Boards and modules&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S3-WROOM-1 / 1U&lt;/strong&gt; — the standard module (the “U” has an external antenna).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S3-MINI-1&lt;/strong&gt; — small, for your own PCB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S3-DevKitC-1 / DevKitM-1&lt;/strong&gt; — the development boards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S3-EYE&lt;/strong&gt; — board with camera and display, for vision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S3-DevKitC-1 N16R8&lt;/strong&gt; — the higher-memory version.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-s3.jpg&quot; alt=&quot;ESP32-S3 board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-S3: the most capable variant for edge AI and multimedia. Photo: VectorVoyager (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-to-pick-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-it-and-when-not-to&quot;&gt;When to pick it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the S3 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are doing &lt;strong&gt;vision, audio or on-device AI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;camera&lt;/strong&gt; or to drive &lt;strong&gt;displays&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;two cores&lt;/strong&gt; and native USB.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;PSRAM&lt;/strong&gt; for large buffers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Do not pick it if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You just want to read sensors and publish over Wi-Fi: a &lt;strong&gt;C3&lt;/strong&gt; does the same for
far less.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;classic Bluetooth&lt;/strong&gt; (it only has BLE): that is the &lt;strong&gt;classic&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;DAC&lt;/strong&gt;: the S3 has none; use the classic or the S2.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Buying an S3 &lt;strong&gt;without PSRAM&lt;/strong&gt; and then wanting vision or audio.&lt;/li&gt;
&lt;li&gt;Buying &lt;strong&gt;octal PSRAM&lt;/strong&gt; and discovering you lose GPIO33–37.&lt;/li&gt;
&lt;li&gt;Assuming it has &lt;strong&gt;classic Bluetooth&lt;/strong&gt; (it is BLE only).&lt;/li&gt;
&lt;li&gt;Counting on &lt;strong&gt;GPIO26–32&lt;/strong&gt; when they are taken by memory.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2 × LX7 cores&lt;/strong&gt;, 512 KB SRAM, &lt;strong&gt;BLE 5&lt;/strong&gt; and &lt;strong&gt;USB OTG&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vector instructions&lt;/strong&gt; make it the best ESP32 for AI and multimedia.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quad or octal PSRAM&lt;/strong&gt;: octal is faster but uses more pins.&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;no DAC&lt;/strong&gt; and &lt;strong&gt;no classic Bluetooth&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It is the “big” option: if you do not need camera/AI, a C3 is more than enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP32-C3&lt;/a&gt;, the one I recommend to
start with. Or go back to the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ESP32-S2 in depth: the ESP32 with real USB (and no Bluetooth)</title>
        <published>2026-09-19T00:00:00+00:00</published>
        <updated>2026-09-19T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-s2-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-s2-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-s2-a-fondo/">&lt;p&gt;The ESP32-S2 is the odd sibling. It arrived in 2019 with a very clear idea:
&lt;strong&gt;native USB&lt;/strong&gt;, lots of pins and Wi-Fi… but &lt;strong&gt;no Bluetooth&lt;/strong&gt;. That single decision
splits opinion: for some it is perfect, for others it is a paperweight.&lt;/p&gt;
&lt;p&gt;Let’s see what it is actually good for.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is-and-how-it-differs-from-the-classic&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-is-and-how-it-differs-from-the-classic&quot; aria-label=&quot;Anchor link for: what-it-is-and-how-it-differs-from-the-classic&quot;&gt;What it is (and how it differs from the classic)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The S2 uses &lt;strong&gt;a single Xtensa LX7 core at 240 MHz&lt;/strong&gt; (the classic has two). That
sounds like a downgrade, but in exchange it ships &lt;strong&gt;USB OTG&lt;/strong&gt;, which is a more
interesting peripheral than it looks.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Core&lt;/td&gt;&lt;td&gt;1 × Xtensa LX7 @ 240 MHz&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;320 KB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;802.11 b/g/n (2.4 GHz)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;&lt;strong&gt;43&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;20 channels, 12-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DAC&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2 channels, 8-bit&lt;/strong&gt; (GPIO17 and GPIO18)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Touch&lt;/td&gt;&lt;td&gt;14 channels&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USB&lt;/td&gt;&lt;td&gt;&lt;strong&gt;native OTG&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;the-good-part-usb-otg&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-good-part-usb-otg&quot; aria-label=&quot;Anchor link for: the-good-part-usb-otg&quot;&gt;The good part: USB OTG&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is not “USB for the serial port”. It is a &lt;strong&gt;full USB controller&lt;/strong&gt;, and that
lets you do things the classic needs an extra chip for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HID&lt;/strong&gt;: emulate a keyboard, mouse or gamepad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDC&lt;/strong&gt;: your own serial port, with your own VID/PID.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MSC&lt;/strong&gt;: make the computer see the ESP32 as a USB drive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host&lt;/strong&gt;: read a flash drive, a USB keyboard or a reader.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And because it is native, forget the CH340 and its drivers. One cable and done.&lt;/p&gt;
&lt;h2 id=&quot;the-bad-part-no-bluetooth&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-bad-part-no-bluetooth&quot; aria-label=&quot;Anchor link for: the-bad-part-no-bluetooth&quot;&gt;The bad part: no Bluetooth&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the toll. If your project needs to send data to a phone over BLE, or talk
to a speaker over classic Bluetooth, &lt;strong&gt;the S2 is not for you&lt;/strong&gt;. Period. It is not
a firmware issue: the radio simply is not there.&lt;/p&gt;
&lt;p&gt;Espressif left it out to cut cost and complexity. It made sense at the time… but
today it means that, when in doubt, you almost always want a &lt;strong&gt;C3&lt;/strong&gt; or an &lt;strong&gt;S3&lt;/strong&gt;
instead.&lt;/p&gt;
&lt;h2 id=&quot;pinout-the-pins-that-matter&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pinout-the-pins-that-matter&quot; aria-label=&quot;Anchor link for: pinout-the-pins-that-matter&quot;&gt;Pinout: the pins that matter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is no official S2 pinout on Commons, so here are the things you will
actually look up (for the rest, see the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.espressif.com/&quot;&gt;Espressif datasheet&lt;/a&gt;):&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pin(s)&lt;/th&gt;&lt;th&gt;What for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO19 / GPIO20&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;USB D− / D+&lt;/strong&gt; (do not reuse them if you use USB)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO1–10&lt;/td&gt;&lt;td&gt;ADC1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO11–20&lt;/td&gt;&lt;td&gt;ADC2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO17 / GPIO18&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;DAC 1 and DAC 2&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO1–14&lt;/td&gt;&lt;td&gt;Touch&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO0, 45, 46&lt;/td&gt;&lt;td&gt;&lt;em&gt;Strapping&lt;/em&gt; (boot)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIO26–32&lt;/td&gt;&lt;td&gt;Internal flash (do not use)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two warnings that carry over from the classic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ADC2 does not work while Wi-Fi is on.&lt;/strong&gt; Use &lt;strong&gt;ADC1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;strapping&lt;/em&gt; pins (especially &lt;strong&gt;GPIO45 and GPIO46&lt;/strong&gt;) are best left alone.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;boards-and-modules&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#boards-and-modules&quot; aria-label=&quot;Anchor link for: boards-and-modules&quot;&gt;Boards and modules&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What you will find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S2-WROOM / WROOM-1&lt;/strong&gt; — the standard module.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S2-MINI-1&lt;/strong&gt; — the small one, ideal for your own PCB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S2-Saola-1&lt;/strong&gt; — the DevKitC-style development board.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S2-Kaluga-1&lt;/strong&gt; — kit with a display and camera.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-S2-DevKitM-1&lt;/strong&gt; — the reduced version.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-s2.svg&quot; alt=&quot;Illustration of the ESP32-S2 and its features&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-S2: native USB OTG, Wi-Fi 4 and no Bluetooth. Own illustration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-to-pick-it-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-it-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-it-and-when-not-to&quot;&gt;When to pick it (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the S2 if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need &lt;strong&gt;real USB&lt;/strong&gt;: HID, CDC, storage, host.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;lots of GPIOs&lt;/strong&gt; (43) and do not care about Bluetooth.&lt;/li&gt;
&lt;li&gt;You are going to use &lt;strong&gt;DAC&lt;/strong&gt; or &lt;strong&gt;touch&lt;/strong&gt; and want native USB as a bonus.&lt;/li&gt;
&lt;li&gt;You are building a USB device you want to emulate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Do not pick it if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need &lt;strong&gt;BLE&lt;/strong&gt; (very common): go for a &lt;strong&gt;C3&lt;/strong&gt; or &lt;strong&gt;S3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You want the cheapest option: the &lt;strong&gt;C3&lt;/strong&gt; is more modern and usually costs the
same or less.&lt;/li&gt;
&lt;li&gt;You need two cores: the S2 has one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typical-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes&quot; aria-label=&quot;Anchor link for: typical-mistakes&quot;&gt;Typical mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Buying it &lt;strong&gt;assuming it has BLE&lt;/strong&gt; because “all ESP32s do”.&lt;/li&gt;
&lt;li&gt;Using &lt;strong&gt;GPIO19/20&lt;/strong&gt; for something else and then wondering why USB never shows
up.&lt;/li&gt;
&lt;li&gt;Reading a sensor on &lt;strong&gt;ADC2 with Wi-Fi on&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Forgetting that &lt;strong&gt;GPIO45/46&lt;/strong&gt; are boot pins and that holding them &lt;code&gt;LOW&lt;/code&gt; can
block boot.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 × LX7 core&lt;/strong&gt;, 320 KB SRAM, &lt;strong&gt;USB OTG&lt;/strong&gt; and &lt;strong&gt;43 GPIOs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Bluetooth&lt;/strong&gt;: its biggest limitation.&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;DAC&lt;/strong&gt; and &lt;strong&gt;touch&lt;/strong&gt;, like the classic.&lt;/li&gt;
&lt;li&gt;It is the clear choice when &lt;strong&gt;USB&lt;/strong&gt; is the star of the project.&lt;/li&gt;
&lt;li&gt;If you are torn between S2 and C3, &lt;strong&gt;the C3 almost always wins&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP32-S3&lt;/a&gt; — same USB, but with two
cores, Bluetooth and AI acceleration. Or go back to the
&lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;series hub&lt;/a&gt; for the full index.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The classic ESP32 in depth: pins, ADC, DAC and when it&#39;s still worth it</title>
        <published>2026-09-18T00:00:00+00:00</published>
        <updated>2026-09-18T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/esp32-clasico-a-fondo/"/>
        <id>https://esp32.tunatek.tech/en/blog/esp32-clasico-a-fondo/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/esp32-clasico-a-fondo/">&lt;p&gt;When people say “ESP32” they almost always mean &lt;strong&gt;this one&lt;/strong&gt;: the 2016 chip with
two cores and 38 pins. It still has the most tutorials, it is the cheapest board
with classic Bluetooth, and even though there are more modern options, it &lt;strong&gt;still
makes a lot of sense&lt;/strong&gt; in 2026.&lt;/p&gt;
&lt;p&gt;But it has a few corners —pins you cannot use, an ADC that is not as nice as the
marketing suggests— that you should know &lt;strong&gt;before&lt;/strong&gt; soldering anything. I have
wasted more than one afternoon by not knowing them, so let’s save you the
trouble.&lt;/p&gt;
&lt;h2 id=&quot;the-chip-not-every-esp32-is-the-same&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-chip-not-every-esp32-is-the-same&quot; aria-label=&quot;Anchor link for: the-chip-not-every-esp32-is-the-same&quot;&gt;The chip: not every “ESP32” is the same&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Inside the module there is a specific chip, and they are not all equal:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Chip&lt;/th&gt;&lt;th&gt;What is special about it&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ESP32-D0WDQ6&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;The original, 2 cores, QFN 6×6 mm&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ESP32-D0WD&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Same but in a 5×5 mm package&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-D0WD-V3&lt;/td&gt;&lt;td&gt;The current revision, used in new modules&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-D0WDR2&lt;/td&gt;&lt;td&gt;With &lt;strong&gt;2 MB of PSRAM inside&lt;/strong&gt; the chip itself&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-S0WD&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Single core&lt;/strong&gt; (rare to see)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For our purposes: &lt;strong&gt;2 × Xtensa LX6 cores at 240 MHz, 520 KB of SRAM and 448 KB of
ROM&lt;/strong&gt;. That is the “classic ESP32”.&lt;/p&gt;
&lt;h2 id=&quot;the-modules-wroom-wrover-and-friends&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-modules-wroom-wrover-and-friends&quot; aria-label=&quot;Anchor link for: the-modules-wroom-wrover-and-friends&quot;&gt;The modules: WROOM, WROVER and friends&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The bare chip is not something you solder by hand. It lives inside a &lt;strong&gt;module&lt;/strong&gt;
with the flash, the crystal and the antenna. The ones you will find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32-WROOM-32E&lt;/strong&gt; — the standard. 4 MB of flash, PCB antenna. Leaves
&lt;strong&gt;GPIO16 and GPIO17&lt;/strong&gt; free.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-WROVER-E&lt;/strong&gt; — same, but with &lt;strong&gt;8 MB of PSRAM&lt;/strong&gt; on top. Note: the PSRAM
eats &lt;strong&gt;GPIO16 and GPIO17&lt;/strong&gt;, so if you need those pins, you cannot use WROVER.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESP32-WROOM-32UE / WROVER-IE&lt;/strong&gt; — no PCB antenna, with a &lt;strong&gt;U.FL&lt;/strong&gt; connector
for an external antenna. The fix when the ESP32 lives inside a metal box.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/esp32-clasico/modulo.jpg&quot; alt=&quot;ESP32-WROOM-32 module with its metal shield&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;The ESP32-WROOM-32: chip, flash and antenna in a single part. Photo: Ubahnverleih (CC0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2026 note:&lt;/strong&gt; for new designs, Espressif recommends the &lt;strong&gt;E series&lt;/strong&gt;
(ESP32-WROOM-32E / WROVER-E). The older modules without the “E” are marked as
&lt;em&gt;not recommended for new designs&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And on the back you can see where everything is:&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/esp32-clasico/modulo-trasera.jpg&quot; alt=&quot;Back side of the ESP32-WROOM-32 module&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;On the back: the ESP32 chip on the left and the flash memory on the right. Photo: Ubahnverleih (CC0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;the-board-you-will-buy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-board-you-will-buy&quot; aria-label=&quot;Anchor link for: the-board-you-will-buy&quot;&gt;The board you will buy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The module is mounted on a &lt;strong&gt;development board&lt;/strong&gt; (devkit) that adds USB, a
regulator and two buttons: &lt;code&gt;EN&lt;/code&gt; (reset) and &lt;code&gt;BOOT&lt;/code&gt; (for flashing). The classic
one is the &lt;strong&gt;ESP32-DevKitC&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/esp32-clasico/devkitc.jpg&quot; alt=&quot;ESP32-DevKitC board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-DevKitC: the module, the micro-USB port, the regulator and the two buttons. Photo: Ubahnverleih (CC0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A warning worth money: these boards have &lt;strong&gt;no native USB&lt;/strong&gt;. The port is a bridge
chip (&lt;strong&gt;CP2102&lt;/strong&gt; or &lt;strong&gt;CH340&lt;/strong&gt;) that talks to the ESP32 over UART. If you have
trouble flashing, it is almost always that chip’s driver, not the ESP32.&lt;/p&gt;
&lt;h2 id=&quot;specs-no-fluff&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#specs-no-fluff&quot; aria-label=&quot;Anchor link for: specs-no-fluff&quot;&gt;Specs, no fluff&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Thing&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Cores&lt;/td&gt;&lt;td&gt;2 × Xtensa LX6 @ up to 240 MHz&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SRAM&lt;/td&gt;&lt;td&gt;520 KB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wi-Fi&lt;/td&gt;&lt;td&gt;802.11 b/g/n (2.4 GHz)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bluetooth&lt;/td&gt;&lt;td&gt;&lt;strong&gt;4.2 classic (BR/EDR) + BLE&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GPIOs&lt;/td&gt;&lt;td&gt;34 total, ~25 usable&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ADC&lt;/td&gt;&lt;td&gt;18 channels, 12-bit (ADC1 + ADC2)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DAC&lt;/td&gt;&lt;td&gt;2 channels, 8-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Touch&lt;/td&gt;&lt;td&gt;10 capacitive pins&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Peripherals&lt;/td&gt;&lt;td&gt;3×UART, 2×I2C, SPI, 2×I2S, CAN (TWAI), SD/MMC, PWM, RMT&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The &lt;strong&gt;classic Bluetooth&lt;/strong&gt; bit is unique to the classic: neither the S2, nor the
C3, nor the S3 have it. If your project talks to a speaker or an old-school
Bluetooth gamepad, this is your chip.&lt;/p&gt;
&lt;h2 id=&quot;the-38-pin-pinout&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-38-pin-pinout&quot; aria-label=&quot;Anchor link for: the-38-pin-pinout&quot;&gt;The 38-pin pinout&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/pinout-esp32-devkitc.png&quot; alt=&quot;Full 38-pin ESP32 DevKitC pinout&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32 (DevKitC, 38 pins) pinout. Source: Wikimedia Commons, CC BY-SA 4.0.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you come from Arduino, here is a mindset shift: &lt;strong&gt;not every pin does
everything&lt;/strong&gt;. There are input-only pins, pins that decide how the chip boots, and
pins that are literally taken internally. Let’s go one by one.&lt;/p&gt;
&lt;h2 id=&quot;the-pins-that-rock&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-pins-that-rock&quot; aria-label=&quot;Anchor link for: the-pins-that-rock&quot;&gt;The pins that rock&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;the-dac-gpio25-and-gpio26&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-dac-gpio25-and-gpio26&quot; aria-label=&quot;Anchor link for: the-dac-gpio25-and-gpio26&quot;&gt;The DAC (GPIO25 and GPIO26)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The classic has &lt;strong&gt;two real analog outputs&lt;/strong&gt; (8-bit). The C3, for example, has
none. You can output an actual voltage, generate a waveform or build a mediocre
but fun synthesizer.&lt;/p&gt;
&lt;h3 id=&quot;touch-10-pins-that-sense-your-finger&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#touch-10-pins-that-sense-your-finger&quot; aria-label=&quot;Anchor link for: touch-10-pins-that-sense-your-finger&quot;&gt;Touch: 10 pins that sense your finger&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With no extra sensor, the chip measures the capacitance of &lt;strong&gt;GPIO0, 2, 4, 12,
13, 14, 15, 27, 32 and 33&lt;/strong&gt;. Perfect for buttons with no moving parts. (This
peripheral disappeared in the S2 and S3, so if you need it, you go back to the
classic.)&lt;/p&gt;
&lt;h3 id=&quot;adc1-the-one-that-works-with-wi-fi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#adc1-the-one-that-works-with-wi-fi&quot; aria-label=&quot;Anchor link for: adc1-the-one-that-works-with-wi-fi&quot;&gt;ADC1: the one that works with Wi-Fi&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;GPIO32 to GPIO39&lt;/strong&gt; are ADC1. They are the only ones you can use while Wi-Fi is
on. Burn this into your memory, because it is the number one cause of “my sensor
reads random values”.&lt;/p&gt;
&lt;h3 id=&quot;and-a-few-lesser-known-extras&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#and-a-few-lesser-known-extras&quot; aria-label=&quot;Anchor link for: and-a-few-lesser-known-extras&quot;&gt;And a few lesser-known extras&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Internal Hall sensor&lt;/strong&gt;, using no pin at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal temperature sensor&lt;/strong&gt; (not very accurate, but it exists).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN (TWAI)&lt;/strong&gt; in hardware, no external module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-pins-that-will-ruin-your-day&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-pins-that-will-ruin-your-day&quot; aria-label=&quot;Anchor link for: the-pins-that-will-ruin-your-day&quot;&gt;The pins that will ruin your day&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;gpio6-to-gpio11-the-flash&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gpio6-to-gpio11-the-flash&quot; aria-label=&quot;Anchor link for: gpio6-to-gpio11-the-flash&quot;&gt;GPIO6 to GPIO11: the flash&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;They are wired to the flash memory. &lt;strong&gt;Never use them.&lt;/strong&gt; If you touch them, the
ESP32 stops booting and looks dead. It is not dead: re-flash it and breathe.&lt;/p&gt;
&lt;h3 id=&quot;the-boot-strapping-pins&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-boot-strapping-pins&quot; aria-label=&quot;Anchor link for: the-boot-strapping-pins&quot;&gt;The boot (strapping) pins&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On power-up, the chip looks at these pins to decide how to boot:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pin&lt;/th&gt;&lt;th&gt;What happens if it is wrong&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO0&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;LOW&lt;/code&gt; enters flash mode; as an output it can block boot&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Must be &lt;code&gt;LOW&lt;/code&gt; or floating at boot&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO12&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;If it is &lt;code&gt;HIGH&lt;/code&gt; at boot, bad news (it is about flash voltage)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPIO15&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Must be &lt;code&gt;HIGH&lt;/code&gt;; otherwise the boot log is silenced&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Rule of thumb: &lt;strong&gt;do not put anything critical on those pins&lt;/strong&gt; and, if you do,
check their state at boot.&lt;/p&gt;
&lt;h3 id=&quot;gpio34-to-gpio39-input-only&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gpio34-to-gpio39-input-only&quot; aria-label=&quot;Anchor link for: gpio34-to-gpio39-input-only&quot;&gt;GPIO34 to GPIO39: input only&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;They have no internal pull-up or pull-down and &lt;strong&gt;cannot be used as outputs&lt;/strong&gt;.
They are perfect for a sensor you only need to read, but if you try to light an
LED with them it will not work and you will spend a while thinking the LED is
broken.&lt;/p&gt;
&lt;h2 id=&quot;the-adc-lies-and-how-to-tame-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-adc-lies-and-how-to-tame-it&quot; aria-label=&quot;Anchor link for: the-adc-lies-and-how-to-tame-it&quot;&gt;The ADC lies (and how to tame it)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the detail that frustrates people most. The ESP32’s ADC is &lt;strong&gt;12-bit&lt;/strong&gt;,
but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It is not linear.&lt;/strong&gt; It deviates a lot near 0 V and near 3.3 V.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It has an offset.&lt;/strong&gt; With 11 dB attenuation it saturates earlier than the
datasheet suggests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It needs calibration.&lt;/strong&gt; ESP-IDF ships an &lt;em&gt;eFuse&lt;/em&gt; calibration API. Use it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ADC2 does not work with Wi-Fi on.&lt;/strong&gt; We repeat: use &lt;strong&gt;ADC1&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need decent, stable measurements, an external &lt;strong&gt;ADS1115&lt;/strong&gt; over I2C will
save you a lot of headaches.&lt;/p&gt;
&lt;h2 id=&quot;psram-when-you-need-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#psram-when-you-need-it&quot; aria-label=&quot;Anchor link for: psram-when-you-need-it&quot;&gt;PSRAM: when you need it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PSRAM is extra memory (typically 8 MB on the WROVER). You need it if you are
going to hold large buffers: images, audio, huge JSONs or network buffers.&lt;/p&gt;
&lt;p&gt;If your project is sensors and a couple of LEDs, &lt;strong&gt;you do not need it&lt;/strong&gt; and the
WROOM is cheaper. And remember the toll: PSRAM uses &lt;strong&gt;GPIO16 and GPIO17&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;when-to-pick-the-classic-and-when-not-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-to-pick-the-classic-and-when-not-to&quot; aria-label=&quot;Anchor link for: when-to-pick-the-classic-and-when-not-to&quot;&gt;When to pick the classic (and when not to)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes, pick the classic if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need &lt;strong&gt;classic Bluetooth&lt;/strong&gt; (not just BLE).&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;DAC&lt;/strong&gt;, &lt;strong&gt;touch&lt;/strong&gt; or &lt;strong&gt;CAN&lt;/strong&gt; without adding anything.&lt;/li&gt;
&lt;li&gt;You need lots of GPIOs and GPIO16/17 free.&lt;/li&gt;
&lt;li&gt;You are following a tutorial that assumes the classic and do not want to fight
different pins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pick something else if…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You want the cheapest, most modern option: a &lt;strong&gt;C3&lt;/strong&gt; does almost the same for
less.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;native USB&lt;/strong&gt; (HID, JTAG): &lt;strong&gt;S2&lt;/strong&gt;, &lt;strong&gt;S3&lt;/strong&gt;, &lt;strong&gt;C3&lt;/strong&gt; or &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need camera, audio or AI: &lt;strong&gt;ESP32-S3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You want Matter/Thread/Zigbee: &lt;strong&gt;C6&lt;/strong&gt; or &lt;strong&gt;H2&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;current-tools-2026&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#current-tools-2026&quot; aria-label=&quot;Anchor link for: current-tools-2026&quot;&gt;Current tools (2026)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are going to program it, these are the living versions today:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tool&lt;/th&gt;&lt;th&gt;Current version&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ESP-IDF&lt;/td&gt;&lt;td&gt;&lt;strong&gt;6.1&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Arduino core&lt;/td&gt;&lt;td&gt;&lt;strong&gt;3.3.11&lt;/strong&gt; (on ESP-IDF 5.5.5)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PlatformIO (&lt;code&gt;platform-espressif32&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;7.1.3&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MicroPython&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1.29&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;esp-hal&lt;/code&gt; (Rust)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1.2.0&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;typical-mistakes-with-the-classic&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typical-mistakes-with-the-classic&quot; aria-label=&quot;Anchor link for: typical-mistakes-with-the-classic&quot;&gt;Typical mistakes with the classic&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Trying to use &lt;strong&gt;GPIO6–11&lt;/strong&gt; “because they look free on the drawing”.&lt;/li&gt;
&lt;li&gt;Putting an &lt;strong&gt;LED on GPIO34–39&lt;/strong&gt; and not understanding why it stays dark.&lt;/li&gt;
&lt;li&gt;Reading a potentiometer on &lt;strong&gt;ADC2&lt;/strong&gt; and getting wild values once Wi-Fi comes
up.&lt;/li&gt;
&lt;li&gt;Using &lt;strong&gt;GPIO12&lt;/strong&gt; as an output and having the board boot whenever it feels
like it.&lt;/li&gt;
&lt;li&gt;Buying a &lt;strong&gt;WROVER&lt;/strong&gt; to use GPIO16/17 and discovering they are taken.&lt;/li&gt;
&lt;li&gt;Blaming your code when the problem is the &lt;strong&gt;CH340 driver&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The classic ESP32 is &lt;strong&gt;2 × LX6 cores, 520 KB SRAM&lt;/strong&gt;, Wi-Fi 4 and &lt;strong&gt;classic
Bluetooth + BLE&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The modules you will see: &lt;strong&gt;WROOM-32E&lt;/strong&gt; (no PSRAM) and &lt;strong&gt;WROVER-E&lt;/strong&gt; (with PSRAM
that eats GPIO16/17).&lt;/li&gt;
&lt;li&gt;It has unique things: &lt;strong&gt;DAC&lt;/strong&gt;, &lt;strong&gt;touch&lt;/strong&gt;, &lt;strong&gt;CAN&lt;/strong&gt; and &lt;strong&gt;classic Bluetooth&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Watch out for &lt;strong&gt;GPIO6–11&lt;/strong&gt;, the &lt;strong&gt;strapping&lt;/strong&gt; pins (0, 2, 12, 15) and
&lt;strong&gt;GPIO34–39&lt;/strong&gt; (input only).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ADC2 does not work with Wi-Fi&lt;/strong&gt;; use &lt;strong&gt;ADC1&lt;/strong&gt; and, if you need precision, an
ADS1115.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; if you want something smaller, cheaper and with native USB, Part 3
is about the &lt;a href=&quot;https://esp32.tunatek.tech/introduccion-esp32/&quot;&gt;ESP32-S2&lt;/a&gt;. And if you do not have a board
yet, start with
&lt;a href=&quot;https://esp32.tunatek.tech/en/blog/que-es-el-esp32-y-su-familia/&quot;&gt;Part 1: what the ESP32 is and its family&lt;/a&gt;.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Image credits&lt;/summary&gt;
&lt;p&gt;Photos from &lt;strong&gt;Wikimedia Commons&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESP32-WROOM-32 module (front and back) and ESP32-DevKitC — Ubahnverleih (CC0)&lt;/li&gt;
&lt;li&gt;ESP32 DevKitC pinout — Vishnu Maiea (CC BY-SA 4.0)&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What is the ESP32? The complete family, pinouts and where to buy it</title>
        <published>2026-09-17T00:00:00+00:00</published>
        <updated>2026-09-17T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/blog/que-es-el-esp32-y-su-familia/"/>
        <id>https://esp32.tunatek.tech/en/blog/que-es-el-esp32-y-su-familia/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/blog/que-es-el-esp32-y-su-familia/">&lt;p&gt;The &lt;strong&gt;ESP32&lt;/strong&gt; is probably the most popular Wi-Fi + Bluetooth microcontroller in
the maker world. It costs less than a coffee, is roughly 20× more powerful than
an Arduino UNO, and comes in a dozen flavours: ESP32, S2, S3, C3, C6, H2, P4…
Picking the wrong variant is the number one beginner mistake.&lt;/p&gt;
&lt;p&gt;This guide is &lt;strong&gt;the one I wish I had read at the start&lt;/strong&gt;: what it exactly is, how
each family member differs, how to read a pinout without getting it wrong, which
one to buy for your project, and &lt;strong&gt;where to get it&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-esp32-in-30-seconds&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-esp32-in-30-seconds&quot; aria-label=&quot;Anchor link for: the-esp32-in-30-seconds&quot;&gt;The ESP32 in 30 seconds&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An ESP32 is a chip (SoC) that includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;32-bit&lt;/strong&gt; processor (1 or 2 cores, Xtensa or RISC-V).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wi-Fi&lt;/strong&gt; and, depending on the variant, &lt;strong&gt;classic Bluetooth, BLE and/or Zigbee/Thread&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SRAM&lt;/strong&gt; and, on some models, external &lt;strong&gt;PSRAM&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Plenty of &lt;strong&gt;peripherals&lt;/strong&gt;: GPIO, ADC, DAC, PWM, I2C, SPI, UART, I2S, CAN…&lt;/li&gt;
&lt;li&gt;All for &lt;strong&gt;$2–5&lt;/strong&gt; on a board that plugs straight into USB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That mix of power, radio and price is what made it the de-facto standard for home IoT.&lt;/p&gt;
&lt;h2 id=&quot;soc-module-and-board-are-not-the-same-thing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#soc-module-and-board-are-not-the-same-thing&quot; aria-label=&quot;Anchor link for: soc-module-and-board-are-not-the-same-thing&quot;&gt;SoC, module and board are not the same thing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A detail that confuses many people:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Term&lt;/th&gt;&lt;th&gt;What it is&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SoC&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;The bare chip&lt;/td&gt;&lt;td&gt;&lt;code&gt;ESP32-D0WDQ6&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Module&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;SoC + flash + antenna + shielding&lt;/td&gt;&lt;td&gt;&lt;code&gt;ESP32-WROOM-32&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Board / devkit&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Module + USB + regulator + buttons&lt;/td&gt;&lt;td&gt;&lt;code&gt;ESP32-DevKitC-32E&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-wroom.jpg&quot; alt=&quot;Close-up of an ESP32-WROOM-32 module with its metal shield&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;An &lt;strong&gt;ESP32-WROOM-32&lt;/strong&gt; module: SoC, flash and antenna in one part. Photo: Ubahnverleih (CC0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When you buy on AliExpress or Mercado Libre you almost always get a &lt;strong&gt;devkit&lt;/strong&gt;
(the full board). When you design your own PCB, you buy the &lt;strong&gt;module&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-esp32-family&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-esp32-family&quot; aria-label=&quot;Anchor link for: the-esp32-family&quot;&gt;The ESP32 family&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All relevant members, in chronological order:&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/familia-esp32.svg&quot; alt=&quot;Timeline of the ESP family: ESP8266, ESP32, S2, C3, S3, C6, H2 and P4&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;The ESP family, from the ESP8266 (2014) to the ESP32-P4 (2024).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And the table that actually matters when buying:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Variant&lt;/th&gt;&lt;th&gt;Year&lt;/th&gt;&lt;th&gt;Core&lt;/th&gt;&lt;th&gt;Radio&lt;/th&gt;&lt;th&gt;GPIOs&lt;/th&gt;&lt;th&gt;Native USB&lt;/th&gt;&lt;th&gt;Best for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ESP8266&lt;/td&gt;&lt;td&gt;2014&lt;/td&gt;&lt;td&gt;Xtensa L106 ×1 @ 160 MHz&lt;/td&gt;&lt;td&gt;Wi-Fi 4&lt;/td&gt;&lt;td&gt;~11 usable&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;Cheapest Wi-Fi projects&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ESP32&lt;/strong&gt; (classic)&lt;/td&gt;&lt;td&gt;2016&lt;/td&gt;&lt;td&gt;Xtensa LX6 ×2 @ 240 MHz&lt;/td&gt;&lt;td&gt;Wi-Fi 4 + BT 4.2&lt;/td&gt;&lt;td&gt;~34 (25 usable)&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;General purpose, cheapest&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-S2&lt;/td&gt;&lt;td&gt;2019&lt;/td&gt;&lt;td&gt;Xtensa LX7 ×1 @ 240 MHz&lt;/td&gt;&lt;td&gt;Wi-Fi 4&lt;/td&gt;&lt;td&gt;~43&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;USB, HID, lots of pins&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-C3&lt;/td&gt;&lt;td&gt;2020&lt;/td&gt;&lt;td&gt;RISC-V ×1 @ 160 MHz&lt;/td&gt;&lt;td&gt;Wi-Fi 4 + BLE 5&lt;/td&gt;&lt;td&gt;~22&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;Modern, inexpensive replacement&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ESP32-S3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2020&lt;/td&gt;&lt;td&gt;Xtensa LX7 ×2 @ 240 MHz&lt;/td&gt;&lt;td&gt;Wi-Fi 4 + BLE 5&lt;/td&gt;&lt;td&gt;~45&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;AI, camera, audio, USB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-C6&lt;/td&gt;&lt;td&gt;2022&lt;/td&gt;&lt;td&gt;RISC-V ×1 @ 160 MHz (+ LP core)&lt;/td&gt;&lt;td&gt;Wi-Fi 6 + BLE 5 + 802.15.4&lt;/td&gt;&lt;td&gt;~30&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;Matter, Thread, Zigbee&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-H2&lt;/td&gt;&lt;td&gt;2023&lt;/td&gt;&lt;td&gt;RISC-V ×1 @ 96 MHz&lt;/td&gt;&lt;td&gt;BLE 5 + 802.15.4&lt;/td&gt;&lt;td&gt;~26&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;Matter/Zigbee nodes without Wi-Fi&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ESP32-P4&lt;/td&gt;&lt;td&gt;2024&lt;/td&gt;&lt;td&gt;RISC-V ×2 @ 400 MHz&lt;/td&gt;&lt;td&gt;&lt;em&gt;no radio&lt;/em&gt;&lt;/td&gt;&lt;td&gt;many&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;HMI, displays, high performance&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Quick rule:&lt;/strong&gt; not sure? Buy an &lt;strong&gt;ESP32-C3&lt;/strong&gt; if you want something cheap and
modern, or an &lt;strong&gt;ESP32-S3&lt;/strong&gt; if you need power, camera or USB.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;variant-by-variant&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#variant-by-variant&quot; aria-label=&quot;Anchor link for: variant-by-variant&quot;&gt;Variant by variant&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;esp8266-the-grandfather-that-still-works&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp8266-the-grandfather-that-still-works&quot; aria-label=&quot;Anchor link for: esp8266-the-grandfather-that-still-works&quot;&gt;ESP8266 — the grandfather that still works&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is not an ESP32, but it is its predecessor and still sells for under $2. It has
&lt;strong&gt;one core&lt;/strong&gt;, no Bluetooth and few GPIOs — yet it is enough for a temperature
sensor publishing over Wi-Fi.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp8266.jpg&quot; alt=&quot;ESP8266 module&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP8266: the chip that put cheap Wi-Fi in makers&#39; hands. Photo: Suyash Dwivedi (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Only consider it if&lt;/strong&gt; price is the only thing that matters. For a little more
you get a C3, which is better at everything.&lt;/p&gt;
&lt;h3 id=&quot;classic-esp32-the-all-rounder&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#classic-esp32-the-all-rounder&quot; aria-label=&quot;Anchor link for: classic-esp32-the-all-rounder&quot;&gt;Classic ESP32 — the all-rounder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The 2016 one. &lt;strong&gt;Two cores&lt;/strong&gt; at 240 MHz, more GPIOs than almost any other, and the
only variant with &lt;strong&gt;classic Bluetooth&lt;/strong&gt; (plus BLE). It is the chip in most old
tutorials and still a perfect choice to start.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-devkitc.jpg&quot; alt=&quot;ESP32 DevKitC development board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;An ESP32-DevKitC: WROOM module, USB, regulator and two buttons. Photo: Edwiyanto (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; no native USB (it uses a CH340 or CP2102 serial chip) and higher
sleep current than modern variants.&lt;/p&gt;
&lt;h3 id=&quot;esp32-s2-the-one-without-bluetooth&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp32-s2-the-one-without-bluetooth&quot; aria-label=&quot;Anchor link for: esp32-s2-the-one-without-bluetooth&quot;&gt;ESP32-S2 — the one without Bluetooth&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The S2 was the first ESP32 with &lt;strong&gt;native USB OTG&lt;/strong&gt; and lots of GPIOs (~43). Its
sin: &lt;strong&gt;no Bluetooth&lt;/strong&gt;. If you do not need it, it is a great option for HID
(keyboards, mice) or pin-hungry projects.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-s2.svg&quot; alt=&quot;Illustration of the ESP32-S2 and its features&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-S2: native USB OTG, Wi-Fi 4 and no Bluetooth. Illustration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;esp32-s3-the-powerful-one&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp32-s3-the-powerful-one&quot; aria-label=&quot;Anchor link for: esp32-s3-the-powerful-one&quot;&gt;ESP32-S3 — the powerful one&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The favourite for ambitious projects: &lt;strong&gt;two LX7 cores&lt;/strong&gt;, BLE 5, native USB and,
above all, &lt;strong&gt;vector instructions&lt;/strong&gt; that speed up AI workloads (voice, vision). It
is what camera boards and display boards use.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-s3.jpg&quot; alt=&quot;ESP32-S3 board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-S3: the most capable variant for edge AI and multimedia. Photo: VectorVoyager (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; pricier than a C3, and overkill if you are not using camera/AI.&lt;/p&gt;
&lt;h3 id=&quot;esp32-c3-the-balanced-one&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp32-c3-the-balanced-one&quot; aria-label=&quot;Anchor link for: esp32-c3-the-balanced-one&quot;&gt;ESP32-C3 — the balanced one&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My default recommendation in 2026. It is &lt;strong&gt;RISC-V&lt;/strong&gt;, with BLE 5, native
USB Serial/JTAG and an ESP8266-like price. For sensors, relays, home automation
and almost any normal project, it is more than enough.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-c3.jpg&quot; alt=&quot;ESP32-C3 NodeMCU-style board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;An ESP32-C3 NodeMCU board: small, cheap and USB-C. Photo: Popolon (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; fewer GPIOs (~22) and no classic Bluetooth (BLE only).&lt;/p&gt;
&lt;h3 id=&quot;esp32-c6-the-matter-one&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp32-c6-the-matter-one&quot; aria-label=&quot;Anchor link for: esp32-c6-the-matter-one&quot;&gt;ESP32-C6 — the Matter one&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first ESP32 with &lt;strong&gt;Wi-Fi 6&lt;/strong&gt; and, more importantly, an &lt;strong&gt;802.15.4&lt;/strong&gt; radio:
that means &lt;strong&gt;Thread, Zigbee and Matter&lt;/strong&gt;. If you want modern, compatible home
automation, this is the chip.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-c6.jpg&quot; alt=&quot;ESP32-C6 development board&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-C6: Wi-Fi 6 + BLE 5 + 802.15.4 (Thread/Zigbee/Matter). Photo: Popolon (CC BY-SA 4.0).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; it needs a recent toolchain (ESP-IDF 5.1+) and some modules are
still hard to find locally.&lt;/p&gt;
&lt;h3 id=&quot;esp32-h2-the-one-without-wi-fi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp32-h2-the-one-without-wi-fi&quot; aria-label=&quot;Anchor link for: esp32-h2-the-one-without-wi-fi&quot;&gt;ESP32-H2 — the one without Wi-Fi&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like the C6 but &lt;strong&gt;without Wi-Fi&lt;/strong&gt;: only BLE and 802.15.4. It sounds odd, but for a
battery-powered Matter node it is perfect (less radio, less power).&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/esp32-h2.svg&quot; alt=&quot;Illustration of the ESP32-H2 and its features&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-H2: BLE 5 + Zigbee/Thread, no Wi-Fi. Illustration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;esp32-p4-the-new-one-no-radio&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#esp32-p4-the-new-one-no-radio&quot; aria-label=&quot;Anchor link for: esp32-p4-the-new-one-no-radio&quot;&gt;ESP32-P4 — the new one (no radio)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The P4 (2024) is different: &lt;strong&gt;no Wi-Fi or Bluetooth&lt;/strong&gt;, but two 400 MHz cores and
support for high-end displays/cameras. It is used as an application host, usually
paired with a C6 for connectivity.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-know-which-board-i-have&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-do-i-know-which-board-i-have&quot; aria-label=&quot;Anchor link for: how-do-i-know-which-board-i-have&quot;&gt;How do I know which board I have?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Look for the &lt;strong&gt;name printed on the metal module&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ESP-WROOM-32&lt;/code&gt; or &lt;code&gt;ESP32-WROOM-32&lt;/code&gt; → &lt;strong&gt;classic ESP32&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESP32-WROVER&lt;/code&gt; → classic &lt;strong&gt;with PSRAM&lt;/strong&gt; (more memory, great for cameras).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESP32-S3-WROOM-1&lt;/code&gt; → &lt;strong&gt;S3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESP32-C3-MINI-1&lt;/code&gt; or &lt;code&gt;ESP32-C3-WROOM-02&lt;/code&gt; → &lt;strong&gt;C3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESP32-C6-WROOM-1&lt;/code&gt; → &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESP32-S2-…&lt;/code&gt; → &lt;strong&gt;S2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESP32-H2-…&lt;/code&gt; → &lt;strong&gt;H2&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you see nothing, look at the pin pattern: the classic’s &lt;strong&gt;GPIO34–39 are
input-only&lt;/strong&gt;, which is unmistakable once you probe a sensor.&lt;/p&gt;
&lt;h2 id=&quot;pinouts-the-pin-maps&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pinouts-the-pin-maps&quot; aria-label=&quot;Anchor link for: pinouts-the-pin-maps&quot;&gt;Pinouts (the pin maps)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;em&gt;pinout&lt;/em&gt; is the map that tells you what each pin does. &lt;strong&gt;Not all pins are
equal&lt;/strong&gt;: some are input-only, some set the boot mode and some are off-limits.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/pinout-esp32-devkitc.png&quot; alt=&quot;Full ESP32-DevKitC pinout&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32 (DevKitC) pinout. Source: Wikimedia Commons, CC BY-SA 4.0.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Guidelines worth gold on the classic ESP32:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GPIO6–11&lt;/strong&gt;: wired to the flash. &lt;strong&gt;Never use them.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO34–39&lt;/strong&gt;: &lt;strong&gt;input only&lt;/strong&gt;, no internal pull-up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO0, 2, 12, 15&lt;/strong&gt;: they affect the boot mode. Avoid them as outputs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO1 (TX0) and GPIO3 (RX0)&lt;/strong&gt;: the serial port. Use with care.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ADC2&lt;/strong&gt; does not work while Wi-Fi is active: use &lt;strong&gt;ADC1&lt;/strong&gt; (GPIO32–39).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the C3 pinout, increasingly common:&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/images/posts/que-es-esp32/pinout-esp32-c3.png&quot; alt=&quot;ESP32-C3 pinout&quot; loading=&quot;lazy&quot;&gt;
  &lt;figcaption&gt;ESP32-C3 pinout. Source: Wikimedia Commons, CC BY-SA 4.0.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Official, always up-to-date pinouts live at
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.espressif.com/&quot;&gt;docs.espressif.com&lt;/a&gt;. When in doubt, that is the
source of truth.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;which-one-should-i-buy-by-project&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#which-one-should-i-buy-by-project&quot; aria-label=&quot;Anchor link for: which-one-should-i-buy-by-project&quot;&gt;Which one should I buy? (by project)&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;I want…&lt;/th&gt;&lt;th&gt;Buy&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;To start and learn&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP32-C3&lt;/strong&gt; or &lt;strong&gt;classic ESP32&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Home Assistant automation&lt;/td&gt;&lt;td&gt;ESP32-C3 or, for Matter, &lt;strong&gt;C6&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Camera, audio or AI&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP32-S3&lt;/strong&gt; (+ PSRAM)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;A battery Matter/Zigbee node&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP32-C6&lt;/strong&gt; or &lt;strong&gt;H2&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Lots of pins or USB HID&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP32-S2&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;The cheapest sensor node&lt;/td&gt;&lt;td&gt;ESP8266 &lt;em&gt;or&lt;/em&gt; ESP32-C3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;A big display / HMI&lt;/td&gt;&lt;td&gt;&lt;strong&gt;ESP32-P4&lt;/strong&gt; + C6&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For your &lt;strong&gt;first board&lt;/strong&gt;, buy &lt;strong&gt;two&lt;/strong&gt;: a cheap C3 to tinker with and an S3 with
PSRAM if you are thinking about cameras or displays. That way you will not run short.&lt;/p&gt;
&lt;h2 id=&quot;where-to-buy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-to-buy&quot; aria-label=&quot;Anchor link for: where-to-buy&quot;&gt;Where to buy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the part almost no Spanish-language tutorial covers well. Prices and
shipping vary a lot by store and country, so treat this as a guide to &lt;strong&gt;where to
look and what to watch out for&lt;/strong&gt;, not a fixed ranking.&lt;/p&gt;
&lt;h3 id=&quot;mx-mexico&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#mx-mexico&quot; aria-label=&quot;Anchor link for: mx-mexico&quot;&gt;🇲🇽 Mexico&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mercado Libre&lt;/strong&gt; — the most practical: domestic shipping, local payment and
competitive prices. &lt;strong&gt;Watch the sellers&lt;/strong&gt;: check reputation and make sure the
photos are of the real product (not a generic render).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Mexico&lt;/strong&gt; — fast shipping (Prime) and easy returns; usually a bit more
expensive than Mercado Libre.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UNIT Electronics&lt;/strong&gt; — Mexican electronics/development store. Good for buying
loose modules, sensors and accessories in the same order, though board stock
varies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local robotics/maker shops&lt;/strong&gt; — many cities have one (CDMX, Guadalajara,
Monterrey); worth it if you need the part &lt;em&gt;today&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;earth-americas-international&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#earth-americas-international&quot; aria-label=&quot;Anchor link for: earth-americas-international&quot;&gt;🌎 International&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AliExpress&lt;/strong&gt; — by far the cheapest. Downside: slow shipping (2–6 weeks) and
variable quality. Great for ordering &lt;strong&gt;several boards and sensors&lt;/strong&gt; at once.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LCSC&lt;/strong&gt; — genuine components and modules at good prices; useful for volume or
PCB design.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adafruit / SparkFun&lt;/strong&gt; — their own boards, great quality and excellent docs.
Expensive to ship to Latin America, but the standard for serious prototypes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mouser / Digi-Key / Farnell&lt;/strong&gt; — &lt;strong&gt;authorized&lt;/strong&gt; distributors: guaranteed
original chips and datasheets. They ship to Mexico, with cost and paperwork.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Espressif (official store)&lt;/strong&gt; — original modules; useful if you manufacture.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-to-avoid-bad-clones&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-avoid-bad-clones&quot; aria-label=&quot;Anchor link for: how-to-avoid-bad-clones&quot;&gt;How to avoid bad clones&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ask about the USB-serial chip.&lt;/strong&gt; CH340 works, but some drivers are painful
on macOS. CP2102 usually gives less trouble.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;30 vs 38 pins.&lt;/strong&gt; Many cheap classic boards only break out 30 pins: you lose
GPIOs. If you can, pick the 38-pin one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USB-C vs micro-USB.&lt;/strong&gt; Micro-USB in 2026 is a pain; pay a little more for C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real PSRAM.&lt;/strong&gt; If you buy an S3 for camera work, make sure it &lt;strong&gt;lists PSRAM&lt;/strong&gt;
(8 MB on the good ones).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Antenna.&lt;/strong&gt; Boards with a U.FL/IPEX connector allow an external antenna if
the ESP32 will live inside a metal enclosure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BOOT and EN buttons.&lt;/strong&gt; Make sure they exist: without &lt;code&gt;BOOT&lt;/code&gt; you sometimes
cannot flash.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;common-beginner-mistakes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#common-beginner-mistakes&quot; aria-label=&quot;Anchor link for: common-beginner-mistakes&quot;&gt;Common beginner mistakes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Buying a board &lt;strong&gt;without native USB&lt;/strong&gt; thinking the serial port is native.&lt;/li&gt;
&lt;li&gt;Choosing the &lt;strong&gt;ESP8266&lt;/strong&gt; “because it is cheaper” when the C3 costs about the
same and is better.&lt;/li&gt;
&lt;li&gt;Buying an &lt;strong&gt;S3 without PSRAM&lt;/strong&gt; for a camera project.&lt;/li&gt;
&lt;li&gt;Forgetting that on the classic the &lt;strong&gt;GPIO34–39 are input only&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Trying to use &lt;strong&gt;ADC2 with Wi-Fi on&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The ESP32 is a SoC with radio, plenty of power and a ridiculous price.&lt;/li&gt;
&lt;li&gt;The family is broad: &lt;strong&gt;ESP8266 → ESP32 → S2 → C3 → S3 → C6 → H2 → P4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;To start: &lt;strong&gt;C3&lt;/strong&gt; (cheap) or &lt;strong&gt;S3&lt;/strong&gt; (powerful). For modern automation: &lt;strong&gt;C6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;pinout&lt;/strong&gt; is not optional: there are forbidden pins and input-only pins.&lt;/li&gt;
&lt;li&gt;Buy where you can return, and distrust boards that are “too cheap”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; pick your board and set up the toolchain. The next chapters of the
&lt;em&gt;ESP32 first steps&lt;/em&gt; series will appear on the &lt;a href=&quot;https://esp32.tunatek.tech/blog/&quot;&gt;blog&lt;/a&gt;; in the
meantime, browse by topic or hit &lt;code&gt;Ctrl + K&lt;/code&gt; to search.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Image credits&lt;/summary&gt;
&lt;p&gt;All photographs come from &lt;strong&gt;Wikimedia Commons&lt;/strong&gt; and are used under their license
(CC0 or CC BY-SA 4.0), with attribution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESP32-WROOM-32 module — Ubahnverleih (CC0)&lt;/li&gt;
&lt;li&gt;ESP32-DevKitC — Edwiyanto (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP32-S3 — VectorVoyager (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP32-C3 — Popolon (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP32-C6 — Popolon (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP32-CAM — Nowforever (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP8266 — Suyash Dwivedi (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP32 DevKitC pinout — Vishnu Maiea (CC BY-SA 4.0)&lt;/li&gt;
&lt;li&gt;ESP32-C3 pinout — Srdocdoc (CC BY-SA 4.0)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ESP32-S2, ESP32-H2 and family illustrations are our own.&lt;/p&gt;
&lt;/details&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Introduction to the ESP32</title>
        <published>2026-09-16T00:00:00+00:00</published>
        <updated>2026-09-16T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/introduccion-esp32/"/>
        <id>https://esp32.tunatek.tech/en/introduccion-esp32/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/introduccion-esp32/">&lt;p&gt;This series is &lt;strong&gt;the gateway to the ESP32&lt;/strong&gt;. It is designed to be read in order,
but each article also works on its own.&lt;/p&gt;
&lt;p&gt;We start by understanding &lt;strong&gt;what it is and which variant fits you&lt;/strong&gt;, continue
with the &lt;strong&gt;frameworks&lt;/strong&gt; (Arduino, ESP-IDF, MicroPython, Rust) and &lt;strong&gt;editors&lt;/strong&gt;,
and finish by writing your &lt;strong&gt;first program&lt;/strong&gt; on real hardware.&lt;/p&gt;
&lt;p&gt;All the code is tested on real boards, with measurements and pinouts — no
copy-pasting from other tutorials.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Explore</title>
        <published>2026-01-16T00:00:00+00:00</published>
        <updated>2026-01-16T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/explorar/"/>
        <id>https://esp32.tunatek.tech/en/explorar/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/explorar/"></content>
        
    </entry>
    <entry xml:lang="en">
        <title>About</title>
        <published>2026-01-15T00:00:00+00:00</published>
        <updated>2026-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>Alejandro Lara</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://esp32.tunatek.tech/en/about/"/>
        <id>https://esp32.tunatek.tech/en/about/</id>
        
        <content type="html" xml:base="https://esp32.tunatek.tech/en/about/">&lt;h2 id=&quot;hi-wave&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hi-wave&quot; aria-label=&quot;Anchor link for: hi-wave&quot;&gt;Hi 👋&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a blog dedicated to the &lt;strong&gt;ESP32&lt;/strong&gt;: the Wi-Fi and Bluetooth
microcontroller that became the heart of countless IoT projects.&lt;/p&gt;
&lt;p&gt;Here you will find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step-by-step tutorials&lt;/strong&gt;, from the first &lt;em&gt;blink&lt;/em&gt; to production IoT.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complete projects&lt;/strong&gt; with schematics, code and design decisions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Engineering notes&lt;/strong&gt;: power, antennas, RTOS, security and debugging.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All content is written in Markdown inside this very repository and built with
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.getzola.org/&quot;&gt;Zola&lt;/a&gt;, a static site generator written in Rust. No
database, no CMS: just text and Git.&lt;/p&gt;
&lt;h2 id=&quot;this-site-s-stack&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#this-site-s-stack&quot; aria-label=&quot;Anchor link for: this-site-s-stack&quot;&gt;This site’s stack&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Layer&lt;/th&gt;&lt;th&gt;Technology&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Generator&lt;/td&gt;&lt;td&gt;Zola (Rust)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Templates&lt;/td&gt;&lt;td&gt;Tera&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Code highlighting&lt;/td&gt;&lt;td&gt;Giallo&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Math&lt;/td&gt;&lt;td&gt;KaTeX&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Search&lt;/td&gt;&lt;td&gt;elasticlunr (index generated by Zola)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;If you want to suggest a topic or fix something, open an &lt;em&gt;issue&lt;/em&gt; or a &lt;em&gt;pull request&lt;/em&gt;.&lt;/p&gt;
</content>
        
    </entry>
</feed>
