Tienes un datalogger que tarda una eternidad en arrancar? Conectas la placa, ves el LED encendido y pasan diez, quince, hasta diecisiete segundos antes de que tu código empiece a correr. No es tu programa: es la tarjeta microSD, o más bien la forma en que el sistema operativo del computador la escanea cada vez que la placa aparece como una unidad USB. La buena noticia es que se arregla con tres cambios chicos que no cuestan nada y que están respaldados por mediciones reales.
En esta guía vas a aprender a exprimir el rendimiento de las tarjetas microSD en proyectos con CircuitPython: cortar el retardo de arranque casi a cero, elegir el driver y el formato correctos, y estructurar tus escrituras para registrar datos más rápido. Todo aplica tanto a placas con ranura microSD integrada (como la Metro RP2350 o el Feather RP2040 Adalogger) como a un Arduino o ESP32 al que le sumas un lector microSD por SPI. Esta versión es una adaptación al español del trabajo de Mikey Sklar publicado en el Adafruit Learning System, con un par de explicaciones extra y precios locales.

El 90% de la ganancia está en 3 cambios
Antes de entrar en detalle, estos son los tres ajustes que más mueven la aguja. Si solo haces estos tres, ya ganaste casi todo:
- Desactiva el USB Mass Storage. Este cambio elimina por completo la ventana lenta del arranque: tu código corre en el instante en que la placa recibe energía. Es el de mayor impacto, lejos.
- Usa una tarjeta chica (2GB o menos, FAT16). Las tarjetas de ese tamaño se formatean en FAT16 de forma automática. En macOS esto baja la espera de arranque de 17 segundos a 0,6 segundos. El formato del sistema de archivos importa más que la velocidad de la tarjeta.
- Usa las librerías sdcardio o sdioio, no adafruit_sdcard. Son más rápidas, vienen integradas en el firmware y cambiar no cuesta nada.
Y si estás eligiendo hardware para un proyecto nuevo: prefiere un microcontrolador con periférico SDMMC nativo, como el RP2350, el ESP32-S3 o el STM32F405. El modo SDIO entrega lecturas de 2 a 4 veces más rápidas que SPI sin escribir una sola línea de código adicional. Las tres ganancias de arriba aplican sin importar qué placa uses.

Ese gráfico resume todo el asunto. El peor caso (USB encendido, FAT32, macOS) son 17 segundos. El mejor (USB apagado, FAT32) baja de 0,1 segundos. Las pruebas se corrieron en una Adafruit Metro RP2040 con una tarjeta SanDisk Clase 10 de 16GB en FAT32 y una de 64MB en FAT16.
Por qué pasa esto (la parte que el tutorial original no explica del todo)
Vale la pena entender el mecanismo, porque así sabes cuándo un cambio te va a servir. Cuando CircuitPython corre, varias placas comparten la tarjeta con tu computador por USB, igual que un pendrive: ves tus archivos directo en el Finder o el Explorador, sin sacar la tarjeta ni usar adaptador. Esa comodidad tiene un costo. Al conectar, el sistema operativo escanea de inmediato la tarjeta entera, y tu código queda esperando varios segundos antes de arrancar. Y mientras corre, el host sigue leyendo en segundo plano en cada escritura a la SD.
La pieza clave es la tabla FAT. El host la lee completa en cada montaje. Una tarjeta SDSC de 2GB o menos genera una tabla FAT16 de apenas 64KB. Una tarjeta grande en FAT32 puede tener una tabla de varios megabytes. La diferencia entre leer 64KB y leer 4MB es 64 veces. Por eso una tarjeta chica y vieja le gana a una grande y nueva en tiempo de arranque: no es velocidad, es cuánto tiene que leer el host antes de soltar el control.
Elegir el driver correcto
CircuitPython tiene tres librerías para tarjetas SD y la diferencia de velocidad entre ellas es enorme. Elige según tu placa:
- sdioio: para placas con periférico SDMMC nativo. Requiere cablear las cuatro líneas de datos. Es la lectura SD más rápida disponible en CircuitPython.
- sdcardio: viene integrada en el firmware, no hay nada que instalar. En placas RP2350 (Metro RP2350, Fruit Jam) la tarjeta se auto monta al arrancar sin escribir código.
- adafruit_sdcard: Python puro, alrededor de 5 veces más lento que sdcardio. Úsala solo cuando sdcardio no esté compilada en el firmware de tu placa.
Una confusión común: en el RP2350 el módulo correcto es sdcardio, no sdioio, porque ahí el SDIO viene integrado y no se expone como módulo separado. En cambio el ESP32-S3, el STM32F405 y el SAMD51 exponen el periférico SDMMC crudo, así que usan sdioio. El RP2040 y el nRF52840 no tienen hardware SDMMC: siempre van por SPI sin importar cómo cablees.
Este diagrama te ayuda a decidir de un vistazo según el rendimiento que necesites:

