<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ESP32 Tutorials | Teach Me Microcontrollers!</title>
	<atom:link href="https://www.teachmemicro.com/category/tutorials/esp32-tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.teachmemicro.com/category/tutorials/esp32-tutorial/</link>
	<description>Microcontroller Tutorials and Resources</description>
	<lastBuildDate>Wed, 21 Oct 2026 23:53:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>

<image>
	<url>https://www.teachmemicro.com/wp-content/uploads/2019/04/blue-icon-65x65.png</url>
	<title>ESP32 Tutorials | Teach Me Microcontrollers!</title>
	<link>https://www.teachmemicro.com/category/tutorials/esp32-tutorial/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>DFRobot FireBeetle 2 ESP32-UE: What Makes This ESP32 Board Different?</title>
		<link>https://www.teachmemicro.com/dfrobot-firebeetle-2-esp32-ue-what-makes-this-esp32-board-different/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 23:24:33 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=13022</guid>

					<description><![CDATA[<p>Most ESP32 development boards are designed for prototyping. Connect a USB cable, upload a sketch, and start experimenting. But when you want to put an ESP32 in an enclosure or run it from a battery, the board's design becomes as important as the microcontroller itself. The DFRobot FireBeetle 2 ESP32-UE addresses several of those practical &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/dfrobot-firebeetle-2-esp32-ue-what-makes-this-esp32-board-different/">DFRobot FireBeetle 2 ESP32-UE: What Makes This ESP32 Board Different?</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Most ESP32 development boards are designed for prototyping. Connect a USB cable, upload a sketch, and start experimenting. But when you want to put an ESP32 in an enclosure or run it from a battery, the board's design becomes as important as the microcontroller itself.</p>
<p>The <strong>DFRobot FireBeetle 2 ESP32-UE</strong> addresses several of those practical requirements. It has an external antenna connector, built-in Li-ion battery charging, low-power hardware, 16 MB flash, and 2 MB PSRAM. It also includes a connector for compatible displays.</p>
<p>In this article, we'll cover what these features do, set up the board in Arduino IDE, and show how to check its Wi-Fi signal strength and sleep current.</p>
<p><span id="more-13022"></span></p>
<p><img data-dominant-color="dbdad9" data-has-transparency="false" style="--dominant-color: #dbdad9;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13125 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Development-Board-with-External-Antenna.avif" alt="ESP32 Development Board with External Antenna" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Development-Board-with-External-Antenna.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Development-Board-with-External-Antenna-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<h2><strong>What Is the FireBeetle 2 ESP32-UE?</strong></h2>
<p>The FireBeetle 2 ESP32-UE uses an <strong>ESP32-WROOM-32UE-N16R2</strong> module. This is based on the original dual-core ESP32, not a newer ESP32-S3 or ESP32-C6. You still get the familiar Wi-Fi, Bluetooth, PWM, ADC, DAC, touch sensing, UART, SPI, and I2C features.</p>
<p>Here are the main specifications:</p>
<ul>
<li>Dual-core Xtensa LX6 processor, up to 240 MHz</li>
<li>16 MB external flash and 2 MB PSRAM</li>
<li>520 KB internal SRAM</li>
<li>2.4 GHz Wi-Fi (802.11 b/g/n)</li>
<li>Bluetooth 4.2 Classic (BR/EDR) and BLE</li>
<li>USB-C for programming and power</li>
<li>Single-cell Li-ion battery connector and onboard charging</li>
<li>GDI display connector and onboard LEDs</li>
<li>Board dimensions: 25.4 × 60 mm</li>
</ul>
<p>DFRobot lists 17 digital pins and 11 analog-capable pins among the board's interfaces. Check the exact pins and their restrictions before wiring a project.</p>
<p><img data-dominant-color="b2b7b8" data-has-transparency="false" style="--dominant-color: #b2b7b8;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13137 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-scaled.avif" alt="ESP32-UE Annotated" width="2212" height="2560" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-scaled.avif 2212w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-259x300.avif 259w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-885x1024.avif 885w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-768x889.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-1327x1536.avif 1327w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-Annotated-01-1769x2048.avif 1769w" sizes="auto, (max-width: 2212px) 100vw, 2212px" /></p>
<p>The processor is familiar. The differences are mostly in how DFRobot has packaged it for projects that need to work away from a desk.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Why Use an External Antenna?</strong></h2>
<p>If you've used a regular ESP32-WROOM module, you've probably seen the exposed PCB antenna at one end. The ESP32-WROOM-32UE replaces that antenna with a small RF connector for an external 2.4 GHz Wi-Fi/Bluetooth antenna.</p>
<p>This matters when the ESP32 sits inside an enclosure. A nearby battery, display, ground plane, wiring, or metal surface can affect antenna performance. An external antenna lets you choose a better location without moving the entire circuit board.</p>
<p>Imagine an outdoor environmental monitor. The board and sensors sit inside a weather-resistant enclosure, while the antenna can be placed away from the crowded electronics or outside the enclosure using suitable weatherproof hardware.</p>
<p><img data-dominant-color="b4b1ae" data-has-transparency="false" style="--dominant-color: #b4b1ae;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13127 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Antenna-Setup-Comparison.avif" alt="ESP32 Antenna Setup Comparison" width="881" height="376" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Antenna-Setup-Comparison.avif 881w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Antenna-Setup-Comparison-300x128.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Antenna-Setup-Comparison-768x328.avif 768w" sizes="auto, (max-width: 881px) 100vw, 881px" /></p>
<p>That does not automatically make the FireBeetle a long-range ESP32. Signal strength also depends on antenna gain, orientation, cable loss, obstacles, interference, and the access point. An external antenna gives you <strong>more control over placement</strong>, not a guaranteed increase in range. We'll return to a simple Wi-Fi comparison after setting up the board.</p>
<div class="box info  "><div class="box-inner-block"><i class="fa tie-shortcode-boxicon"></i>
			Use a compatible 2.4 GHz antenna and connector assembly. Attach the antenna before performing wireless tests.
			</div></div>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Battery Power Without a Separate Charger Board</strong></h2>
<p>A better antenna location solves one problem for a remote sensor. The next is power.</p>
<p>The FireBeetle has a PH2.0 connector for a <strong>single-cell 3.7 V nominal Li-ion/LiPo battery</strong>. A fully charged cell can reach about 4.2 V. The board also includes charging circuitry, so you can connect USB power to charge the attached battery while you develop or service the device.</p>
<p>On a typical ESP32 prototype, you might need a separate battery charger and a suitable regulator. The FireBeetle already includes much of that hardware, which can reduce the number of extra modules and wires.</p>
<p><img data-dominant-color="cecac6" data-has-transparency="false" style="--dominant-color: #cecac6;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13128 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Board-and-LiPo-Battery-Flat-Lay.avif" alt="ESP32 Board and LiPo Battery Flat Lay" width="768" height="512" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Board-and-LiPo-Battery-Flat-Lay.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-Board-and-LiPo-Battery-Flat-Lay-300x200.avif 300w" sizes="auto, (max-width: 768px) 100vw, 768px" /></p>
<p>Before connecting a battery, check the connector polarity against the board documentation. PH2.0 connectors on different products do not always use the same wiring order. Use a suitable protected cell or battery pack and follow the manufacturer's charging and handling requirements.</p>
<p>If you're building a solar-powered device, you still need a charging and power-management arrangement suitable for the solar panel and battery. The battery connector alone is not a solar charge controller.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>How Low Can the FireBeetle Go?</strong></h2>
<p>Battery power becomes much more useful when the ESP32 can sleep between readings.</p>
<p>The ESP32 itself supports deep sleep, but a development board contains more than the ESP32. Its regulator, USB interface, LEDs, and other circuits may continue drawing current even while the processor sleeps.</p>
<p>DFRobot includes a <strong>low-power solder jumper</strong>, connected by default. According to DFRobot, disconnecting it reduces static consumption by approximately 500 µA, and the board can reach about <strong>13 µA in deep sleep</strong> under the manufacturer's stated conditions. Treat that number as a published specification rather than a measured result for your complete project.</p>
<p><img data-dominant-color="3a3634" data-has-transparency="false" style="--dominant-color: #3a3634;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13138 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/low-power-jumper-esp32-ue.avif" alt="Low-power jumper" width="869" height="1159" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/low-power-jumper-esp32-ue.avif 869w, https://www.teachmemicro.com/wp-content/uploads/2026/10/low-power-jumper-esp32-ue-225x300.avif 225w, https://www.teachmemicro.com/wp-content/uploads/2026/10/low-power-jumper-esp32-ue-768x1024.avif 768w" sizes="auto, (max-width: 869px) 100vw, 869px" /></p>
<p>There is a tradeoff. With the jumper disconnected, DFRobot says the onboard RGB LED can only be driven when USB power is present. If you don't need that LED in a battery-powered design, the reduced standby current may be worthwhile.</p>
<p>We'll use a short deep-sleep sketch later and measure current from the battery connection. The actual result will also depend on sensors, displays, pull-ups, and other connected hardware.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What Do 16 MB Flash and 2 MB PSRAM Add?</strong></h2>
<p>The ESP32-UE module carries <strong>16 MB flash</strong>, compared with the 4 MB found on many basic ESP32 development boards. That extra storage can make room for larger firmware images, OTA update partitions, web pages, fonts, and other files.</p>
<p>The amount available to a sketch or filesystem still depends on the selected flash-size settings and partition scheme. A 16 MB chip doesn't mean one Arduino sketch can automatically use all 16 MB.</p>
<p>PSRAM serves a different purpose. It adds 2 MB of external working memory, which can help when an application needs large buffers, such as a graphical interface, web response data, or image content. PSRAM is slower than internal RAM and is not a substitute for it in every application.</p>
<p>Also, <strong>having PSRAM on the module doesn't mean every allocation automatically uses it</strong>. The selected firmware configuration must initialize PSRAM, and applications may need PSRAM-aware allocations or libraries. We'll check shortly whether Arduino detects it.</p>
<h3><strong>The GDI Display Connector</strong></h3>
<p>The board also has DFRobot's GDI display interface. It uses an 18-pin FPC connection for compatible displays, helping reduce the jumper-wire clutter found in some display prototypes.</p>
<p><img data-dominant-color="abafb0" data-has-transparency="false" style="--dominant-color: #abafb0;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13129 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-GDI-Display.avif" alt="ESP32-UE GDI Display" width="673" height="570" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-GDI-Display.avif 673w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-GDI-Display-300x254.avif 300w" sizes="auto, (max-width: 673px) 100vw, 673px" /></p>
<p>For example, a sensor node could read temperature and humidity, update a local dashboard, and send the same measurements over Wi-Fi:</p>
<div class="tmm-flow-container tmm-flow-container--branched" role="img" aria-label="Flow diagram: Sensors to FireBeetle ESP32-UE; FireBeetle ESP32-UE to Compatible GDI Display; FireBeetle ESP32-UE to Wi-Fi; Wi-Fi to MQTT / Web Server."><div class="tmm-flow-canvas" data-tmm-flow-graph style="--tmm-flow-columns:4"><svg class="tmm-flow-lines" aria-hidden="true" focusable="false"><defs><marker id="tmm-flow-arrowhead-1" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto-start-reverse" markerUnits="strokeWidth"><path d="M0,0 L8,4 L0,8 Z"></path></marker></defs></svg><div class="tmm-flow-grid"><span class="tmm-flow-node" data-tmm-flow-node="0" style="--tmm-flow-column:1;--tmm-flow-row:1;--tmm-flow-order:1">Sensors</span><span class="tmm-flow-node" data-tmm-flow-node="1" style="--tmm-flow-column:2;--tmm-flow-row:1;--tmm-flow-order:2">FireBeetle ESP32-UE</span><span class="tmm-flow-node" data-tmm-flow-node="2" style="--tmm-flow-column:3;--tmm-flow-row:1;--tmm-flow-order:3">Compatible GDI Display</span><span class="tmm-flow-node" data-tmm-flow-node="3" style="--tmm-flow-column:3;--tmm-flow-row:2;--tmm-flow-order:4">Wi-Fi</span><span class="tmm-flow-node" data-tmm-flow-node="4" style="--tmm-flow-column:4;--tmm-flow-row:1;--tmm-flow-order:5">MQTT / Web Server</span></div><div class="tmm-flow-relations"><span class="tmm-flow-relation" data-tmm-flow-from="0" data-tmm-flow-to="1" data-tmm-flow-label="" data-tmm-flow-bidirectional="0">Sensors <span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span> FireBeetle ESP32-UE</span><span class="tmm-flow-relation" data-tmm-flow-from="1" data-tmm-flow-to="2" data-tmm-flow-label="" data-tmm-flow-bidirectional="0">FireBeetle ESP32-UE <span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span> Compatible GDI Display</span><span class="tmm-flow-relation" data-tmm-flow-from="1" data-tmm-flow-to="3" data-tmm-flow-label="" data-tmm-flow-bidirectional="0">FireBeetle ESP32-UE <span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span> Wi-Fi</span><span class="tmm-flow-relation" data-tmm-flow-from="3" data-tmm-flow-to="4" data-tmm-flow-label="" data-tmm-flow-bidirectional="0">Wi-Fi <span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span> MQTT / Web Server</span></div><span class="tmm-flow-marker-id" data-tmm-flow-marker="tmm-flow-arrowhead-1"></span></div></div>
<p>This is one reason the extra flash and PSRAM are useful together. They leave more room for assets and display buffers in projects using graphical libraries such as LVGL. Make sure the specific display and its library support the FireBeetle's GDI pin mapping; GDI isn't a universal connector for all displays.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Understanding the FireBeetle ESP32-UE Pinout</strong></h2>
<p>The pinout is mostly familiar, but DFRobot uses Arduino-style aliases alongside the underlying ESP32 GPIO numbers.</p>
<p>For example, the onboard indicator LED is on <strong>GPIO2</strong>, which DFRobot labels <strong>D9</strong> in its FireBeetle Arduino examples. The onboard WS2812 RGB LED uses GPIO5/D8, while the user button uses GPIO27/D4.</p>
<p><img data-dominant-color="d1d7d0" data-has-transparency="false" style="--dominant-color: #d1d7d0;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13130 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-pinout.avif" alt="ESP32-UE pinout diagram" width="1077" height="717" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-pinout.avif 1077w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-pinout-300x200.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-pinout-1024x682.avif 1024w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-pinout-768x511.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/10/ESP32-UE-pinout-310x205.avif 310w" sizes="auto, (max-width: 1077px) 100vw, 1077px" /></p>
<p>Check the actual GPIO number when adapting a generic ESP32 example. Some pins have boot-strapping functions, connect to onboard components, or are reserved for module memory or programming. The module's flash/PSRAM connections also mean you should not assume every GPIO number mentioned in a generic ESP32 tutorial is available for general use.</p>
<p>For analog sensors, one restriction is especially important. The original <span style="box-sizing: border-box; margin: 0px; padding: 0px;">ESP32 shares <strong>ADC2</strong></span><strong> with Wi-Fi</strong>. If your project needs Wi-Fi and analog readings at the same time, use an available ADC1 pin instead. On this board, <strong>GPIO34 and GPIO35</strong> are useful ADC1 options. Both are input-only and have no internal pull-up or pull-down resistors.</p>
<p>That small pin choice can save a lot of debugging in a Wi-Fi sensor project.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Getting Started with Arduino IDE</strong></h2>
<p>You can program the ESP32-UE with Arduino IDE, ESP-IDF, or MicroPython. We'll use Arduino here because the first tests need only a few lines of code.</p>
<p>To set up the board in Arduino IDE:</p>
<ol>
<li>Install the <strong>esp32 by Espressif Systems</strong> boards package through Boards Manager. If it isn't listed, add <code>https://espressif.github.io/arduino-esp32/package_esp32_index.json</code> under Additional Boards Manager URLs.</li>
<li>Go to <strong>Tools &gt; Board &gt; ESP32 Arduino &gt; FireBeetle ESP32-E</strong>. This is the selection shown in <a href="https://wiki.dfrobot.com/dfr1140/docs/23452">DFRobot's ESP32-UE getting-started guide</a>, despite the board itself being the UE antenna variant.</li>
<li>Connect the board with a USB-C data cable and select the correct serial port.</li>
<li>Upload the blink sketch below.</li>
</ol>
<pre><code>const int LED_PIN = D9;  // FireBeetle alias for GPIO2

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}</code></pre>
<p>The small onboard LED should turn on for half a second and off for half a second. It's a useful first check that the board, USB connection, and Arduino settings are working.</p>
<h3><strong>Checking PSRAM</strong></h3>
<p>Next, upload this sketch and open Serial Monitor at 115200 baud:</p>
<pre><code>void setup() {
  Serial.begin(115200);
  delay(1000);

  if (psramFound()) {
    Serial.println("PSRAM detected");
    Serial.print("Total PSRAM: ");
    Serial.println(ESP.getPsramSize());
    Serial.print("Free PSRAM: ");
    Serial.println(ESP.getFreePsram());
  } else {
    Serial.println("PSRAM not detected");
  }
}

void loop() {
}</code></pre>
<p>A correctly initialized N16R2 module should report about 2 MB of total PSRAM, with some memory already in use.</p>
<figure id="attachment_13131" aria-describedby="caption-attachment-13131" style="width: 768px" class="wp-caption aligncenter"><img data-dominant-color="eaeef3" data-has-transparency="false" style="--dominant-color: #eaeef3;" loading="lazy" decoding="async" class="wp-image-13131 size-full not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon.avif" alt="" width="768" height="512" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon-300x200.avif 300w" sizes="auto, (max-width: 768px) 100vw, 768px" /><figcaption id="caption-attachment-13131" class="wp-caption-text">[Actual Arduino Serial Monitor output showing PSRAM detection on the FireBeetle ESP32-UE]</figcaption></figure>If you get "PSRAM not detected," check the board package, selected board, and PSRAM option under Tools if the installed core exposes one. PSRAM support depends on the build configuration, so the message alone does not prove the hardware lacks memory.</p>
<h3><strong>Connecting to Wi-Fi and Reading RSSI</strong></h3>
<p>Now for a test that relates directly to the external antenna. This sketch connects to a 2.4 GHz network and prints the received signal strength indicator (RSSI) every second.</p>
<pre><code>#include &lt;WiFi.h&gt;

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED &amp;&amp;
         millis() - start &lt; 15000) {
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWi-Fi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWi-Fi connection timed out");
  }
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("RSSI: ");
    Serial.print(WiFi.RSSI());
    Serial.println(" dBm");
  } else {
    Serial.println("Wi-Fi disconnected");
  }
  delay(1000);
}</code></pre>
<p>RSSI is expressed in dBm. -45 dBm indicates a stronger received signal than -80 dBm. The number will fluctuate as the radio environment changes.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Comparing Wi-Fi Signal Strength</strong></h2>
<p>To see what antenna placement changes in practice, compare the FireBeetle against a regular ESP32 board with a PCB antenna. Use the same access point, 2.4 GHz network, and test locations. Keep board and antenna orientation consistent, collect at least ten readings at each point, and calculate the average.</p>
<p>Record the external antenna model and any RF cable used. If possible, repeat the test with the FireBeetle antenna inside and outside the enclosure. That gives a more useful comparison than assuming an external antenna is always better.</p>
<figure id="attachment_13131-2" aria-describedby="caption-attachment-13131-2" style="width: 768px" class="wp-caption aligncenter"><img data-dominant-color="eaeef3" data-has-transparency="false" style="--dominant-color: #eaeef3;" loading="lazy" decoding="async" class="size-full wp-image-13131 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon.avif" alt="" width="768" height="512" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon-300x200.avif 300w" sizes="auto, (max-width: 768px) 100vw, 768px" /><figcaption id="caption-attachment-13131-2" class="wp-caption-text">[Photograph of the actual Wi-Fi comparison setup showing both ESP32 boards and the antenna placement]</figcaption></figure>Remember that RSSI measures how strongly the ESP32 receives the access point's signal. It does not measure both directions of the Wi-Fi link or prove the maximum communication range. Still, it's a practical first test of how the two antenna arrangements behave at your chosen locations.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Measuring Deep-Sleep Current</strong></h2>
<p>The other feature worth checking is power consumption. For a simple test, we can make the ESP32 sleep for 60 seconds, wake up, and then go back to sleep.</p>
<pre><code>#include "esp_sleep.h"

void setup() {
  Serial.begin(115200);
  delay(500);

  esp_sleep_enable_timer_wakeup(60ULL * 1000000ULL);
  Serial.println("Entering deep sleep for 60 seconds");
  Serial.flush();
  esp_deep_sleep_start();
}

