¿Tu ESP32 no arranca con la Tarjeta SD? Solución al conflicto del GPIO12 (MISO)


Si tu ESP32 no arranca nunca cuando alimentas el módulo SD a 3.3V, pero a veces funciona a 5V, no te vuelvas loco buscando un fallo en la fuente de alimentación. Estás ante un problema de hardware muy específico y traicionero: el conflicto del pin GPIO12 (MISO) como pin de arranque o strapping pin.

El Diagnóstico: Conflicto de arranque en GPIO12

Al reiniciarse, el ESP32 lee el estado lógico de ciertos pines especiales para decidir su modo de operación. Uno de ellos es el GPIO12.

¿Cuál es el problema?

Si durante el arranque la tarjeta SD mantiene el pin GPIO12 en nivel alto (High), el ESP32 interpreta que debe configurar el voltaje de su memoria flash interna a 1.8V en lugar de los 3.3V que necesitan casi todos los módulos comerciales.

El resultado es catastrófico:

  • Con la flash forzada a 1.8V, el ESP32 no puede leer su propio programa.
  • El sistema entra en un bucle de error o simplemente se queda «muerto».

Esto explica por qué con 5V funciona de forma intermitente: los niveles lógicos se vuelven impredecibles y a veces, por puro azar, el pin no se lee como «alto» en el instante crítico.

Solución Profesional: Fijar la flash a 3.3V vía eFuse

La solución recomendada por Espressif es quemar un eFuse interno. Esto obliga al ESP32 a usar siempre 3.3V para la flash, ignorando lo que pase en el GPIO12 durante el arranque.

Nota importante: Esta operación es irreversible, pero totalmente segura para las placas ESP32 estándar. Desconecta la tarjeta SD antes de realizar este proceso.

Paso a paso en Windows 11 (usando el IDE de Arduino)

No necesitas instalar herramientas complejas; el paquete de ESP32 para Arduino ya incluye lo necesario.

1. Localiza la herramienta espefuse

Navega a la siguiente ruta (sustituyendo tu usuario):

C:\Users\[USUARIO]\AppData\Local\Arduino15\packages\esp32\tools\esptool_py\5.1.0\

Si no ves la carpeta AppData, activa «Elementos ocultos» en la pestaña «Vista» de tu explorador.

2. Abre la terminal

En la barra de direcciones de esa carpeta, escribe cmd y pulsa Enter. Se abrirá la consola directamente en esa ruta.

3. Identifica tu puerto COM

Conecta tu ESP32 y búscalo en el Administrador de Dispositivos bajo «Puertos (COM y LPT)». Ejemplo: COM4.

4. Ejecuta el comando de fijación de voltaje

Escribe el siguiente comando (ajusta tu puerto COM):

espefuse.exe --port COM4 set_flash_voltage 3.3V

5. Confirma la operación

La herramienta te pedirá una confirmación final. Escribe exactamente:

BURN

y pulsa Enter. Si ves el mensaje “Successfully burned eFuses”, ¡felicidades! Tu GPIO12 ya no causará conflictos.

Alternativas sin cambios irreversibles

Si prefieres no tocar los eFuses, existen dos caminos adicionales:

Opción A: Aislamiento mediante hardware

Puedes añadir un transistor PNP para «desconectar» el pin MISO de la SD durante el arranque. El transistor solo dejará pasar la señal cuando el pin CS (Chip Select) esté activo, evitando que la SD interfiera en el encendido.

Opción B: Reasignación de pines (Software)

El ESP32 permite mover el bus SPI a otros pines gracias a su matriz de conmutación. Puedes mover el MISO del pin 12 al pin 19, por ejemplo:

C++

#define SPI_MISO 19 // Cambiado de 12 a 19
SPI.begin(SCK, SPI_MISO, MOSI, CS);
SD.begin(CS);

Requiere cambiar el cableado físico en tu placa o PCB.

Tabla Resumen de Soluciones

OpciónVentajasDesventajas
Quemar eFuseDefinitiva y profesional. Libera el pin 12.Irreversible.
Transistor PNPNo altera el ESP32 internamente.Añade componentes al circuito.
Cambiar PinLimpio y sin riesgos.Requiere modificar el PCB o cableado.

Conclusión

Para proyectos robustos la solución del eFuse es la más lógica y estándar en la industria. Te permite usar el módulo SD a 3.3V con total confianza, asegurando que tu sistema arranque siempre a la primera.

Si quieres profundizar más en la optimización de tus proyectos, no te pierdas nuestro último post sobre como optimizar un ordenador portátil para ejecutar herramientas de CAD: https://soloelectronicos.com/2026/04/04/guia-completa-analiza-tu-pc-y-optimiza-autocad-caso-real-hp-core-i3/

Registro de Datos con ESP32: Sensor BME280 y Tarjeta MicroSD


Introducción

En el mundo de los sistemas embebidos, la capacidad de almacenar información para su posterior análisis es vital. Ya sea que estés monitoreando el clima de un invernadero o el rendimiento de una máquina, una tarjeta microSD es la herramienta perfecta para proyectos de Datalogging.

En este artículo, vamos a configurar un ESP32 para leer datos ambientales de un sensor BME280 y guardarlos en un archivo de texto dentro de una tarjeta microSD. Lo mejor de todo es que cada lectura incluirá una marca de tiempo precisa (Epoch time) obtenida mediante un servidor NTP vía WiFi, lo que te permitirá organizar tus datos cronológicamente de forma profesional.