Desactivar la presentación USB Mass Storage
Este es el cambio de mayor impacto sobre el tiempo de arranque. Al impedir que la tarjeta SD aparezca como una unidad de almacenamiento masivo (MSC) frente al USB, eliminas todo el escaneo del sistema operativo.
El único costo: no vas a poder acceder a la tarjeta desde tu computador mientras CircuitPython está corriendo. Para un datalogger que solo registra datos, ese intercambio vale totalmente la pena.
La forma fácil es por settings.toml. Agrega esta línea, requiere CircuitPython 10.2.1 o superior, y necesitas un ciclo de energía completo (desconectar y reconectar): un soft reset no alcanza.
CIRCUITPY_SDCARD_USB = false
La forma difícil es con un flag de compilación personalizado de CircuitPython. Para builds custom, el flag es:
CIRCUITPY_SDCARD_USB=0
Tamaño y formato de la tarjeta
Como ya viste, el mayor impacto después del USB está en el formato. La regla práctica: usa la tarjeta más chica que te alcance para tus datos. Una SDSC de 2GB o menos viene en FAT16 y reduce mucho el retardo de arranque, porque el host lee la tabla FAT completa en cada montaje y esa tabla es diminuta.
Esta es la relación entre capacidad, sistema de archivos y soporte en CircuitPython:
| Tipo de tarjeta | Capacidad | Sistema de archivos por defecto | Soporte en CircuitPython |
|---|---|---|---|
| SDSC | 2GB o menos | FAT16 | Totalmente soportado |
| SDHC | 4GB a 32GB | FAT32 | Totalmente soportado |
| SDXC | 64GB a 2TB | exFAT | Solo placas con CIRCUITPY_FULL_BUILD=1 |
| SDUC | más de 2TB | exFAT | No soportado |
Un dato útil sobre FAT16: todas las tarjetas SDSC producen una tabla FAT16 de unos 64KB sin importar su capacidad. Los formateadores eligen el tamaño de cluster más chico que mantenga el conteo de clusters bajo el techo de 65.525 de FAT16, lo que siempre cae cerca de 32.768 clusters por 2 bytes, o sea 64KB. Para tarjetas SDHC en FAT32, el formateador oficial de la SD Association usa clusters más grandes para achicar la tabla FAT y reducir la amplificación de escritura. Windows, en cambio, formatea por defecto con clusters de 4KB, lo que infla la tabla FAT pero desperdicia menos espacio en archivos chicos.
Patrones de escritura: cómo escribir importa tanto como la velocidad de la tarjeta
Aquí hay una trampa silenciosa que arruina el rendimiento de muchos dataloggers. Cada close() fuerza un flush de la tabla FAT y de la entrada de directorio, y eso es muy lento. Si abres y cierras el archivo en cada lectura, estás pagando ese costo miles de veces. Cuatro reglas para escribir bien:
- Abre el archivo una sola vez, fuera del bucle de captura, no en cada iteración.
- Usa modo binario (
wboab), no texto. El modo texto hace codificación en cada escritura. - Agrupa las escrituras chicas. Cada cruce de frontera de sector es un read modify write en la tarjeta. Acumula los datos en un bytearray y escríbelos todos juntos.
- flush() en lugar de close(). flush() confirma los datos sin cerrar el archivo. El intercambio de seguridad: si se corta la energía entre dos flush, pierdes lo que quedó en buffer desde el último flush. Por eso conviene llamar a flush() en checkpoints naturales, no después de cada byte.
Así se ve el código lento, el que abre y cierra en cada escritura:
while capturing:
with open("/sd/log.bin", "a") as f: # text mode
f.write(data) # opens and closes on every write
Y así se ve el código rápido, que abre una vez, escribe en binario y confirma con flush en checkpoints:
f = open("/sd/log.bin", "ab")
while capturing:
f.write(data)
if checkpoint:
f.flush() # commits data without closing
f.close()
Frecuencia máxima del bus SPI
Si vas por SPI (por ejemplo con un lector microSD conectado a un Arduino o ESP32), puedes ajustar la frecuencia del reloj. Estos son los valores de referencia:
- 4 MHz: seguro para cables largos o protoboard.
- 8 MHz: valor conservador por defecto.
- 16 a 24 MHz: buen techo para pistas cortas de PCB.
- 25 MHz: límite de la especificación SPI para SD; no lo subas más. Algunas tarjetas corren a 40 o 50 MHz pero arriesgas corrupción silenciosa y no ganas nada: lo que te frena es el sistema de archivos, no el reloj.
Para ajustar la frecuencia con sdcardio en modo SPI:
sd = sdcardio.SDCard(spi, board.SD_CS, baudrate=24_000_000) # up to 25 MHz
En SDIO hay más margen: el modo High Speed está especificado hasta 50 MHz. A diferencia de SPI, subir el reloj SDIO sí rinde de verdad, porque las lecturas escalan con el reloj y tienes 4 líneas de datos trabajando. Los 40 MHz están confirmados funcionando en el ESP32-S3 con sdioio, donde la velocidad de lectura subió notoriamente frente a las placas SPI. Para ajustarla con sdioio:
sd = sdioio.SDCard(
clock=board.SDIO_CLOCK,
command=board.SDIO_COMMAND,
data=board.SDIO_DATA,
frequency=40_000_000 # 40 MHz confirmed on ESP32-S3
)
Rendimiento de la tarjeta y la trampa de las velocidades UHS
No te dejes llevar por las etiquetas llamativas. Cualquier tarjeta Clase 10 es más que suficiente: CircuitPython topa alrededor de 2 MB/s, y hasta las tarjetas baratas llegan a eso. Las velocidades UHS-I (U3, A1, A2, SDR50) no aplican en modo SPI y no te van a ayudar. Una tarjeta carísima no te da nada extra en este contexto.