void loop() {
}</code></pre>
<p>Use the Wi-Fi sketch from the previous section to record current while connected, then upload the deep-sleep sketch for the two sleep measurements. For current measurements, disconnect USB power and measure at the battery supply with a meter that can resolve microamp-level current. Keep the antenna connected but remove unnecessary external loads, such as a display or sensors, for the initial board-only comparison.</p>
<p>Measure with the low-power jumper intact, then repeat after disconnecting it, following DFRobot's instructions. Power the board down before changing the jumper, and note the meter and battery supply used. Wi-Fi active current changes rapidly, so a single instantaneous reading does not represent all operating conditions.</p>
<figure id="attachment_13131-3" aria-describedby="caption-attachment-13131-3" style="width: 768px" class="wp-caption aligncenter"><img data-dominant-color="eaeef3" data-has-transparency="false" style="--dominant-color: #eaeef3;" loading="lazy" decoding="async" class="size-full wp-image-13131 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon.avif" alt="" width="768" height="512" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/10/Image-in-Progress-Gear-Icon-300x200.avif 300w" sizes="auto, (max-width: 768px) 100vw, 768px" /><figcaption id="caption-attachment-13131-3" class="wp-caption-text">[Actual microamp-capable current meter connected at the FireBeetle battery supply during deep sleep]</figcaption></figure>For an environmental monitor that wakes only every few minutes, sleep current is important. But total battery life also depends on wake duration, Wi-Fi reconnection time, sensor consumption, and how often you transmit readings.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Is the FireBeetle 2 ESP32-UE Worth Choosing?</strong></h2>
<p>I wouldn't buy the FireBeetle just to blink LEDs or learn basic ESP32 programming. A cheaper, generic ESP32 board will do those jobs.</p>
<p>The FireBeetle becomes more interesting when several requirements appear together. Imagine a monitoring device in an enclosure that reads sensors every few minutes, reports data over Wi-Fi, and runs on a battery. In that case, you can position the antenna away from the electronics, use the onboard charger, and reduce standby current between readings. If you need a local dashboard, the extra memory and GDI interface are useful additions.</p>
<p>There are also reasons to choose something else. The FireBeetle uses the original ESP32 architecture. An ESP32-S3 board may be a better fit for newer processing features or native USB, while an ESP32-C6 is worth considering for Wi-Fi 6 or IEEE 802.15.4 support. Those boards have different peripheral and software tradeoffs, so the newer chip isn't automatically better for every project.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Final Thoughts</strong></h2>
<p>What makes the FireBeetle 2 ESP32-UE useful isn't a faster processor. It's the combination of an external antenna connection, battery-oriented power hardware, low-power options, and enough memory for a more complete IoT interface.</p>
<p>For a breadboard experiment, these details may not matter. But for an ESP32 that needs to sit inside a box, spend most of its time asleep, and communicate reliably, those details are exactly what I'd check before choosing a board.</p>
<p>Need board-specific pin mappings, power details, and reference drawings? See the <a href="https://wiki.dfrobot.com/dfr1140/">official DFRobot FireBeetle 2 ESP32-UE documentation</a>.</p>
<p>The post <a href="https://www.teachmemicro.com/dfrobot-firebeetle-2-esp32-ue-what-makes-this-esp32-board-different/">DFRobot FireBeetle 2 ESP32-UE: What Makes This ESP32 Board Different?</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32 AI Guide: What Can ESP32 and ESP32-S3 Actually Do?</title>
		<link>https://www.teachmemicro.com/esp32-ai/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Sat, 26 Sep 2026 10:47:23 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12627</guid>

					<description><![CDATA[<p>Artificial intelligence often brings to mind powerful GPUs, huge servers, and applications like ChatGPT. An ESP32, meanwhile, is a microcontroller with only a fraction of the processing power and memory of a modern computer. Surprisingly, these two worlds are becoming increasingly connected. An ESP32 can run small machine-learning models locally, recognize voice commands, classify sensor data, &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-ai/">ESP32 AI Guide: What Can ESP32 and ESP32-S3 Actually Do?</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Artificial intelligence often brings to mind powerful GPUs, huge servers, and applications like ChatGPT. An <em>ESP32</em>, meanwhile, is a microcontroller with only a fraction of the processing power and memory of a modern computer. Surprisingly, these two worlds are becoming increasingly connected.</p>
<p>An ESP32 can run small machine-learning models locally, recognize voice commands, classify sensor data, process images, and even communicate with much larger AI models through the Internet. Newer devices such as the <em>ESP32-S3</em> are especially interesting because Espressif added processor instructions that accelerate neural-network and signal-processing operations.</p>
<p>However, the term <em>ESP32 AI</em> can mean several different things. It may refer to TinyML running directly on the microcontroller, an ESP32 acting as a client for cloud-based AI, an AI camera project, or even the popular AI-Thinker ESP32-CAM board. In this guide, I will separate those concepts and look at what AI on an ESP32 can realistically do.</p>
<p><span id="more-12627"></span></p>
<p><img data-dominant-color="dfe2e5" data-has-transparency="false" style="--dominant-color: #dfe2e5;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13003 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-with-sensors.avif" alt="ESP32 with Sensors" width="836" height="471" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-with-sensors.avif 836w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-with-sensors-300x169.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-with-sensors-768x433.avif 768w" sizes="auto, (max-width: 836px) 100vw, 836px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What Does ESP32 AI Mean?</strong></h2>
<p>There isn't one specific technology called "ESP32 AI." Instead, there are several ways to combine artificial intelligence with an ESP32. The most important distinction is <em>where the AI model actually runs</em>.</p>
<h3><strong>1. AI Running Directly on the ESP32</strong></h3>
<p>In this setup, the trained machine-learning model is stored in the ESP32's flash memory and inference occurs directly on the microcontroller. For example, a microphone could continuously listen for the words "ON" and "OFF." Instead of sending every audio sample to a server, the ESP32 processes the audio locally and decides which word it heard. This is often called <em>edge AI</em>, <em>embedded machine learning</em>, or <em>TinyML</em>. I already have a complete <a href="/tinyml-with-esp32-tutorial/">TinyML with ESP32 tutorial</a> that covers the model-training and deployment process in detail. This article will focus more on what is possible and which approach makes sense for a particular project.</p>
<h3><strong>2. ESP32 Connecting to Cloud AI</strong></h3>
<p>The ESP32 does not necessarily have to run the AI model. Because it has Wi-Fi, the ESP32 can collect data and send it to an AI service running on a much more powerful server.</p>
<p>The basic architecture looks like this:<br />
<div class="tmm-flow-container tmm-flow-container--linear" role="img" aria-label="Flow diagram: Sensor / User to ESP32 - Wi-Fi; ESP32 - Wi-Fi to Cloud AI / LLM; Cloud AI / LLM to ESP32; ESP32 to Display / Relay / Speaker / Actuator."><div class="tmm-flow-row"><span class="tmm-flow-node">Sensor / User</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">ESP32 - Wi-Fi</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Cloud AI / LLM</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">ESP32</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Display / Relay / Speaker / Actuator</span></div></div>
I used this method in my <a href="/esp32-meets-ai-talking-to-large-language-models-via-openrouter/">ESP32 and LLM project using OpenRouter</a>. The ESP32 sends a prompt over Wi-Fi while the actual language model runs remotely.</p>
<h3><strong>3. ESP32 as Part of an AI System</strong></h3>
<p>There is also a middle ground. An ESP32 might preprocess sensor data locally and only send interesting events to a server. For example, it could detect unusual vibration using a small local model and then send the captured data to a more powerful AI service for further analysis. This hybrid approach can reduce bandwidth while still allowing the system to use large models.</p>
<p><img data-dominant-color="eaeeef" data-has-transparency="false" style="--dominant-color: #eaeeef;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13004 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/local-ai-vs-cloud-ai-vs-hybrid-ai.avif" alt="Local AI vs Cloud AI vs Hybrid AI" width="1004" height="565" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/local-ai-vs-cloud-ai-vs-hybrid-ai.avif 1004w, https://www.teachmemicro.com/wp-content/uploads/2026/09/local-ai-vs-cloud-ai-vs-hybrid-ai-300x169.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/local-ai-vs-cloud-ai-vs-hybrid-ai-768x432.avif 768w" sizes="auto, (max-width: 1004px) 100vw, 1004px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32 AI vs AI-Thinker ESP32-CAM</strong></h2>
<p>One source of confusion is worth clearing up early. Searching for "ESP32 AI" often returns results involving the <em>AI-Thinker ESP32-CAM</em>. Despite the name, <em>AI-Thinker is the manufacturer/brand associated with the module</em>. The "AI" in AI-Thinker does not mean that the ESP32-CAM itself contains a dedicated artificial-intelligence processor. The ESP32-CAM is still useful for AI projects because it combines an ESP32 with a camera. Images can either be processed locally with sufficiently small models or sent to another device or server for more demanding computer-vision tasks.</p>
<p>So:</p>
<table>
<thead>
<tr>
<th>Term</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>ESP32 AI</td>
<td>Using artificial intelligence or machine learning with an ESP32</td>
</tr>
<tr>
<td>AI-Thinker</td>
<td>A hardware/module manufacturer</td>
</tr>
<tr>
<td>AI-Thinker ESP32-CAM</td>
<td>An ESP32 camera board commonly used for vision projects</td>
</tr>
</tbody>
</table>
<p>The two concepts overlap, but they are not the same thing.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Can an ESP32 Really Run Artificial Intelligence?</strong></h2>
<p>Yes, but the important word is <em>inference</em>. Most ESP32 AI projects do not train their neural networks on the microcontroller. Training might require thousands or millions of calculations performed repeatedly over a large dataset. Instead, training normally takes place on a PC or cloud platform. Once training is finished, the much smaller resulting model is exported and placed on the ESP32.</p>
<p>The workflow therefore looks like this:<br />
<div class="tmm-flow-container tmm-flow-container--linear" role="img" aria-label="Flow diagram: Collect Data to Train Model on PC / Cloud; Train Model on PC / Cloud to Optimize / Quantize Model; Optimize / Quantize Model to Convert Model for ESP32; Convert Model for ESP32 to Flash Model to ESP32; Flash Model to ESP32 to Run Inference Locally."><div class="tmm-flow-row"><span class="tmm-flow-node">Collect Data</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Train Model on PC / Cloud</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Optimize / Quantize Model</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Convert Model for ESP32</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Flash Model to ESP32</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Run Inference Locally</span></div></div>
Inference simply means giving an already-trained model some new input and asking it for a prediction.</p>
<p>For example:<br />
<div class="tmm-flow-container tmm-flow-container--linear" role="img" aria-label="Flow diagram: Microphone sample to Machine-learning model; Machine-learning model to &quot;ON&quot; = 92% &quot;OFF&quot; = 5% &quot;Other&quot; = 3%."><div class="tmm-flow-row"><span class="tmm-flow-node">Microphone sample</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">Machine-learning model</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">&quot;ON&quot; = 92% &quot;OFF&quot; = 5% &quot;Other&quot; = 3%</span></div></div>
This is a much smaller job than training the network from scratch.</p>
<p><img data-dominant-color="e9eaea" data-has-transparency="false" style="--dominant-color: #e9eaea;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13005 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/ai-model-training-for-esp32.avif" alt="AI Model training for ESP32" width="887" height="444" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/ai-model-training-for-esp32.avif 887w, https://www.teachmemicro.com/wp-content/uploads/2026/09/ai-model-training-for-esp32-300x150.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/ai-model-training-for-esp32-768x384.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/09/ai-model-training-for-esp32-660x330.avif 660w" sizes="auto, (max-width: 887px) 100vw, 887px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Why the ESP32-S3 Is Better for AI</strong></h2>
<p>The original ESP32 can run small machine-learning models, and that is exactly what I used in my earlier TinyML projects. However, if I were buying a board specifically for a new ESP32 AI project today, I would normally choose an <em>ESP32-S3</em>, preferably a version with PSRAM. The ESP32-S3 includes vector instructions that accelerate operations commonly found in neural networks and digital signal processing. It is important to describe this correctly: the ESP32-S3 does <em>not</em> have a large dedicated neural-processing unit comparable to the AI accelerator found in some application processors. Instead, its processor includes instructions that make certain mathematical operations considerably more efficient.</p>
<p>This matters because neural networks repeatedly perform operations such as multiplication and accumulation:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_f559a8bf877f0595eb85774956a64e05.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="y = \sum_{i=0}^{n} w_i x_i + b" /></span><script type='math/tex'>y = \sum_{i=0}^{n} w_i x_i + b</script></p>
<p>where:</p>
<ul>
<li><strong>x</strong> represents input values,</li>
<li><strong>w</strong> represents trained weights,</li>
<li><strong>b</strong> is the bias, and</li>
<li><strong>y</strong> is the resulting output.</li>
</ul>
<p>A neural network may perform these operations thousands or millions of times for a single inference. The ESP32-S3 can therefore execute appropriately optimized models faster than a classic ESP32.</p>
<h3><strong>PSRAM Also Matters</strong></h3>
<p>Processor speed isn't the only limitation. A machine-learning model needs memory for:</p>
<ul>
<li>model weights,</li>
<li>input data,</li>
<li>intermediate layer outputs,</li>
<li>the tensor arena or working memory, and</li>
<li>your normal application code and buffers.</li>
</ul>
<p>For very small sensor models, internal RAM may be enough. Camera and audio applications become much more demanding. An ESP32-S3 board with <em>external PSRAM</em> gives you considerably more room for frame buffers and larger models. That does not mean PSRAM automatically makes inference fast. External memory is generally slower than internal SRAM. However, having a slower place to store something is much better than not having enough memory to run the model at all.</p>
<p><img data-dominant-color="d5d2d5" data-has-transparency="false" style="--dominant-color: #d5d2d5;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13006 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-vs-esp32-s3.avif" alt="ESP32 vs ESP32-S3" width="887" height="444" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-vs-esp32-s3.avif 887w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-vs-esp32-s3-300x150.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-vs-esp32-s3-768x384.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-vs-esp32-s3-660x330.avif 660w" sizes="auto, (max-width: 887px) 100vw, 887px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What Kind of AI Can an ESP32 Run?</strong></h2>
<p>"AI" covers an enormous range of applications. Some are well suited to microcontrollers while others are completely unrealistic. Here are several applications that fit the ESP32 particularly well.</p>
<h3><strong>Sensor Classification</strong></h3>
<p>This is one of the easiest places to start. Suppose an accelerometer is attached to a machine. Instead of simply checking whether vibration exceeds a fixed threshold, a trained model could classify several operating states:</p>
<ul>
<li>normal operation,</li>
<li>idle,</li>
<li>unbalanced load,</li>
<li>excessive vibration,</li>
<li>possible fault.</li>
</ul>
<p>The input consists of relatively small numerical datasets, so the model can also remain small.</p>
<h3><strong>Anomaly Detection</strong></h3>
<p>Instead of teaching the ESP32 every possible fault condition, a model can learn what normal sensor readings look like and identify unusual patterns. Possible applications include:</p>
<ul>
<li>machine condition monitoring,</li>
<li>water pump monitoring,</li>
<li>battery monitoring,</li>
<li>unexpected power consumption, and</li>
<li>environmental sensors.</li>
</ul>
<p>This is an area where embedded AI can be more useful than simply putting a fixed threshold inside an <code>if()</code> statement.</p>
<h3><strong>Voice and Sound Recognition</strong></h3>
<p>Audio is another good match for the ESP32-S3. Instead of converting speech into arbitrary sentences, a small model might recognize a limited vocabulary such as: LIGHT, ON, OFF, FAN, OPEN, CLOSE</p>
<p>That task is much easier than full speech-to-text. I have a separate <a href="/voice-command-recognition-with-esp32-and-tinyml-using-edge-impulse/">ESP32 TinyML voice command project using Edge Impulse</a> for a practical example.</p>
<p>Other audio applications include:</p>
<ul>
<li>glass-breaking detection,</li>
<li>alarm detection,</li>
<li>machine noise classification,</li>
<li>clap or sound recognition, and</li>
<li>wake-word detection.</li>
</ul>
<h3><strong>Image Classification</strong></h3>
<p>A camera image can be reduced to a small resolution and passed through a lightweight neural network. The output could answer a question such as:</p>
<blockquote><p>Is this object:</p>
<p>Person 0.91 Cat 0.05 Background 0.04</p></blockquote>
<p>This is more realistic for an ESP32 than asking it to fully understand a high-resolution image.</p>
<h3><strong>Object Detection</strong></h3>
<p>Object detection is harder than simple image classification because the model must determine both <em>what</em> an object is and <em>where</em> it appears in the image. Optimized object-detection models can run on newer ESP32 hardware, but memory usage and inference time quickly become important. For a battery-operated camera expected to recognize one or two objects, an ESP32-S3 may make sense. For multi-object high-resolution detection at high frame rates, a Raspberry Pi or more powerful processor is normally a better choice.</p>
<h3><strong>Gesture Recognition</strong></h3>
<p>Gesture recognition can use either camera images or motion sensors. An accelerometer-based gesture recognizer is particularly attractive because the input data is tiny compared with an image. You could teach a device to recognize different movements and perform commands without buttons.</p>
<p><img data-dominant-color="dddedd" data-has-transparency="false" style="--dominant-color: #dddedd;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13007 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/six-esp32-applications.avif" alt="ESP32 Applications" width="922" height="615" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/six-esp32-applications.avif 922w, https://www.teachmemicro.com/wp-content/uploads/2026/09/six-esp32-applications-300x200.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/six-esp32-applications-768x512.avif 768w" sizes="auto, (max-width: 922px) 100vw, 922px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>On-Device ESP32 AI vs Cloud AI</strong></h2>
<p>Running a model locally is not automatically better.</p>
<p>The right solution depends on what the project needs.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>On-Device AI</th>
<th>Cloud AI</th>
</tr>
</thead>
<tbody>
<tr>
<td>Internet required</td>
<td>No</td>
<td>Usually yes</td>
</tr>
<tr>
<td>Latency</td>
<td>Very low for suitable models</td>
<td>Depends on network/server</td>
</tr>
<tr>
<td>Model size</td>
<td>Very limited</td>
<td>Can be enormous</td>
</tr>
<tr>
<td>Privacy</td>
<td>Data can remain local</td>
<td>Data normally leaves device</td>
</tr>
<tr>
<td>Operating cost</td>
<td>No per-request API fee</td>
<td>May have API charges</td>
</tr>
<tr>
<td>AI capability</td>
<td>Specialized tasks</td>
<td>Complex vision, speech and LLMs</td>
</tr>
<tr>
<td>Offline operation</td>
<td>Yes</td>
<td>No</td>
</tr>
</tbody>
</table>
<p>For example, imagine a smart door. A local ESP32 model could detect a particular sound or wake word without sending continuous microphone recordings anywhere.</p>
<p>However, if you want the user to ask:</p>
<blockquote><p><em>"Was anyone standing near the front door while I was away this afternoon?"</em></p></blockquote>
<p>that is a much more complicated task. Sending selected images or event data to a larger AI model would make more sense.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32 AI Frameworks and Tools</strong></h2>
<p>There are now several ways to deploy AI models on ESP32 devices.</p>
<h3><strong>TensorFlow Lite for Microcontrollers</strong></h3>
<p>TensorFlow Lite for Microcontrollers, commonly called TFLM, is designed to run neural-network inference on microcontrollers with limited RAM. It is useful when you want to understand the model deployment process more directly. I have a separate <a href="/getting-started-with-tensorflow-lite-on-esp32-with-voice-activity-detection-project/">TensorFlow Lite on ESP32 tutorial</a> with a voice activity detection example.</p>
<h3><strong>ESP-DL</strong></h3>
<p><em>ESP-DL</em> is Espressif's neural-network inference framework for ESP devices. Its current toolchain can take trained models, quantize them, and convert them into a format optimized for supported Espressif chips. This is particularly interesting for ESP32-S3 projects because the framework can make use of optimized kernels for the chip. If I were developing a new performance-sensitive ESP32-S3 AI project, ESP-DL would be one of the first frameworks I would investigate.</p>
<h3><strong>ESP-WHO</strong></h3>
<p><em>ESP-WHO</em> is aimed more specifically at computer-vision applications.</p>
<p>Typical applications include:</p>
<ul>
<li>face detection,</li>
<li>face recognition,</li>
<li>camera-based classification, and</li>
<li>other embedded vision projects.</li>
</ul>
<p>It is therefore worth checking when your ESP32 AI project starts with a camera rather than a microphone or sensor.</p>
<h3><strong>ESP-SR</strong></h3>
<p>For audio applications, Espressif also provides <em>ESP-SR</em>. It contains components for functions such as:</p>
<ul>
<li>audio front-end processing,</li>
<li>wake-word detection, and</li>
<li>speech-command recognition.</li>
</ul>
<p>For a product that only needs to understand a limited command vocabulary, this is much more realistic than running a general speech-to-text model.</p>
<h3><strong>Edge Impulse</strong></h3>
<p>Edge Impulse provides a higher-level workflow for collecting datasets, extracting features, training models, and deploying them to embedded devices. It is especially convenient when experimenting with:</p>
<ul>
<li>accelerometers,</li>
<li>microphones,</li>
<li>environmental sensors, and</li>
<li>small image datasets.</li>
</ul>
<p>It can save a lot of setup time when your main goal is testing whether machine learning improves the project rather than building the ML toolchain yourself.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>How Much Faster Is ESP32-S3 for AI?</strong></h2>
<p>This is something I prefer to measure rather than answer only from specifications. A useful experiment is to run the <em>same small neural-network model</em> on a classic ESP32 and an ESP32-S3. The model from my existing TinyML tutorial can be reused so that the network itself remains constant.</p>
<p>The important measurements are:</p>
<ul>
<li>model size,</li>
<li>inference time,</li>
<li>available heap before loading the model,</li>
<li>available heap while the model is running, and</li>
<li>whether PSRAM is required.</li>
</ul>
<p>Inference time can be measured around the model's <code>Invoke()</code> function:</p>
<pre><code>unsigned long startTime = micros();

TfLiteStatus invokeStatus = interpreter-&gt;Invoke();

unsigned long inferenceTime = micros() - startTime;

Serial.print("Inference time: ");
Serial.print(inferenceTime);
Serial.println(" us");
</code></pre>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Can an ESP32 Run an LLM?</strong></h2>
<p>Technically, extremely small experimental language models can be squeezed into surprisingly limited hardware. However, this needs some perspective. The language models people normally associate with AI assistants contain millions or billions of parameters and require far more memory and processing power than a normal ESP32 can provide.</p>
<p>So if the goal is something like this:</p>
<blockquote><p>User: Should I water my tomato plants today?</p>
<p>ESP32: Based on the soil moisture, temperature, weather forecast and your previous watering schedule, I recommend waiting until tomorrow.</p></blockquote>
<p>the practical architecture is usually:</p>
<div class="tmm-flow-container tmm-flow-container--linear" role="img" aria-label="Flow diagram: ESP32 sensors to ESP32; ESP32 to Wi-Fi and Wi-Fi to ESP32; Wi-Fi to LLM API and LLM API to Wi-Fi."><div class="tmm-flow-row"><span class="tmm-flow-node">ESP32 sensors</span><span class="tmm-flow-edge"><span class="tmm-flow-arrow" aria-hidden="true">&#8594;</span></span><span class="tmm-flow-node">ESP32</span><span class="tmm-flow-edge tmm-flow-edge--bidirectional"><span class="tmm-flow-arrow" aria-hidden="true">&#8596;</span></span><span class="tmm-flow-node">Wi-Fi</span><span class="tmm-flow-edge tmm-flow-edge--bidirectional"><span class="tmm-flow-arrow" aria-hidden="true">&#8596;</span></span><span class="tmm-flow-node">LLM API</span></div></div>
<p>The ESP32 handles sensors, actuators and networking while the LLM handles natural-language reasoning. That is the approach demonstrated in my <a href="/esp32-meets-ai-talking-to-large-language-models-via-openrouter/">ESP32 OpenRouter AI project</a>. There are experimental reasons to run tiny language models locally, but I would not choose an ESP32 for a project that actually needs ChatGPT-like conversation.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>When Should You Use AI Instead of Normal ESP32 Code?</strong></h2>
<p>Not every project benefits from machine learning. Suppose a soil moisture sensor reads between 0 and 4095 and you simply want to switch a pump on below a fixed threshold.</p>
<p>Normal code is better:</p>
<pre><code>if (moisture &lt; threshold) {
    startPump();
}
</code></pre>
<p>A neural network would add complexity without solving a real problem. AI becomes more useful when the input contains a <em>pattern that is difficult to describe using simple rules<em>.</em></em></p>
<p>Consider vibration monitoring. A normal program might say:</p>
<pre><code>if (vibration &gt; 500) {
    fault = true;
}
</code></pre>
<p>But suppose a healthy motor sometimes exceeds 500 during startup while a failing bearing creates a particular frequency pattern even though its peak vibration remains below 500. Now the problem is no longer just a threshold. A trained model may be able to distinguish those patterns.</p>
<p>A simple rule I use is:</p>
<div class="box info  "><div class="box-inner-block"><i class="fa tie-shortcode-boxicon"></i>
			<strong>If you can describe the decision reliably using a few conditions, use normal code. If you need to recognize a pattern from many measurements, machine learning becomes much more interesting.</strong>
			</div></div>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Which ESP32 Should You Use for AI?</strong></h2>
<p>For most new projects, this is how I would choose:</p>
<table>
<thead>
<tr>
<th>Project</th>
<th>Recommended Hardware</th>
<th>Approach</th>
</tr>
</thead>
<tbody>
<tr>
<td>Simple sensor classification</td>
<td>ESP32 or ESP32-S3</td>
<td>Local TinyML</td>
</tr>
<tr>
<td>Vibration anomaly detection</td>
<td>ESP32-S3</td>
<td>Local model</td>
</tr>
<tr>
<td>Wake-word detection</td>
<td>ESP32-S3</td>
<td>Local audio AI</td>
</tr>
<tr>
<td>Voice commands</td>
<td>ESP32-S3</td>
<td>Local TinyML / ESP-SR</td>
</tr>
<tr>
<td>Small image classifier</td>
<td>ESP32-S3 with PSRAM</td>
<td>Local vision model</td>
</tr>
<tr>
<td>Camera object detection</td>
<td>ESP32-S3 with PSRAM</td>
<td>Optimized local model or hybrid</td>
</tr>
<tr>
<td>Natural-language assistant</td>
<td>Any Wi-Fi ESP32</td>
<td>Cloud LLM</td>
</tr>
<tr>
<td>Complex image understanding</td>
<td>ESP32 camera + server</td>
<td>Cloud/server AI</td>
</tr>
</tbody>
</table>
<p>The interesting part is that the most powerful AI does not necessarily require the most powerful ESP32. If the microcontroller only needs to send a JSON request to an online LLM, even a classic ESP32 may be perfectly adequate. It is <em>local inference</em> where the ESP32-S3's extra capabilities become important.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32 AI Project Ideas</strong></h2>
<p>If you want to experiment with ESP32 AI, here are some projects that are realistic enough to build:</p>
<ul>
<li><strong>Machine vibration classifier</strong> — use an accelerometer to distinguish normal and abnormal operation.</li>
<li><strong>Offline voice-controlled switch</strong> — recognize a handful of commands locally without sending audio to the cloud.</li>
<li><strong>Sound classifier</strong> — distinguish alarms, claps, machinery or other sounds using an I2S microphone.</li>
<li><strong>Smart camera</strong> — detect whether a person or object is present before saving or transmitting an image.</li>
<li><strong>Gesture controller</strong> — classify accelerometer movements and use them to control a device.</li>
<li><strong>Sensor anomaly detector</strong> — identify unusual temperature, current, pressure or vibration patterns.</li>
<li><strong>AI sensor assistant</strong> — collect sensor readings on the ESP32 and send them to an LLM to generate a human-readable explanation.</li>
</ul>
<p>The first five can potentially operate entirely offline. The final example is better suited to a cloud AI service.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32 AI Frequently Asked Questions</strong></h2>
<h3><strong>Is the ESP32 powerful enough for AI?</strong></h3>
<p>Yes, if the model and task are small enough. Sensor classification, anomaly detection, wake words, simple audio classification and lightweight vision applications can all be appropriate. Large generative AI models are not.</p>
<h3><strong>Do I need an ESP32-S3 for machine learning?</strong></h3>
<p>No. The original ESP32 can run small TinyML models. However, the ESP32-S3 is generally a better choice for new on-device AI projects because of its vector instructions and the availability of boards with substantial PSRAM.</p>
<h3><strong>Does the ESP32-S3 have an AI accelerator?</strong></h3>
<p>It has processor extensions designed to accelerate neural-network and signal-processing calculations. It is better to think of these as <em>AI-friendly vector instructions</em> rather than a separate high-performance NPU.</p>
<h3><strong>Do I need PSRAM?</strong></h3>
<p>Not always. Very small sensor models can run entirely from internal memory. PSRAM becomes increasingly useful for camera frames, audio buffers and larger neural networks.</p>
<h3><strong>Can ESP32 run ChatGPT locally?</strong></h3>
<p>Not in the sense most people expect from ChatGPT. Tiny experimental language models are possible, but practical conversational AI is better handled by having the ESP32 communicate with an online LLM.</p>
<h3><strong>Is ESP32-CAM an AI board?</strong></h3>
<p>The camera makes it useful for AI applications, but the "AI" in AI-Thinker ESP32-CAM refers to the module manufacturer rather than a dedicated AI processor.</p>
<h3><strong>Should I use TensorFlow Lite, ESP-DL or Edge Impulse?</strong></h3>
<p>TensorFlow Lite for Microcontrollers is useful for understanding conventional embedded ML deployment. ESP-DL is attractive when targeting Espressif hardware and taking advantage of optimized implementations. Edge Impulse provides a convenient end-to-end platform for collecting data, training a model and deploying it to the ESP32.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Final Thoughts</strong></h2>
<p>The ESP32 is not going to replace a GPU, Raspberry Pi, or cloud AI server. That is also not what makes <em>ESP32 AI</em> interesting. Microcontrollers operate directly beside sensors and actuators. If a tiny model can recognize the pattern you need, an ESP32 can make a decision locally within a small, inexpensive, and low-power device.</p>
<p>For simple machine-learning experiments, the classic ESP32 is still usable. For new projects that require local audio, vision, or larger models, the <em>ESP32-S3 is the much more interesting platform</em>, particularly when paired with PSRAM. And if the AI task is simply too large for a microcontroller, Wi-Fi gives us another option: let the ESP32 handle the physical world while a cloud model handles the heavy computation.</p>
<p>If you want to build your first model rather than just explore the possibilities, continue with my <a href="/tinyml-with-esp32-tutorial/">TinyML with ESP32 Tutorial</a>. For voice projects, see my <a href="/voice-command-recognition-with-esp32-and-tinyml-using-edge-impulse/">ESP32 voice command recognition tutorial</a>. And if your goal is to connect an ESP32 to a large language model, see my <a href="/esp32-meets-ai-talking-to-large-language-models-via-openrouter/">ESP32 LLM/OpenRouter project</a>.</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-ai/">ESP32 AI Guide: What Can ESP32 and ESP32-S3 Actually Do?</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32-S31 Explained: Specs, RISC-V, Wi-Fi 6 and ESP32-S3 Comparison</title>
		<link>https://www.teachmemicro.com/esp32-s31-explained-specs-risc-v-wi-fi-6-and-esp32-s3-comparison/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Tue, 22 Sep 2026 22:01:47 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12867</guid>

					<description><![CDATA[<p>The ESP32 family has changed quite a bit since the first appearance of the original ESP32. We have had the ESP32-S2, S3, C3, C6 and several other variants aimed at specific applications. Now Espressif has introduced another major member of the family: the ESP32-S31. At first glance, the name makes it sound like a small &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-s31-explained-specs-risc-v-wi-fi-6-and-esp32-s3-comparison/">ESP32-S31 Explained: Specs, RISC-V, Wi-Fi 6 and ESP32-S3 Comparison</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The ESP32 family has changed quite a bit since the first appearance of the original ESP32. We have had the ESP32-S2, S3, C3, C6 and several other variants aimed at specific applications. Now Espressif has introduced another major member of the family: the ESP32-S31. At first glance, the name makes it sound like a small update to the <a href="https://www.teachmemicro.com/esp32-s3-getting-started-guide-pinout-arduino-ide-usb-and-first-project/">ESP32-S3</a>. It isn't.</p>
<p>The ESP32-S31 moves to a dual-core RISC-V processor running at up to 320 MHz, adds <a href="https://en.wikipedia.org/wiki/Wi-Fi_6">Wi-Fi 6</a>, brings back Bluetooth Classic, includes an IEEE 802.15.4 radio for Zigbee and Thread, and adds considerably more hardware for displays, cameras, audio and edge AI.</p>
<p>Espressif announced the ESP32-S31 in March 2026 and moved the device into mass production in July. So unlike some chips that remain development announcements for months, the S31 is already moving into development boards and production modules.</p>
<p><span id="more-12867"></span></p>
<p><img data-dominant-color="bababa" data-has-transparency="false" style="--dominant-color: #bababa;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12981 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-vs-esp32-s3.avif" alt="ESP32-S31 vs ESP32-S3" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-vs-esp32-s3.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-vs-esp32-s3-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What is the ESP32-S31?</strong></h2>
<p>The ESP32-S31 is a high-performance wireless microcontroller from Espressif intended for connected devices that need more processing power and more interfaces than a typical ESP32 application. Its two main processor cores use the 32-bit RISC-V architecture and can operate at up to 320 MHz. One of those cores includes a 128-bit data path and SIMD instructions intended to accelerate operations commonly found in signal processing, image processing and machine-learning workloads.</p>
<p>That already makes the architecture quite different from the ESP32-S3. The S3 uses two Xtensa LX7 cores running at up to 240 MHz.</p>
<p>The ESP32-S31 also provides 512 KB of internal SRAM, while external or in-package high-speed PSRAM can provide much larger working memory for applications such as graphical interfaces, cameras and AI models. Espressif currently lists ESP32-S31 chip variants with 16 MB or 32 MB of in-package Octal SPI PSRAM.</p>
<p>The important specifications can be summarized as follows:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>ESP32-S31</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU</td>
<td>Dual-core 32-bit RISC-V</td>
</tr>
<tr>
<td>Maximum CPU Clock</td>
<td>320 MHz</td>
</tr>
<tr>
<td>Internal SRAM</td>
<td>512 KB</td>
</tr>
<tr>
<td>External/In-package PSRAM</td>
<td>High-speed 8-bit DDR PSRAM, including 16 MB and 32 MB chip variants</td>
</tr>
<tr>
<td>Wi-Fi</td>
<td>2.4 GHz Wi-Fi 6 / 802.11ax</td>
</tr>
<tr>
<td>Bluetooth</td>
<td>Bluetooth 5.4 LE + Bluetooth Classic</td>
</tr>
<tr>
<td>802.15.4</td>
<td>Yes, for Zigbee and Thread</td>
</tr>
<tr>
<td>GPIO</td>
<td>Up to 60 programmable GPIOs</td>
</tr>
<tr>
<td>USB</td>
<td>USB 2.0 High-Speed OTG + USB Serial/JTAG</td>
</tr>
<tr>
<td>Ethernet</td>
<td>Gigabit Ethernet MAC</td>
</tr>
<tr>
<td>Camera</td>
<td>8- to 16-bit DVP</td>
</tr>
<tr>
<td>Image Acceleration</td>
<td>JPEG codec, PPA and 2D-DMA</td>
</tr>
</tbody>
</table>
<p>Those specifications put the ESP32-S31 somewhere between the traditional ESP32 microcontrollers and Espressif's more application-processor-like devices.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S31 Uses RISC-V</strong></h2>
<p>One of the biggest changes is the processor architecture. ESP32-S3 uses Espressif's familiar Xtensa LX7 cores. ESP32-S31 instead uses RISC-V, continuing Espressif's shift toward the open instruction-set architecture already found in chips such as the <a href="https://www.teachmemicro.com/esp32-c3-super-mini-getting-started-guide-pinout-arduino-ide-setup-and-built-in-led/">ESP32-C3</a> and ESP32-C6.</p>
<p>The two high-performance cores run at up to 320 MHz. Espressif also includes a 40 MHz low-power coprocessor, which allows some monitoring and low-power tasks to continue while the main processors are inactive. The increased clock frequency alone does not explain all of the performance improvement. One CPU core provides a 128-bit data path with SIMD instructions. SIMD, or Single Instruction Multiple Data, allows one instruction to operate on several pieces of data at the same time.</p>
<p>Consider image processing. If an algorithm needs to perform the same mathematical operation on thousands of pixels, processing several pixel values simultaneously can be much faster than processing each one individually. This is also useful for DSP operations, audio processing and neural-network inference. The S31 therefore isn't simply a faster ESP32 for blinking LEDs or reading sensors. Much of its additional hardware makes more sense once the application starts handling large streams of data.</p>
<p><img data-dominant-color="e9f1f4" data-has-transparency="false" style="--dominant-color: #e9f1f4;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12983 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-block-diagram.avif" alt="ESP32-S31 Block Diagram" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-block-diagram.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-block-diagram-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Wi-Fi 6, Bluetooth and 802.15.4</strong></h2>
<p>Connectivity is probably the area where the ESP32-S31 separates itself most clearly from the ESP32-S3. The S31 supports 2.4 GHz Wi-Fi 6, or IEEE 802.11ax. Note the 2.4 GHz specification here: Wi-Fi 6 support does not mean that the ESP32-S31 suddenly becomes a 5 GHz Wi-Fi device. Its integrated radio operates in the 2.4 GHz band.</p>
<p>Bluetooth support is also considerably broader. ESP32-S31 supports both Bluetooth 5.4 Low Energy and Bluetooth Classic BR/EDR. This is interesting because Bluetooth Classic disappeared from several newer ESP32 variants, including the ESP32-S3. Bringing it back makes the S31 more useful for applications such as Bluetooth speakers and other devices that still need compatibility with traditional Bluetooth audio. Bluetooth LE support also extends to LE Audio, including the LC3 codec and multi-stream audio capabilities. Espressif specifically highlights audio as one of the intended application areas for the chip.</p>
<p>There is also an IEEE 802.15.4 radio, which provides the hardware foundation for protocols such as Zigbee and Thread. That means one ESP32-S31 can potentially act as a much more capable smart-home controller than an S3. For example, a gateway could communicate with Wi-Fi devices, Bluetooth devices and Thread or Zigbee sensors without requiring separate wireless microcontrollers for every protocol. This also makes the chip particularly interesting for Matter gateways and border-router-style devices.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Gigabit Ethernet</strong></h2>
<p>Another surprising addition is a 1000 Mbps Ethernet MAC. The important word here is MAC. The ESP32-S31 does not magically provide an RJ45 Ethernet connection directly from the chip. A design still needs the appropriate external Ethernet PHY and magnetics. Espressif's own ESP32-S31-Function-CoreBoard-1 demonstrates this approach. The board connects the S31's RGMII interface to an external Ethernet PHY and provides an RJ45 connector capable of 10/100/1000 Mbps auto-negotiation. Still, having a Gigabit-capable Ethernet MAC inside an ESP32-class SoC is significant. It makes applications such as network gateways, industrial controllers and high-bandwidth edge devices much more practical.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S31 for Displays and Cameras</strong></h2>
<p>The S31 is clearly designed for products with more sophisticated user interfaces. It includes a DVP camera interface supporting 8- to 16-bit data, along with several LCD interfaces. These include parallel RGB displays up to 24 bits as well as I8080 and MOTO6800-style interfaces. Hardware can convert between formats including RGB565 and several YUV formats. Espressif also provides dedicated image-processing hardware such as a JPEG codec, Pixel Processing Accelerator (PPA) and 2D-DMA.</p>
<p>Why does that matter? Without dedicated hardware, operations such as moving a framebuffer, resizing an image or handling camera data can consume a large percentage of CPU time. The ESP32-S31 can offload some of those jobs. That gives the main processors more time for application logic, networking or AI inference. Up to 14 capacitive-touch channels are also available, making the chip suitable for touch panels and appliances where physical buttons are being replaced by interactive displays. I can see this being particularly useful for smart control panels, video doorbells, small instrument displays and voice-enabled appliances.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Edge AI on the ESP32-S31</strong></h2>
<p>Espressif has been promoting AI capabilities since the ESP32-S3, so we should be careful about what "AI" means here. The ESP32-S31 is not intended to compete with a desktop GPU running a large language model. Instead, its hardware acceleration makes it suitable for smaller edge AI inference tasks where data must be processed directly on the device. Examples include keyword recognition, wake-word detection, image classification, object detection, anomaly detection and signal classification.</p>
<p>The combination of SIMD instructions, a 128-bit data path, hardware image processing, fast PSRAM and dedicated mathematical acceleration makes these workloads considerably more practical than they were on earlier ESP32 devices. Espressif also lists CORDIC acceleration among the S31's dedicated hardware. This also explains the amount of PSRAM available. A simple sensor-reading program doesn't need 16 MB or 32 MB of RAM. Camera frame buffers, graphical interfaces, neural-network tensors and audio buffers certainly can.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Peripheral Interfaces</strong></h2>
<p>Despite its emphasis on multimedia, the ESP32-S31 is still a microcontroller. The chip provides traditional interfaces such as SPI, I2C, UART, I2S, PWM and GPIO alongside newer or higher-performance peripherals. It includes four main-system UART controllers plus a low-power UART. SPI interfaces support normal SPI as well as Dual, Quad and, on some controllers, Octal operation. There are also two high-performance I2C controllers plus a low-power I2C interface.</p>
<p>USB receives a major upgrade to USB 2.0 High-Speed OTG. High-Speed USB is a substantial improvement over the USB Full-Speed interface found on the ESP32-S3. The S31 also includes interfaces for CAN FD, SD/MMC, motor-control PWM, LED PWM, RMT, pulse counting and parallel I/O. On the analog side, the documentation lists ADC, DAC, a temperature sensor, touch sensing and an analog voltage comparator. With up to 60 programmable GPIOs, larger designs are less likely to run into the pin limitations that sometimes appear when an ESP32 project starts combining a display, camera, external memory and several peripherals.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S31 vs ESP32-S3</strong></h2>
<p>The S31 may look like the natural replacement for the ESP32-S3, but that doesn't mean every S3 project needs one.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>ESP32-S31</th>
<th>ESP32-S3</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU</td>
<td>Dual-core RISC-V</td>
<td>Dual-core Xtensa LX7</td>
</tr>
<tr>
<td>Maximum Clock</td>
<td>320 MHz</td>
<td>240 MHz</td>
</tr>
<tr>
<td>Internal SRAM</td>
<td>512 KB</td>
<td>512 KB</td>
</tr>
<tr>
<td>Wi-Fi</td>
<td>2.4 GHz Wi-Fi 6</td>
<td>2.4 GHz Wi-Fi 4</td>
</tr>
<tr>
<td>Bluetooth LE</td>
<td>Bluetooth 5.4</td>
<td>Bluetooth 5</td>
</tr>
<tr>
<td>Bluetooth Classic</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Zigbee / Thread Radio</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>GPIO</td>
<td>Up to 60</td>
<td>Up to 45</td>
</tr>
<tr>
<td>USB</td>
<td>USB 2.0 High-Speed</td>
<td>USB 2.0 Full-Speed</td>
</tr>
<tr>
<td>Ethernet MAC</td>
<td>Gigabit</td>
<td>No equivalent integrated Gigabit MAC</td>
</tr>
<tr>
<td>AI / Multimedia Hardware</td>
<td>Expanded SIMD, JPEG, PPA, 2D-DMA and other accelerators</td>
<td>SIMD/vector acceleration</td>
</tr>
</tbody>
</table>
<p>Espressif itself recommends the S31 for gateways, bridges and AI multimedia devices where multi-protocol connectivity or higher processing performance is important. The company still recommends the S3 for more cost-sensitive applications that don't need these capabilities. That seems like the sensible way to look at the two chips.</p>
<p>If your project is reading an I2C sensor and uploading a value to an MQTT server, an ESP32-S31 would probably be excessive. If your project combines a camera, display, voice interface, Wi-Fi, Bluetooth and Thread, then the advantages start to become obvious.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S31 Modules and Development Boards</strong></h2>
<p>Espressif is already offering modules around the new chip. The ESP32-S31-WROOM-1 family is listed with different flash and PSRAM capacities, while the ESP32-S31-WROOM-3 is being used on Espressif's multimedia and function development boards.</p>
<p>One interesting example is the ESP32-S31-Korvo-1. This development board is clearly aimed at showing what the chip can do beyond ordinary IoT sensing. It includes audio hardware, dual microphones, speaker outputs, microSD support, USB High-Speed connectivity and connectors for an LCD and camera. A current WROOM-3 configuration used by the board includes 16 MB flash and 16 MB PSRAM. Espressif also provides the ESP32-S31-Function-CoreBoard-1, which adds Gigabit Ethernet and audio hardware while breaking out the important GPIO connections.</p>
<figure id="attachment_12980" aria-describedby="caption-attachment-12980" style="width: 724px" class="wp-caption aligncenter"><img data-dominant-color="cacbcb" data-has-transparency="false" style="--dominant-color: #cacbcb;" loading="lazy" decoding="async" class="wp-image-12980 size-full not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-development-boards.avif" alt="ESP32-S31 Development Boards" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-development-boards.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s31-development-boards-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /><figcaption id="caption-attachment-12980" class="wp-caption-text"><em>Left: ESP32-S31 Function Coreboard; Right: ESP32-S31 Korvo-1</em></figcaption></figure>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Programming the ESP32-S31</strong></h2>
<p>For now, ESP-IDF is the safest development environment for the ESP32-S31. Espressif says S31 support is available in the ESP-IDF master and v6.1 branches, with official tagged support planned from ESP-IDF 6.1.1 onward. Arduino support is a different story.</p>
<p>As of September 2026, the stable Arduino-ESP32 documentation still does not list the S31 among officially supported SoCs. Espressif developers have been working on S31 support for Arduino 4.x, which is based on ESP-IDF 6.1, but the Arduino team's current roadmap places the 4.0 release in November 2026. So if you purchase an ESP32-S31 board today expecting exactly the same Arduino IDE experience as an ESP32-S3 DevKit, expect some rough edges.</p>
<p>For developers already comfortable with ESP-IDF, however, the S31 can already be explored properly. This situation should improve as the software ecosystem catches up with the hardware.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Security Features</strong></h2>
<p>The ESP32-S31 also includes considerably more security hardware than is necessary for the average hobby project, but that becomes important in commercial products. The chip supports secure boot, flash and PSRAM encryption, hardware cryptographic acceleration and protected key handling. Hardware support includes AES-128/256, RSA, ECDSA and ECC operations. Espressif also includes TRNG and a RAM-based physical unclonable function, or PUF, as part of its security architecture.</p>
<p>Flash encryption uses XTS-AES-256, while secure boot can verify signed firmware before it executes. Together, these mechanisms make it more difficult to extract proprietary firmware or replace legitimate software with unauthorized code. These features may not matter while experimenting with a development board, but they become very important once an ESP32-based product leaves the lab.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Who is the ESP32-S31 For?</strong></h2>
<p>The ESP32-S31 makes the most sense when several previously separate requirements start appearing in the same project. A smart-home gateway is one example. It may need Wi-Fi for the local network, Thread or Zigbee for sensors, Bluetooth for commissioning, Ethernet for reliable wired connectivity and enough processing power to run local automation logic.</p>
<p>A smart display is another. Now the device may need LCD graphics, touch input, audio, Wi-Fi, Bluetooth and perhaps a camera.  The same applies to voice assistants, industrial gateways, security panels and camera-based edge devices. For those applications, the ESP32-S31 can potentially replace several chips with one highly integrated SoC.</p>
<p>For basic sensor nodes and conventional ESP32 projects, however, the S31 is unlikely to make the ESP32-S3, C3 or C6 obsolete. Those devices are cheaper, mature and already have a large software ecosystem.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Final Thoughts</strong></h2>
<p>The ESP32-S31 feels less like another variation of the ESP32 and more like Espressif stretching the definition of what an ESP32-class microcontroller can handle. You still get familiar microcontroller peripherals such as GPIO, SPI, I2C, UART and PWM. But those now sit beside a 320 MHz dual-core RISC-V processor, high-speed PSRAM, Wi-Fi 6, Bluetooth Classic and LE, Zigbee/Thread connectivity, High-Speed USB, Gigabit Ethernet, camera and display interfaces, and dedicated multimedia accelerators.</p>
<p>The hardware is impressive. The main limitation right now is software maturity. ESP-IDF is already the primary path for development, while Arduino support is still catching up. For developers who depend heavily on mature Arduino libraries, the ESP32-S3 remains easier to use today. But once the ecosystem matures, the ESP32-S31 could become one of Espressif's most interesting devices for smart displays, gateways, audio products and edge-AI projects. And considering how many interfaces Espressif has managed to put into a single microcontroller, there should be plenty of projects worth testing on it.</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-s31-explained-specs-risc-v-wi-fi-6-and-esp32-s3-comparison/">ESP32-S31 Explained: Specs, RISC-V, Wi-Fi 6 and ESP32-S3 Comparison</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32-S3 PSRAM: How to Enable, Detect and Use It in Arduino</title>
		<link>https://www.teachmemicro.com/esp32-s3-psram-how-to-enable-detect-and-use-it-in-arduino/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Sun, 20 Sep 2026 02:18:19 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12838</guid>

					<description><![CDATA[<p>One of the reasons I like the ESP32-S3 is that you can get a surprising amount of memory on a very small development board. Some variants come with 2 MB of PSRAM, while others have 8 MB. That is much more memory than the ESP32-S3 has internally. However, the advertised PSRAM size does not tell &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-s3-psram-how-to-enable-detect-and-use-it-in-arduino/">ESP32-S3 PSRAM: How to Enable, Detect and Use It in Arduino</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>One of the reasons I like the ESP32-S3 is that you can get a surprising amount of memory on a very small development board. Some variants come with 2 MB of PSRAM, while others have 8 MB. That is much more memory than the ESP32-S3 has internally. However, the advertised PSRAM size does not tell you how much of it your program can actually use.</p>
<p>I ran into this while testing an <a href="https://www.teachmemicro.com/esp32-s3-mini-getting-started-guide/">ESP32-S3 Mini</a>. I knew the chip on my board was supposed to have 2 MB of PSRAM. One of my first tests successfully allocated a 1 MB buffer; however, it was surprisingly easy to read that result as if the board only had 1 MB available. Another memory test showed the actual 2 MB.</p>
<p>The important part was figuring out what each PSRAM value actually represented.</p>
<p>There is the total PSRAM physically available to the chip. Then there is the amount currently free. There is also the largest continuous block that your program can allocate. Those numbers are related, but they are not necessarily equal. In this tutorial, I'll show you how to enable PSRAM in the Arduino IDE, confirm that the ESP32-S3 actually detects it, allocate buffers inside it and check how much usable memory remains.</p>
<p><span id="more-12838"></span></p>
<p><img data-dominant-color="dbddde" data-has-transparency="false" style="--dominant-color: #dbddde;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12851 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-psram-hero.avif" alt="ESP32-S3 PSRAM Hero" width="836" height="471" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-psram-hero.avif 836w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-psram-hero-300x169.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-psram-hero-768x433.avif 768w" sizes="auto, (max-width: 836px) 100vw, 836px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What is PSRAM on the ESP32-S3?</strong></h2>
<p>The ESP32-S3 already contains internal <a href="https://en.wikipedia.org/wiki/Static_random-access_memory">SRAM</a>. This is where your program keeps variables, task stacks, temporary buffers, and other runtime data. Internal RAM becomes limited once the project starts using large buffers. A small sensor program will probably never care about PSRAM. This becomes noticeable in projects that:</p>
<ul>
<li>Store camera frame buffers</li>
<li>Run TinyML models</li>
<li>Build large JSON documents</li>
<li>Process audio samples</li>
<li>Buffer data before writing to an SD card</li>
<li>Store images for a display</li>
<li>Receive large network packets or files</li>
</ul>
<p>These applications can quickly consume the available internal SRAM. <strong>PSRAM</strong>, or pseudo-static RAM, gives the ESP32-S3 an additional external memory space. Depending on the hardware configuration, the PSRAM can be connected through Quad SPI or Octal SPI.</p>
<p>Once initialized, PSRAM can be allocated much like normal RAM. However, it is still external memory and not simply another block of internal SRAM. Because it is external memory, it is slower and has some restrictions that internal SRAM does not.</p>
<p><img data-dominant-color="f1f1f2" data-has-transparency="false" style="--dominant-color: #f1f1f2;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12852 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-memory.avif" alt="ESP32-S3 Memory" width="718" height="349" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-memory.avif 718w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-s3-memory-300x146.avif 300w" sizes="auto, (max-width: 718px) 100vw, 718px" /></p>
<p>If you are also deciding which ESP32-S3 pins are available for a project, see my <a href="https://www.teachmemicro.com/esp32-s3-pinout/">ESP32-S3 pinout guide</a>. Some GPIO pins are used internally by flash and PSRAM on certain modules.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Does Your ESP32-S3 Actually Have PSRAM?</strong></h2>
<p>Not every ESP32-S3 board has PSRAM. Two boards sold as "ESP32-S3" can have different flash and PSRAM configurations. For Espressif modules, the suffix printed on the chip or module often gives us a clue.</p>
<table>
<thead>
<tr>
<th>Marking</th>
<th>Flash</th>
<th>PSRAM</th>
<th>PSRAM Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>N4R2</td>
<td>4 MB</td>
<td>2 MB</td>
<td>QSPI</td>
</tr>
<tr>
<td>N8R2</td>
<td>8 MB</td>
<td>2 MB</td>
<td>QSPI</td>
</tr>
<tr>
<td>N16R2</td>
<td>16 MB</td>
<td>2 MB</td>
<td>QSPI</td>
</tr>
<tr>
<td>N4R8</td>
<td>4 MB</td>
<td>8 MB</td>
<td>OPI</td>
</tr>
<tr>
<td>N8R8</td>
<td>8 MB</td>
<td>8 MB</td>
<td>OPI</td>
</tr>
<tr>
<td>N16R8</td>
<td>16 MB</td>
<td>8 MB</td>
<td>OPI</td>
</tr>
</tbody>
</table>
<p>For PSRAM, look at the <strong>R</strong> suffix. <strong>R2</strong> indicates 2 MB PSRAM, while <strong>R8</strong> indicates 8 MB PSRAM. There are also ESP32-S3 variants without PSRAM, so don't assume every board includes it. On generic boards such as the ESP32-S3 Super Mini, I would not trust the product listing alone. Check the actual marking on the chip or module if possible. This is what I did with my own board. On the image below, you can see "F<strong>N4R2</strong>P415070," which means this board has 2MB of PSRAM. I trust the device marking more than the seller's listing.</p>
<p><img data-dominant-color="464342" data-has-transparency="false" style="--dominant-color: #464342;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12645 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cpu-closeup.avif" alt="ESP32-S3 Super Mini CPU Close Up" width="652" height="869" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cpu-closeup.avif 652w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cpu-closeup-225x300.avif 225w" sizes="auto, (max-width: 652px) 100vw, 652px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Enabling ESP32-S3 PSRAM in Arduino IDE</strong></h2>
<p>The Arduino configuration also has to match the installed PSRAM. If you are using the generic ESP32-S3 board definition, select:</p>
<pre><code>Tools &gt; Board &gt; ESP32 Arduino &gt; ESP32S3 Dev Module</code></pre>
<p><img data-dominant-color="ebf0f0" data-has-transparency="false" style="--dominant-color: #ebf0f0;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12949 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/arduino-tools-esp32-board.avif" alt="" width="329" height="321" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/arduino-tools-esp32-board.avif 329w, https://www.teachmemicro.com/wp-content/uploads/2026/09/arduino-tools-esp32-board-300x293.avif 300w" sizes="auto, (max-width: 329px) 100vw, 329px" /></p>
<p>Then look for:</p>
<pre><code>Tools &gt; PSRAM</code></pre>
<p><img data-dominant-color="f2f2f3" data-has-transparency="false" style="--dominant-color: #f2f2f3;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12950 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/arduino-tools-psram.avif" alt="" width="638" height="117" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/arduino-tools-psram.avif 638w, https://www.teachmemicro.com/wp-content/uploads/2026/09/arduino-tools-psram-300x55.avif 300w" sizes="auto, (max-width: 638px) 100vw, 638px" /></p>
<p>Depending on the Arduino-ESP32 version and selected board, you may see options such as:</p>
<ul>
<li>Disabled</li>
<li>QSPI PSRAM</li>
<li>OPI PSRAM</li>
</ul>
<p>For a board with <strong>R2</strong> PSRAM, select:</p>
<pre><code>QSPI PSRAM</code></pre>
<p>Then, for a board with <strong>R8</strong> PSRAM, select:</p>
<pre><code>OPI PSRAM</code></pre>
<p>For example, if the device marking indicates an R2 configuration, I would select:</p>
<pre><code>Tools &gt; PSRAM &gt; QSPI PSRAM</code></pre>
<p>A wrong PSRAM or flash setting can also prevent the board from booting correctly. So if an ESP32-S3 starts rebooting after uploading even a simple sketch, the PSRAM setting is one of the first things I would check.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Detecting PSRAM from an Arduino Sketch</strong></h2>
<p>These are my Arduino settings for this article, so make sure you have the same before uploading and running the sketches here:</p>
<ul>
<li><strong>Board:</strong> <em>ESP32S3 Dev Module</em> if your specific Mini board isn't listed</li>
<li><strong>USB CDC On Boot:</strong> <em>Enabled</em></li>
<li><strong>Upload Mode:</strong> <em>UART0 / Hardware CDC</em></li>
<li><strong>USB Mode:</strong> <em>Hardware CDC and JTAG</em> if that option is available</li>
<li><strong>Port:</strong> <em>&lt;your ESP32-S3's COM Port&gt;</em></li>
<li><strong>Serial Monitor:</strong> <em>115200</em></li>
</ul>
<p>Before allocating PSRAM, first check whether the Arduino core detects it. The simplest test is <em>psramFound()</em>:</p>
<pre><code>void setup() {
  Serial.begin(115200);
  delay(2000);

  if (psramFound()) {
    Serial.println("PSRAM detected!");
  } else {
    Serial.println("PSRAM not found.");
  }
}

void loop() {
}</code></pre>
<p>If everything is configured correctly, you should see:</p>
<pre><code>PSRAM detected!</code></pre>
<p>&nbsp;</p>
<p><img data-dominant-color="f9fafa" data-has-transparency="false" style="--dominant-color: #f9fafa;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12953 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-detected-1.avif" alt="" width="616" height="225" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-detected-1.avif 616w, https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-detected-1-300x110.avif 300w" sizes="auto, (max-width: 616px) 100vw, 616px" /></p>
<p>If you get:</p>
<pre><code>PSRAM not found.</code></pre>
<p>A failed detection test can also be caused by the board or PSRAM configuration.</p>
<p>Check these first:</p>
<ul>
<li>The exact ESP32-S3 chip or module variant</li>
<li>The board selected in Arduino IDE</li>
<li>The QSPI or OPI PSRAM setting</li>
<li>The memory specification supplied by the board manufacturer</li>
</ul>
<p>Only after those checks would I start suspecting a hardware problem.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Checking ESP32-S3 PSRAM Size</strong></h2>
<p>The <em>ESP</em> object reports the total, free, minimum-free, and maximum allocatable PSRAM.</p>
<p>Try this sketch:</p>
<pre><code>void setup() {
  Serial.begin(115200);
  delay(2000);

  Serial.println("ESP32-S3 PSRAM Test");
  Serial.println("-------------------");

  if (!psramFound()) {
    Serial.println("PSRAM not detected.");
    return;
  }

  Serial.println("PSRAM detected: YES");

  Serial.print("Total PSRAM: ");
  Serial.print(ESP.getPsramSize() / 1024.0 / 1024.0, 2);
  Serial.println(" MB");

  Serial.print("Free PSRAM: ");
  Serial.print(ESP.getFreePsram() / 1024.0);
  Serial.println(" KB");

  Serial.print("Minimum free PSRAM: ");
  Serial.print(ESP.getMinFreePsram() / 1024.0);
  Serial.println(" KB");

  Serial.print("Largest free block: ");
  Serial.print(ESP.getMaxAllocPsram() / 1024.0);
  Serial.println(" KB");
}

void loop() {
}</code></pre>
<p>On a 2 MB ESP32-S3, the important result should be close to:</p>
<pre><code>PSRAM detected: YES
Total PSRAM: 2.00 MB</code></pre>
<p>The other numbers will vary depending on the Arduino core, libraries and anything your program has already allocated. The total PSRAM value alone is not enough when debugging memory use.</p>
<p><img data-dominant-color="dfe9ea" data-has-transparency="false" style="--dominant-color: #dfe9ea;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12954 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-allocation.avif" alt="" width="607" height="253" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-allocation.avif 607w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-allocation-300x125.avif 300w" sizes="auto, (max-width: 607px) 100vw, 607px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Total PSRAM Is Not the Same as Free PSRAM</strong></h2>
<p>There are four useful numbers in the previous program:</p>
<table>
<thead>
<tr>
<th>Function</th>
<th>What It Tells You</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>ESP.getPsramSize()</em></td>
<td>Total PSRAM detected by the ESP32-S3</td>
</tr>
<tr>
<td><em>ESP.getFreePsram()</em></td>
<td>PSRAM currently unused</td>
</tr>
<tr>
<td><em>ESP.getMinFreePsram()</em></td>
<td>Lowest free-PSRAM level reached since boot</td>
</tr>
<tr>
<td><em>ESP.getMaxAllocPsram()</em></td>
<td>Largest single contiguous block that can currently be allocated</td>
</tr>
</tbody>
</table>
<p><em>ESP.getMaxAllocPsram()</em> is especially important when allocating large buffers.</p>
<p>For example, suppose the ESP32 reports:</p>
<pre><code>Free PSRAM:          1200 KB
Largest free block:   700 KB</code></pre>
<p>You have 1.2 MB free in total, but that does <strong>not</strong> mean you can allocate a single 1 MB buffer. The free memory may be split into several smaller regions. The heap is <strong>fragmented</strong>: the free memory exists, but it is split into smaller blocks. Free PSRAM and maximum allocatable PSRAM therefore need to be checked separately. This is what confused my earlier 1 MB allocation test. A successful 1 MB allocation tells me that a 1 MB block was available. It does not tell me that the board physically contains only 1 MB of PSRAM.</p>
<p><img data-dominant-color="cddcce" data-has-transparency="false" style="--dominant-color: #cddcce;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12940 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/before-after-fragmentation.avif" alt="Before and after fragmentation" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/before-after-fragmentation.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/before-after-fragmentation-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Allocating Memory with ps_malloc()</strong></h2>
<p>Next, we can allocate a buffer directly in PSRAM. Arduino-ESP32 provides <em>ps_malloc()</em>, which works much like the normal C <em>malloc()</em> function except that the allocation is specifically requested from PSRAM.</p>
<p>Here's a simple example that tries to allocate 1 MB:</p>
<pre><code>void setup() {
  Serial.begin(115200);
  delay(2000);

  if (!psramFound()) {
    Serial.println("PSRAM not available.");
    return;
  }

  const size_t bufferSize = 1024 * 1024;

  uint8_t *buffer = (uint8_t *)ps_malloc(bufferSize);

  if (buffer == NULL) {
    Serial.println("PSRAM allocation failed!");
    return;
  }

  Serial.println("1 MB PSRAM allocation successful.");

  free(buffer);
  Serial.println("Buffer released.");
}

void loop() {
}</code></pre>
<p>Always check whether the returned pointer is <em>NULL</em>. Large allocations can fail even when PSRAM is enabled. Also notice that we release the PSRAM buffer using:</p>
<pre><code>free(buffer);</code></pre>
<p>You don't need a special <em>ps_free()</em> function.</p>
<p><img data-dominant-color="ebece9" data-has-transparency="false" style="--dominant-color: #ebece9;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12941 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/ps_malloc_workflow.avif" alt="PS_Malloc workflow" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/ps_malloc_workflow.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/ps_malloc_workflow-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Actually Writing Data to PSRAM</strong></h2>
<p>I also wanted to verify that the allocated memory could be written and read back correctly. Let's allocate 1 MB, fill it with data and then verify the values.</p>
<pre><code>void setup() {
  Serial.begin(115200);
  delay(2000);

  if (!psramFound()) {
    Serial.println("PSRAM not detected.");
    return;
  }

  const size_t bufferSize = 1024 * 1024;

  uint8_t *buffer = (uint8_t *)ps_malloc(bufferSize);

  if (buffer == NULL) {
    Serial.println("Could not allocate 1 MB in PSRAM.");
    return;
  }

  Serial.println("1 MB allocated successfully.");

  // Fill the buffer with a repeating pattern
  for (size_t i = 0; i &lt; bufferSize; i++) {
    buffer[i] = i &amp; 0xFF;
  }

  // Verify the contents
  bool passed = true;

  for (size_t i = 0; i &lt; bufferSize; i++) {
    if (buffer[i] != (i &amp; 0xFF)) {
      passed = false;
      break;
    }
  }

  if (passed) {
    Serial.println("PSRAM read/write test PASSED.");
  } else {
    Serial.println("PSRAM read/write test FAILED.");
  }

  free(buffer);
}

void loop() {
}</code></pre>
<p>This verifies more than allocation alone:</p>
<ul>
<li>Confirms PSRAM initialization</li>
<li>Confirms that a large contiguous block is available</li>
<li>Writes across the allocated region</li>
<li>Reads the data back</li>
<li>Checks that the contents were preserved</li>
</ul>
<p>A successful result should look like:</p>
<pre><code>1 MB allocated successfully.
PSRAM read/write test PASSED.</code></pre>
<p><img data-dominant-color="e0eaea" data-has-transparency="false" style="--dominant-color: #e0eaea;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12955 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-alloc-test.avif" alt="" width="612" height="255" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-alloc-test.avif 612w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-alloc-test-300x125.avif 300w" sizes="auto, (max-width: 612px) 100vw, 612px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ps_malloc() vs malloc() vs heap_caps_malloc()</strong></h2>
<p><em>ps_malloc()</em> is not the only allocator that can use PSRAM. ESP32 applications also use <em>malloc()</em>. With PSRAM enabled, the ESP32 heap allocator can also place some ordinary allocations in external RAM. That means ordinary calls to <em>malloc()</em> may also use PSRAM depending on the allocation size, available memory, and configuration.</p>
<p>This lets existing libraries use the larger heap without calling <em>ps_malloc()</em> directly. For memory tests, I use <em>ps_malloc()</em> so I know the buffer is coming from PSRAM:</p>
<pre><code>uint8_t *buffer = (uint8_t *)ps_malloc(bufferSize);</code></pre>
<p>For even more control, we can use the ESP32 capability-based allocator:</p>
<pre><code>#include "esp_heap_caps.h"

uint8_t *buffer = (uint8_t *)heap_caps_malloc(
    bufferSize,
    MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
);</code></pre>
<p>The <em>MALLOC_CAP_SPIRAM</em> flag specifically requests external PSRAM. For most Arduino projects, <em>ps_malloc()</em> is easier to read. I would reach for <em>heap_caps_malloc()</em> when I need more specific control over the type of memory being requested.</p>
<p><img data-dominant-color="e4e5e5" data-has-transparency="false" style="--dominant-color: #e4e5e5;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12932 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32_malloc.avif" alt="ESP32 PSRAM malloc()" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32_malloc.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32_malloc-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>When Should You Use PSRAM?</strong></h2>
<p>PSRAM is best suited to <strong>large data where the lowest possible access latency is not required</strong>.</p>
<p>Good candidates include:</p>
<ul>
<li>Camera frames</li>
<li>Image buffers</li>
<li>Audio sample buffers</li>
<li>Large arrays</li>
<li>Machine-learning tensor arenas</li>
<li>Large strings</li>
<li>JSON documents</li>
<li>Network receive buffers</li>
<li>Temporary file buffers</li>
</ul>
<p>For example, an ESP32-S3 used for <a href="https://www.teachmemicro.com/tinyml-with-esp32-tutorial/">TinyML</a> may need hundreds of kilobytes just for model tensors and intermediate data. Moving this kind of bulk data to PSRAM leaves more internal SRAM available for the rest of the application. A 300 KB buffer might consume an uncomfortable amount of internal RAM. Put the same bulk data in PSRAM and you preserve internal memory for the operating system, Wi-Fi, task stacks, and peripherals.</p>
<p><img data-dominant-color="d6dfe5" data-has-transparency="false" style="--dominant-color: #d6dfe5;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12933 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-use-case.avif" alt="PSRAM use case" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-use-case.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-use-case-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>PSRAM Is Not Just More Internal SRAM</strong></h2>
<p>An ESP32-S3 with 8 MB of PSRAM does not behave like a microcontroller with 8 MB of internal SRAM. External PSRAM sits behind the ESP32-S3's memory interface and cache. Frequently accessed data can perform reasonably well, but large accesses eventually exceed what the cache can hide. Use PSRAM when <strong>capacity</strong> matters. Keep frequently accessed or timing-sensitive data in internal SRAM. There is little benefit in moving small variables to PSRAM just because it is available. Use PSRAM for the large objects that actually justify it.</p>
<p><img data-dominant-color="cbd2d0" data-has-transparency="false" style="--dominant-color: #cbd2d0;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12934 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/sram-vs-psram.avif" alt="SRAM vs PSRAM" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/sram-vs-psram.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/sram-vs-psram-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Some Data Still Needs Internal RAM</strong></h2>
<p>Some data cannot or should not be placed in PSRAM. Peripheral and DMA operations can have additional memory requirements. Some hardware structures must remain in internal memory even if the main data buffer lives in PSRAM. FreeRTOS task stacks are also normally kept in internal RAM.</p>
<p>PSRAM and external flash also share parts of the ESP32-S3 external-memory and cache system. This becomes relevant if you are writing lower-level code, performing flash operations, or debugging difficult timing-related crashes. This usually does not matter for a simple image or data buffer, but it matters more in drivers, networking, DMA, flash operations, and real-time applications.</p>
<p>A practical rule is:</p>
<div class="box info  aligncenter"><div class="box-inner-block"><i class="fa tie-shortcode-boxicon"></i>
			
<p><strong>Use PSRAM for bulk storage. Keep timing-critical and hardware-sensitive data in internal RAM unless you have a specific reason not to.</strong></p>

			</div></div>
<figure id="attachment_12935" aria-describedby="caption-attachment-12935" style="width: 724px" class="wp-caption aligncenter"><img data-dominant-color="cdd4d7" data-has-transparency="false" style="--dominant-color: #cdd4d7;" loading="lazy" decoding="async" class="wp-image-12935 size-full not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-applications.avif" alt="PSRAM applications" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-applications.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-applications-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /><figcaption id="caption-attachment-12935" class="wp-caption-text"><em>Left: PSRAM Applications: images, audio, large arrays, ML tensors; Right: Internal SRAM Applications: task stacks, timing-critical variables, hardware/DMA control structures</em></figcaption></figure>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Monitoring PSRAM While Your Program Runs</strong></h2>
<p>A memory leak or fragmentation problem may not become visible until the program has been running for a while. For debugging, I find it useful to periodically print both free PSRAM and the largest allocatable block.</p>
<pre><code>void printPsramStatus() {
  Serial.print("Free PSRAM: ");
  Serial.print(ESP.getFreePsram() / 1024);
  Serial.println(" KB");

  Serial.print("Largest block: ");
  Serial.print(ESP.getMaxAllocPsram() / 1024);
  Serial.println(" KB");

  Serial.print("Minimum free PSRAM: ");
  Serial.print(ESP.getMinFreePsram() / 1024);
  Serial.println(" KB");
}</code></pre>
<p>Call this at different stages of your program.</p>
<p>For example:</p>
<pre><code>printPsramStatus();

camera.begin();

printPsramStatus();

loadModel();

printPsramStatus();</code></pre>
<p>Comparing these readings shows which initialization step consumed the PSRAM. <em>getMinFreePsram()</em> records the lowest free-PSRAM level reached since boot. A temporary allocation might have already been released by the time you check the Serial Monitor, but the minimum value can reveal that memory usage briefly spiked.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Why Can an Allocation Fail When PSRAM Is Still Free?</strong></h2>
<p>Suppose your Serial Monitor says:</p>
<pre><code>Free PSRAM: 1300 KB</code></pre>
<p>Then this fails:</p>
<pre><code>ps_malloc(1024 * 1024);</code></pre>
<p>The reason becomes clear when you check the largest allocatable block.</p>
<p>Check:</p>
<pre><code>ESP.getMaxAllocPsram()</code></pre>
<p>You may discover something like:</p>
<pre><code>Free PSRAM:       1300 KB
Largest block:     800 KB</code></pre>
<p>The allocator has 1.3 MB available overall, but there is no single 1 MB continuous region. This can happen after many differently sized allocations and frees. If your application depends on a very large buffer, allocate it early during startup rather than waiting until the heap has been used heavily. If your application needs one large buffer, allocate it early before repeated allocations fragment the heap.</p>
<p><img data-dominant-color="cbddcf" data-has-transparency="false" style="--dominant-color: #cbddcf;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12936 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-memory-fragmentation.avif" alt="ESP32 Memory Fragmentation" width="887" height="444" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-memory-fragmentation.avif 887w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-memory-fragmentation-300x150.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-memory-fragmentation-768x384.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-memory-fragmentation-660x330.avif 660w" sizes="auto, (max-width: 887px) 100vw, 887px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 PSRAM Troubleshooting</strong></h2>
<h3><strong>PSRAM Size Shows 0 Bytes</strong></h3>
<p>First check:</p>
<pre><code>psramFound()</code></pre>
<p>If that also returns false, verify the Arduino IDE PSRAM configuration.</p>
<p>For R2 devices:</p>
<pre><code>Tools &gt; PSRAM &gt; QSPI PSRAM</code></pre>
<p>For R8 devices:</p>
<pre><code>Tools &gt; PSRAM &gt; OPI PSRAM</code></pre>
<p>Also confirm that your ESP32-S3 variant actually contains PSRAM.</p>
<h3><strong>The Board Keeps Rebooting</strong></h3>
<p>An incorrect flash or PSRAM mode can prevent some ESP32-S3 boards from starting correctly. Check the exact chip or module marking rather than guessing based on the development-board name.</p>
<h3><strong>ps_malloc() Returns NULL</strong></h3>
<p>Print:</p>
<pre><code>ESP.getFreePsram()
ESP.getMaxAllocPsram()</code></pre>
<p>The largest available block may be smaller than the buffer you are requesting. Also make sure the result of every allocation is checked before using the pointer.</p>
<h3><strong>My 2 MB Board Shows Slightly Less Than 2 MB Free</strong></h3>
<p>That is normal. <em>ESP.getPsramSize()</em> reports the total detected PSRAM, while <em>ESP.getFreePsram()</em> tells you how much remains available after system initialization and allocations. Don't use the free-memory value to identify how much memory is physically there.</p>
<h3><strong>I Allocated 1 MB. Does That Mean My Board Has 1 MB PSRAM?</strong></h3>
<p>No.</p>
<p>It only proves that the allocator successfully found a 1 MB continuous block.</p>
<p>Use:</p>
<pre><code>ESP.getPsramSize()</code></pre>
<p>to determine the total detected PSRAM.</p>
<p><img data-dominant-color="e8edee" data-has-transparency="false" style="--dominant-color: #e8edee;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12937 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-troubleshooting.avif" alt="ESP32 PSRAM troubleshooting" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-troubleshooting.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/psram-troubleshooting-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Putting It All Together</strong></h2>
<p>I use the following sketch as a quick PSRAM check on a new ESP32-S3 board:</p>
<pre><code>void setup() {
  Serial.begin(115200);
  delay(2000);

  Serial.println();
  Serial.println("ESP32-S3 PSRAM Check");
  Serial.println("====================");

  if (!psramFound()) {
    Serial.println("PSRAM: NOT DETECTED");
    return;
  }

  Serial.println("PSRAM: DETECTED");

  Serial.printf(
    "Total PSRAM: %.2f MB\n",
    ESP.getPsramSize() / 1024.0 / 1024.0
  );

  Serial.printf(
    "Free PSRAM: %.2f MB\n",
    ESP.getFreePsram() / 1024.0 / 1024.0
  );

  Serial.printf(
    "Largest block: %.2f MB\n",
    ESP.getMaxAllocPsram() / 1024.0 / 1024.0
  );

  const size_t testSize = 1024 * 1024;

  uint8_t *testBuffer = (uint8_t *)ps_malloc(testSize);

  if (testBuffer != NULL) {
    Serial.println("1 MB allocation: PASS");
    memset(testBuffer, 0x55, testSize);
    Serial.println("1 MB write: PASS");
   free(testBuffer);
  } else {
    Serial.println("1 MB allocation: FAIL");
  }
}

void loop() {
}</code></pre>
<p>From this output I can verify that PSRAM is detected, see the total and available memory, check the largest block, and confirm that a reasonably large buffer can actually be allocated.</p>
<p><img data-dominant-color="e2ecec" data-has-transparency="false" style="--dominant-color: #e2ecec;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12956 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-check.avif" alt="" width="614" height="247" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-check.avif 614w, https://www.teachmemicro.com/wp-content/uploads/2026/09/esp32-psram-check-300x121.avif 300w" sizes="auto, (max-width: 614px) 100vw, 614px" /></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Conclusion</strong></h2>
<p>PSRAM is useful when an ESP32-S3 project needs large image, audio, machine-learning, or network buffers. It should not be treated the same as internal SRAM. First, make sure your particular ESP32-S3 actually contains PSRAM. Then configure the correct QSPI or OPI mode in Arduino IDE and verify it using <em>psramFound()</em> and <em>ESP.getPsramSize()</em>. After that, functions such as <em>ps_malloc()</em> make it straightforward to place large buffers in external memory.</p>
<p>My testing showed why <strong>total memory, free memory, and largest allocatable memory are three different things</strong>. Checking all three usually makes allocation problems much easier to trace.</p>
<p>In the next experiment, I will take this a step further and compare <strong>ESP32-S3 internal SRAM against PSRAM</strong>, including allocation size, read/write speed and what happens as the working buffer becomes larger.</p>
<p><img data-dominant-color="d5e1e3" data-has-transparency="false" style="--dominant-color: #d5e1e3;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12938 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/09/internal-sram-vs-psram-benchmark.avif" alt="ESP32 Internal SRAM vs PSRAM benchmark" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/09/internal-sram-vs-psram-benchmark.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/09/internal-sram-vs-psram-benchmark-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<p>The post <a href="https://www.teachmemicro.com/esp32-s3-psram-how-to-enable-detect-and-use-it-in-arduino/">ESP32-S3 PSRAM: How to Enable, Detect and Use It in Arduino</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32-S3 Mini Getting Started Guide: Super Mini Pinout, Arduino IDE Setup, PSRAM and RGB LED</title>
		<link>https://www.teachmemicro.com/esp32-s3-mini-getting-started-guide/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Mon, 24 Aug 2026 04:33:59 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12625</guid>

					<description><![CDATA[<p>The ESP32-S3 Mini, often sold as the ESP32-S3 Super Mini, packs a surprisingly powerful ESP32-S3 microcontroller into a board only slightly larger than its USB-C connector. Despite its size, the board gives you a dual-core processor, Wi-Fi, Bluetooth Low Energy, native USB, PSRAM on some versions, and enough GPIO pins for many embedded projects. There &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-s3-mini-getting-started-guide/">ESP32-S3 Mini Getting Started Guide: Super Mini Pinout, Arduino IDE Setup, PSRAM and RGB LED</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The <strong>ESP32-S3 Mini</strong>, often sold as the <strong>ESP32-S3 Super Mini</strong>, packs a surprisingly powerful ESP32-S3 microcontroller into a board only slightly larger than its USB-C connector. Despite its size, the board gives you a dual-core processor, Wi-Fi, Bluetooth Low Energy, native USB, PSRAM on some versions, and enough GPIO pins for many embedded projects.</p>
<p>There is one problem: documentation for these generic Super Mini boards is often incomplete. Different online sellers sometimes show different pin diagrams, memory specifications, and even different onboard LED connections.</p>
<p>In this guide, I will show you how to set up the ESP32-S3 Super Mini in the Arduino IDE, identify the hardware you actually received, test its flash and PSRAM, and control the onboard RGB LED. We will also look at the pinout and some common upload problems.</p>
<p><span id="more-12625"></span></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What is the ESP32-S3 Mini?</strong></h2>
<p><img data-dominant-color="c3c3c3" data-has-transparency="false" style="--dominant-color: #c3c3c3;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12644 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cover.avif" alt="ESP32-S3 Super Mini Hero" width="597" height="517" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cover.avif 597w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cover-300x260.avif 300w" sizes="auto, (max-width: 597px) 100vw, 597px" /></p>
<p>The ESP32-S3 Super Mini is a small third-party development board built around the <strong>ESP32-S3</strong> microcontroller. The ESP32-S3 itself uses two Xtensa LX7 CPU cores running at up to 240 MHz and includes 2.4 GHz Wi-Fi and Bluetooth Low Energy.</p>
<p>The particular Super Mini version commonly sold online uses an <strong>ESP32-S3FH4R2</strong>. The letters at the end are important:</p>
<ul>
<li><strong>F</strong> - the chip contains flash memory.</li>
<li><strong>H4</strong> - 4 MB of flash is integrated into the package.</li>
<li><strong>R2</strong> - 2 MB of PSRAM is integrated into the package.</li>
</ul>
<p>This makes the small board considerably more capable than its physical size suggests. In particular, the PSRAM can be useful for frame buffers, image processing, web applications, and other programs that need more working memory than the ESP32-S3's internal RAM can comfortably provide.</p>
<p>However, not every board advertised as an "ESP32-S3 Mini" necessarily contains the same chip. Before relying on the memory specifications printed by a seller, I recommend checking the marking on the ESP32-S3 itself and then verifying the memory through software.</p>
<p><img data-dominant-color="464342" data-has-transparency="false" style="--dominant-color: #464342;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12645 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cpu-closeup.avif" alt="ESP32-S3 Super Mini CPU Close Up" width="652" height="869" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cpu-closeup.avif 652w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cpu-closeup-225x300.avif 225w" sizes="auto, (max-width: 652px) 100vw, 652px" /></p>
<h3><strong>ESP32-S3 Mini vs ESP32-S3-MINI-1</strong></h3>
<p>There is also an official Espressif product named the <strong>ESP32-S3-MINI-1</strong>. Do not confuse this with the ESP32-S3 Super Mini development board shown in this tutorial.</p>
<p>The ESP32-S3-MINI-1 is an Espressif module intended to be soldered into another PCB. The ESP32-S3 Super Mini, meanwhile, is a complete development board with a USB-C connector, voltage regulator, buttons, and exposed pins.</p>
<p>Online stores sometimes shorten both names to "ESP32-S3 Mini", which is why the terminology can be confusing.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 Super Mini Specifications</strong></h2>
<p>For the common ESP32-S3FH4R2-based version, the important specifications are:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>ESP32-S3 Super Mini</th>
</tr>
</thead>
<tbody>
<tr>
<td>Microcontroller</td>
<td>ESP32-S3</td>
</tr>
<tr>
<td>CPU</td>
<td>Dual-core Xtensa LX7</td>
</tr>
<tr>
<td>Maximum CPU Frequency</td>
<td>240 MHz</td>
</tr>
<tr>
<td>Internal SRAM</td>
<td>512 KB</td>
</tr>
<tr>
<td>Flash</td>
<td>4 MB on ESP32-S3FH4R2 version</td>
</tr>
<tr>
<td>PSRAM</td>
<td>2 MB QSPI on ESP32-S3FH4R2 version</td>
</tr>
<tr>
<td>Wi-Fi</td>
<td>2.4 GHz 802.11 b/g/n</td>
</tr>
<tr>
<td>Bluetooth</td>
<td>Bluetooth Low Energy</td>
</tr>
<tr>
<td>USB</td>
<td>Native USB through USB-C</td>
</tr>
<tr>
<td>Logic Voltage</td>
<td>3.3 V</td>
</tr>
<tr>
<td>Onboard RGB LED</td>
<td>Typically WS2812 on GPIO48</td>
</tr>
</tbody>
</table>
<p>The <strong>3.3 V logic level</strong> is worth remembering. Do not apply 5 V directly to an ESP32-S3 GPIO pin.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 Super Mini Pinout</strong></h2>
<p>The compact Super Mini board exposes fewer pins than a full-size ESP32-S3 development board. This is one of the compromises required to make the board so small.</p>
<p>The version used for this guide has GPIO1 through GPIO13 together with the default UART TX and RX pins.</p>
<p><img data-dominant-color="dfdbd6" data-has-transparency="false" style="--dominant-color: #dfdbd6;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12646 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout.avif" alt="" width="1920" height="2106" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout.avif 1920w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout-274x300.avif 274w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout-934x1024.avif 934w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout-768x842.avif 768w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout-1400x1536.avif 1400w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-pinout-1867x2048.avif 1867w" sizes="auto, (max-width: 1920px) 100vw, 1920px" /></p>
<table>
<thead>
<tr>
<th>Board Label</th>
<th>ESP32-S3 GPIO</th>
<th>Useful Functions</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>TX</td>
<td>GPIO43</td>
<td>UART TX, digital I/O</td>
<td>Default UART0 transmit pin</td>
</tr>
<tr>
<td>RX</td>
<td>GPIO44</td>
<td>UART RX, digital I/O</td>
<td>Default UART0 receive pin</td>
</tr>
<tr>
<td>1</td>
<td>GPIO1</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Good general-purpose pin</td>
</tr>
<tr>
<td>2</td>
<td>GPIO2</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Good general-purpose pin</td>
</tr>
<tr>
<td>3</td>
<td>GPIO3</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Strapping pin; use with some care at boot</td>
</tr>
<tr>
<td>4</td>
<td>GPIO4</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Good general-purpose pin</td>
</tr>
<tr>
<td>5</td>
<td>GPIO5</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Good general-purpose pin</td>
</tr>
<tr>
<td>6</td>
<td>GPIO6</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Good general-purpose pin</td>
</tr>
<tr>
<td>7</td>
<td>GPIO7</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Good general-purpose pin</td>
</tr>
<tr>
<td>8</td>
<td>GPIO8</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Useful for I2C</td>
</tr>
<tr>
<td>9</td>
<td>GPIO9</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>Useful for I2C</td>
</tr>
<tr>
<td>10</td>
<td>GPIO10</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>General-purpose</td>
</tr>
<tr>
<td>11</td>
<td>GPIO11</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>ADC2 channel</td>
</tr>
<tr>
<td>12</td>
<td>GPIO12</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>ADC2 channel</td>
</tr>
<tr>
<td>13</td>
<td>GPIO13</td>
<td>ADC, touch, PWM, digital I/O</td>
<td>ADC2 channel</td>
</tr>
<tr>
<td>RGB</td>
<td>GPIO48*</td>
<td>WS2812 RGB LED</td>
<td>Onboard; not normally exposed</td>
</tr>
</tbody>
</table>
<p><em>*GPIO48 is commonly used for the RGB LED on this Super Mini layout. Generic boards can vary, so check your board if the RGB example later in this guide does not work.</em></p>
<h3><strong>Where are GPIO19 and GPIO20?</strong></h3>
<p>The ESP32-S3 has native USB support. GPIO19 and GPIO20 can serve as the USB D- and D+ signals, respectively. On this board, the USB-C connector already uses the ESP32-S3's USB interface, so these pins are not presented like ordinary header pins.</p>
<p>This native USB connection is one of the reasons the Super Mini can be made so small: it does not necessarily need a separate CH340, CP2102, or other USB-to-UART converter.</p>
<h3><strong>Which Pins Should Beginners Use?</strong></h3>
<p>For initial projects, I would start with GPIO1, GPIO2, GPIO4, GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12 or GPIO13.</p>
<p>GPIO3 is usable, but it is also one of the ESP32-S3's strapping pins. A circuit that forces an inappropriate logic level on a strapping pin during reset can change the way the microcontroller boots.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Installing ESP32-S3 Support in Arduino IDE</strong></h2>
<p>If you have already programmed another ESP32 board using the Arduino IDE, you may already have Espressif's Arduino core installed. Otherwise, install the ESP32 package using the Arduino IDE's Boards Manager.</p>
<ol>
<li>Open the <strong>Arduino IDE</strong>.</li>
<li>Open <strong>Boards Manager</strong>.</li>
<li>Search for <strong>esp32</strong>.</li>
<li>Install the package published by <strong>Espressif Systems</strong>.</li>
<li>Restart the Arduino IDE if necessary.</li>
</ol>
<p><img data-dominant-color="edf1f1" data-has-transparency="false" style="--dominant-color: #edf1f1;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12647 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-library.avif" alt="" width="447" height="182" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-library.avif 447w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-library-300x122.avif 300w" sizes="auto, (max-width: 447px) 100vw, 447px" /></p>
<p>The generic Super Mini normally does not have its own entry in the Arduino board list. Instead, select:</p>
<pre><code>Tools &gt; Board &gt; ESP32 Arduino &gt; ESP32S3 Dev Module</code></pre>
<p>This gives us access to the configuration options needed for the S3.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Recommended Arduino IDE Settings</strong></h2>
<p>For a common ESP32-S3FH4R2 Super Mini, I recommend starting with these settings:</p>
<table>
<thead>
<tr>
<th>Arduino IDE Setting</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Board</td>
<td>ESP32S3 Dev Module</td>
</tr>
<tr>
<td>CPU Frequency</td>
<td>240MHz</td>
</tr>
<tr>
<td>USB CDC On Boot</td>
<td>Enabled</td>
</tr>
<tr>
<td>Flash Size</td>
<td>4MB (32Mb)</td>
</tr>
<tr>
<td>Flash Mode</td>
<td>QIO</td>
</tr>
<tr>
<td>PSRAM</td>
<td>QSPI PSRAM</td>
</tr>
<tr>
<td>Partition Scheme</td>
<td>Default 4MB with SPIFFS</td>
</tr>
<tr>
<td>Upload Mode</td>
<td>UART0 / Hardware CDC</td>
</tr>
</tbody>
</table>
<p><strong>QSPI PSRAM is especially important.</strong> The ESP32-S3FH4R2 contains 2 MB of Quad SPI PSRAM. Selecting the wrong PSRAM type can prevent the board from booting correctly or cause the PSRAM test to fail.</p>
<p><img data-dominant-color="f8f8f8" data-has-transparency="false" style="--dominant-color: #f8f8f8;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12648 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/arduino-settings-esp32-s3.avif" alt="" width="515" height="751" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/arduino-settings-esp32-s3.avif 515w, https://www.teachmemicro.com/wp-content/uploads/2026/08/arduino-settings-esp32-s3-206x300.avif 206w" sizes="auto, (max-width: 515px) 100vw, 515px" /></p>
<h3><strong>Why Enable USB CDC On Boot?</strong></h3>
<p>On many older ESP32 boards, a separate USB-to-serial IC creates the COM port. The ESP32-S3 can instead expose a serial interface directly through its internal USB hardware.</p>
<p>With <strong>USB CDC On Boot = Enabled</strong>, calls such as:</p>
<pre><code>Serial.println("Hello");</code></pre>
<p>can appear directly in the Arduino Serial Monitor through the USB-C connection.</p>
<p>If your sketch uploads correctly but the Serial Monitor remains completely blank, this setting is one of the first things I would check.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>First Test: Serial Output</strong></h2>
<p>Before testing anything more complicated, let's confirm that the microcontroller can run a sketch and communicate with the computer.</p>
<pre><code>void setup() {
  Serial.begin(115200);

  delay(2000);

  Serial.println();
  Serial.println("ESP32-S3 Super Mini is running!");
}

void loop() {
  Serial.println("Hello from ESP32-S3");
  delay(1000);
}</code></pre>
<p>Upload the program and open the Serial Monitor at <strong>115200 baud</strong>.</p>
<p>You should see something similar to:</p>
<pre><code>ESP32-S3 Super Mini is running!
Hello from ESP32-S3
Hello from ESP32-S3
Hello from ESP32-S3</code></pre>
<p><img data-dominant-color="e8f0f0" data-has-transparency="false" style="--dominant-color: #e8f0f0;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12650 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/hello-esp32-s3.avif" alt="" width="662" height="747" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/hello-esp32-s3.avif 662w, https://www.teachmemicro.com/wp-content/uploads/2026/08/hello-esp32-s3-266x300.avif 266w" sizes="auto, (max-width: 662px) 100vw, 662px" /></p>
<p>If this works, we have already confirmed three things: the ESP32-S3 is running, USB programming works and USB serial output works.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Testing the ESP32-S3 Mini Flash and PSRAM</strong></h2>
<p>One specification I would definitely verify on a generic ESP32-S3 Super Mini is its memory. Fortunately, Arduino gives us functions that can report the flash and PSRAM sizes directly.</p>
<p>Upload the following program:</p>
<pre><code>#include &lt;Arduino.h&gt;

void setup() {
  Serial.begin(115200);
  delay(2000);

  Serial.println("ESP32-S3 Hardware Test");
  Serial.println("----------------------");

  Serial.print("Chip model: ");
  Serial.println(ESP.getChipModel());

  Serial.print("CPU cores: ");
  Serial.println(ESP.getChipCores());

  Serial.print("CPU frequency: ");
  Serial.print(ESP.getCpuFreqMHz());
  Serial.println(" MHz");

  Serial.print("Flash size: ");
  Serial.print(ESP.getFlashChipSize() / 1024.0 / 1024.0, 2);
  Serial.println(" MB");

  Serial.print("PSRAM detected: ");
  Serial.println(psramFound() ? "YES" : "NO");

  Serial.print("PSRAM size: ");
  Serial.print(ESP.getPsramSize() / 1024.0 / 1024.0, 2);
  Serial.println(" MB");

  Serial.print("Free PSRAM: ");
  Serial.print(ESP.getFreePsram() / 1024);
  Serial.println(" KB");
}

void loop() {
}</code></pre>
<h3><strong>Expected Result for the ESP32-S3FH4R2 Version</strong></h3>
<p>On a Super Mini that really contains an ESP32-S3FH4R2, the important parts of the result should look approximately like this:</p>
<pre><code>ESP32-S3 Hardware Test
----------------------
Chip model: ESP32-S3
CPU cores: 2
CPU frequency: 240 MHz
Flash size: 4.00 MB
PSRAM detected: YES
PSRAM size: 2.00 MB
Free PSRAM: 2045 KB</code></pre>
<p><em><img data-dominant-color="f3f7f7" data-has-transparency="false" style="--dominant-color: #f3f7f7;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12658 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-ram-1.avif" alt="" width="612" height="560" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-ram-1.avif 612w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-ram-1-300x275.avif 300w" sizes="auto, (max-width: 612px) 100vw, 612px" /></em></p>
<p>If the program reports <strong>PSRAM size: 0 MB</strong>, this does not immediately mean your board lacks PSRAM. First verify that:</p>
<pre><code>Tools &gt; PSRAM &gt; QSPI PSRAM</code></pre>
<p>is selected.</p>
<p>If PSRAM still does not appear, inspect the marking on the chip. A different ESP32-S3 variant may have been fitted to your board.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Experiment: Actually Allocating Data in PSRAM</strong></h2>
<p>Detecting PSRAM is useful, but I also wanted a test that actually writes data to it. The following experiment allocates a 1 MB buffer using PSRAM, fills it with data, and then checks whether the allocation succeeded.</p>
<pre><code>#include &lt;Arduino.h&gt;

const size_t BUFFER_SIZE = 1024 * 1024;

void setup() {
  Serial.begin(115200);
  delay(2000);

  if (!psramFound()) {
    Serial.println("PSRAM not found.");
    return;
  }

  Serial.print("Free PSRAM before allocation: ");
  Serial.print(ESP.getFreePsram());
  Serial.println(" bytes");

  uint8_t *buffer = (uint8_t *)ps_malloc(BUFFER_SIZE);

  if (buffer == NULL) {
    Serial.println("1 MB PSRAM allocation FAILED.");
    return;
  }

  Serial.println("1 MB PSRAM allocation successful.");

  for (size_t i = 0; i &lt; BUFFER_SIZE; i++) {
    buffer[i] = i &amp; 0xFF;
  }

  bool passed = true;

  for (size_t i = 0; i &lt; BUFFER_SIZE; i++) {
    if (buffer[i] != (i &amp; 0xFF)) {
      passed = false;
      break;
    }
  }

  Serial.println(passed ?
                 "PSRAM read/write test PASSED." :
                 "PSRAM read/write test FAILED.");

  Serial.print("Free PSRAM after allocation: ");
  Serial.print(ESP.getFreePsram());
  Serial.println(" bytes");

  free(buffer);
}

void loop() {
}</code></pre>
<p>For a working 2 MB PSRAM device, the 1 MB allocation should succeed. More importantly, the final verification confirms that the data written to the buffer can also be read back correctly.</p>
<p>A successful test should produce something similar to:</p>
<pre><code>Free PSRAM before allocation: 2095103 bytes
1 MB PSRAM allocation successful.
PSRAM read/write test PASSED.
Free PSRAM after allocation: 1046511 bytes</code></pre>
<p>This experiment also demonstrates why PSRAM is useful. A one-megabyte buffer would consume far too much of the ESP32-S3's normal internal RAM, while the external/in-package PSRAM gives memory-hungry applications much more room.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Using the ESP32-S3 Super Mini RGB LED</strong></h2>
<p>Another nice feature of many ESP32-S3 Super Mini boards is the onboard addressable RGB LED. On the version covered by this guide, the LED is a WS2812-compatible device connected to <strong>GPIO48</strong>.</p>
<p>An addressable RGB LED is different from three ordinary LEDs. Instead of supplying separate red, green, and blue signals, we send a digital data stream containing the required color.</p>
<h3><img data-dominant-color="656768" data-has-transparency="false" style="--dominant-color: #656768;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12653 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-rgb-led-closeup.avif" alt="ESP32-S3 Super Mini RGB LED Close Up" width="651" height="477" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-rgb-led-closeup.avif 651w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-rgb-led-closeup-300x220.avif 300w" sizes="auto, (max-width: 651px) 100vw, 651px" /></h3>
<h3><strong>Installing the NeoPixel Library</strong></h3>
<p>Open the Arduino Library Manager and install the <strong>Adafruit NeoPixel</strong> library.</p>
<p>Then upload this example:</p>
<pre><code>#include &lt;Adafruit_NeoPixel.h&gt;

#define RGB_PIN 48
#define NUM_PIXELS 1

Adafruit_NeoPixel pixel(
  NUM_PIXELS,
  RGB_PIN,
  NEO_GRB + NEO_KHZ800
);

void setup() {
  pixel.begin();
  pixel.clear();
  pixel.show();
}

void loop() {
  // Red
  pixel.setPixelColor(0, pixel.Color(50, 0, 0));
  pixel.show();
  delay(1000);

  // Green
  pixel.setPixelColor(0, pixel.Color(0, 50, 0));
  pixel.show();
  delay(1000);

  // Blue
  pixel.setPixelColor(0, pixel.Color(0, 0, 50));
  pixel.show();
  delay(1000);

  // Off
  pixel.clear();
  pixel.show();
  delay(1000);
}</code></pre>
<p>I deliberately limited the color values to 50 instead of the maximum 255. Full-brightness WS2812 LEDs can be surprisingly bright, and there is no reason to run the LED at maximum power for a simple test.</p>
<h3><strong>Expected RGB Test Result</strong></h3>
<p>The onboard LED should cycle through:</p>
<ol>
<li>Red for one second</li>
<li>Green for one second</li>
<li>Blue for one second</li>
<li>Off for one second</li>
</ol>
<h3><img data-dominant-color="d2d2d1" data-has-transparency="false" style="--dominant-color: #d2d2d1;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12654 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-RGB-LED.avif" alt="ESP32-S3 RGB LED" width="964" height="380" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-RGB-LED.avif 964w, https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-RGB-LED-300x118.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-RGB-LED-768x303.avif 768w" sizes="auto, (max-width: 964px) 100vw, 964px" /></h3>
<h3><strong>What if GPIO48 Does Not Work?</strong></h3>
<p>The "Super Mini" name is used by multiple manufacturers, and not all board revisions are identical. Some ESP32-S3 boards use another GPIO for the addressable LED.</p>
<p>If the code runs but the LED remains dark:</p>
<ul>
<li>Check the seller's pinout for your exact board.</li>
<li>Inspect the board for a WS2812-style LED.</li>
<li>Try the GPIO number specified by the board manufacturer.</li>
<li>Do not assume that every ESP32-S3 board uses GPIO48.</li>
</ul>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Testing Wi-Fi</strong></h2>
<p>Since the ESP32-S3 includes Wi-Fi, a quick network scan is another useful hardware test. It verifies that the radio and antenna are operating without requiring your Wi-Fi password.</p>
<pre><code>#include &lt;WiFi.h&gt;

void setup() {
  Serial.begin(115200);
  delay(2000);

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  Serial.println("Scanning Wi-Fi networks...");

  int networks = WiFi.scanNetworks();

  if (networks == 0) {
    Serial.println("No Wi-Fi networks found.");
  } else {
    Serial.print(networks);
    Serial.println(" networks found:");

    for (int i = 0; i &lt; networks; i++) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.println(" dBm)");
    }
  }
}

void loop() {
}</code></pre>
<p>The output will depend entirely on your location. A typical result might look like:</p>
<pre><code>Scanning Wi-Fi networks...
13 networks found:
1: Stacey's_Wifi_2.4 (-65 dBm)
2: Stacey's_Wifi_2.4_EXT (-71 dBm)
3: innengarten_Guest (-82 dBm)
...
</code></pre>
<p><img data-dominant-color="ecf1f2" data-has-transparency="false" style="--dominant-color: #ecf1f2;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12655 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-WiFi-Scan.avif" alt="" width="615" height="409" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-WiFi-Scan.avif 615w, https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-WiFi-Scan-300x200.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/08/ESP32-S3-WiFi-Scan-310x205.avif 310w" sizes="auto, (max-width: 615px) 100vw, 615px" /><br />
If the board can reliably find nearby 2.4 GHz networks, we now know that the basic radio system and onboard antenna are working.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 Super Mini BOOT and RESET Buttons</strong></h2>
<p>The board normally provides two small buttons: <strong>BOOT</strong> and <strong>RESET</strong>.</p>
<p>The RESET button resets the ESP32-S3. The BOOT button is associated with the bootstrapping circuitry and is useful when manually forcing the chip into its firmware download mode.</p>
<p>Most uploads should work without touching either button. However, these buttons become useful if a program crashes early during startup, disables USB functionality or otherwise makes the normal upload process unreliable.</p>
<p><img data-dominant-color="6e6d6a" data-has-transparency="false" style="--dominant-color: #6e6d6a;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12656 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-buttons-closeup.avif" alt="" width="652" height="869" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-buttons-closeup.avif 652w, https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-buttons-closeup-225x300.avif 225w" sizes="auto, (max-width: 652px) 100vw, 652px" /></p>
<h3><strong>Manually Entering Download Mode</strong></h3>
<p>If the Arduino IDE cannot upload to the board, try the following:</p>
<ol>
<li>Press and hold <strong>BOOT</strong>.</li>
<li>Press and release <strong>RESET</strong>.</li>
<li>Release <strong>BOOT</strong>.</li>
<li>Check the Arduino IDE's Port menu again.</li>
<li>Select the newly detected port.</li>
<li>Upload the sketch.</li>
</ol>
<p>You can also try holding BOOT while connecting the USB cable.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Troubleshooting the ESP32-S3 Super Mini</strong></h2>
<h3><strong>No COM Port Appears</strong></h3>
<p>First try another USB cable. Some USB-C cables are intended only for charging and contain no data connections.</p>
<p>If the cable is good, manually enter download mode using the BOOT and RESET buttons. Then check whether a new serial device appears.</p>
<h3><strong>Sketch Uploads but Serial Monitor is Blank</strong></h3>
<p>Verify:</p>
<pre><code>Tools &gt; USB CDC On Boot &gt; Enabled</code></pre>
<p>Also make sure the Serial Monitor baud rate matches the value in:</p>
<pre><code>Serial.begin(115200);</code></pre>
<p>After changing USB-related settings, upload the sketch again.</p>
<h3><strong>PSRAM Reports 0 Bytes</strong></h3>
<p>Check:</p>
<pre><code>Tools &gt; PSRAM &gt; QSPI PSRAM</code></pre>
<p>Then rerun the memory test.</p>
<p>If PSRAM is still unavailable, read the ESP32-S3 chip marking. Your board may use a different variant than the common ESP32-S3FH4R2.</p>
<h3><strong>Board Resets After Enabling PSRAM</strong></h3>
<p>Make sure you did not select <strong>OPI PSRAM</strong> for an FH4R2 board. Its integrated 2 MB PSRAM uses Quad SPI, so select <strong>QSPI PSRAM</strong>.</p>
<h3><strong>RGB LED Does Not Light</strong></h3>
<p>GPIO48 is common for the ESP32-S3 Super Mini RGB LED, but board revisions differ. Verify the pinout supplied with your particular board.</p>
<h3><strong>Upload Suddenly Stops Working After Running a Sketch</strong></h3>
<p>Because the board uses the ESP32-S3's native USB interface, the USB connection is partly under the control of the microcontroller itself. A crashing application can therefore make the normal serial port disappear.</p>
<p>Use the BOOT/RESET procedure to enter the ESP32-S3 ROM downloader and recover the board.</p>
<h3><strong>Uploads Fail at High Speed</strong></h3>
<p>If uploads are unreliable, lower the upload speed. A lower setting takes slightly longer but can be more reliable with some computers, USB hubs and cables.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 Super Mini Test Summary</strong></h2>
<p>Before using a generic development board in a larger project, I like to verify its important features instead of relying entirely on the seller's specifications. For the ESP32-S3 Super Mini, the tests in this guide cover most of the board's important hardware.</p>
<table>
<thead>
<tr>
<th>Test</th>
<th>Expected Result for Common FH4R2 Board</th>
<th>Actual Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU identification</td>
<td>ESP32-S3, 2 cores, 240 MHz</td>
<td> ESP32-S3, 2 cores, 240 MHz</td>
</tr>
<tr>
<td>Flash memory</td>
<td>4 MB</td>
<td>4 MB</td>
</tr>
<tr>
<td>PSRAM detection</td>
<td>2 MB</td>
<td>1 MB</td>
</tr>
<tr>
<td>1 MB PSRAM allocation</td>
<td>Pass</td>
<td>Pass</td>
</tr>
<tr>
<td>USB Serial</td>
<td>Pass</td>
<td>Pass</td>
</tr>
<tr>
<td>RGB LED</td>
<td>Red, green and blue on GPIO48</td>
<td>Red, green and blue on GPIO48</td>
</tr>
<tr>
<td>Wi-Fi scan</td>
<td>Nearby 2.4 GHz networks detected</td>
<td>Pass</td>
</tr>
</tbody>
</table>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Is the ESP32-S3 Super Mini Worth Using?</strong></h2>
<p>The ESP32-S3 Super Mini is an interesting board because it gives you most of the important ESP32-S3 features without the size of a conventional development board.</p>
<p>Compared with smaller single-core ESP32 variants, the S3 gives you considerably more processing power. The common ESP32-S3FH4R2 version also includes 2 MB of PSRAM, which makes it particularly attractive for projects involving displays, large buffers, web interfaces, and other memory-intensive applications.</p>
<p>Native USB is another advantage. Besides normal serial communication, the ESP32-S3's USB hardware makes the chip suitable for projects involving USB devices. That creates possibilities beyond the usual Wi-Fi sensor and web-server projects.</p>
<p>The main disadvantage is documentation. "ESP32-S3 Super Mini" is not one tightly controlled board design, so a pinout or memory specification found online may not describe every version being sold.</p>
<p>Fortunately, we can verify most of the important details ourselves. Check the chip marking, run the flash and PSRAM test, confirm the RGB LED GPIO and keep a copy of the pinout for the exact board you own. Once those details are known, the ESP32-S3 Super Mini becomes a very capable compact development board for embedded and IoT projects.</p>
<aside class="tmm-product-card tmm-product-card--align-center tmm-product-card--layout-default" style="--tmm-product-card-title-lines:3;--tmm-product-card-desc-lines:5;" aria-label="Product recommendation: ESP32-S3 Super Mini">
							<div class="tmm-product-card__media">
					<img width="150" height="150" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-s3-super-mini-cover-image-150x150.avif" class="tmm-product-card__image not-transparent wp-post-image" alt="ESP32-S3 Super Mini" loading="lazy" decoding="async" data-has-transparency="false" data-dominant-color="d5d4d4" style="--dominant-color: #d5d4d4;" />				</div>
			
			<div class="tmm-product-card__content">
				<div class="tmm-product-card__title">ESP32-S3 Super Mini</div>

									<p class="tmm-product-card__description">ESP32S3SuperMini is positioned as a high-performance, low-power, cost-effective IoT mini development board for low-power IoT applications and wireless wearable applications.</p>
							</div>

							<div class="tmm-product-card__actions">
					<a class="button tmm-product-card__button" href="https://amzn.to/4gn4NZV" target="_blank" rel="noopener" aria-label="Check Price for ESP32-S3 Super Mini">
						Check Price					</a>
				</div>
					</aside>
<p>The post <a href="https://www.teachmemicro.com/esp32-s3-mini-getting-started-guide/">ESP32-S3 Mini Getting Started Guide: Super Mini Pinout, Arduino IDE Setup, PSRAM and RGB LED</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Adding an External Antenna to ESP32: U.FL, PCB Modifications, and Placement</title>
		<link>https://www.teachmemicro.com/adding-antenna-to-esp32/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Fri, 31 Jul 2026 00:36:54 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12389</guid>

					<description><![CDATA[<p>Adding an antenna to ESP32 can improve Wi-Fi and Bluetooth reliability when the board is installed far from an access point, placed inside an enclosure, or surrounded by components that interfere with its built-in PCB antenna. However, the modification involves more than soldering a piece of wire to the board. The antenna connection is part &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/adding-antenna-to-esp32/">Adding an External Antenna to ESP32: U.FL, PCB Modifications, and Placement</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Adding an antenna to ESP32 can improve Wi-Fi and Bluetooth reliability when the board is installed far from an access point, placed inside an enclosure, or surrounded by components that interfere with its built-in PCB antenna. However, the modification involves more than soldering a piece of wire to the board.</p>
<p>The antenna connection is part of a carefully designed radio-frequency path. The antenna, connector, coaxial cable, PCB trace, matching components, and surrounding ground plane all affect how much of the ESP32's transmitted power is actually radiated.</p>
<p>In this tutorial, we will look at the safest ways of adding an external antenna to an ESP32. This includes choosing a module with a factory-installed U.FL connector, changing an antenna selection jumper, modifying an existing PCB, selecting the correct antenna, and positioning it inside the finished project.</p>
<p><span id="more-12389"></span></p>
<p><strong>Important:</strong> The antenna arrangement differs between ESP32 boards. Before moving or removing any component, find the schematic for your exact development board and inspect the RF section under magnification.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<p><!-- Suggested image: Three ESP32 antenna configurations side by side: PCB antenna module, U.FL module, and development board with an antenna selector jumper. --></p>
<h2><strong>Why Add an External Antenna to an ESP32?</strong></h2>
<p>Most ESP32 development boards already contain a small meandered PCB antenna. For a board sitting openly on a desk, this antenna is often sufficient. Problems usually appear after the board is installed in the final product.</p>
<p>An external antenna may be useful when:</p>
<ul>
<li>The ESP32 is installed inside a metal enclosure.</li>
<li>A battery, LCD, motor, relay, or large PCB is close to the built-in antenna.</li>
<li>The device must communicate through several walls.</li>
<li>The ESP32 is located near the edge of the access point's coverage.</li>
<li>The product needs an antenna mounted outside its enclosure.</li>
<li>The orientation of the built-in PCB antenna is unsuitable for the installation.</li>
<li>A directional antenna is required for a fixed point-to-point link.</li>
</ul>
<p>An external antenna does not automatically guarantee longer range. A badly positioned external antenna connected through a poor cable can perform worse than the original PCB antenna. The entire wireless link must be considered.</p>
<p>A simplified link budget can be written as:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_fe449c7f36fc03606417804b0d84e286.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="P_R = P_T + G_T + G_R - L_{path} - L_{cable} - L_{mismatch}" /></span><script type='math/tex'>P_R = P_T + G_T + G_R - L_{path} - L_{cable} - L_{mismatch}</script></p>
<p>Here, <em>P<sub>R</sub></em> is the received power, <em>P<sub>T</sub></em> is the transmitted power, <em>G<sub>T</sub></em> and <em>G<sub>R</sub></em> are antenna gains, and the remaining terms represent path, cable, and impedance mismatch losses.</p>
<p>This equation explains why installing a higher-gain antenna may not help when a long, lossy cable or an incorrectly modified RF trace introduces additional losses.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Understand Which Type of ESP32 Board You Have</strong></h2>
<p><img data-dominant-color="c5c4c2" data-has-transparency="false" style="--dominant-color: #c5c4c2;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12391 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-antenna-configurations.avif" alt="ESP32 Antenna Configuration" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-antenna-configurations.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-antenna-configurations-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<p>The term “ESP32 board” can refer to the ESP32 chip, a shielded ESP32 module, or a complete development board. The antenna may be part of any one of these assemblies.</p>
<table>
<thead>
<tr>
<th>Board or Module Type</th>
<th>Antenna Arrangement</th>
<th>Recommended Approach</th>
</tr>
</thead>
<tbody>
<tr>
<td>ESP32 module with PCB antenna</td>
<td>Antenna is etched directly onto the module PCB</td>
<td>Use the existing antenna or replace the module with an external-antenna version</td>
</tr>
<tr>
<td>ESP32 module ending in U or UE</td>
<td>Factory-installed micro-coaxial connector</td>
<td>Connect a compatible external antenna</td>
</tr>
<tr>
<td>Development board with PCB antenna and U.FL connector</td>
<td>A small RF jumper selects one antenna path</td>
<td>Move the jumper to the external-antenna position</td>
</tr>
<tr>
<td>Board with no connector but an accessible RF feed</td>
<td>Modification requires isolating the existing antenna</td>
<td>Attach a short 50 Ω micro-coaxial cable at the RF feed</td>
</tr>
<tr>
<td>Custom PCB using a bare ESP32 chip</td>
<td>RF matching and antenna network are designed on the PCB</td>
<td>Use controlled-impedance layout and RF validation</td>
</tr>
</tbody>
</table>
<h3><strong>ESP32 Modules with External Antenna Connectors</strong></h3>
<p>Espressif sells several module families in separate PCB-antenna and external-antenna versions. Examples include:</p>
<table>
<thead>
<tr>
<th>PCB Antenna Version</th>
<th>External Antenna Version</th>
</tr>
</thead>
<tbody>
<tr>
<td>ESP32-WROOM-32E</td>
<td>ESP32-WROOM-32UE</td>
</tr>
<tr>
<td>ESP32-S3-WROOM-1</td>
<td>ESP32-S3-WROOM-1U</td>
</tr>
<tr>
<td>ESP32-C3-WROOM-02</td>
<td>ESP32-C3-WROOM-02U</td>
</tr>
</tbody>
</table>
<p>The letter <strong>U</strong> commonly indicates an external-antenna connector in Espressif module names. However, this naming convention should not be assumed for every third-party board. Always verify the full module number printed on the metal shield.</p>
<p>A module such as the ESP32-WROOM-32UE does not contain the familiar meandered PCB antenna. Its RF output is routed directly to the small connector on the module. This is normally the easiest and most reliable option for adding an external antenna.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What Is a U.FL Connector?</strong></h2>
<p><img data-dominant-color="dfdcd3" data-has-transparency="false" style="--dominant-color: #dfdcd3;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12390 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/rf-connector-reference-chart.avif" alt="RF Connector Reference chart" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/rf-connector-reference-chart.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/07/rf-connector-reference-chart-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<p>U.FL is a miniature 50 Ω coaxial connector family made by Hirose. ESP32 sellers sometimes call the same connector an IPEX connector. More precisely, Espressif's first-generation external antenna connector is compatible with Hirose U.FL, I-PEX MHF I, and Amphenol AMC cable plugs.</p>
<p>These connectors are very small and should be handled carefully. The cable plug must be centered directly over the board receptacle and pressed vertically downward. When correctly connected, it should produce a small tactile click.</p>
<p>Do not press the connector at an angle. Doing so can bend the center contact or pull the receptacle away from the PCB.</p>
<p>Also be careful when ordering cables. I-PEX MHF I and MHF 4 are different connector families. An MHF 4 cable is smaller and should not be forced onto a first-generation U.FL or MHF I receptacle.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h3><strong>U.FL-to-SMA Pigtails</strong></h3>
<p>A common arrangement uses a short U.FL-to-SMA coaxial pigtail. The U.FL end connects to the ESP32 module, while the SMA end is mounted through the enclosure. A larger external whip antenna then screws onto the SMA connector.</p>
<p>This arrangement provides two advantages:</p>
<ul>
<li>The fragile U.FL connector remains protected inside the enclosure.</li>
<li>The external antenna can be replaced without repeatedly disconnecting the U.FL plug.</li>
</ul>
<p>Choose the SMA end carefully. SMA and reverse-polarity SMA connectors look similar but have different center contacts. Verify that the panel connector and antenna are compatible before ordering.</p>
<aside class="tmm-product-card tmm-product-card--align-center tmm-product-card--layout-default" style="--tmm-product-card-title-lines:3;--tmm-product-card-desc-lines:5;" aria-label="Product recommendation: 2.4 GHz 3 dBi U.FL-to-SMA Antenna Kit">
							<div class="tmm-product-card__media">
					<img width="150" height="150" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/esp32-antenna-150x150.avif" class="tmm-product-card__image not-transparent wp-post-image" alt="" loading="lazy" decoding="async" data-has-transparency="false" data-dominant-color="eae8e5" style="--dominant-color: #eae8e5;" />				</div>
			
			<div class="tmm-product-card__content">
				<div class="tmm-product-card__title">2.4 GHz 3 dBi U.FL-to-SMA Antenna Kit</div>

									<p class="tmm-product-card__description">An external antenna and U.FL-to-SMA pigtail combination suitable for ESP32 boards with a compatible U.FL/IPEX antenna connector, making it easy to mount the antenna outside an enclosure.</p>
							</div>

							<div class="tmm-product-card__actions">
					<a class="button tmm-product-card__button" href="https://amzn.to/4xf9WsP" target="_blank" rel="noopener" aria-label="Check Price for 2.4 GHz 3 dBi U.FL-to-SMA Antenna Kit">
						Check Price					</a>
				</div>
					</aside>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<p><!-- Suggested image: Close-up diagram comparing U.FL/MHF I, MHF 4, SMA, and RP-SMA connectors. --></p>
<h2><strong>Method 1: Use an ESP32 Module with a Factory U.FL Connector</strong></h2>
<p>The best method is to begin with a board or module designed for an external antenna. Examples include development boards populated with an ESP32-WROOM-32UE, ESP32-S3-WROOM-1U, or ESP32-C3-WROOM-02U.</p>
<h3><strong>Parts Required</strong></h3>
<ul>
<li>ESP32 development board with an external-antenna module</li>
<li>Compatible U.FL or MHF I cable assembly</li>
<li>2.4 GHz, 50 Ω antenna suitable for the module</li>
<li>Optional U.FL-to-SMA bulkhead pigtail</li>
<li>Plastic connector tool or fine nonmetallic tweezers</li>
</ul>
<aside class="tmm-product-card tmm-product-card--align-center tmm-product-card--layout-default" style="--tmm-product-card-title-lines:3;--tmm-product-card-desc-lines:5;" aria-label="Product recommendation: DFRobot FireBeetle 2 ESP32-C5-U">
							<div class="tmm-product-card__media">
					<img width="150" height="150" src="https://www.teachmemicro.com/wp-content/uploads/2026/08/firebeetle-esp32-150x150.avif" class="tmm-product-card__image not-transparent wp-post-image" alt="" loading="lazy" decoding="async" data-has-transparency="false" data-dominant-color="d7d5d2" style="--dominant-color: #d7d5d2;" />				</div>
			
			<div class="tmm-product-card__content">
				<div class="tmm-product-card__title">DFRobot FireBeetle 2 ESP32-C5-U</div>

									<p class="tmm-product-card__description">A compact ESP32 development board with a factory U.FL external antenna connector, dual-band 2.4/5 GHz Wi-Fi 6, Bluetooth LE, Thread and Zigbee support. A good option when you need reliable external-antenna connectivity without modifying the RF section of the board.</p>
							</div>

							<div class="tmm-product-card__actions">
					<a class="button tmm-product-card__button" href="https://www.dfrobot.com/product-3144.html?tracking=UcPQpy" target="_blank" rel="noopener" aria-label="Check Price for DFRobot FireBeetle 2 ESP32-C5-U">
						Check Price					</a>
				</div>
					</aside>
<h3><strong>Connection Procedure</strong></h3>
<ol>
<li>Disconnect USB power and any external power supply.</li>
<li>Confirm the connector type using the module datasheet.</li>
<li>Inspect the U.FL receptacle for contamination or damage.</li>
<li>Align the cable plug directly over the receptacle.</li>
<li>Press downward on the metal connector body rather than on the cable.</li>
<li>Route the cable so that it does not pull sideways on the connector.</li>
<li>Add strain relief to the cable several millimeters away from the receptacle.</li>
<li>Install the antenna before applying power.</li>
</ol>
<p>Do not attach adhesive, epoxy, or hot glue directly over the connector until the connection has been tested. Strain relief should hold the cable to the main PCB without pulling on the RF receptacle.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Method 2: Move the ESP32 Antenna Selection Jumper</strong></h2>
<p>Some development boards contain both a PCB antenna and a U.FL-style connector. Only one path should normally be active. A small zero-ohm resistor or solder bridge connects the ESP32's RF feed to the selected antenna.</p>
<p>This arrangement is particularly common on some ESP32 camera boards and compact IoT development boards.</p>
<p><!-- Suggested image: Enlarged three-pad antenna selector showing center RF feed, PCB antenna route, and U.FL route. --></p>
<h3><strong>How the Three-Pad Selector Works</strong></h3>
<p><img data-dominant-color="759574" data-has-transparency="false" style="--dominant-color: #759574;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12397 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/pcb-antenna-jumper-selection.avif" alt="PCB antenna jumper selection" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/pcb-antenna-jumper-selection.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/07/pcb-antenna-jumper-selection-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<p>A typical selector contains three pads:</p>
<ul>
<li>The center pad is connected to the ESP32 RF output.</li>
<li>One outside pad leads to the built-in PCB antenna.</li>
<li>The other outside pad leads to the U.FL connector.</li>
</ul>
<p>A zero-ohm resistor bridges the center pad to one of the two antenna paths. To select the external antenna, the resistor is removed from the PCB-antenna path and installed between the center pad and the connector path.</p>
<p>The arrangement is not identical on every board. The external path may be above, below, or beside the original jumper. Never assume that rotating the resistor by 90 degrees is correct without tracing the circuit.</p>
<h3><strong>Tools Required</strong></h3>
<ul>
<li>Fine-tip temperature-controlled soldering iron</li>
<li>Fine soldering tweezers</li>
<li>Flux</li>
<li>Solder wick</li>
<li>Magnification</li>
<li>ESD-safe work surface</li>
<li>Multimeter for checking shorts and continuity</li>
</ul>
<h3><strong>Modification Procedure</strong></h3>
<ol>
<li>Remove all power from the board.</li>
<li>Take a clear photograph of the original jumper position.</li>
<li>Identify the radio feed, PCB antenna route, and connector route from the schematic or PCB traces.</li>
<li>Apply a small amount of flux to the zero-ohm resistor.</li>
<li>Heat both ends evenly and lift the component with tweezers.</li>
<li>Clean the pads using solder wick if necessary.</li>
<li>Place the resistor between the RF feed pad and the external-connector pad.</li>
<li>Inspect the joint under magnification.</li>
<li>Check that the PCB antenna path is no longer connected.</li>
<li>Connect the external antenna before powering the ESP32.</li>
</ol>
<p>A solder blob can sometimes be used instead of reinstalling the zero-ohm resistor, but it must not bridge all three pads. Connecting the PCB antenna and external antenna simultaneously creates an uncontrolled RF junction that can cause severe impedance mismatch.</p>
<p>A multimeter can identify an accidental short or open circuit, but it cannot prove that the RF path has a 50 Ω characteristic impedance at 2.4 GHz. Proper RF performance must be evaluated through signal, throughput, or network-analyzer testing.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Method 3: Add a Coaxial Connection to a Board Without U.FL</strong></h2>
<p>This is the most difficult method and should normally be used only for experimentation. If a standard ESP32-WROOM module already contains the PCB antenna, the RF path is part of the module itself. The carrier board does not usually provide a convenient antenna feed that can be modified.</p>
<p>For this type of board, replacing the complete module or development board with an external-antenna version is usually safer than cutting into the module's PCB antenna.</p>
<h3><strong>When a Direct PCB Modification Is Possible</strong></h3>
<p>A modification may be possible when:</p>
<ul>
<li>The RF feed trace is visible and accessible.</li>
<li>The board contains an exposed matching network.</li>
<li>The existing PCB antenna can be disconnected without disturbing the matching components.</li>
<li>A nearby ground point is available for the coaxial shield.</li>
<li>The modification is being performed on a prototype rather than a certified production product.</li>
</ul>
<h3><strong>Why a Loose Wire Is Not Recommended</strong></h3>
<p>A common shortcut is to solder a random wire to the antenna feed. Although the wire may radiate some RF energy, it does not provide a controlled 50 Ω connection. The exposed section of wire, ground geometry, nearby objects, and solder joint all become part of the antenna.</p>
<p>The free-space wavelength at 2.4 GHz is approximately:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_d6d4c8846f3d015b890e99d150ee535a.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\lambda = \frac{c}{f} \approx 125\text{ mm}" /></span><script type='math/tex'>\lambda = \frac{c}{f} \approx 125\text{ mm}</script></p>
<p>A free-space quarter wavelength is therefore approximately:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_d0544a6dc77d49991dc706d41a6ad392.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{\lambda}{4} \approx 31\text{ mm}" /></span><script type='math/tex'>\frac{\lambda}{4} \approx 31\text{ mm}</script></p>
<p>This does not mean that soldering a 31 mm wire to the ESP32 will produce a properly matched antenna. Practical antennas are affected by conductor width, ground plane dimensions, dielectric material, enclosure, loading, and nearby components.</p>
<h3><strong>Recommended Direct-Modification Approach</strong></h3>
<p>When a direct modification is unavoidable, use a short length of 50 Ω micro-coaxial cable rather than an unshielded wire.</p>
<ol>
<li>Locate the antenna feed and matching network.</li>
<li>Determine which side of the series component is connected to the radio.</li>
<li>Remove the jumper or cut the trace leading to the built-in antenna.</li>
<li>Solder the coaxial cable's center conductor to the radio-side RF feed.</li>
<li>Solder the coaxial shield to ground immediately beside the feed point.</li>
<li>Keep the exposed center conductor extremely short.</li>
<li>Secure the cable to the PCB so movement does not pull on the RF pad.</li>
<li>Terminate the other end at a proper U.FL, SMA, or other 50 Ω connector.</li>
</ol>
<p>The shield connection is as important as the center conductor. A long shield lead creates inductance and can make an otherwise short connection behave poorly at 2.4 GHz.</p>
<p>Do not scrape or cut the antenna trace while the board is powered. Avoid excessive heat because small RF pads can separate easily from the PCB.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Designing an External Antenna Connection on a Custom ESP32 PCB</strong></h2>
<p><img data-dominant-color="a1b09f" data-has-transparency="false" style="--dominant-color: #a1b09f;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12396 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/good-vs-poor-rf-layout.avif" alt="good-vs-poor-rf-layout" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/good-vs-poor-rf-layout.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/07/good-vs-poor-rf-layout-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<p>If you are creating a custom ESP32 board, the RF connection should be designed into the PCB rather than added afterward.</p>
<p>The RF trace between the matching network and antenna connector should have a characteristic impedance of approximately 50 Ω. The correct trace width depends on:</p>
<ul>
<li>PCB dielectric thickness</li>
<li>Copper thickness</li>
<li>Dielectric constant</li>
<li>Distance to the reference ground plane</li>
<li>Whether the trace is microstrip or coplanar waveguide</li>
<li>Spacing between the trace and surrounding ground copper</li>
</ul>
<p>Because these values depend on the PCB manufacturer's stack-up, copying the RF trace width from another board does not guarantee the correct impedance.</p>
<h3><strong>RF Layout Guidelines</strong></h3>
<ul>
<li>Keep the RF trace as short as possible.</li>
<li>Do not create branches or stubs in the antenna path.</li>
<li>Keep the trace width consistent.</li>
<li>Avoid routing the RF trace through vias.</li>
<li>Maintain a continuous ground reference beneath the trace.</li>
<li>Use ground vias along the sides of a coplanar RF trace.</li>
<li>Keep crystals, high-speed clocks, USB lines, UART lines, and switching regulators away from the antenna section.</li>
<li>Place the matching network close to the ESP32 RF output or antenna as directed by the reference design.</li>
<li>Keep copper and signal traces away from the connector area where required by the connector footprint.</li>
<li>Include a pi or CLC matching footprint even when the initial design uses zero-ohm or unpopulated components.</li>
</ul>
<p>The matching network gives you a way to compensate for the final PCB, connector, enclosure, and antenna during RF testing. The correct matching values normally require a vector network analyzer or equivalent RF measurement setup.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Choosing the Correct ESP32 External Antenna</strong></h2>
<p>The antenna must match the radio, connector, installation, and certification requirements of the exact ESP32 module.</p>
<h3><strong>Frequency</strong></h3>
<p>Common ESP32, ESP32-C3, and ESP32-S3 modules operate their Wi-Fi and Bluetooth radios in the 2.4 GHz band. A 2.4 GHz Wi-Fi or Wi-Fi/Bluetooth antenna is therefore required for these modules.</p>
<p>Do not select an antenna only because it physically fits the connector. An antenna intended only for GPS, cellular, LoRa, or sub-GHz operation may have very poor performance at 2.4 GHz.</p>
<p>For newer ESP32 variants supporting additional radio bands, use an antenna specified for every band that the design will use.</p>
<h3><strong>Impedance</strong></h3>
<p>The antenna and cable should have a nominal impedance of 50 Ω. This matches the RF system used by the ESP32 module and standard Wi-Fi antenna assemblies.</p>
<h3><strong>Antenna Gain</strong></h3>
<p>Higher gain does not mean that the antenna generates additional power. It concentrates radiation in particular directions while reducing it in others.</p>
<p>For example, a vertical high-gain whip may provide more horizontal coverage but create weaker areas directly above or below the antenna. A low-gain antenna may produce a more useful radiation pattern for a device whose orientation changes.</p>
<p>Certification must also be considered. Some Espressif external-antenna module datasheets specify the antenna used during certification and recommend that replacement antenna gain not exceed that value. The ESP32-WROOM-32UE and ESP32-S3-WROOM-1U documentation, for example, specifies a 2.4 GHz, 50 Ω antenna and lists 2.33 dBi as the certification antenna's maximum gain.</p>
<p>That value should not automatically be applied to every ESP32 module. Check the datasheet and certification documents for your exact part number. Using a different antenna type or higher gain may require additional EMC or regulatory testing.</p>
<h3><strong>External Whip Antenna</strong></h3>
<p>A screw-on whip antenna is useful when the antenna can be mounted outside the enclosure. It is easy to replace and can be oriented after installation.</p>
<h3><strong>Adhesive FPC Antenna</strong></h3>
<p>An adhesive flexible antenna can be installed inside a plastic enclosure. It should be mounted according to the antenna manufacturer's instructions. Some flexible antennas are designed to operate against a specific ground plane, while others require clearance from metal.</p>
<p>Do not fold, cut, or sharply bend the active antenna section. The coaxial cable may usually be routed around the enclosure, but the radiating element should remain in its intended shape.</p>
<h3><strong>PCB Antenna</strong></h3>
<p>A separate PCB antenna can be connected through a coaxial cable and mounted away from the ESP32 board. As with an FPC antenna, the antenna's ground-plane and clearance requirements must be followed.</p>
<h3><strong>Directional Antenna</strong></h3>
<p>A patch, panel, or Yagi-style antenna may be useful for a fixed point-to-point connection. It must be aimed correctly and may not be suitable for devices that move or need coverage in several directions.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32 Antenna Placement</strong></h2>
<p>Antenna placement is often more important than antenna gain. Moving an ordinary antenna away from metal and electrical noise can produce a greater improvement than replacing it with a higher-gain antenna in the same poor location.</p>
<h3><strong>Keep the Antenna Away from Metal</strong></h3>
<p>Metal close to an antenna can block radiation and change its resonant frequency. Avoid placing the antenna directly against:</p>
<ul>
<li>Metal enclosures</li>
<li>Large batteries</li>
<li>Heat sinks</li>
<li>LCD frames</li>
<li>Metal mounting plates</li>
<li>Large connectors</li>
<li>Shielding cans</li>
</ul>
<p>When using a metal enclosure, mount the antenna outside through a bulkhead connector. The coaxial cable can pass through the wall while the antenna remains in free space.</p>
<h3><strong>Keep the Antenna Away from Noise Sources</strong></h3>
<p>Switching regulators, DC motors, relays, high-speed displays, USB circuits, memory buses, and digital clocks can introduce interference. Place the antenna and its cable away from these circuits whenever possible.</p>
<p>Do not route the antenna cable parallel to high-current motor or relay wiring. If the paths must cross, crossing at approximately 90 degrees is generally preferable to running them together.</p>
<h3><strong>Respect the PCB Antenna Keepout Area</strong></h3>
<p>When using an ESP32 module's built-in PCB antenna, place the antenna end at the edge of the carrier PCB. Allowing the antenna to extend beyond the edge is usually the preferred arrangement.</p>
<p>If the antenna cannot extend past the board, there should be no copper, traces, or components under or beside the active antenna region. Espressif recommends providing at least 15 mm of clearance around the PCB antenna inside the finished enclosure.</p>
<p>The exact keepout geometry should come from the hardware design guide for the selected module.</p>
<h3><strong>Consider Polarization</strong></h3>
<p>A straight whip antenna normally has linear polarization. For communication with a typical access point whose antennas are vertical, starting with the ESP32 antenna vertically oriented is reasonable.</p>
<p>Rotating one antenna by 90 degrees relative to the other can reduce the received signal. Reflections inside buildings may reduce or change this effect, so the final orientation should still be tested experimentally.</p>
<h3><strong>Do Not Coil the Cable Around the Antenna</strong></h3>
<p>Extra coaxial cable should be routed away from the radiating element. Do not wrap it tightly around the whip or place a coil directly behind an adhesive antenna. The cable shield and nearby conductive objects can alter the antenna pattern.</p>
<h3><strong>Test the Finished Enclosure</strong></h3>
<p>An antenna that performs well on an open workbench may behave differently after the enclosure, battery, display, and wiring are installed. Always evaluate the complete assembled product.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<p><!-- Suggested image: Good and bad ESP32 antenna placement examples inside plastic and metal enclosures. --></p>
<h2><strong>Testing the ESP32 Antenna Modification</strong></h2>
<p>Test the original antenna before making the modification so that you have a baseline. Use the same ESP32 board, access point, location, power supply, orientation, and firmware for both tests.</p>
<p>Useful measurements include:</p>
<ul>
<li>Average RSSI</li>
<li>Packet loss</li>
<li>Connection and reconnection time</li>
<li>TCP or UDP throughput</li>
<li>Maximum usable distance</li>
<li>Performance through walls</li>
<li>Performance at different antenna orientations</li>
</ul>
<p>RSSI is measured in dBm. Values closer to zero represent a stronger received signal. Because RSSI changes with movement, reflections, and nearby people, compare averages rather than relying on one reading.</p>
<h3><strong>Arduino RSSI Test Sketch</strong></h3>
<p>The following sketch connects to an access point and prints individual RSSI readings followed by their average:</p>
<pre><code>#include &lt;WiFi.h&gt;

const char *ssid = "YOUR_WIFI_SSID";
const char *password = "YOUR_WIFI_PASSWORD";

const int sampleCount = 20;
const unsigned long sampleDelayMs = 500;

void setup() {
  Serial.begin(115200);
  delay(1000);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.print("Connecting");

  unsigned long startTime = millis();

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");

    if (millis() - startTime &gt; 30000) {
      Serial.println("\nConnection timed out.");
      return;
    }
  }

  Serial.println("\nConnected.");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.print("BSSID: ");
  Serial.println(WiFi.BSSIDstr());
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wi-Fi disconnected.");
    delay(2000);
    return;
  }

  long rssiTotal = 0;

  Serial.println("Collecting RSSI samples:");

  for (int i = 0; i &lt; sampleCount; i++) {
    int32_t rssi = WiFi.RSSI();
    rssiTotal += rssi;

    Serial.print("Sample ");
    Serial.print(i + 1);
    Serial.print(": ");
    Serial.print(rssi);
    Serial.println(" dBm");

    delay(sampleDelayMs);
  }

  float averageRssi = (float)rssiTotal / sampleCount;

  Serial.print("Average RSSI: ");
  Serial.print(averageRssi, 1);
  Serial.println(" dBm\n");

  delay(3000);
}</code></pre>
<p>Record several test runs with the original antenna and several more with the external antenna. Do not hold the board or antenna during one test and place it on a table during another. Your hand can affect the antenna and invalidate the comparison.</p>
<h3><strong>Use More Than RSSI</strong></h3>
<p>An improved RSSI reading does not always mean that the entire connection is better. Interference, packet retries, antenna pattern, and access-point behavior can affect actual data transfer.</p>
<p>For a more useful evaluation, transfer a large file or run a local TCP throughput test while monitoring packet loss and disconnections. Repeat the test in the location where the device will actually operate.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Troubleshooting an ESP32 External Antenna</strong></h2>
<h3><strong>The External Antenna Performs Worse</strong></h3>
<p>Check the following:</p>
<ul>
<li>The zero-ohm jumper may still select the PCB antenna.</li>
<li>Both antenna paths may accidentally be connected.</li>
<li>The U.FL plug may not be fully seated.</li>
<li>The antenna may be designed for the wrong frequency.</li>
<li>The antenna may be too close to metal.</li>
<li>The coaxial cable may be damaged or excessively long.</li>
<li>The antenna may have a null in the direction of the access point.</li>
<li>The connector or RF pad may have been damaged during soldering.</li>
</ul>
<h3><strong>Wi-Fi Works Only When the Board Is Close to the Router</strong></h3>
<p>This often indicates an open or badly mismatched antenna path. Inspect the selector resistor and U.FL connection. Confirm that the antenna is connected to the radio side of the matching network rather than to the isolated PCB-antenna side.</p>
<h3><strong>The Signal Changes When the Cable Is Touched</strong></h3>
<p>A large change when touching the cable can indicate that the cable shield is not properly grounded, the connector is loose, or an exposed section of conductor is acting as part of the antenna.</p>
<h3><strong>The U.FL Connector Detached from the PCB</strong></h3>
<p>Do not attempt to glue it back in place and expect the RF path to work. The center signal pad and surrounding ground pads must be electrically restored. If the pads have lifted, repair normally requires microscope-assisted micro-soldering and a careful RF connection.</p>
<h3><strong>The Board Resets While Transmitting</strong></h3>
<p>This problem is more likely related to the power supply than the antenna. Wi-Fi transmission produces short current peaks. Check the 3.3 V regulator, USB cable, supply wiring, and decoupling capacitors.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Frequently Asked Questions</strong></h2>
<h3><strong>Can I connect an antenna directly to an ESP32 GPIO?</strong></h3>
<p>No. The Wi-Fi and Bluetooth antenna uses the ESP32's RF output path, not a general-purpose input/output pin. Connecting an antenna to a GPIO will not improve radio range and may expose that GPIO to unwanted RF signals or static discharge.</p>
<h3><strong>Can I use the PCB antenna and external antenna at the same time?</strong></h3>
<p>Not by simply connecting both paths together. A passive split creates an impedance mismatch and divides transmitted power. A proper diversity or dual-antenna design requires an RF switch, matching network, and support from the selected ESP32 variant and firmware.</p>
<h3><strong>Can I solder an SMA connector directly to the board?</strong></h3>
<p>Only when the board has a correctly designed 50 Ω RF footprint and sufficient mechanical support. A full-size SMA connector is too large to hang from a small antenna feed pad. A short micro-coaxial pigtail connected to a panel-mounted SMA connector is usually safer.</p>
<h3><strong>Will a 9 dBi antenna give three times the ESP32 range?</strong></h3>
<p>Not necessarily. Gain is directional, cable loss reduces the improvement, and the other end of the connection must still receive and return data. Higher gain may also exceed the antenna conditions used for the module's regulatory certification.</p>
<h3><strong>Does the external antenna improve both Wi-Fi and Bluetooth?</strong></h3>
<p>On common ESP32 modules, Wi-Fi and Bluetooth share the 2.4 GHz RF path. A correctly selected external antenna can therefore affect both. The exact internal radio arrangement should still be confirmed in the datasheet for the selected ESP32 variant.</p>
<h3><strong>Can I operate an external-antenna ESP32 without an antenna?</strong></h3>
<p>Avoid intentionally transmitting for extended periods without an antenna. An open connector produces a severe impedance mismatch, greatly reduces communication performance, and may stress the RF output stage.</p>
<h3><strong>Is firmware configuration required after moving the antenna jumper?</strong></h3>
<p>Normally, no. A passive zero-ohm antenna selector changes the physical RF path and is not controlled by software. Boards using an electronic RF switch or antenna-diversity circuit may require GPIO or ESP-IDF configuration.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Summary</strong></h2>
<p>The safest way of adding an external antenna to an ESP32 is to use a module designed for it, such as an ESP32-WROOM-32UE or ESP32-S3-WROOM-1U. The factory connector preserves the module's controlled RF path and avoids cutting the built-in PCB antenna.</p>
<p>For boards containing both a PCB antenna and a U.FL connector, locate the antenna selector and move its zero-ohm jumper to the external path. Do not leave both antenna paths connected.</p>
<p>Directly modifying a PCB-antenna module is possible in some cases, but it requires isolating the existing antenna and attaching a properly grounded 50 Ω micro-coaxial cable. A loose wire is not a reliable substitute for a matched antenna connection.</p>
<p>Finally, pay close attention to placement. Keep the antenna away from metal, high-speed circuits, batteries, displays, and noisy wiring. Test the complete device in its final enclosure using RSSI, packet loss, and actual throughput rather than assuming that a larger antenna will automatically provide better range.</p>
<p>The post <a href="https://www.teachmemicro.com/adding-antenna-to-esp32/">Adding an External Antenna to ESP32: U.FL, PCB Modifications, and Placement</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32-S3 Analog Input Leakage Current: High-Impedance ADC Design</title>
		<link>https://www.teachmemicro.com/esp32-s3-analog-input-leakage-current/</link>
					<comments>https://www.teachmemicro.com/esp32-s3-analog-input-leakage-current/#respond</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Tue, 28 Jul 2026 03:13:06 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12350</guid>

					<description><![CDATA[<p>The ESP32-S3 analog-to-digital converter works well with low-impedance voltage sources. However, problems can appear when the analog signal comes from a high-value resistor divider, a resistive sensor, or another circuit that cannot supply much current. You may notice that the measured voltage is lower than expected, the first reading is different from the following readings, &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-s3-analog-input-leakage-current/">ESP32-S3 Analog Input Leakage Current: High-Impedance ADC Design</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The ESP32-S3 analog-to-digital converter works well with low-impedance voltage sources. However, problems can appear when the analog signal comes from a high-value resistor divider, a resistive sensor, or another circuit that cannot supply much current.</p>
<p>You may notice that the measured voltage is lower than expected, the first reading is different from the following readings, or one ADC channel appears to affect another. These symptoms are often blamed on <strong>analog input leakage current</strong>. Leakage is part of the problem, but the ESP32-S3's switched-capacitor ADC input also creates a temporary load whenever a conversion starts.</p>
<p>In this article, we will examine how ESP32-S3 analog input leakage affects high-impedance circuits and how to design an ADC input that produces stable and repeatable readings.</p>
<p><span id="more-12350"></span></p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>How the ESP32-S3 ADC Input Works</strong></h2>
<p>The ESP32-S3 contains two 12-bit successive-approximation ADC units. Together, they provide 20 analog input channels:</p>
<table>
<thead>
<tr>
<th>ADC Unit</th>
<th>Channels</th>
<th>GPIO Pins</th>
</tr>
</thead>
<tbody>
<tr>
<td>ADC1</td>
<td>ADC1_CH0 to ADC1_CH9</td>
<td>GPIO1 to GPIO10</td>
</tr>
<tr>
<td>ADC2</td>
<td>ADC2_CH0 to ADC2_CH9</td>
<td>GPIO11 to GPIO20</td>
</tr>
</tbody>
</table>
<p>For most projects, ADC1 is the better choice. Espressif recommends ADC1, and ADC2 analog functions cannot be used normally while Wi-Fi is using the ADC2 peripheral.</p>
<p>A 12-bit conversion produces values from 0 to 4095. However, the raw result is not automatically equal to an exact voltage because the internal reference voltage varies from one chip to another. The ESP32-S3 reference is designed around 1.1 V, but its actual value can vary approximately from 1.0 V to 1.2 V. For this reason, calibrated voltage functions should be used whenever possible.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What Is Analog Input Leakage Current?</strong></h2>
<p>An ideal ADC input would have infinite resistance and draw no current from the measured circuit. A real microcontroller pin contains protection structures, switches, multiplexers, transistors, parasitic capacitance, and internal analog circuitry. Small currents can therefore flow into or out of the pin.</p>
<p>When the source resistance is low, this current produces almost no visible error. When the source resistance is hundreds of kilohms or several megohms, even a tiny current can create a measurable voltage drop.</p>
<p>The approximate DC error caused by leakage is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_06ca51353687d5f7e2e937cd03c1a494.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt=" V_{error}=I_{leak}\times R_{source} " /></span><script type='math/tex'> V_{error}=I_{leak}\times R_{source} </script></p>
<p>For example, suppose an analog source has an equivalent resistance of 200 kΩ. The resulting errors would be:</p>
<table>
<thead>
<tr>
<th>Assumed Leakage Current</th>
<th>Voltage Error with 200 kΩ Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>10 nA</td>
<td>2 mV</td>
</tr>
<tr>
<td>50 nA</td>
<td>10 mV</td>
</tr>
<tr>
<td>100 nA</td>
<td>20 mV</td>
</tr>
<tr>
<td>1 µA</td>
<td>200 mV</td>
</tr>
</tbody>
</table>
<p>The ESP32-S3 datasheet specifies a maximum high-level and low-level digital GPIO input current of 50 nA under its stated DC test conditions. However, this value should <strong>not</strong> be treated as a guaranteed ADC input leakage specification. The datasheet does not provide a separate worst-case analog leakage value covering ADC conversions, attenuation settings, temperature, board contamination, and all operating modes.</p>
<p>For a high-impedance design, it is safer to consider the 50 nA figure only as a pin-level reference. The complete ADC circuit should be tested across temperature and operating conditions, or isolated from the signal source using an analog buffer.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>The ADC Is a Dynamic Load</strong></h2>
<p><img data-dominant-color="edeef0" data-has-transparency="false" style="--dominant-color: #edeef0;" loading="lazy" decoding="async" class="aligncenter wp-image-12365 size-full not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/impedance-variation.avif" alt="Source impedance variation" width="718" height="235" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/impedance-variation.avif 718w, https://www.teachmemicro.com/wp-content/uploads/2026/07/impedance-variation-300x98.avif 300w" sizes="auto, (max-width: 718px) 100vw, 718px" /></p>
<p>Leakage current explains steady DC error, but it does not explain every problem seen with high-impedance inputs. The ESP32-S3 uses a successive-approximation ADC, which includes an internal sampling network.</p>
<p>At the beginning of a conversion, an internal switch briefly connects the selected GPIO to a sampling capacitor. The input source must provide enough charge for this capacitor to approach the input voltage during the available acquisition period.</p>
<p>A simplified settling relationship is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_57871c5086b6249b2b61e5ea5d7553f0.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt=" V_{error}=V_{step}e^{-\frac{t_{acq}}{R_{source}C_{sample}}} " /></span><script type='math/tex'> V_{error}=V_{step}e^{-\frac{t_{acq}}{R_{source}C_{sample}}} </script></p>
<p>Here, <em>Rsource</em> is the source resistance, <em>Csample</em> is the effective internal sampling capacitance, and <em>tacq</em> is the acquisition time.</p>
<p>As the source resistance increases, the capacitor takes longer to charge. If the ADC starts its conversion before the voltage settles, the result can be lower or higher than the actual signal. This effect may appear even when the static leakage current is extremely small.</p>
<p>The internal attenuation network also changes the signal path. Consequently, source loading and conversion error may vary with the selected attenuation setting.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Why the First ADC Reading Can Be Wrong</strong></h2>
<p>The ADC input multiplexer connects several analog channels to the same converter. When software changes from one channel to another, the sampling network can retain a small amount of charge from the previous channel.</p>
<p>A low-impedance source quickly replaces this charge. A high-impedance source may require more time. The first reading can therefore be influenced by:</p>
<ul>
<li>The voltage previously measured on another ADC channel</li>
<li>Residual charge in the sampling network</li>
<li>The selected attenuation setting</li>
<li>The external filter capacitor</li>
<li>The time between channel selection and conversion</li>
</ul>
<p>A common software solution is to perform one dummy conversion after changing channels and discard its result. This helps, but it does not replace proper analog input design.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>High-Value Resistor Divider Example</strong></h2>
<p>Consider a circuit that measures a supply voltage of up to 15 V. To minimize battery drain, we use a 1 MΩ upper resistor and a 220 kΩ lower resistor.</p>
<p>The voltage presented to the ESP32-S3 is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_781a090fa519aa3a6b619eadb7a9f4e4.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{ADC}=V_{IN}\frac{R_{BOTTOM}}{R_{TOP}+R_{BOTTOM}}" /></span><script type='math/tex'>V_{ADC}=V_{IN}\frac{R_{BOTTOM}}{R_{TOP}+R_{BOTTOM}}</script></p>
<p>At 15 V:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_b42fce7284f9fb9a7c588fda9302878c.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{ADC}=15\frac{220000}{1000000+220000}=2.705\text{ V}" /></span><script type='math/tex'>V_{ADC}=15\frac{220000}{1000000+220000}=2.705\text{ V}</script></p>
<p>This keeps the input below the ESP32-S3 datasheet's 2.9 V effective calibrated range for the highest attenuation setting.</p>
<p>The divider current at 15 V is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_3bad6b6c6d698ebaf0deeb2c1e473624.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{DIV}=\frac{15}{1000000+220000}=12.3\mu\text{A}" /></span><script type='math/tex'>I_{DIV}=\frac{15}{1000000+220000}=12.3\mu\text{A}</script></p>
<p>The ADC does not see 1.22 MΩ as its source resistance. The Thevenin resistance at the divider output is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_add2bb1513c56f52f309512b1f7d9408.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="R_{TH}=R_{TOP}\parallel R_{BOTTOM}" /></span><script type='math/tex'>R_{TH}=R_{TOP}\parallel R_{BOTTOM}</script></p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_01bd6c320f788e257b00ef2f005be99b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="R_{TH}=\frac{1000000\times220000}{1000000+220000}=180.3\text{ k}\Omega" /></span><script type='math/tex'>R_{TH}=\frac{1000000\times220000}{1000000+220000}=180.3\text{ k}\Omega</script></p>
<p>This is still a relatively high source impedance. An assumed leakage current of 100 nA would produce approximately:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_5b0a0eb47806ec13eae54dde4dce27fd.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{error}=100\text{ nA}\times180.3\text{ k}\Omega=18.0\text{ mV}" /></span><script type='math/tex'>V_{error}=100\text{ nA}\times180.3\text{ k}\Omega=18.0\text{ mV}</script></p>
<p>At the original 15 V input, the equivalent error is multiplied by the divider ratio:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_2ac995f837aa778b04a40ae0f88177f6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{IN_error}=18.0\text{ mV}\times\frac{1220000}{220000}\approx100\text{ mV}" /></span><script type='math/tex'>V_{IN_error}=18.0\text{ mV}\times\frac{1220000}{220000}\approx100\text{ mV}</script></p>
<p>This calculation only estimates static leakage error. Sampling transients, resistor tolerance, ADC error, noise, temperature, and PCB leakage can add further error.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Adding a Capacitor to the ADC Input</strong></h2>
<p>Espressif recommends placing a 0.1 µF capacitor between the ADC pin and ground. The capacitor performs two useful functions:</p>
<ul>
<li>It filters high-frequency noise before it reaches the ADC.</li>
<li>It acts as a local charge reservoir for the ADC sampling capacitor.</li>
</ul>
<p><img data-dominant-color="f6f6f7" data-has-transparency="false" style="--dominant-color: #f6f6f7;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12364 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-s3-adc-circuit.avif" alt="ESP32-S3 ADC Added capacitor" width="724" height="543" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-s3-adc-circuit.avif 724w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-s3-adc-circuit-300x225.avif 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></p>
<p>For the 1 MΩ and 220 kΩ divider, the approximate time constant with a 0.1 µF capacitor is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_fc9f92edb00764728e1996ea4fce8204.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\tau=R_{TH}C" /></span><script type='math/tex'>\tau=R_{TH}C</script></p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_18a3fdec57ae339d54c9785dd5cbc5a7.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\tau=180.3\text{ k}\Omega\times0.1\mu\text{F}=18.0\text{ ms}" /></span><script type='math/tex'>\tau=180.3\text{ k}\Omega\times0.1\mu\text{F}=18.0\text{ ms}</script></p>
<p>A capacitor is normally considered nearly settled after about five time constants:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_f08e5213fb1b9dd9e33eb4c4a1136fad.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="t_{settle}\approx5\tau=90\text{ ms}" /></span><script type='math/tex'>t_{settle}\approx5\tau=90\text{ ms}</script></p>
<p>If the divider is permanently connected, the capacitor remains charged and this delay is not usually needed before every measurement. If the divider is switched on only when a reading is required, the firmware should wait approximately 90 to 100 ms before sampling.</p>
<p>The capacitor and divider also create a low-pass filter. Its approximate cutoff frequency is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_7b1eed22ba7d7c6e86854fb49f3183a8.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="f_c=\frac{1}{2\pi R_{TH}C}" /></span><script type='math/tex'>f_c=\frac{1}{2\pi R_{TH}C}</script></p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_dd474d35e45eb768446289d4f8b57329.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="f_c=\frac{1}{2\pi(180.3\text{k}\Omega)(0.1\mu\text{F})}\approx8.8\text{ Hz}" /></span><script type='math/tex'>f_c=\frac{1}{2\pi(180.3\text{k}\Omega)(0.1\mu\text{F})}\approx8.8\text{ Hz}</script></p>
<p>This is suitable for battery voltage, temperature, and other slowly changing signals. It may be too slow for audio, vibration, or fast control signals.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Method 1: Reduce the Divider Resistance</strong></h2>
<p>The simplest way to reduce loading error is to use lower resistor values. A 100 kΩ and 22 kΩ divider has the same ratio as the 1 MΩ and 220 kΩ divider, but its Thevenin resistance is only about 18 kΩ.</p>
<table>
<thead>
<tr>
<th>Divider</th>
<th>Current at 15 V</th>
<th>Thevenin Resistance</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 MΩ and 220 kΩ</td>
<td>12.3 µA</td>
<td>180.3 kΩ</td>
</tr>
<tr>
<td>100 kΩ and 22 kΩ</td>
<td>123 µA</td>
<td>18.0 kΩ</td>
</tr>
<tr>
<td>47 kΩ and 10 kΩ</td>
<td>263 µA</td>
<td>8.25 kΩ</td>
</tr>
</tbody>
</table>
<p>The lower-value divider consumes more current, but it is less affected by leakage, PCB contamination, and ADC sampling transients.</p>
<p>For mains-powered equipment, the additional current may not matter. For a battery-powered sensor that sleeps most of the time, a switched divider may provide a better compromise.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Method 2: Use a Switched Voltage Divider</strong></h2>
<p>A switched divider keeps the resistors disconnected while the ESP32-S3 is sleeping. The firmware enables the divider shortly before taking a measurement and disables it afterward.</p>
<p>A high-side P-channel MOSFET or a low-leakage analog load switch can be used to connect the upper resistor to the measured supply. After enabling the circuit, wait for the divider and filter capacitor to settle.</p>
<p>The switch itself must also be selected carefully. MOSFET off-state leakage, gate leakage, and contamination around the ADC node may become significant when using megohm resistors.</p>
<p>A low-side switch should generally be avoided for this application because it can leave the ADC pin connected to the measured voltage through the upper resistor while the lower resistor is disconnected. This can make the pin float, forward-bias protection structures, or create an unexpected current path.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Method 3: Buffer the Signal with an Op-Amp</strong></h2>
<p>For very high-impedance sensors, the best solution is usually a voltage follower.</p>
<p>The sensor or resistor network connects to the op-amp input, while the op-amp output drives the ESP32-S3 ADC. The op-amp presents a very high input resistance to the sensor and a low output resistance to the ADC.</p>
<p>Look for the following characteristics:</p>
<ul>
<li>Very low input bias current</li>
<li>Operation from a 3.3 V supply</li>
<li>Rail-to-rail input and output</li>
<li>Input common-mode range that includes the measured signal</li>
<li>Output swing that covers the required ADC voltage range</li>
<li>Low offset voltage and low drift</li>
<li>Stability when driving a capacitive load</li>
</ul>
<p>A small resistor, typically between 100 Ω and 1 kΩ, can be placed between the op-amp output and the ADC capacitor. This resistor isolates the amplifier from the capacitor and can improve stability.</p>
<p>Some sensor types have an impedance so high that they should never be connected directly to a microcontroller ADC. In such cases, an amplifier designed for extremely low input bias current is required.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Method 4: Improve PCB Layout and Cleanliness</strong></h2>
<p>At megohm impedance levels, the PCB becomes part of the analog circuit. Flux residue, dust, moisture, solder mask contamination, and fingerprints can create leakage paths comparable to the signal current.</p>
<p>Use these layout practices:</p>
<ul>
<li>Keep the high-impedance trace short.</li>
<li>Place the filter capacitor close to the ESP32-S3 pin.</li>
<li>Keep the trace away from switching regulators, clocks, USB, and antenna circuitry.</li>
<li>Avoid routing digital signals parallel to the ADC trace.</li>
<li>Clean flux residue from the board.</li>
<li>Use a ground plane around ordinary low-level analog traces.</li>
<li>For extremely high impedance, consider a driven guard around the sensitive node.</li>
</ul>
<p>Also make sure that internal pull-up and pull-down resistors are disabled on the ADC pin. These resistors are approximately tens of kilohms and will completely disturb a high-value divider.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Choosing the ADC Attenuation</strong></h2>
<p>The ESP32-S3 ADC supports several attenuation settings. Higher attenuation permits a larger voltage at the pin but usually produces more conversion error near the upper end of the range.</p>
<table>
<thead>
<tr>
<th>Arduino Setting</th>
<th>Approximate ESP32-S3 Range</th>
<th>Datasheet Effective Calibrated Range</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>ADC_ATTEN_DB_0</em></td>
<td>Up to approximately 0.95 V</td>
<td>0 to 0.85 V</td>
</tr>
<tr>
<td><em>ADC_ATTEN_DB_2_5</em></td>
<td>Up to approximately 1.25 V</td>
<td>0 to 1.10 V</td>
</tr>
<tr>
<td><em>ADC_ATTEN_DB_6</em></td>
<td>Up to approximately 1.75 V</td>
<td>0 to 1.60 V</td>
</tr>
<tr>
<td><em>ADC_ATTEN_DB_11</em></td>
<td>Up to approximately 3.10 V</td>
<td>0 to 2.90 V</td>
</tr>
</tbody>
</table>
<p>The Arduino API continues to use the name <em>ADC_ATTEN_DB_11</em>, while newer ESP-IDF documentation may describe the highest attenuation as 12 dB.</p>
<p>For best accuracy, do not design the divider so that the maximum expected voltage is exactly at the upper ADC limit. Leave margin for supply variation, resistor tolerance, transients, and calibration error.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Arduino ESP32-S3 ADC Example</strong></h2>
<p>The following sketch reads a high-value 1 MΩ and 220 kΩ divider connected to GPIO4. GPIO4 is an ADC1 pin on the ESP32-S3.</p>
<p>The circuit should include a 0.1 µF ceramic capacitor from GPIO4 to ground.</p>
<pre><code>#include &lt;Arduino.h&gt;

const uint8_t ADC_PIN = 4;

const float R_TOP = 1000000.0f;
const float R_BOTTOM = 220000.0f;

const uint8_t SAMPLE_COUNT = 32;

uint32_t readAdcMillivolts()
{
    uint64_t total = 0;

    // Dummy conversion to help the ADC input settle.
    (void)analogRead(ADC_PIN);
    delayMicroseconds(500);

    for (uint8_t i = 0; i &lt; SAMPLE_COUNT; i++)
    {
        total += analogReadMilliVolts(ADC_PIN);
        delayMicroseconds(500);
    }

    return (uint32_t)(total / SAMPLE_COUNT);
}

float readInputVoltage()
{
    const uint32_t adcMillivolts = readAdcMillivolts();
    const float adcVoltage = adcMillivolts / 1000.0f;

    return adcVoltage * (R_TOP + R_BOTTOM) / R_BOTTOM;
}

void setup()
{
    Serial.begin(115200);

    analogReadResolution(12);
    analogSetPinAttenuation(ADC_PIN, ADC_ATTEN_DB_11);

    delay(100);
}

void loop()
{
    const uint32_t adcMillivolts = readAdcMillivolts();
    const float inputVoltage =
        (adcMillivolts / 1000.0f) *
        (R_TOP + R_BOTTOM) / R_BOTTOM;

    Serial.printf(
        "ADC: %lu mV, Input: %.3f V\n",
        (unsigned long)adcMillivolts,
        inputVoltage
    );

    delay(1000);
}</code></pre>
<p>The <em>analogReadMilliVolts()</em> function returns a calibrated voltage rather than an uncorrected raw ADC count. Averaging reduces random noise, while the dummy conversion helps after the input multiplexer or attenuation circuitry has changed state.</p>
<p>The code does not compensate for resistor tolerance, leakage, PCB contamination, or gain and offset error in the complete circuit. Final calibration should be performed using a trusted multimeter or voltage reference.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Two-Point Calibration</strong></h2>
<p>For better accuracy, apply two known input voltages and record the corresponding ESP32-S3 readings. The corrected voltage can then be represented as:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_49285d1232c2a11d26264dee8f43deaa.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{corrected}=mV_{measured}+b" /></span><script type='math/tex'>V_{corrected}=mV_{measured}+b</script></p>
<p>The gain is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_12a6f19256e56bf72976d94897ee7693.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="m=\frac{V_{actual2}-V_{actual1}}{V_{measured2}-V_{measured1}}" /></span><script type='math/tex'>m=\frac{V_{actual2}-V_{actual1}}{V_{measured2}-V_{measured1}}</script></p>
<p>The offset is:</p>
<p><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_486d713efdead5e330ce9b674e16985b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b=V_{actual1}-mV_{measured1}" /></span><script type='math/tex'>b=V_{actual1}-mV_{measured1}</script></p>
<p>Store the resulting gain and offset in flash or non-volatile storage. This calibration corrects consistent gain and offset errors, but it cannot fully correct unstable leakage, insufficient settling time, or temperature-dependent errors.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Sampling High-Impedance ADC Channels</strong></h2>
<p>Use the following sampling sequence when reading a high-impedance source:</p>
<ol>
<li>Enable the divider or sensor power, when applicable.</li>
<li>Wait for the external RC network to settle.</li>
<li>Select the ADC channel and attenuation.</li>
<li>Perform one dummy conversion.</li>
<li>Take multiple calibrated readings.</li>
<li>Average or median-filter the samples.</li>
<li>Disable the measurement circuit when finished.</li>
</ol>
<p>Do not sample faster than the source and filter network can settle. Increasing the sample rate does not improve a circuit whose source cannot recharge the ADC input between conversions.</p>
<p>If several ADC channels have very different voltages, consider reading each channel twice and discarding the first conversion. A buffer amplifier for each high-impedance channel provides a more reliable solution.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Wi-Fi and ADC Noise</strong></h2>
<p>ADC1 can be used while Wi-Fi is active, but wireless transmission causes rapidly changing current consumption. These current pulses can introduce noise into the power and ground networks.</p>
<p>For precision measurements:</p>
<ul>
<li>Use ADC1 instead of ADC2.</li>
<li>Add proper supply decoupling near the ESP32-S3.</li>
<li>Place the ADC capacitor close to the pin.</li>
<li>Avoid taking critical readings during Wi-Fi transmission.</li>
<li>Average several readings.</li>
<li>Consider temporarily stopping wireless activity during calibration or precision sampling.</li>
</ul>
<p>The ESP32-S3 datasheet's ADC characterization was performed with a 100 nF capacitor, a DC input signal, an ambient temperature of 25 °C, and Wi-Fi disabled. A real application may therefore show more noise than the published test results.</p>
<p><strong><div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div></strong></p>
<h2><strong>Common ESP32-S3 High-Impedance ADC Problems</strong></h2>
<table>
<thead>
<tr>
<th>Symptom</th>
<th>Likely Cause</th>
<th>Recommended Fix</th>
</tr>
</thead>
<tbody>
<tr>
<td>Reading is consistently low</td>
<td>Leakage or insufficient acquisition settling</td>
<td>Lower source resistance, add a capacitor, or use a buffer</td>
</tr>
<tr>
<td>First reading is different</td>
<td>Residual charge from another channel</td>
<td>Discard the first conversion</td>
</tr>
<tr>
<td>Reading changes when touched</td>
<td>Input is floating or extremely high impedance</td>
<td>Add a defined bias path and buffer the signal</td>
</tr>
<tr>
<td>Channels affect each other</td>
<td>Multiplexer charge and insufficient settling</td>
<td>Slow the sampling sequence or buffer each channel</td>
</tr>
<tr>
<td>Voltage changes in humid conditions</td>
<td>PCB surface leakage</td>
<td>Clean the board and improve guarding</td>
</tr>
<tr>
<td>Large spikes during wireless activity</td>
<td>Supply or ground noise</td>
<td>Improve decoupling, layout, and sampling timing</td>
</tr>
<tr>
<td>Upper voltage range is inaccurate</td>
<td>Operating near the attenuation limit</td>
<td>Change the divider ratio and add voltage margin</td>
</tr>
</tbody>
</table>
<h2>ESP32-S3 High-Impedance ADC Design Checklist</h2>
<ul>
<li>Prefer GPIO1 to GPIO10 on ADC1.</li>
<li>Keep the maximum ADC voltage below the calibrated effective range.</li>
<li>Add approximately 0.1 µF between the ADC pin and ground.</li>
<li>Calculate the divider's Thevenin resistance.</li>
<li>Estimate leakage error using the required voltage accuracy.</li>
<li>Allow at least five external RC time constants after switching the circuit on.</li>
<li>Discard the first reading after changing channels.</li>
<li>Average multiple calibrated readings.</li>
<li>Disable internal pull-up and pull-down resistors.</li>
<li>Keep the ADC trace short and away from noisy signals.</li>
<li>Clean the PCB when using megohm impedances.</li>
<li>Use an op-amp buffer when the sensor impedance is very high.</li>
<li>Calibrate the complete circuit, not only the ADC.</li>
</ul>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Conclusion</strong></h2>
<p>The ESP32-S3 ADC input should not be treated as an ideal infinite-resistance voltmeter. Static leakage current can create voltage error when the source impedance is high, while the ADC's internal sampling network can temporarily load the signal during each conversion.</p>
<p>A 0.1 µF capacitor at the ADC pin is an important starting point and is recommended by Espressif. However, the capacitor must be combined with adequate settling time, suitable divider values, ADC1 channel selection, averaging, careful PCB layout, and calibration.</p>
<p>For battery monitoring and other slowly changing signals, a high-value divider with a local capacitor may provide acceptable performance. For extremely high-impedance sensors or precision measurements, a low-bias-current op-amp buffer is the more reliable solution.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>References</strong></h2>
<ul>
<li><a href="https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf">Espressif ESP32-S3 Series Datasheet</a></li>
<li><a href="https://docs.espressif.com/projects/esp-hardware-design-guidelines/en/latest/esp32s3/">ESP32-S3 Hardware Design Guidelines</a></li>
<li><a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/api/adc.html">Arduino-ESP32 ADC API</a></li>
<li><a href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/adc/adc_calibration.html">ESP32-S3 ADC Calibration Driver</a></li>
</ul>
<p>The post <a href="https://www.teachmemicro.com/esp32-s3-analog-input-leakage-current/">ESP32-S3 Analog Input Leakage Current: High-Impedance ADC Design</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/esp32-s3-analog-input-leakage-current/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Power an ESP32-S3 with AA Batteries</title>
		<link>https://www.teachmemicro.com/how-to-power-an-esp32-s3-with-aa-batteries/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Tue, 21 Jul 2026 00:36:29 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12295</guid>

					<description><![CDATA[<p>The ESP32-S3 is commonly powered through its USB port while programming and testing. However, USB power is not always practical for projects installed outdoors, mounted on walls, or placed far from an electrical outlet. In this tutorial, we will build an ESP32-S3 AA battery power supply using two AA cells and an MT3608 boost converter. &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/how-to-power-an-esp32-s3-with-aa-batteries/">How to Power an ESP32-S3 with AA Batteries</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The ESP32-S3 is commonly powered through its USB port while programming and testing. However, USB power is not always practical for projects installed outdoors, mounted on walls, or placed far from an electrical outlet.</p>
<p>In this tutorial, we will build an <strong>ESP32-S3 AA battery power supply</strong> using two AA cells and an MT3608 boost converter. We will also add an optional battery-voltage monitor and use deep sleep to make the batteries last longer.</p>
<p><span id="more-12295"></span></p>
<p>The short answer is that an ESP32-S3 can run from AA batteries, but the batteries should not normally be connected directly to the development board. The voltage must remain stable, and the power circuit must handle the short current bursts produced when the ESP32-S3 uses Wi-Fi or Bluetooth.</p>
<blockquote><p>This tutorial assumes an ESP32-S3 development board similar to the Espressif ESP32-S3-DevKitC-1. Other ESP32-S3 boards may have different regulators, power LEDs, USB circuits, pin labels, and power-input arrangements. Check your board’s schematic before applying power through its 3V3 pin.</p></blockquote>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Can an ESP32-S3 Run on AA Batteries?</strong></h2>
<p>Yes. Two AA batteries can power an ESP32-S3 when used with a suitable voltage converter. The ESP32-S3 chip normally operates from a 3.3 V supply. Its acceptable supply range is approximately 3.0 V to 3.6 V. The power source must also handle the ESP32-S3’s brief current peaks when its radio begins transmitting.</p>
<p>A pair of alkaline AA batteries has a nominal voltage of:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_5e1a9e3affa6368dbf38f3a867844cfd.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="2 \times 1.5\text{ V} = 3.0\text{ V}" /></span><script type='math/tex'>2 \times 1.5\text{ V} = 3.0\text{ V}</script></p>
<p>At first glance, 3.0 V may appear close enough to the ESP32-S3’s operating voltage. The problem is that battery voltage does not remain fixed. A fresh alkaline cell may measure above 1.5 V without a load. Its voltage then gradually falls as the battery discharges. The terminal voltage can also drop suddenly when the ESP32-S3 draws a high-current pulse. Directly connecting two AA cells to the 3V3 pin may therefore work initially but become unreliable as the batteries discharge. The ESP32-S3 may reset when Wi-Fi starts, fail to boot, or stop operating long before the batteries are completely empty.</p>
<p>To avoid this problem, we will use an <strong>MT3608 boost converter</strong> adjusted to provide a regulated 3.3 V output.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>What Is the MT3608?</strong></h2>
<p>The MT3608 is a small step-up or <strong>boost converter</strong>. A boost converter takes a lower DC voltage and raises it to a higher regulated voltage.</p>
<p>Common MT3608 breakout modules include:</p>
<ul>
<li>An MT3608 switching-regulator IC</li>
<li>An inductor</li>
<li>A Schottky diode</li>
<li>Input and output capacitors</li>
<li>A multi-turn adjustment potentiometer</li>
<li>IN+, IN−, OUT+, and OUT− connection pads</li>
</ul>
<p>The MT3608 IC has an input-voltage range of approximately 2 V to 24 V and an adjustable output. Its switching frequency is 1.2 MHz. For this project, the module raises the changing voltage from two AA cells to a regulated 3.3 V:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_a017593452a0a1194a9cc141ebf45f55.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{\text{BATTERY}} \longrightarrow \text{MT3608} \longrightarrow 3.3\text{ V}" /></span><script type='math/tex'>V_{\text{BATTERY}} \longrightarrow \text{MT3608} \longrightarrow 3.3\text{ V}</script></p>
<p>The MT3608 is inexpensive and widely available, which makes it practical for a prototype or hobby project.</p>
<h3><strong>The MT3608 Is Boost-Only</strong></h3>
<p>An important limitation is that the MT3608 can only raise voltage. It cannot reduce a voltage that is higher than the desired output. For example, an MT3608 should not be used to convert a three-cell alkaline battery pack from approximately 4.5 V down to 3.3 V. That would require a buck converter or buck-boost converter instead. Two alkaline or two NiMH AA cells remain below the desired 3.3 V output during normal use, so they are suitable for this circuit.</p>
<h3><strong>MT3608 Current Ratings</strong></h3>
<p>Many online listings describe an MT3608 module as a “2 A boost converter.” This does not necessarily mean that the module can continuously supply 2 A at its output under all conditions.</p>
<p>The available output current depends on:</p>
<ul>
<li>Input voltage</li>
<li>Output voltage</li>
<li>Converter efficiency</li>
<li>Inductor rating</li>
<li>Diode rating</li>
<li>PCB layout</li>
<li>Cooling</li>
<li>Battery condition and internal resistance</li>
</ul>
<p>At a low battery voltage, the converter must draw more current from the batteries than it delivers at its output.</p>
<p>Ignoring converter losses for a moment:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_9c7711005537dd32c6d3a3dc34c612e8.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{\text{IN}}I_{\text{IN}} \approx V_{\text{OUT}}I_{\text{OUT}}" /></span><script type='math/tex'>V_{\text{IN}}I_{\text{IN}} \approx V_{\text{OUT}}I_{\text{OUT}}</script></p>
<p>After including converter efficiency:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_d5cd53bf6b6d6502e7d45a47a78dae4e.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{IN}} = \frac{V_{\text{OUT}}I_{\text{OUT}}}{V_{\text{IN}}\eta}" /></span><script type='math/tex'>I_{\text{IN}} = \frac{V_{\text{OUT}}I_{\text{OUT}}}{V_{\text{IN}}\eta}</script></p>
<p>For example, supplying 500 mA at 3.3 V from a 2.0 V battery pack at 85% efficiency would require approximately:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_2401054c657c8d8638c3d133b2658c46.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{IN}} = \frac{3.3 \times 0.5}{2.0 \times 0.85}" /></span><script type='math/tex'>I_{\text{IN}} = \frac{3.3 \times 0.5}{2.0 \times 0.85}</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_08bbb5dba71e84cc759afcb7a28838c3.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{IN}} \approx 0.97\text{ A}" /></span><script type='math/tex'>I_{\text{IN}} \approx 0.97\text{ A}</script></p>
<p>The ESP32-S3 will not continuously draw 500 mA in a typical sensor project, but the batteries and converter must tolerate its short radio-current peaks.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>AA Battery Configurations for the MT3608</strong></h2>
<p>Here is what happens with common AA battery arrangements:</p>
<table>
<thead>
<tr>
<th>Battery configuration</th>
<th>Approximate nominal voltage</th>
<th>Suitable with MT3608?</th>
</tr>
</thead>
<tbody>
<tr>
<td>One alkaline AA</td>
<td>1.5 V</td>
<td>No; below the MT3608’s specified input range</td>
</tr>
<tr>
<td>Two alkaline AAs</td>
<td>3.0 V</td>
<td>Yes; boost to 3.3 V</td>
</tr>
<tr>
<td>Three alkaline AAs</td>
<td>4.5 V</td>
<td>No; the MT3608 cannot step down to 3.3 V</td>
</tr>
<tr>
<td>Four alkaline AAs</td>
<td>6.0 V</td>
<td>No; use a step-down converter</td>
</tr>
<tr>
<td>Two NiMH AAs</td>
<td>2.4 V</td>
<td>Yes; boost to 3.3 V</td>
</tr>
<tr>
<td>Three NiMH AAs</td>
<td>3.6 V</td>
<td>No; the pack may be above the required output</td>
</tr>
</tbody>
</table>
<p>Two AA cells are therefore the most convenient arrangement for this MT3608 circuit.</p>
<p><img data-dominant-color="d7d6d1" data-has-transparency="false" style="--dominant-color: #d7d6d1;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12303 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-powering-options.avif" alt="ESP32-S3 Powering Options" width="836" height="471" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-powering-options.avif 836w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-powering-options-300x169.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-powering-options-768x433.avif 768w" sizes="auto, (max-width: 836px) 100vw, 836px" /></p>
<p>Because the MT3608 requires approximately 2 V at its input, the converter will eventually stop operating when a two-cell pack falls to about 1 V per cell.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Required Components</strong></h2>
<p>For the basic ESP32-S3 AA battery circuit, you will need:</p>
<ul>
<li>ESP32-S3 development board</li>
<li>MT3608 adjustable boost-converter module</li>
<li>Two-cell AA battery holder</li>
<li>Two matching AA batteries</li>
<li>On/off switch</li>
<li>470 µF electrolytic capacitor rated for at least 6.3 V</li>
<li>0.1 µF ceramic capacitor</li>
<li>Multimeter</li>
<li>Jumper wires or soldered connections</li>
</ul>
<p>For battery-voltage measurement, you will also need:</p>
<ul>
<li>Two 100 kΩ resistors</li>
<li>One optional 0.1 µF capacitor</li>
</ul>
<p>Use batteries of the same type, brand, capacity, and approximate age. Do not mix alkaline batteries with rechargeable batteries in the same holder.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Adjusting the MT3608 to 3.3 V</strong></h2>
<p>The MT3608 is an adjustable converter. It must be configured before it is connected to the ESP32-S3.</p>
<blockquote><p><strong>Do not connect the MT3608 output to the ESP32-S3 until you have measured and adjusted its output voltage.</strong> An incorrectly adjusted module can output a voltage high enough to damage the board.</p></blockquote>
<p>Follow these steps:</p>
<ol>
<li>Insert the two AA batteries into the holder.</li>
<li>Connect the battery holder’s positive wire to MT3608 IN+.</li>
<li>Connect the battery holder’s negative wire to MT3608 IN−.</li>
<li>Set your multimeter to DC voltage.</li>
<li>Measure between MT3608 OUT+ and OUT−.</li>
<li>Turn the adjustment potentiometer slowly while watching the multimeter.</li>
<li>Stop when the output reads approximately 3.30 V.</li>
<li>Disconnect the batteries before wiring the ESP32-S3.</li>
</ol>
<p>The potentiometer on many MT3608 modules is multi-turn. It may require several rotations before the output voltage visibly changes. Do not assume that every module adjusts in the same direction. Watch the multimeter while turning the potentiometer.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 AA Battery Wiring Diagram</strong></h2>
<p>After adjusting the MT3608 to 3.3 V, connect the complete circuit as follows:<br />
<img data-dominant-color="d5d2d1" data-has-transparency="false" style="--dominant-color: #d5d2d1;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12300 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-circuit.avif" alt="ESP32-S3-AA-battery-circuit" width="849" height="539" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-circuit.avif 849w, https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-circuit-300x190.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-circuit-768x488.avif 768w" sizes="auto, (max-width: 849px) 100vw, 849px" /><br />
Observe the polarity of the electrolytic capacitor:</p>
<ul>
<li>Capacitor positive lead to MT3608 OUT+</li>
<li>Capacitor negative lead to ground</li>
</ul>
<p>The 470 µF capacitor helps supply short bursts of current when the ESP32-S3 radio begins transmitting. The 0.1 µF ceramic capacitor helps suppress higher-frequency noise. Install the capacitors close to the ESP32-S3 power pins rather than close to the battery holder. Long wires add resistance and inductance, reducing the capacitors’ ability to support fast current pulses.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Why We Connect the MT3608 to the 3V3 Pin</strong></h2>
<p>Most ESP32-S3 development boards include an onboard regulator that converts USB or 5 V input to 3.3 V.</p>
<p>One option would be to adjust the MT3608 to 5 V and connect it to the board’s 5V input. However, the power would pass through two conversion stages:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_11baa0169c342cec13b386afdb3ea105.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{AA batteries} \longrightarrow 5\text{ V boost} \longrightarrow 3.3\text{ V regulator}" /></span><script type='math/tex'>\text{AA batteries} \longrightarrow 5\text{ V boost} \longrightarrow 3.3\text{ V regulator}</script></p>
<p>Each conversion stage wastes some energy.</p>
<p>By adjusting the MT3608 to 3.3 V and connecting it directly to the 3V3 pin, we bypass the development board’s onboard regulator:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_1865d1c2872fe8631aeb1f9bd7284218.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{AA batteries} \longrightarrow 3.3\text{ V boost} \longrightarrow \text{ESP32-S3}" /></span><script type='math/tex'>\text{AA batteries} \longrightarrow 3.3\text{ V boost} \longrightarrow \text{ESP32-S3}</script></p>
<p>The disadvantage is that the board no longer has another regulator between the MT3608 and the ESP32-S3. The MT3608 output must therefore be adjusted accurately and checked before every major wiring change.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Important USB Power Warning</strong></h2>
<p>Disconnect the AA battery supply before connecting the ESP32-S3 to USB unless the board or external circuit includes proper power-source isolation.</p>
<p>Connecting USB power and an external 3.3 V supply at the same time may cause current to flow backward into one of the power sources.</p>
<p>A simple approach during development is:</p>
<ol>
<li>Switch off or disconnect the AA battery holder.</li>
<li>Connect USB and upload the sketch.</li>
<li>Disconnect USB.</li>
<li>Reconnect or switch on the battery supply.</li>
</ol>
<p>A more advanced design can use:</p>
<ul>
<li>Schottky-diode isolation</li>
<li>An ideal-diode controller</li>
<li>A load switch</li>
<li>A power multiplexer</li>
<li>A jumper that selects USB or battery power</li>
</ul>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Adding an ESP32-S3 Battery Voltage Monitor</strong></h2>
<p>The ESP32-S3 can measure the battery voltage using one of its ADC pins. The measurement must be taken from the battery side of the MT3608. Measuring the converter output would normally show approximately 3.3 V even as the batteries discharge.</p>
<p>For a two-cell AA pack, use the following voltage divider:<br />
<img data-dominant-color="d5d1cf" data-has-transparency="false" style="--dominant-color: #d5d1cf;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12301 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-level-detection.avif" alt="ESP32 S3 AA battery detection" width="805" height="526" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-level-detection.avif 805w, https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-level-detection-300x196.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/07/ESP32-S3-AA-battery-level-detection-768x502.avif 768w" sizes="auto, (max-width: 805px) 100vw, 805px" /><br />
GPIO4 is an ADC-capable pin on the ESP32-S3 and corresponds to ADC1 channel 3.</p>
<p>The two equal resistors divide the battery voltage by two:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_d0add98ad55c0cdc88048b507a466899.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{\text{ADC}} = V_{\text{BATTERY}} \times \frac{100\,\text{k}\Omega}{100\,\text{k}\Omega + 100\,\text{k}\Omega}" /></span><script type='math/tex'>V_{\text{ADC}} = V_{\text{BATTERY}} \times \frac{100\,\text{k}\Omega}{100\,\text{k}\Omega + 100\,\text{k}\Omega}</script></p>
<p>Therefore:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_d130dfdb8911f0c0c85c0791bdfeae02.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{\text{BATTERY}} = V_{\text{ADC}} \times 2" /></span><script type='math/tex'>V_{\text{BATTERY}} = V_{\text{ADC}} \times 2</script></p>
<p>A fresh two-cell alkaline pack measuring 3.2 V produces approximately:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_ec4685acde79bad4f6c18310f6c88ac9.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{\text{ADC}} = \frac{3.2}{2} = 1.6\text{ V}" /></span><script type='math/tex'>V_{\text{ADC}} = \frac{3.2}{2} = 1.6\text{ V}</script></p>
<p>An optional 0.1 µF capacitor from GPIO4 to ground can reduce noise and help stabilize the ADC reading. This is especially useful because the two 100 kΩ resistors create a relatively high-impedance source for the ADC.</p>
<p>The resistor divider continuously draws a small current:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_43b8c72aa5b0a3b28486faa3fbb85209.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I = \frac{3.0\text{ V}}{200\,\text{k}\Omega}" /></span><script type='math/tex'>I = \frac{3.0\text{ V}}{200\,\text{k}\Omega}</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_600f9c5dd5d57ff227ea07eadc9434ac.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I = 15\,\mu\text{A}" /></span><script type='math/tex'>I = 15\,\mu\text{A}</script></p>
<p>This is small compared with the consumption of a normal ESP32-S3 development board. However, it can become significant in a highly optimized low-power design. On a custom PCB, the voltage divider can be enabled only when a measurement is required by using a MOSFET or analog switch.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>ESP32-S3 AA Battery and Deep-Sleep Code</strong></h2>
<p>The following Arduino sketch reads the AA battery-pack voltage and then places the ESP32-S3 into deep sleep for ten minutes.</p>
<pre><code>#include &lt;Arduino.h&gt;

#define BATTERY_ADC_PIN       4
#define SLEEP_TIME_SECONDS    600

const float R1 = 100000.0;
const float R2 = 100000.0;

float readBatteryVoltage()
{
  const int numberOfSamples = 32;
  uint32_t totalMillivolts = 0;

  for (int i = 0; i &lt; numberOfSamples; i++)
  {
    totalMillivolts += analogReadMilliVolts(BATTERY_ADC_PIN);
    delay(5);
  }

  float adcMillivolts =
      totalMillivolts / (float)numberOfSamples;

  float adcVoltage = adcMillivolts / 1000.0;

  // Reconstruct the original battery voltage.
  float batteryVoltage =
      adcVoltage * ((R1 + R2) / R2);

  return batteryVoltage;
}

void setup()
{
  Serial.begin(115200);
  delay(1000);

  analogReadResolution(12);
  analogSetPinAttenuation(BATTERY_ADC_PIN, ADC_11db);

  float batteryVoltage = readBatteryVoltage();

  Serial.print("AA battery pack voltage: ");
  Serial.print(batteryVoltage, 2);
  Serial.println(" V");

  /*
   * Read sensors or transmit data here.
   *
   * Keep this section as short as possible.
   * Wi-Fi, Bluetooth and sensors consume much
   * more current than deep sleep.
   */

  Serial.println("Entering deep sleep...");
  Serial.flush();

  esp_sleep_enable_timer_wakeup(
      (uint64_t)SLEEP_TIME_SECONDS * 1000000ULL
  );

  esp_deep_sleep_start();
}

void loop()
{
  // The ESP32-S3 restarts setup() after waking
  // from deep sleep.
}</code></pre>
<p>The Arduino-ESP32 API provides <em>analogReadMilliVolts()</em>, which returns a calibrated voltage value rather than a raw ADC count.</p>
<p>The 11 dB attenuation setting increases the input range available to the ADC. The divided battery voltage should remain well below the ESP32-S3 ADC pin’s maximum level.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>How the Deep-Sleep Code Works</strong></h2>
<p>The ESP32-S3 executes <em>setup()</em> after power-up and after every deep-sleep wake-up.</p>
<p><img data-dominant-color="eff1f2" data-has-transparency="false" style="--dominant-color: #eff1f2;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12302 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-power-timeline.avif" alt="" width="836" height="471" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-power-timeline.avif 836w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-power-timeline-300x169.avif 300w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-power-timeline-768x433.avif 768w" sizes="auto, (max-width: 836px) 100vw, 836px" /></p>
<p>The program performs the following sequence:</p>
<ol>
<li>Configures the ADC.</li>
<li>Reads the AA battery-pack voltage.</li>
<li>Performs the required sensor or communication task.</li>
<li>Configures a ten-minute wake-up timer.</li>
<li>Enters deep sleep.</li>
<li>Restarts when the timer expires.</li>
</ol>
<p>The sleep duration is configured here:</p>
<pre><code>#define SLEEP_TIME_SECONDS 600</code></pre>
<p>For a five-minute interval, change it to:</p>
<pre><code>#define SLEEP_TIME_SECONDS 300</code></pre>
<p>For a one-hour interval:</p>
<pre><code>#define SLEEP_TIME_SECONDS 3600</code></pre>
<p>Deep sleep powers down the ESP32-S3 CPUs and most digital peripherals while retaining selected RTC circuitry. The ESP32-S3 chip itself can reach a deep-sleep current of only a few microamps under datasheet conditions. A complete development board will normally consume more because it may also contain:</p>
<ul>
<li>A voltage regulator</li>
<li>USB-to-UART circuitry</li>
<li>USB interface circuitry</li>
<li>A power indicator LED</li>
<li>An addressable RGB LED</li>
<li>Flash memory</li>
<li>PSRAM</li>
<li>Pull-up resistors</li>
<li>Other support components</li>
</ul>
<p>The MT3608 module also consumes current while operating, even when the ESP32-S3 is asleep.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Is the MT3608 Good for Deep-Sleep Projects?</strong></h2>
<p>The MT3608 is suitable for learning, prototyping, and inexpensive battery-powered projects. However, it is not necessarily the best converter for an ultra-low-power sensor node.</p>
<p>The total sleep current includes:</p>
<ul>
<li>ESP32-S3 development-board sleep current</li>
<li>MT3608 operating current</li>
<li>Any indicator LED on the MT3608 module</li>
<li>Battery-monitor divider current</li>
<li>Sensor standby current</li>
<li>Leakage through connected peripherals</li>
</ul>
<p>Some generic MT3608 modules include an indicator LED that remains on continuously. Even a small LED current can become significant when the ESP32-S3 spends most of its time sleeping. For a project intended to run for many months or years, consider a boost converter designed specifically for low-quiescent-current operation.</p>
<p>The MT3608 remains useful for this tutorial because it is:</p>
<ul>
<li>Inexpensive</li>
<li>Widely available</li>
<li>Easy to adjust</li>
<li>Easy to mount on a breadboard or prototype board</li>
<li>Capable of supplying an ESP32-S3 when properly selected and tested</li>
</ul>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Estimating ESP32-S3 AA Battery Runtime</strong></h2>
<p>Battery runtime depends more on average current than on the highest current peak.</p>
<p>A basic runtime estimate is:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_654b267138c4f0c0834bfd5a80ecf6f1.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{Runtime (hours)} = \frac{\text{Battery capacity (mAh)}}{\text{Average battery current (mA)}}" /></span><script type='math/tex'>\text{Runtime (hours)} = \frac{\text{Battery capacity (mAh)}}{\text{Average battery current (mA)}}</script></p>
<p>Suppose the ESP32-S3:</p>
<ul>
<li>Draws 120 mA while awake</li>
<li>Remains awake for five seconds</li>
<li>Wakes every ten minutes</li>
<li>Draws 0.3 mA from the 3.3 V rail while sleeping</li>
</ul>
<p>Its average current on the regulated 3.3 V rail is approximately:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_d4adf6f552dd7113dd7b70281a1f2c21.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{AVG}} = 120\left(\frac{5}{600}\right) + 0.3\left(\frac{595}{600}\right)" /></span><script type='math/tex'>I_{\text{AVG}} = 120\left(\frac{5}{600}\right) + 0.3\left(\frac{595}{600}\right)</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_90fbb09b1d4daaaa2174040ae0e6aa6e.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{AVG}} \approx 1.30\text{ mA}" /></span><script type='math/tex'>I_{\text{AVG}} \approx 1.30\text{ mA}</script></p>
<p>Assuming an average battery voltage of 2.4 V and an MT3608 efficiency of 85%:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_60ae932dd66e7154db3613aa6164d6d1.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{BATTERY}} = \frac{3.3 \times 1.30}{2.4 \times 0.85}" /></span><script type='math/tex'>I_{\text{BATTERY}} = \frac{3.3 \times 1.30}{2.4 \times 0.85}</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_452da26b987489d60c867e59fa7fa1b5.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{BATTERY}} \approx 2.1\text{ mA}" /></span><script type='math/tex'>I_{\text{BATTERY}} \approx 2.1\text{ mA}</script></p>
<p>Using a conservative usable battery capacity of 2000 mAh:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_c72abbcb6bfa2b7690a9f18b72cfe64f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{Runtime} = \frac{2000}{2.1}" /></span><script type='math/tex'>\text{Runtime} = \frac{2000}{2.1}</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_da97dfea8763830023f188315b1552f3.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{Runtime} \approx 953\text{ hours}" /></span><script type='math/tex'>\text{Runtime} \approx 953\text{ hours}</script></p>
<p>This is approximately 40 days.</p>
<p>However, this simplified calculation does not include the MT3608 module’s own operating current. Suppose the converter module and its indicator LED draw an additional 1 mA from the battery pack:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_52a6d6edcc84af6d56c47c599f8b53ee.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{TOTAL}} = 2.1\text{ mA} + 1.0\text{ mA}" /></span><script type='math/tex'>I_{\text{TOTAL}} = 2.1\text{ mA} + 1.0\text{ mA}</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_a6824aee4a2390796c7a3eb001e2b14a.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="I_{\text{TOTAL}} = 3.1\text{ mA}" /></span><script type='math/tex'>I_{\text{TOTAL}} = 3.1\text{ mA}</script></p>
<p>The estimated runtime would then become:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_e1a451a43fbb361634f6d3a4cff388c4.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{Runtime} = \frac{2000}{3.1}" /></span><script type='math/tex'>\text{Runtime} = \frac{2000}{3.1}</script></p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_7e76d3781b30bc36a3ff78ac59018ba5.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\text{Runtime} \approx 645\text{ hours}" /></span><script type='math/tex'>\text{Runtime} \approx 645\text{ hours}</script></p>
<p>This is approximately 27 days.</p>
<p>This example shows why converter idle current matters in a deep-sleep project.</p>
<p>Actual runtime may be lower because of:</p>
<ul>
<li>MT3608 quiescent and indicator-LED current</li>
<li>Battery internal resistance</li>
<li>Low-temperature operation</li>
<li>Wi-Fi connection time</li>
<li>Sensor consumption</li>
<li>Development-board LEDs</li>
<li>Battery age</li>
<li>Reduced alkaline capacity at higher discharge currents</li>
<li>The MT3608’s approximately 2 V minimum input</li>
<li>Conversion losses that change with load and battery voltage</li>
</ul>
<p>The best approach is to measure the current of the complete circuit using the actual batteries, converter module, sensors, development board, and firmware.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Alkaline or Rechargeable AA Batteries?</strong></h2>
<p>Both alkaline and NiMH AA batteries can be used with the MT3608.</p>
<h3><strong>Alkaline AA Batteries</strong></h3>
<p>Alkaline batteries have a nominal voltage of 1.5 V per cell. Two cells produce a nominal 3.0 V, which the MT3608 can raise to 3.3 V. Alkaline cells are widely available and have a relatively low self-discharge rate. However, their voltage continuously falls during use, and their effective capacity decreases under heavier loads. The high current pulses produced by Wi-Fi may cause a larger temporary voltage drop when alkaline batteries are old, cold, or partially discharged.</p>
<h3><strong>NiMH Rechargeable AA Batteries</strong></h3>
<p>NiMH batteries typically have a nominal voltage of 1.2 V per cell. Two cells therefore provide approximately:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_8601b2b1661b215f75a0dbb2a6a61d3b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="2 \times 1.2\text{ V} = 2.4\text{ V}" /></span><script type='math/tex'>2 \times 1.2\text{ V} = 2.4\text{ V}</script></p>
<p>The MT3608 raises this to 3.3 V. NiMH batteries generally handle repeated high-current pulses better than ordinary alkaline batteries and can be recharged many times. For a frequently used wireless sensor, NiMH cells may be more economical. Low-self-discharge NiMH batteries are especially useful when the device spends long periods asleep.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Improving ESP32-S3 AA Battery Life</strong></h2>
<h3><strong>Use Deep Sleep</strong></h3>
<p>Do not leave the ESP32-S3 running continuously if it only needs to take a measurement every few minutes. Deep sleep normally provides a much larger improvement than simply reducing the CPU frequency while the chip remains awake.</p>
<h3><strong>Keep Wi-Fi Sessions Short</strong></h3>
<p>Connecting to Wi-Fi and transmitting data consume considerably more current than sleeping.</p>
<p>A battery-powered application should normally:</p>
<ol>
<li>Wake up.</li>
<li>Read its sensors.</li>
<li>Connect to the network.</li>
<li>Transmit its data.</li>
<li>Disconnect or shut down the radio.</li>
<li>Return to deep sleep.</li>
</ol>
<h3><strong>Remove or Disable Power LEDs</strong></h3>
<p>A power LED drawing even 1 mA becomes significant when the ESP32-S3 spends most of its time in deep sleep. Inspect both the ESP32-S3 board and the MT3608 module for always-on LEDs. Some boards allow the LED resistor to be removed. Others require cutting a trace. Only modify a board after inspecting its schematic and PCB connections.</p>
<h3><strong>Turn Sensors Off While Sleeping</strong></h3>
<p>Some sensors continue drawing current even while the ESP32-S3 is asleep. A load switch, P-channel MOSFET, or regulator-enable pin can disconnect sensor power before deep sleep.</p>
<h3><strong>Keep the Wires Short</strong></h3>
<p>Long, thin wires add resistance. A high current pulse can produce a temporary voltage drop across them:</p>
<p style="text-align: center;"><span class='MathJax_Preview'><img src='https://www.teachmemicro.com/wp-content/plugins/latex/cache/tex_6b4299cfa2a51ebe04bd563cc1a30371.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="V_{\text{DROP}} = I \times R" /></span><script type='math/tex'>V_{\text{DROP}} = I \times R</script></p>
<p>Keep the battery, MT3608, capacitor, and ESP32-S3 power connections short and secure.</p>
<h3><strong>Use a Low-Power Converter for Long Deployments</strong></h3>
<p>The MT3608 is useful for prototyping, but a low-quiescent-current fixed-output converter is a better choice when maximizing runtime is more important than minimizing component cost.</p>
<h3><strong>Move to a Custom PCB</strong></h3>
<p>Development boards are excellent for prototyping, but their USB interface, LEDs, regulator, and support circuitry are not always optimized for battery operation. A custom PCB using an ESP32-S3 module and a low-power converter can achieve much lower sleep current.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Troubleshooting the ESP32-S3 MT3608 Circuit</strong></h2>
<h3><strong>The ESP32-S3 Resets When Wi-Fi Starts</strong></h3>
<p>This is usually caused by the 3.3 V rail dropping during a radio-current burst.</p>
<p>Check the following:</p>
<ul>
<li>MT3608 output voltage under load</li>
<li>Battery condition</li>
<li>Battery-holder contacts</li>
<li>Wire length and thickness</li>
<li>Output-capacitor value and placement</li>
<li>Solder joints</li>
<li>MT3608 module quality</li>
</ul>
<p>Place the 470 µF capacitor close to the ESP32-S3. Measure the 3.3 V rail while the ESP32-S3 starts Wi-Fi rather than measuring it only when the board is idle.</p>
<h3><strong>The MT3608 Output Does Not Change</strong></h3>
<p>The adjustment potentiometer may require many turns before the voltage changes. Continue turning it slowly while monitoring the output with a multimeter. Do not connect the ESP32-S3 while experimenting with the adjustment.</p>
<h3><strong>The MT3608 Cannot Reach 3.3 V</strong></h3>
<p>Measure the battery voltage at IN+ and IN−. The input may have fallen below the MT3608’s operating range, or the battery voltage may collapse when a load is connected.</p>
<p>Also inspect:</p>
<ul>
<li>Battery polarity</li>
<li>Loose holder contacts</li>
<li>Incorrect input/output wiring</li>
<li>A damaged converter module</li>
<li>An excessive load on the output</li>
</ul>
<h3><strong>The Board Works with USB but Not with Batteries</strong></h3>
<p>Measure the following voltages:</p>
<ol>
<li>Battery-pack voltage without a load</li>
<li>Battery-pack voltage with the ESP32-S3 connected</li>
<li>MT3608 input voltage</li>
<li>MT3608 output voltage</li>
<li>ESP32-S3 3V3-pin voltage during startup</li>
</ol>
<p>A reading of 3.3 V with no load does not guarantee that the converter can maintain 3.3 V during startup or Wi-Fi transmission.</p>
<h3><strong>The Battery Reading Is Too High or Too Low</strong></h3>
<p>Verify the actual resistor values and voltage-divider wiring. The battery-positive connection must come from the battery side of the MT3608. The ADC pin must connect to the junction of the two resistors. Average several ADC samples and compare the result with a multimeter. A small calibration factor can be added after testing:</p>
<pre><code>batteryVoltage *= 1.03;</code></pre>
<p>Use a correction factor based on measurements from your own board and resistor divider.</p>
<h3><strong>The Deep-Sleep Current Is Still High</strong></h3>
<p>The ESP32-S3 chip may be sleeping correctly while the rest of the circuit continues drawing current.</p>
<p>Check:</p>
<ul>
<li>ESP32-S3 power LED</li>
<li>MT3608 indicator LED</li>
<li>USB-to-UART circuitry</li>
<li>MT3608 operating current</li>
<li>Sensor standby current</li>
<li>Battery voltage divider</li>
<li>External pull-up resistors</li>
<li>Other connected modules</li>
</ul>
<p>Measure current at the battery holder so that the reading includes the entire circuit rather than only the ESP32-S3 board.</p>
<div class="clear"></div><div style="margin-top:20px; margin-bottom:20px;" class="divider divider-solid"></div>
<h2><strong>Conclusion</strong></h2>
<p>Powering an ESP32-S3 with AA batteries is possible using a properly adjusted MT3608 boost converter. Two alkaline or two NiMH AA cells provide a suitable input for the MT3608. The module raises the changing battery voltage to a regulated 3.3 V that can be applied to the ESP32-S3 board’s 3V3 pin. Before connecting the development board, always use a multimeter to adjust the MT3608 output to 3.3 V. Add a large capacitor close to the ESP32-S3 to support Wi-Fi current bursts, and avoid connecting USB and external 3.3 V power simultaneously unless the sources are properly isolated.</p>
<p>The MT3608 is a practical and affordable choice for prototypes. However, its operating current and any onboard indicator LED can reduce the runtime of a deep-sleep project. Applications intended to operate for many months should use a converter specifically designed for low-quiescent-current battery operation. Battery life will ultimately depend on how long the ESP32-S3 remains awake. By reading sensors quickly, keeping Wi-Fi sessions short, turning off peripherals, and entering deep sleep between measurements, an ESP32-S3 AA battery project can operate for weeks or potentially months.</p>
<p>The post <a href="https://www.teachmemicro.com/how-to-power-an-esp32-s3-with-aa-batteries/">How to Power an ESP32-S3 with AA Batteries</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Connect IR Proximity Sensor with ESP32</title>
		<link>https://www.teachmemicro.com/how-to-connect-ir-proximity-sensor-with-esp32/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Tue, 07 Jul 2026 00:11:42 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<category><![CDATA[Sensor Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12185</guid>

					<description><![CDATA[<p>In this tutorial, we will connect an IR proximity sensor with the ESP32. This sensor is commonly used for obstacle detection, line-following robots, object counters, and simple automation projects where you only need to know if an object is near or not. The common IR proximity sensor module has an infrared LED, an IR receiver, &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/how-to-connect-ir-proximity-sensor-with-esp32/">How to Connect IR Proximity Sensor with ESP32</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial, we will connect an <strong>IR proximity sensor</strong> with the <strong>ESP32</strong>. This sensor is commonly used for <a href="https://www.teachmemicro.com/arduino-robot-obstacle-avoiding/">obstacle detection</a>, <a href="https://www.teachmemicro.com/implementing-pid-for-a-line-follower-robot/">line-following robots</a>, object counters, and simple automation projects where you only need to know if an object is near or not.</p>
<p>The common IR proximity sensor module has an infrared LED, an IR receiver, a comparator IC, and a small potentiometer for adjusting the detection distance. Most modules only have three pins: <strong>VCC</strong>, <strong>GND</strong>, and <strong>OUT</strong>. Some versions also include an <strong>AO</strong> pin for analog output.</p>
<p>For this tutorial, we will first use the digital output pin, as it is the easiest way to detect an object using the ESP32.</p>
<p><span id="more-12185"></span></p>
<h3><strong>ESP32 IR Proximity Sensor Wiring Diagram</strong></h3>
<p>The safest way to connect the IR sensor to the ESP32 is to power the sensor from the <span style="box-sizing: border-box; margin: 0px; padding: 0px;"><strong>ESP32's 3.3V pin</strong></span>. Many IR sensor modules can run from 3.3V to 5V, but the ESP32 GPIO pins are 3.3V pins. Powering the module from 3.3V keeps the OUT signal at a safer voltage level for the ESP32.</p>
<p>Connect the sensor as follows:</p>
<p><img data-dominant-color="d8dbd8" data-has-transparency="false" style="--dominant-color: #d8dbd8;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12189 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-wiring-digital.avif" alt="ESP32 IR Proximity Wiring - Digital" width="660" height="432" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-wiring-digital.avif 660w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-wiring-digital-300x196.avif 300w" sizes="auto, (max-width: 660px) 100vw, 660px" /></p>
<table>
<thead>
<tr>
<th>IR Proximity Sensor Pin</th>
<th>ESP32 Pin</th>
</tr>
</thead>
<tbody>
<tr>
<td>VCC</td>
<td>3V3</td>
</tr>
<tr>
<td>GND</td>
<td>GND</td>
</tr>
<tr>
<td>OUT</td>
<td>GPIO 27</td>
</tr>
</tbody>
</table>
<p>For this example, I used <strong>GPIO 27</strong> as the input pin. You can use other ESP32 GPIO pins, but avoid GPIO pins used for bootstrapping unless you know what you are doing. GPIO 34 to GPIO 39 are input-only pins, so they can also be used for reading sensor signals, but they cannot be used to drive LEDs or other output devices.</p>
<p>If your sensor has four pins, the pins are usually:</p>
<table>
<thead>
<tr>
<th>Sensor Pin</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td>VCC</td>
<td>Power supply</td>
</tr>
<tr>
<td>GND</td>
<td>Ground</td>
</tr>
<tr>
<td>DO</td>
<td>Digital output</td>
</tr>
<tr>
<td>AO</td>
<td>Analog output</td>
</tr>
</tbody>
</table>
<p>Use <strong>DO</strong> for simple object detection. Use <strong>AO</strong> only if you want to read a changing analog value.</p>
<h3><strong>Basic ESP32 IR Sensor Code</strong></h3>
<p>After wiring the sensor, upload this sketch to your ESP32:</p>
<pre><code class="language-cpp">#define IR_SENSOR_PIN 27

void setup() {
  Serial.begin(115200);
  pinMode(IR_SENSOR_PIN, INPUT);
}

void loop() {
  int sensorValue = digitalRead(IR_SENSOR_PIN);

  if (sensorValue == LOW) {
    Serial.println("Object detected");
  } else {
    Serial.println("No object");
  }

  delay(300);
}
</code></pre>
<p>Open the Serial Monitor and set the baud rate to <strong>115200</strong>. Place your hand or any object in front of the IR sensor. You should see the message change from “No object” to “Object detected”.</p>
<p>Most IR obstacle sensors are <strong>active LOW</strong>. This means the output pin becomes LOW when the sensor detects an object. This is why the code checks:</p>
<pre><code class="language-cpp">if (sensorValue == LOW)
</code></pre>
<p>If your sensor behaves the opposite way, just reverse the condition.</p>
<h3><strong>Using an LED Indicator</strong></h3>
<p>The Serial Monitor is useful for testing, but sometimes it is better to see the sensor output using an LED. In this next example, we will turn on an LED connected to GPIO 26 whenever an object is detected.</p>
<p>Connect the LED as follows:</p>
<p><img data-dominant-color="d6d9d6" data-has-transparency="false" style="--dominant-color: #d6d9d6;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12191 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-led.avif" alt="ESP32 IR Proximity with LED indicator circuit" width="660" height="432" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-led.avif 660w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-led-300x196.avif 300w" sizes="auto, (max-width: 660px) 100vw, 660px" /></p>
<table>
<thead>
<tr>
<th>LED Part</th>
<th>ESP32 Connection</th>
</tr>
</thead>
<tbody>
<tr>
<td>LED anode (+)</td>
<td>GPIO 26 through a 220Ω resistor</td>
</tr>
<tr>
<td>LED cathode (-)</td>
<td>GND</td>
</tr>
</tbody>
</table>
<p>Here is the code:</p>
<pre><code class="language-cpp">#define IR_SENSOR_PIN 27
#define LED_PIN 26

void setup() {
  Serial.begin(115200);

  pinMode(IR_SENSOR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  int sensorValue = digitalRead(IR_SENSOR_PIN);

  if (sensorValue == LOW) {
    Serial.println("Object detected");
    digitalWrite(LED_PIN, HIGH);
  } else {
    Serial.println("No object");
    digitalWrite(LED_PIN, LOW);
  }

  delay(300);
}
</code></pre>
<p>This is a simple setup, but it is already useful for testing object detection. You can replace the LED with a buzzer, relay module, or motor driver input depending on your project.</p>
<h3><strong>Adjusting the Detection Distance</strong></h3>
<p>Most IR proximity sensor modules have a small potentiometer. This potentiometer sets the reference voltage of the comparator circuit. In simpler terms, it adjusts how sensitive the sensor is.</p>
<p>Turn the potentiometer slowly while watching the Serial Monitor. If the sensor detects an object even when nothing is nearby, reduce the sensitivity. If it does not detect your hand or object, increase the sensitivity.</p>
<p>The detection distance depends on several things:</p>
<ul>
<li>color of the object</li>
<li>reflectiveness of the surface</li>
<li>angle of the object</li>
<li>ambient light</li>
<li>supply voltage</li>
<li>sensor module quality</li>
</ul>
<p>White or shiny objects are usually easier to detect because they reflect more infrared light. Black or matte objects may be harder to detect because they absorb more light.</p>
<h3><strong>Reading the Analog Output</strong></h3>
<p>Some IR proximity sensor modules include an <strong>AO</strong> pin. This pin gives an analog voltage that changes depending on the received IR light. If you want to read this value, connect the sensor like this:</p>
<p><img data-dominant-color="d8dad8" data-has-transparency="false" style="--dominant-color: #d8dad8;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12190 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-wiring-analog.avif" alt="ESP32 IR Proximity Wiring - Analog" width="660" height="432" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-wiring-analog.avif 660w, https://www.teachmemicro.com/wp-content/uploads/2026/07/esp32-ir-proximity-wiring-analog-300x196.avif 300w" sizes="auto, (max-width: 660px) 100vw, 660px" /></p>
<table>
<thead>
<tr>
<th>IR Sensor Pin</th>
<th>ESP32 Pin</th>
</tr>
</thead>
<tbody>
<tr>
<td>VCC</td>
<td>3V3</td>
</tr>
<tr>
<td>GND</td>
<td>GND</td>
</tr>
<tr>
<td>AO</td>
<td>GPIO 34</td>
</tr>
</tbody>
</table>
<p>GPIO 34 is a good choice for analog input because it is an input-only ADC pin.</p>
<p>Upload this code:</p>
<pre><code class="language-cpp">#define IR_ANALOG_PIN 34

void setup() {
  Serial.begin(115200);

  analogReadResolution(12); // ESP32 default: 0 to 4095
  analogSetPinAttenuation(IR_ANALOG_PIN, ADC_11db);
}

void loop() {
  int analogValue = analogRead(IR_ANALOG_PIN);

  Serial.print("IR analog value: ");
  Serial.println(analogValue);

  delay(300);
}
</code></pre>
<p>The ESP32 returns a value from <strong>0 to 4095</strong> by default when using 12-bit ADC resolution. A higher or lower value does not directly mean “distance in centimeters”. It only tells you that the received IR reflection changed.</p>
<p>If you need actual distance measurement, this sensor is not the best choice. Use it as a proximity or obstacle detector, not as an accurate distance sensor. For distance measurement, consider sensors such as the VL53L0X time-of-flight sensor or an ultrasonic sensor.</p>
<h3><strong>Simple ESP32 Web Server Example</strong></h3>
<p>Since we are using an ESP32, we can also display the sensor status on a web page. This is useful if you want to monitor the sensor wirelessly.</p>
<p>Replace the WiFi name and password with your own:</p>
<pre><code class="language-cpp">#include &lt;WiFi.h&gt;
#include &lt;WebServer.h&gt;

#define IR_SENSOR_PIN 27

const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";

WebServer server(80);

String getSensorStatus() {
  int sensorValue = digitalRead(IR_SENSOR_PIN);

  if (sensorValue == LOW) {
    return "Object detected";
  } else {
    return "No object";
  }
}

void handleRoot() {
  String html = "&lt;!DOCTYPE html&gt;&lt;html&gt;";
  html += "&lt;head&gt;";
  html += "&lt;meta name='viewport' content='width=device-width, initial-scale=1'&gt;";
  html += "&lt;meta http-equiv='refresh' content='1'&gt;";
  html += "&lt;style&gt;";
  html += "body{font-family:Arial;text-align:center;margin-top:50px;}";
  html += ".box{display:inline-block;padding:20px;border:1px solid #ccc;border-radius:8px;}";
  html += "&lt;/style&gt;";
  html += "&lt;/head&gt;";
  html += "&lt;body&gt;";
  html += "&lt;div class='box'&gt;";
  html += "&lt;h2&gt;ESP32 IR Proximity Sensor&lt;/h2&gt;";
  html += "&lt;h1&gt;" + getSensorStatus() + "&lt;/h1&gt;";
  html += "&lt;/div&gt;";
  html += "&lt;/body&gt;&lt;/html&gt;";

  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);
  pinMode(IR_SENSOR_PIN, INPUT);

  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("ESP32 IP Address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.begin();
}

void loop() {
  server.handleClient();
}
</code></pre>
<p>After uploading the code, open the Serial Monitor. Once the ESP32 connects to your WiFi network, it will print its IP address. Open that IP address in a browser connected to the same network.</p>
<p>The page refreshes every second and shows whether the sensor detects an object or not.</p>
<h3><strong>How the IR Proximity Sensor Works</strong></h3>
<p>The IR proximity sensor uses an infrared LED to transmit invisible light. When an object is in front of the sensor, some of this infrared light bounces back and reaches the IR receiver.</p>
<p>The module then compares the receiver signal against a reference level set by the potentiometer. This comparison is usually done by an LM393 comparator IC. If the reflected IR signal is strong enough, the comparator changes the state of the OUT pin.</p>
<p>This is why the output is digital. The ESP32 does not need to know the exact light intensity. It only reads whether the comparator output is HIGH or LOW.</p>
<p>The limitation is that the sensor depends heavily on reflection. A white surface may be detected farther away than a black surface. A shiny surface may give a stronger response than a dull one. Sunlight or strong ambient light may also affect the sensor.</p>
<h3><strong>Common Problems and Fixes</strong></h3>
<h4><strong>The sensor always says “Object detected”</strong></h4>
<p>Adjust the potentiometer slowly. The sensitivity may be too high. Also check if the sensor is facing a nearby surface such as the table or breadboard.</p>
<h4><strong>The sensor never detects anything</strong></h4>
<p>Check the wiring first. Make sure VCC goes to 3V3, GND goes to GND, and OUT goes to GPIO 27. Also try adjusting the potentiometer in the opposite direction.</p>
<h4><strong>The output is reversed</strong></h4>
<p>Some modules may behave differently. If your sensor prints “Object detected” when there is no object, change the condition from:</p>
<pre><code class="language-cpp">if (sensorValue == LOW)
</code></pre>
<p>to:</p>
<pre><code class="language-cpp">if (sensorValue == HIGH)
</code></pre>
<h4><strong>The ESP32 restarts or behaves strangely</strong></h4>
<p>Do not power the sensor from 5V and connect its OUT pin directly to the ESP32. The ESP32 uses 3.3V logic. If your module must be powered from 5V, use a voltage divider or a logic level shifter on the OUT pin.</p>
<h4><strong>The analog value is not stable</strong></h4>
<p>This is normal for simple IR modules. The reading can change because of hand movement, object color, surface angle, and ambient light. Take several readings and average them if you need a smoother value.</p>
<h3><strong>Final Thoughts</strong></h3>
<p>Connecting an IR proximity sensor with the ESP32 is straightforward if you use the digital output pin. The important thing is to remember that the sensor module and the ESP32 do not always use the same logic voltage. For beginner projects, power the IR sensor from the ESP32’s 3.3V pin and connect the OUT pin to a safe GPIO like GPIO 27.</p>
<p>This sensor is best used for simple object detection. It is not a precision distance sensor, but it works well for robot obstacle detection, counters, touchless triggers, and other projects where you only need to know if something is nearby.</p>
<p>The post <a href="https://www.teachmemicro.com/how-to-connect-ir-proximity-sensor-with-esp32/">How to Connect IR Proximity Sensor with ESP32</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ESP32-C3 Super Mini Getting Started Guide: Pinout, Arduino IDE Setup, and Built-In LED</title>
		<link>https://www.teachmemicro.com/esp32-c3-super-mini-getting-started-guide-pinout-arduino-ide-setup-and-built-in-led/</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Fri, 26 Jun 2026 22:02:15 +0000</pubDate>
				<category><![CDATA[ESP32 Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=12039</guid>

					<description><![CDATA[<p>The ESP32-C3 Super Mini is one of those tiny development boards that looks almost too small to be useful at first. But once you plug it in and get past the first upload, it becomes a very handy board for compact Wi-Fi and BLE projects. It is smaller than the usual ESP32 DevKit board, it uses &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-c3-super-mini-getting-started-guide-pinout-arduino-ide-setup-and-built-in-led/">ESP32-C3 Super Mini Getting Started Guide: Pinout, Arduino IDE Setup, and Built-In LED</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The <strong>ESP32-C3 Super Mini</strong> is one of those tiny development boards that looks almost too small to be useful at first. But once you plug it in and get past the first upload, it becomes a very handy board for compact Wi-Fi and BLE projects. It is smaller than the usual ESP32 DevKit board, it uses USB-C on most versions, and it can run Arduino sketches without much trouble. The only catch is that the <strong>ESP32-C3 Super Mini pinout</strong> can be a little confusing because some pins have boot functions, some are used by the onboard LED, and some online pinout diagrams do not always agree with each other.</p>
<p>In this guide, I will walk you through the important parts: what the board is, which Arduino IDE board option to select, how to upload your first sketch, which pins are safe to use, and how to blink the <strong>ESP32-C3 Super Mini built-in LED pin</strong>.</p>
<p><span id="more-12039"></span></p>
<p>If your board was sold as a <strong>Core ESP32-C3 board for Arduino</strong>, this guide should still help. Most of those small boards use the same ESP32-C3 chip and work with the same Arduino core.</p>
<h2><strong>What Is the ESP32-C3 Super Mini?</strong></h2>
<p>The ESP32-C3 Super Mini is a small development board based on Espressif’s ESP32-C3 microcontroller. Unlike the older and more common <a href="https://www.teachmemicro.com/esp32-board-guide-for-beginners/">ESP32 boards</a>, the ESP32-C3 does not use the dual-core Xtensa processor. Instead, it uses a single-core 32-bit RISC-V processor. For most Arduino projects, this difference is not something you need to worry about right away. Your digital outputs, analog inputs, Wi-Fi sketches, web servers, and sensor projects still work in the same familiar Arduino style.</p>
<p>The board gives you:</p>
<div class="checklist tie-list-shortcode">
<ul>
<li>Wi-Fi</li>
<li>Bluetooth Low Energy</li>
<li>Digital input and output pins</li>
<li>PWM</li>
<li>Analog inputs</li>
<li>I2C</li>
<li>SPI</li>
<li>UART</li>
<li>Native USB programming</li>
<li>A very small footprint</li>
</ul>
</div>
<p>That combination makes it useful for compact IoT projects, sensor nodes, Wi-Fi buttons, BLE beacons, and small battery-powered experiments.</p>
<hr />
<h2><strong>Why Use the ESP32-C3 Super Mini?</strong></h2>
<p>The biggest advantage is size. A full-size ESP32 DevKit board is easier to handle, but it takes up more space on a breadboard or inside an enclosure. The ESP32-C3 Super Mini gives you the main ESP32 features in a much smaller board.</p>
<p>I would use this board when:</p>
<div class="checklist tie-list-shortcode">
<ul>
<li>The project needs Wi-Fi but space is limited.</li>
<li>I want a cheap board for a small sensor node.</li>
<li>I need BLE but not Bluetooth Classic.</li>
<li>I want something smaller than an ESP32 DevKit.</li>
<li>I want a board that can plug directly into USB-C.</li>
</ul>
</div>
<p>However, I would not use it as my very first ESP32 board if I had no experience at all. The pins are closer together, the labeling can vary between sellers, and some GPIO pins have special boot behavior. It is still beginner-friendly, but you need to pay attention to the pinout.</p>
<hr />
<h2><strong>ESP32-C3 Super Mini Specifications</strong></h2>
<p>Here are the typical specifications of an ESP32-C3 Super Mini board:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Typical Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Microcontroller</td>
<td>ESP32-C3</td>
</tr>
<tr>
<td>CPU</td>
<td>32-bit RISC-V single-core</td>
</tr>
<tr>
<td>Clock Speed</td>
<td>Up to 160 MHz</td>
</tr>
<tr>
<td>Wireless</td>
<td>2.4 GHz Wi-Fi and Bluetooth LE</td>
</tr>
<tr>
<td>SRAM</td>
<td>400 KB</td>
</tr>
<tr>
<td>ROM</td>
<td>384 KB</td>
</tr>
<tr>
<td>Flash</td>
<td>Usually 4 MB</td>
</tr>
<tr>
<td>Logic Level</td>
<td>3.3V</td>
</tr>
<tr>
<td>USB</td>
<td>Native USB through USB-C</td>
</tr>
<tr>
<td>ADC Pins</td>
<td>GPIO0 to GPIO5</td>
</tr>
<tr>
<td>Built-in LED</td>
<td>Usually GPIO8</td>
</tr>
<tr>
<td>Buttons</td>
<td>BOOT and RESET</td>
</tr>
</tbody>
</table>
<p>The flash size is usually 4 MB, but it is still worth checking your specific board. Some online listings reuse the same photos for slightly different versions.</p>
<hr />
<h2><strong>ESP32-C3 Super Mini Board Layout</strong></h2>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2026/06/esp32-c3-super-mini-board-details.avif"><img data-dominant-color="c1c1c1" data-has-transparency="false" style="--dominant-color: #c1c1c1;" loading="lazy" decoding="async" class="aligncenter size-full wp-image-12046 not-transparent" src="https://www.teachmemicro.com/wp-content/uploads/2026/06/esp32-c3-super-mini-board-details.avif" alt="ESP32 C3 Super Mini board layout" width="590" height="667" srcset="https://www.teachmemicro.com/wp-content/uploads/2026/06/esp32-c3-super-mini-board-details.avif 590w, https://www.teachmemicro.com/wp-content/uploads/2026/06/esp32-c3-super-mini-board-details-265x300.avif 265w" sizes="auto, (max-width: 590px) 100vw, 590px" /></a></p>
<p>Most ESP32-C3 Super Mini boards have a USB-C connector on one end and the antenna on the other end. You will usually find two small buttons on the board:</p>
<ul>
<li><strong>BOOT button</strong></li>
<li><strong>RESET button</strong></li>
</ul>
<p>The BOOT button is useful when the board does not automatically enter upload mode. The RESET button simply restarts the board. You may also see a small LED near the center or side of the board. On many ESP32-C3 Super Mini boards, this LED is connected to GPIO8. This is the LED we will test later. One important layout note: keep the antenna area clear. Avoid placing metal parts, large wires, batteries, or copper areas directly under the antenna side of the board. The board may still work, but Wi-Fi range can suffer.</p>
<hr />
<h2><strong>ESP32-C3 Super Mini Pinout</strong></h2>
<p>The exact ESP32-C3 Super Mini pinout can vary slightly depending on the manufacturer, but most boards expose a similar group of pins.</p>
<div align="center"><iframe loading="lazy" style="border: 1px solid #e2e8f0; border-radius: 8px;" src="https://micropinouts.com/embed/board/esp32-c3-super-mini" width="800" height="600" frameborder="0"></iframe></div>
<p>A common pinout looks like this:</p>
<table>
<thead>
<tr>
<th>Board Label</th>
<th align="right">GPIO</th>
<th>Common Use</th>
</tr>
</thead>
<tbody>
<tr>
<td>5V</td>
<td align="right">-</td>
<td>5V from USB or 5V input</td>
</tr>
<tr>
<td>GND</td>
<td align="right">-</td>
<td>Ground</td>
</tr>
<tr>
<td>3V3</td>
<td align="right">-</td>
<td>3.3V output</td>
</tr>
<tr>
<td>0</td>
<td align="right">GPIO0</td>
<td>Digital I/O, ADC, PWM</td>
</tr>
<tr>
<td>1</td>
<td align="right">GPIO1</td>
<td>Digital I/O, ADC, PWM</td>
</tr>
<tr>
<td>2</td>
<td align="right">GPIO2</td>
<td>Digital I/O, ADC, PWM, strapping pin</td>
</tr>
<tr>
<td>3</td>
<td align="right">GPIO3</td>
<td>Digital I/O, ADC, PWM</td>
</tr>
<tr>
<td>4</td>
<td align="right">GPIO4</td>
<td>Digital I/O, ADC, PWM</td>
</tr>
<tr>
<td>5</td>
<td align="right">GPIO5</td>
<td>Digital I/O, ADC, PWM</td>
</tr>
<tr>
<td>6</td>
<td align="right">GPIO6</td>
<td>Digital I/O, PWM</td>
</tr>
<tr>
<td>7</td>
<td align="right">GPIO7</td>
<td>Digital I/O, PWM</td>
</tr>
<tr>
<td>8</td>
<td align="right">GPIO8</td>
<td>Digital I/O, often built-in LED</td>
</tr>
<tr>
<td>9</td>
<td align="right">GPIO9</td>
<td>Digital I/O, BOOT-related pin</td>
</tr>
<tr>
<td>10</td>
<td align="right">GPIO10</td>
<td>Digital I/O, PWM</td>
</tr>
<tr>
<td>20</td>
<td align="right">GPIO20</td>
<td>UART RX / GPIO</td>
</tr>
<tr>
<td>21</td>
<td align="right">GPIO21</td>
<td>UART TX / GPIO</td>
</tr>
</tbody>
</table>
<p>Some boards also print SDA and SCL labels beside GPIO8 and GPIO9. That does not mean you must always use those pins for I2C. On the ESP32-C3, you can usually assign I2C to different GPIO pins in your code.</p>
<hr />
<h2><strong>Pins You Should Be Careful With</strong></h2>
<p>This is the part that many beginners miss. Some ESP32-C3 pins are <strong>strapping pins</strong>. The chip checks these pins while booting. If your external circuit pulls one of these pins to the wrong level during reset, the board may fail to boot or fail to upload.</p>
<p>Be careful with these pins:</p>
<table>
<thead>
<tr>
<th>Pin</th>
<th>Why It Needs Care</th>
</tr>
</thead>
<tbody>
<tr>
<td>GPIO2</td>
<td>Strapping pin</td>
</tr>
<tr>
<td>GPIO8</td>
<td>Strapping pin and often built-in LED</td>
</tr>
<tr>
<td>GPIO9</td>
<td>Strapping pin and usually connected to BOOT</td>
</tr>
<tr>
<td>GPIO18 / GPIO19</td>
<td>Used for native USB on many ESP32-C3 boards</td>
</tr>
</tbody>
</table>
<p>This does not mean you can never use these pins. You can. But for your first projects, it is better to start with less troublesome pins.</p>
<hr />
<h2><strong>Best GPIO Pins for Beginner Projects</strong></h2>
<p>For simple LEDs, buttons, sensors, and digital outputs, I would start with:</p>
<div class="checklist tie-list-shortcode">
<ul>
<li>GPIO0</li>
<li>GPIO1</li>
<li>GPIO3</li>
<li>GPIO4</li>
<li>GPIO5</li>
<li>GPIO6</li>
<li>GPIO7</li>
<li>GPIO10</li>
</ul>
</div>
<p>For analog input, use:</p>
<div class="checklist tie-list-shortcode">
<ul>
<li>GPIO0</li>
<li>GPIO1</li>
<li>GPIO2</li>
<li>GPIO3</li>
<li>GPIO4</li>
<li>GPIO5</li>
</ul>
</div>
<p>For UART, many boards use:</p>
<ul>
<li>GPIO20 = RX</li>
<li>GPIO21 = TX</li>
</ul>
<p>For the built-in LED, try: GPIO8</p>
<p>If GPIO8 does not work on your board, try GPIO10. Some clone boards use a different LED pin.</p>
<hr />
<h2><strong>Powering the ESP32-C3 Super Mini</strong></h2>
<p>The easiest way to power the board is through the USB-C connector.</p>
<p>You may also see <strong>5V</strong>, <strong>3V3</strong>, and <strong>GND</strong> pins on the board.</p>
<p>Here is what they mean:</p>
<ul>
<li><strong>5V</strong> is usually connected to the USB 5V line.</li>
<li><strong>3V3</strong> is the regulated 3.3V supply.</li>
<li><strong>GND</strong> is ground.</li>
</ul>
<p>The ESP32-C3 itself is a <strong>3.3V device</strong>. Its GPIO pins are not 5V tolerant. Do not connect a 5V signal directly to any GPIO pin. This is especially important when using modules like relays, ultrasonic sensors, or some older 5V Arduino modules. If a module outputs 5V, use a level shifter or voltage divider before connecting it to the ESP32-C3.</p>
<hr />
<h2><strong>Installing ESP32-C3 Support in Arduino IDE</strong></h2>
<p>To program the ESP32-C3 Super Mini with Arduino IDE, you need to install the ESP32 board package.</p>
<p>Open Arduino IDE, then go to:</p>
<p><em>File &gt; Preferences</em></p>
<p>Find <strong>Additional Boards Manager URLs</strong> and add this URL:</p>
<p><em>https://espressif.github.io/arduino-esp32/package_esp32_index.json</em></p>
<p>Then go to:</p>
<p><em>Tools &gt; Board &gt; Boards Manager</em></p>
<p>Search for: <em>esp32</em></p>
<p>Then, install the package named: <em>esp32 by Espressif Systems</em></p>
<p>After installation, restart Arduino IDE.</p>
<hr />
<h2><strong>Which Board Should You Select?</strong></h2>
<p>For most ESP32-C3 Super Mini boards, select:</p>
<p><em>Tools &gt; Board &gt; esp32 &gt; ESP32C3 Dev Module</em></p>
<p>This is the board option I would try first if your board is listed online as an ESP32-C3 Super Mini or Core ESP32-C3 board for Arduino.</p>
<p>Use these settings as a starting point:</p>
<table>
<thead>
<tr>
<th>Arduino IDE Setting</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Board</td>
<td>ESP32C3 Dev Module</td>
</tr>
<tr>
<td>USB CDC On Boot</td>
<td>Enabled</td>
</tr>
<tr>
<td>CPU Frequency</td>
<td>160 MHz</td>
</tr>
<tr>
<td>Flash Size</td>
<td>4MB</td>
</tr>
<tr>
<td>Upload Speed</td>
<td>921600</td>
</tr>
<tr>
<td>Port</td>
<td>Select the detected USB port</td>
</tr>
</tbody>
</table>
<p>The most important setting here is <strong>USB CDC On Boot</strong>. If this is disabled, your sketch may upload, but the Serial Monitor may not show anything through USB. If upload fails at 921600, lower the upload speed to 460800 or 115200.</p>
<hr />
<h2><strong>First Sketch: Check If the Board Is Working</strong></h2>
<p>Before connecting sensors or LEDs, upload a simple serial test sketch.</p>
<pre><code class="language-cpp">void setup() {
  Serial.begin(115200);
  delay(2000);

  Serial.println();
  Serial.println("ESP32-C3 Super Mini test");

  Serial.print("Chip model: ");
  Serial.println(ESP.getChipModel());

  Serial.print("Chip revision: ");
  Serial.println(ESP.getChipRevision());

  Serial.print("CPU frequency: ");
  Serial.print(ESP.getCpuFreqMHz());
  Serial.println(" MHz");

  Serial.print("Flash size: ");
  Serial.print(ESP.getFlashChipSize() / (1024 * 1024));
  Serial.println(" MB");
}

void loop() {
  Serial.println("Board is running...");
  delay(1000);
}
</code></pre>
<p>Upload the sketch, then open the Serial Monitor at: <em>115200 baud</em>. If you see the board information and the “Board is running...” message, your Arduino IDE setup is working. If you see nothing, press RESET once. Also check that <strong>USB CDC On Boot</strong> is enabled.</p>
<hr />
<h2><strong>If Upload Does Not Work</strong></h2>
<p>Some ESP32-C3 Super Mini boards enter upload mode automatically. Others are a little stubborn.</p>
<p>If Arduino IDE gets stuck at “Connecting...”, try this:</p>
<ol>
<li>Click Upload.</li>
<li>When you see “Connecting...”, hold the BOOT button.</li>
<li>Release BOOT once the upload starts.</li>
</ol>
<p>If that still does not work, hold BOOT, tap RESET, then try uploading again. Also check the USB cable. A surprising number of upload problems are caused by charge-only USB-C cables.</p>
<hr />
<h2><strong>ESP32-C3 Super Mini Built-In LED Pin</strong></h2>
<p>On many ESP32-C3 Super Mini boards, the built-in LED is connected to <strong>GPIO8</strong>. This LED is usually <strong>active LOW</strong>. That means the logic feels backward:</p>
<p>LOW = LED ON</p>
<p>HIGH = LED OFF</p>
<p>Upload this sketch to test the onboard LED:</p>
<pre><code class="language-cpp">#define LED_PIN 8

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, LOW);   // Turn LED ON
  delay(500);

  digitalWrite(LED_PIN, HIGH);  // Turn LED OFF
  delay(500);
}
</code></pre>
<p>If the onboard LED blinks, your board uses GPIO8 for the built-in LED. If nothing happens, try GPIO10:</p>
<pre><code class="language-cpp">#define LED_PIN 10
</code></pre>
<p>Some boards only have a power LED. If the LED turns on whenever the board is powered and never responds to your sketch, then it may not be connected to a GPIO pin.</p>
<hr />
<h2><strong>Why the Built-In LED Pin Can Be Annoying</strong></h2>
<p>GPIO8 is convenient because it is often connected to the onboard LED. However, GPIO8 is also a strapping pin. For a simple blink test, this is not a big problem. But if you connect an external circuit to GPIO8, especially a circuit with a pull-up or pull-down resistor, it may affect the way the ESP32-C3 boots.</p>
<p>So here is the practical rule: <em>Use GPIO8 for the onboard LED test. For external LEDs, buttons, and sensors, use another GPIO unless you have a reason to use GPIO8.</em></p>
<hr />
<h2><strong>Testing Wi-Fi on the ESP32-C3 Super Mini</strong></h2>
<p>Once the board can upload sketches, the next useful test is Wi-Fi. The ESP32-C3 supports 2.4 GHz Wi-Fi. It does not connect to 5 GHz-only networks.</p>
<p>Upload this Wi-Fi scanner:</p>
<pre><code class="language-cpp">#include &lt;WiFi.h&gt;

void setup() {
  Serial.begin(115200);
  delay(2000);

  Serial.println();
  Serial.println("ESP32-C3 Wi-Fi scan");

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  int n = WiFi.scanNetworks();

  if (n == 0) {
    Serial.println("No networks found.");
  } else {
    Serial.print("Networks found: ");
    Serial.println(n);

    for (int i = 0; i &lt; n; i++) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print("  RSSI: ");
      Serial.print(WiFi.RSSI(i));
      Serial.println(" dBm");
      delay(10);
    }
  }
}

void loop() {
}
</code></pre>
<p>Open the Serial Monitor at 115200 baud. You should see nearby Wi-Fi networks. If the scan works, your Wi-Fi hardware is fine.</p>
<hr />
<h2><strong>Connecting the ESP32-C3 Super Mini to Wi-Fi</strong></h2>
<p>Now try connecting to your router.</p>
<pre><code class="language-cpp">#include &lt;WiFi.h&gt;

const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("Wi-Fi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
}
</code></pre>
<p>Replace the Wi-Fi name and password with your own network credentials. If the board keeps failing to connect, check that your network is 2.4 GHz. Many routers combine 2.4 GHz and 5 GHz under one network name, which usually works, but a 5 GHz-only network will not.</p>
<hr />
<h2><strong>Simple Web Server LED Control</strong></h2>
<p>Here is a small web server example that controls the built-in LED from a browser. This sketch assumes the onboard LED is on GPIO8 and active LOW.</p>
<pre><code class="language-cpp">#include &lt;WiFi.h&gt;
#include &lt;WebServer.h&gt;

const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";

#define LED_PIN 8

WebServer server(80);

bool ledOn = false;

void handleRoot() {
  String html = "&lt;!DOCTYPE html&gt;&lt;html&gt;";
  html += "&lt;head&gt;";
  html += "&lt;meta name='viewport' content='width=device-width, initial-scale=1'&gt;";
  html += "&lt;style&gt;";
  html += "body{font-family:Arial;text-align:center;margin-top:40px;}";
  html += "button{font-size:24px;padding:12px 24px;margin:10px;}";
  html += "&lt;/style&gt;";
  html += "&lt;/head&gt;";

  html += "&lt;body&gt;";
  html += "&lt;h1&gt;ESP32-C3 Super Mini LED&lt;/h1&gt;";
  html += "&lt;p&gt;LED is ";
  html += ledOn ? "ON" : "OFF";
  html += "&lt;/p&gt;";
  html += "&lt;p&gt;&lt;a href='/on'&gt;&lt;button&gt;ON&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;";
  html += "&lt;p&gt;&lt;a href='/off'&gt;&lt;button&gt;OFF&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;";
  html += "&lt;/body&gt;&lt;/html&gt;";

  server.send(200, "text/html", html);
}

void handleOn() {
  ledOn = true;
  digitalWrite(LED_PIN, LOW);   // active-low LED ON
  handleRoot();
}

void handleOff() {
  ledOn = false;
  digitalWrite(LED_PIN, HIGH);  // active-low LED OFF
  handleRoot();
}

void setup() {
  Serial.begin(115200);
  delay(1000);

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);  // start with LED OFF

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("Wi-Fi connected!");
  Serial.print("Open this address in your browser: http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/on", handleOn);
  server.on("/off", handleOff);

  server.begin();
}

void loop() {
  server.handleClient();
}
</code></pre>
<p>After uploading, open the Serial Monitor and copy the IP address. Open that address in a browser connected to the same Wi-Fi network. This is a good first “real” ESP32-C3 project because it tests USB, serial output, Wi-Fi, GPIO, and a simple web page.</p>
<hr />
<h2><strong>Using I2C on the ESP32-C3 Super Mini</strong></h2>
<p>Many ESP32-C3 Super Mini pinout diagrams show GPIO8 as SDA and GPIO9 as SCL. That can work, but I do not always recommend it for beginners because those pins have special boot behavior. A safer approach is to define the I2C pins yourself.</p>
<p>For example, you can try GPIO6 and GPIO7:</p>
<pre><code class="language-cpp">#include &lt;Wire.h&gt;

#define SDA_PIN 6
#define SCL_PIN 7

void setup() {
  Serial.begin(115200);
  delay(1000);

  Wire.begin(SDA_PIN, SCL_PIN);

  Serial.println("Scanning I2C bus...");

  for (byte address = 1; address &lt; 127; address++) {
    Wire.beginTransmission(address);
    byte error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at 0x");
      if (address &lt; 16) Serial.print("0");
      Serial.println(address, HEX);
    }
  }

  Serial.println("Scan complete.");
}

void loop() {
}
</code></pre>
<p>If your OLED display or sensor is already wired to the pins labeled SDA and SCL on your board, change the pin definitions to match those labels.</p>
<p>For example:</p>
<pre><code class="language-cpp">#define SDA_PIN 8
#define SCL_PIN 9
</code></pre>
<p>Just remember that GPIO8 and GPIO9 are not the safest pins for every circuit.</p>
<hr />
<h2><strong>Reading an Analog Sensor</strong></h2>
<p>The ESP32-C3 has analog input pins on GPIO0 to GPIO5. Here is a simple potentiometer test using GPIO0:</p>
<pre><code class="language-cpp">#define POT_PIN 0

void setup() {
  Serial.begin(115200);
}

void loop() {
  int value = analogRead(POT_PIN);

  Serial.print("ADC value: ");
  Serial.println(value);

  delay(300);
}
</code></pre>
<p>Wire the potentiometer like this:</p>
<table>
<thead>
<tr>
<th>Potentiometer Pin</th>
<th>ESP32-C3 Super Mini</th>
</tr>
</thead>
<tbody>
<tr>
<td>One outer pin</td>
<td>3V3</td>
</tr>
<tr>
<td>Other outer pin</td>
<td>GND</td>
</tr>
<tr>
<td>Middle pin</td>
<td>GPIO0</td>
</tr>
</tbody>
</table>
<p>Do not connect the potentiometer to 5V. The analog input pin should only receive a voltage between 0V and 3.3V.</p>
<hr />
<h2><strong>Using UART on GPIO20 and GPIO21</strong></h2>
<p>Many ESP32-C3 Super Mini boards expose GPIO20 and GPIO21 as RX and TX. Typical wiring looks like this:</p>
<table>
<thead>
<tr>
<th>ESP32-C3 Super Mini</th>
<th>External Serial Device</th>
</tr>
</thead>
<tbody>
<tr>
<td>GPIO20 RX</td>
<td>TX</td>
</tr>
<tr>
<td>GPIO21 TX</td>
<td>RX</td>
</tr>
<tr>
<td>GND</td>
<td>GND</td>
</tr>
</tbody>
</table>
<p>Here is a simple UART bridge sketch:</p>
<pre><code class="language-cpp">HardwareSerial MySerial(1);

#define RX_PIN 20
#define TX_PIN 21

void setup() {
  Serial.begin(115200);
  MySerial.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN);

  Serial.println("UART test started");
}

void loop() {
  if (MySerial.available()) {
    Serial.write(MySerial.read());
  }

  if (Serial.available()) {
    MySerial.write(Serial.read());
  }
}
</code></pre>
<p>This is useful when testing GPS modules, serial sensors, or other microcontrollers. Again, check voltage levels. The ESP32-C3 uses 3.3V logic.</p>
<hr />
<h2><strong>Common Problems and Fixes</strong></h2>
<h3><strong>The Board Does Not Show Up in Arduino IDE</strong></h3>
<p>Try another USB cable first. Make sure it is a data cable, not just a charging cable.</p>
<p>Then try:</p>
<ul>
<li>Another USB port</li>
<li>Pressing RESET</li>
<li>Holding BOOT while plugging in the board</li>
<li>Restarting Arduino IDE</li>
<li>Checking whether the port appears in Device Manager or your operating system’s serial device list</li>
</ul>
<p>Most ESP32-C3 Super Mini boards use native USB, so they usually do not need a separate CH340 or CP210x driver. But clone boards can vary.</p>
<h3><strong>Upload Gets Stuck at “Connecting...”</strong></h3>
<p>Put the board into bootloader mode manually:</p>
<ol>
<li>Hold BOOT.</li>
<li>Click Upload.</li>
<li>Release BOOT when upload starts.</li>
</ol>
<p>If needed, hold BOOT, tap RESET, release RESET, then release BOOT.</p>
<h3><strong>Serial Monitor Is Blank</strong></h3>
<p>Check these settings:</p>
<ul>
<li>Serial Monitor baud rate is 115200.</li>
<li>USB CDC On Boot is enabled.</li>
<li>Correct port is selected.</li>
<li>The sketch has <code>Serial.begin(115200);</code>.</li>
<li>You added a short delay after <code>Serial.begin()</code>.</li>
</ul>
<p>This is one of the most common ESP32-C3 beginner issues.</p>
<h3><strong>The Built-In LED Does Not Blink</strong></h3>
<p>Try GPIO8 first, then GPIO10.</p>
<p>Also remember that many ESP32-C3 Super Mini boards use active-low LED wiring. So this turns the LED on:</p>
<pre><code class="language-cpp">digitalWrite(LED_PIN, LOW);
</code></pre>
<p>And this turns it off:</p>
<pre><code class="language-cpp">digitalWrite(LED_PIN, HIGH);
</code></pre>
<p>If the LED never responds, it may only be a power LED.</p>
<h3><strong>The Board Resets When Wi-Fi Starts</strong></h3>
<p>Wi-Fi needs short bursts of current. If the USB cable or port is weak, the board may reset when Wi-Fi turns on.</p>
<p>Try:</p>
<ul>
<li>A better USB cable</li>
<li>A different USB port</li>
<li>A powered USB hub</li>
<li>Removing external loads from the 3.3V pin</li>
<li>Powering external modules separately</li>
</ul>
<p>Always connect grounds together when using an external power supply for sensors or modules.</p>
<hr />
<h2><strong>Recommended First Projects</strong></h2>
<p>Once the board is working, these are good projects to try:</p>
<ul>
<li>Built-in LED blink</li>
<li>Wi-Fi scanner</li>
<li>Web server LED control</li>
<li>OLED display using I2C</li>
<li>BME280 weather monitor</li>
<li>DHT22 temperature and humidity logger</li>
<li>MQTT sensor node</li>
<li>BLE beacon</li>
<li>Deep sleep battery monitor</li>
<li>UART GPS reader</li>
</ul>
<p>The ESP32-C3 Super Mini is especially good for small connected projects where a full-size ESP32 board feels too large.</p>
<hr />
<h2><strong>Frequently Asked Questions</strong></h2>
<h3><strong>What board should I select for ESP32-C3 Super Mini in Arduino IDE?</strong></h3>
<p>Select <strong>ESP32C3 Dev Module</strong>. This is the best starting option for most generic ESP32-C3 Super Mini boards.</p>
<h3><strong>Is the ESP32-C3 Super Mini compatible with Arduino?</strong></h3>
<p>Yes. Install the ESP32 board package by Espressif, then select <strong>ESP32C3 Dev Module</strong> in Arduino IDE.</p>
<h3><strong>What is the ESP32-C3 Super Mini built-in LED pin?</strong></h3>
<p>On many boards, the built-in LED is connected to <strong>GPIO8</strong>. It is usually active LOW, so writing <em>LOW</em> turns the LED on.</p>
<h3><strong>Why does my built-in LED not blink?</strong></h3>
<p>Your board may use a different LED pin, or the LED may only be a power indicator. Try GPIO8 first, then GPIO10.</p>
<h3><strong>Can I use GPIO8 and GPIO9?</strong></h3>
<p>Yes, but be careful. GPIO8 and GPIO9 are strapping pins. GPIO8 is often connected to the built-in LED, while GPIO9 is usually related to the BOOT button.</p>
<h3><strong>Can I connect 5V sensors to the ESP32-C3 Super Mini?</strong></h3>
<p>Only if the sensor output is 3.3V-compatible. The ESP32-C3 GPIO pins are not 5V tolerant. Use a level shifter when needed.</p>
<h3><strong>Does the ESP32-C3 support Bluetooth Classic?</strong></h3>
<p>No. The ESP32-C3 supports Bluetooth Low Energy, not Bluetooth Classic.</p>
<h3><strong>Can the ESP32-C3 Super Mini run MicroPython?</strong></h3>
<p>Yes. The board can run Arduino sketches, MicroPython, ESP-IDF projects, and PlatformIO projects. This guide focuses on Arduino IDE.</p>
<hr />
<h2><strong>Conclusion</strong></h2>
<p>The ESP32-C3 Super Mini is a small but capable board for Wi-Fi and Bluetooth Low Energy projects. It is not as forgiving as a large ESP32 DevKit board because the pins are closer together and some GPIOs have boot functions, but it is still a very useful board once you understand the basics.</p>
<p>For a smooth start, remember these points:</p>
<ul>
<li>Select <strong>ESP32C3 Dev Module</strong> in Arduino IDE.</li>
<li>Enable <strong>USB CDC On Boot</strong>.</li>
<li>Use GPIO8 for the built-in LED on most boards.</li>
<li>Remember that the built-in LED is usually active LOW.</li>
<li>Be careful with GPIO2, GPIO8, and GPIO9.</li>
<li>Do not connect 5V signals directly to any GPIO pin.</li>
</ul>
<p>After you get the first blink and Wi-Fi test working, the ESP32-C3 Super Mini becomes a great board for compact IoT projects, web-controlled devices, and small wireless sensor builds.</p>
<p>The post <a href="https://www.teachmemicro.com/esp32-c3-super-mini-getting-started-guide-pinout-arduino-ide-setup-and-built-in-led/">ESP32-C3 Super Mini Getting Started Guide: Pinout, Arduino IDE Setup, and Built-In LED</a> appeared first on <a href="https://www.teachmemicro.com">Teach Me Microcontrollers!</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: www.teachmemicro.com @ 2026-11-01 11:16:46 by W3 Total Cache
-->