El uso de una tarjeta microSD es especialmente útil para proyectos de registro de datos. Como ejemplo, le mostraremos cómo guardar las lecturas del sensor de un sensor BME280 con marcas de tiempo ( tiempo de época ).

Descripción general del proyecto de tarjeta microSD BME280 de registro de datos ESP32

Requisitos previos

Para este ejemplo, asegúrese de tener instaladas las siguientes bibliotecas:

Puede instalar estas bibliotecas utilizando el administrador de bibliotecas de Arduino. En tu IDE de Arduino, ve a Sketch > Incluir biblioteca > Administrar bibliotecas… Luego, busca los nombres de las bibliotecas e instálalos.

Diagrama esquemático

Para este ejemplo, debe conectar el módulo de la tarjeta microSD y el sensor BME280 al ESP32. Aquí hay una lista de las piezas necesarias:

  • Placa de desarrollo ESP32 (lea: Las mejores placas de desarrollo ESP32 )
  • sonda BME280
  • Módulo de tarjeta MicroSD
  • Tarjeta micro SD
  • Cables de puente
  • Tablero de circuitos

Conecte el circuito siguiendo el siguiente diagrama esquemático.

Diagrama esquemático del circuito de la tarjeta microSD ESP32 BME280

También puedes echar un vistazo a las siguientes tablas:

BME280ESP32
VIN3V3
TIERRATIERRA
SCLGPIO22
ASDGPIO21
módulo de tarjeta microSDESP32
3V33,3 V
CSGPIO5
MOSIGPIO23
CLKGPIO18
MISOGPIO19
TIERRATIERRA

https://8d47f2cdfa0fea8c35311dc564e24b83.safeframe.googlesyndication.com/safeframe/1-0-38/html/container.html

Código

Copie el siguiente código en su IDE de Arduino. Este boceto obtiene lecturas del sensor BME280 (temperatura, humedad y presión) y las registra en un archivo en la tarjeta microSD cada 30 segundos. También registra la marca de tiempo (tiempo de época solicitado a un servidor NTP).


// Libraries for SD card
#include "FS.h"
#include "SD.h"
#include <SPI.h>

//Libraries for BME280 sensor
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Libraries to get time from NTP Server
#include <WiFi.h>
#include "time.h"

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

// BME280 I2C
Adafruit_BME280 bme;

// Variables to hold sensor readings
float temp;
float hum;
float pres;
String dataMessage;

// NTP server to request epoch time
const char* ntpServer = "pool.ntp.org";

// Variable to save current epoch time
unsigned long epochTime; 

// Function that gets current epoch time
unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return(0);
  }
  time(&now);
  return now;
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

// Init BME280
void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

// Initialize SD card
void initSDCard(){
   if (!SD.begin()) {
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }
  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

// Write to the SD card
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

// Append data to the SD card
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void setup() {
  Serial.begin(115200);
  
  initWiFi();
  initBME();
  initSDCard();
  configTime(0, 0, ntpServer);
  
  // If the data.txt file doesn't exist
  // Create a file on the SD card and write the data labels
  File file = SD.open("/data.txt");
  if(!file) {
    Serial.println("File doesn't exist");
    Serial.println("Creating file...");
    writeFile(SD, "/data.txt", "Epoch Time, Temperature, Humidity, Pressure \r\n");
  }
  else {
    Serial.println("File already exists");  
  }
  file.close();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    //Get epoch time
    epochTime = getTime();
    
    //Get sensor readings
    temp = bme.readTemperature();
    //temp = 1.8*bme.readTemperature() + 32;
    hum = bme.readHumidity();
    pres = bme.readPressure()/100.0F;

    //Concatenate all info separated by commas
    dataMessage = String(epochTime) + "," + String(temp) + "," + String(hum) + "," + String(pres)+ "\r\n";
    Serial.print("Saving data: ");
    Serial.println(dataMessage);

    //Append the data to file
    appendFile(SD, "/data.txt", dataMessage.c_str());

    lastTime = millis();
  }
}

Inserte sus credenciales de red en las siguientes variables y el código funcionará de inmediato:

const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Este ejemplo utiliza las funciones que hemos visto anteriormente para escribir y agregar datos a la tarjeta microSD (escribirArchivo()yagregar archivo ()funciones).

Demostración

Sube el código a tu tablero. Puede comprobar en el monitor serie si todo funciona como se esperaba.

ESP32 BME280 Registro de datos en tarjeta microSD Monitor serie

Deje que el proyecto funcione durante un tiempo para recopilar algunas lecturas. Luego, inserte la tarjeta microSD en su computadora, y debería tener un archivo llamado datos.txt con las lecturas del sensor.

ESP32 BME280 Registro de datos a archivo en tarjeta microSD

Conclusión

Implementar un sistema de registro en SD te permite independizar tus proyectos de una conexión constante a la nube y asegurar que no se pierda ninguna lectura importante. Este método es la base para estaciones meteorológicas autónomas y sistemas de monitoreo industrial.

Si te ha gustado este tutorial, no te pierdas nuestro último post donde exploramos como optimizar un ordenador portátil para ejecutar aplicaciones avanzadas [Optimizar un portátil para uso con herramientas avanzadas].