Ese círculo rojo marca el símbolo de Clase 10, que es justamente lo único que te importa mirar al comprar.
SPI contra SDIO: cuándo vale la pena la interfaz más rápida
La nomenclatura confunde porque el mismo resultado (la velocidad SDIO) se alcanza con nombres de módulo distintos según el chip. Esta tabla muestra exactamente qué usa cada MCU por debajo:
| MCU | Periférico SD por hardware | Módulo CircuitPython | Modo usado | Placas de ejemplo |
|---|---|---|---|---|
| RP2350 | SDMMC nativo | sdcardio | SDIO 4 bits (auto detectado) | Metro RP2350, Fruit Jam |
| ESP32-S3 | SDMMC nativo | sdioio | SDIO 4 bits (breakout cableado) | Feather ESP32-S3 más breakout |
| STM32F405 | SDMMC nativo | sdioio | SDIO 4 bits | Feather STM32F405 Express |
| SAMD51 | SDHC nativo | sdioio | SDIO 4 bits | Grand Central M4, Metro M4 |
| RP2040 | Ninguno | sdcardio | SPI 1 bit solamente | Feather RP2040 Adalogger |
| SAMD21 | Ninguno | sdcardio | SPI 1 bit solamente | Metro M0, Feather M0 |
| nRF52840 | Ninguno (QSPI es solo flash) | sdcardio | SPI 1 bit solamente | Feather nRF52840 |
Benchmarks: throughput medido en placas y drivers reales
Para cerrar, estos son los números medidos de escritura, lectura y registro de líneas por segundo. Sirven para calibrar expectativas: nota cómo la combinación SDIO más el driver correcto se despega del resto, y cómo adafruit_sdcard sobre SPI queda muy por detrás.
| Placa / Runtime | Driver | Interfaz | Escritura | Lectura | Registro |
|---|---|---|---|---|---|
| Metro RP2350 con Arduino SdFat | SdFat | SDIO | 568 kB/s | 10.309 kB/s | 74.162 líneas/s |
| Metro RP2350 con CircuitPython | sdcardio | SDIO | 696 kB/s | 1.333 kB/s | 15.151 líneas/s |
| STM32F405 con CircuitPython | sdioio | SDIO | 593 kB/s | 2.287 kB/s | medición no disponible |
| Fruit Jam (RP2350B) con CircuitPython | sdcardio | SDIO | 490 kB/s aprox | 980 kB/s aprox | 12.000 líneas/s aprox |
| Feather ESP32-S3 más breakout con CircuitPython | sdioio | SDIO 4 bits | 470 kB/s | 1.456 kB/s | 11.907 líneas/s |
| Feather RP2040 Adalogger con CircuitPython | sdcardio | SPI | 468 kB/s | 595 kB/s | 9.978 líneas/s |
| Grand Central M4 con CircuitPython | adafruit_sdcard | SPI | 120 kB/s aprox | 160 kB/s aprox | 160 líneas/s aprox |
| Feather RP2350 con CircuitPython | adafruit_sdcard | SPI | 19 kB/s | 24 kB/s | 479 líneas/s |
Fíjate en la última fila: adafruit_sdcard sobre SPI escribe a 19 kB/s, mientras que sdcardio sobre SDIO en la misma familia de chip llega a cientos de kB/s. Cambiar de librería, que no cuesta nada, te puede dar un salto de más de 30 veces.
Variantes y mejoras
Una vez que tienes la base andando, hay varias formas de llevar el proyecto más lejos:
- Datalogger con marca de tiempo: combina la tarjeta microSD con un módulo RTC DS3231 por I2C para que cada línea del log lleve fecha y hora exactas, incluso después de un corte de energía. Ideal para registrar temperatura, humedad o consumo a lo largo de días.
- Buffer en RAM antes de escribir: si tu sensor entrega datos muy rápido, acumula varias muestras en un bytearray en memoria y escribe a la SD solo cada cierto número de muestras. Reduces los cruces de sector y le sacas más throughput a la tarjeta, justo como muestran los benchmarks.
- Rotación de archivos por día: en lugar de un único log gigante, abre un archivo nuevo por fecha (por ejemplo log_2026_05_30.bin). Te queda más ordenado para analizar y evitas tablas de directorio enormes que ralentizan el montaje.
Personalización para Chile
Las placas Adafruit del tutorial original (Metro RP2350, Feather RP2040 Adalogger) traen la ranura microSD integrada, pero no es la única forma de aplicar esta guía. Si ya tienes un Arduino o un ESP32 sin ranura, en MechatronicStore consigues lo necesario para sumar lectura de SD por SPI, que es justo el camino que cubren las secciones de driver sdcardio y frecuencia SPI:
- Módulo datalogger para tarjeta microSD (SKU G-014) por $3.800: lector microSD compacto que se conecta por SPI. Perfecto para un datalogger con Arduino o ESP32.
- Shield datalogger para tarjeta de memoria SD (SKU G-016) por $3.990: usa tarjeta SD de tamaño completo y se monta directo sobre un Arduino Uno, cómodo para prototipos.
Una recomendación local concreta: para que esta guía rinda, no compres la tarjeta más grande, compra la más chica que te sirva. Una microSD Clase 10 de 2GB o menos, formateada en FAT16, te dará el mejor tiempo de arranque. Si solo encuentras tarjetas de 8GB o 16GB, igual funcionan, pero recuerda que el formato pesa más que la capacidad.
Recursos
- Tutorial original (inglés): SD card Optimization with CircuitPython por Mikey Sklar, Adafruit Learning System.
- Datos completos de benchmark: el set de datos publicado por el autor, referenciado en la guía original de Adafruit.
- Documentación adicional: librería sdcardio y librería sdioio en la documentación oficial de CircuitPython (docs.circuitpython.org).
Versión chilena con componentes en stock local en MechatronicStore.




