Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
MK4001MTD-USB-Bridge — Firmware RP2040 que conecta un microdrive SDIO Toshiba MK4001MTD de 0.85" como un dispositivo de almacenamiento masivo USB, implementando la pila completa del protocolo SDIO-ATA desde cero con lecturas/escrituras aceleradas por PIO y recuperación de sectores defectuosos. | Kitploit
Herramientas/GitHubGitHub/will127534/mk4001mtd-usb-bridge
Seguridad de Sistemas EmbebidosIngeniería InversaRecuperación de DatosHacking de HardwareSeguridad de HardwareSeguridad de Hardware e IoTAnálisis de Firmware
GitHubwill127534/mk4001mtd-usb-bridge

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

MK4001MTD-USB-Bridge

Firmware RP2040 que conecta un microdrive SDIO Toshiba MK4001MTD de 0.85" como un dispositivo de almacenamiento masivo USB, implementando la pila completa del protocolo SDIO-ATA desde cero con lecturas/escrituras aceleradas por PIO y recuperación de sectores defectuosos.

Ver Repositorio
4212hace 1 mesRevisado por Kitploit

MK4001MTD USB Bridge

Firmware RP2040 Pico que puentea un microdrive SDIO Toshiba MK4001MTD de 0.85" como dispositivo de almacenamiento masivo USB. _DSC1170 _DSC1354

El MK4001MTD es un microdrive de 4 GB originalmente usado en el Nokia N91 y otros dispositivos, como reproductores MP3 o unidades USB, cuando el almacenamiento flash aún era bastante caro.

Quizás hayas visto presentaciones que afirman que esta unidad usa el protocolo MMC, pero eso es incorrecto. He estado investigando esto por un tiempo: intenté construir un lector de tarjetas MMCplus de 8 bits y probé diferentes lectores SD/MMC sin éxito. Como último recurso, compré un Nokia N91 para capturar trazas lógicas y confirmar qué protocolo usa realmente.

Aquí la foto cuando intentaba usarlo con mi placa lectora 8bit-MMCPlus, y resulta que no es MMC :( _DSC0484

Así que terminé comprando el N91 para recolectar trazas: _DSC1093 _DSC1131

A diferencia de los microdrives ATA/CF estándar, utiliza una interfaz SDIO con comandos ATA tunelizados a través de CMD52/CMD53. Ningún controlador existente soporta este protocolo, por lo que este firmware implementa la pila completa desde cero.

Esto me sorprendió, porque existe un estándar SDIO-to-ATA llamado CE-ATA. Pero si observas la línea de tiempo de lanzamiento, CE-ATA llegó después que esta unidad. Como resultado, esta unidad depende completamente de comandos SDIO, y CE-ATA no está disponible. CE-ATA tiene dos nuevos comandos CMD60/CMD61 y utiliza CMD12/39, pero se puede ver en las trazas que no usa ninguno de ellos.

El segundo punto de hardware es que otra desinformación flotando —afirmando que es una tarjeta MMCPlus de 8 bits— no solo es falsa, sino que el pinout tampoco sigue el estándar MMC. Puedes encontrar el manual de servicio del Nokia N91 con algo de documentación sobre el pinout: aunque la numeración de pines sigue el estándar MMCPlus, la asignación de pines no. Este es un detalle importante si lo estás cableando tú mismo: usa el mismo conector MMC, pero la asignación de pines es diferente, más en la sección de Hardware.

Finalmente, ten en cuenta que esto es co-desarrollado con Claude/OpenClaw. Yo recolecté las trazas lógicas manualmente y configuré una estación de prueba de bucle cerrado para que OpenClaw iterara en el desarrollo —analizando las trazas e implementando funcionalidades. La documentación será principalmente escrita por Claude; también agregaré mis notas inline. También he leído y verificado la documentación yo mismo, y debería ser confiable y fácil de seguir.

Para obtener información sobre el análisis de la traza del N91, está en /docs/N91_TRACE_ANALYSIS.md; también he puesto allí el manual de servicio del N91 junto con las trazas lógicas sin procesar.

Ver más en la publicación del blog aquí: https://www.willwhang.dev/Reading-MK4001MTD/
Verlo en acción aquí: https://youtu.be/GC4xil3_Bbc

Estado

Almacenamiento masivo USB completamente funcional con lecturas/escrituras aceleradas por PIO y gestión de energía en reposo.

Cómo funciona

Arquitectura

root@kitploit:~
USB Host ←→ USB MSC (TinyUSB) ←→ Capa ATA ←→ Capa SDIO (PIO) ←→ MK4001MTD

El firmware tiene cuatro capas:

  1. USB MSC (msc_device.c) — TinyUSB Mass Storage Class. Traduce SCSI READ(10)/WRITE(10) a operaciones de sectores ATA. Buffer EP de 32 KB, agrupando hasta 64 sectores por transferencia USB. La E/S de la unidad se superpone con USB en ambas direcciones, como un puente ATA-USB real con un disco de caché: un pre-buscador de lectura secuencial obtiene el siguiente bloque mientras el anterior se transmite al host, y las escrituras se ponen en cola y se vacían mientras USB recibe la siguiente pieza. El dispositivo anuncia su caché de escritura (Página de modo Caching, WCE=1 — los hosts reportan "Write cache: enabled" y emiten SYNCHRONIZE CACHE en fsync/desmontaje/suspensión, que el firmware respeta). Un vaciado en segundo plano fallido se refleja como MEDIUM ERROR en la próxima WRITE o SYNCHRONIZE CACHE; las escrituras a sectores malos conocidos siguen una ruta síncrona estricta.

  2. ATA-over-SDIO (ata_sdio.c) — Implementa comandos ATA (IDENTIFY, READ SECTORS, WRITE SECTORS) escribiendo en registros ATA mapeados en el espacio de direcciones de la función SDIO 1 a través de CMD52, y transfiriendo datos de sectores a través de CMD53. Lógica de reintento de 3 niveles a nivel de CMD, datos y ATA.

  3. PIO SDIO (sdio_pio.c, sdio.pio) — SDIO acelerado por hardware usando el periférico PIO del RP2040 (bus de 4 bits a 10 MHz, 4 ciclos PIO por bit con sincronizadores de entrada omitidos). Tres programas PIO comparten una sola máquina de estados mediante intercambio dinámico de programas:

    • CMD tx/rx (24 instrucciones) — envía comandos SDIO y recibe respuestas
    • DAT read (12 instrucciones) — lee bloques de datos del bus DAT de 4 bits mediante DMA de intercambio de bytes (sin reempaquetado del CPU); el CRC del bloque N se verifica mientras el bloque N+1 fluye
    • DAT write (14 instrucciones) — escribe bloques de datos en el bus DAT de 4 bits mediante DMA, con recepción de estado CRC incorporada y espera ocupada; el flujo de nibbles del bloque N+1 se construye mientras el bloque N se transfiere
  4. () — Inicialización de GPIO y control de energía del HDD. Toda la comunicación SDIO usa PIO.

Notas humanas: Curiosamente, Claude fue muy reacio a implementar SDIO en PIO, y se desperdiciaron muchos ciclos de desarrollo yendo y viniendo entre PIO y bit-banging.

El Protocolo SDIO-ATA

El MK4001MTD se presenta como una tarjeta SDIO con una función de E/S. La inicialización estándar de tarjetas SDIO (CMD5/CMD3/CMD7) configura el bus, luego los registros ATA se acceden mediante comandos SDIO:

Acceso a registros (CMD52): Cada registro ATA está mapeado a una dirección de función 1:

Transferencia de datos (CMD53): Los datos de sectores se transfieren emitiendo CMD53 en modo bloque apuntando al registro DATA (dirección 0x00). Para lecturas de múltiples sectores, un solo CMD53 con block_count=N transfiere N × 512 bytes en una sola transacción SDIO multi-bloque.

Señalización de interrupción: La unidad señala la preparación del sector activando una interrupción SDIO (bit INT_PENDING 1 en el registro CCCR 0x05). La lectura del registro ATA STATUS borra la interrupción.

Ruta de Lectura (PIO Multi-Bloque)

Para una lectura de 16 sectores:

root@kitploit:~
1. Escribir registros ATA mediante PIO CMD52:
     SECCOUNT=16, LBA_LO/MID/HI, DEV/HEAD=0xE0, CMD=0x20

2. Sondear STATUS mediante CMD52 hasta que DRQ (bit 3) esté activo

3. Cambiar PIO al programa de lectura DAT
4. Enviar CMD53: block_mode=1, fn=1, addr=0x0000, block_count=16

5. Lectura DAT PIO: para cada uno de los 16 bloques:
   a. Esperar bit de inicio (todas las líneas DAT en bajo)
   b. DMA de 1024 nibbles (512 bytes) desde FIFO RX de PIO al búfer
   c. Esperar a que SM termine de enviar los nibbles de CRC+fin (sondear PC de SM)
   d. Reempaquetar nibbles → bytes en el lugar

6. Cambiar PIO de nuevo al programa CMD

Ruta de Escritura (PIO Multi-Bloque)

Para una escritura de 16 sectores:

root@kitploit:~
1. Escribir registros ATA mediante PIO CMD52:
     SECCOUNT=16, LBA, DEV/HEAD=0xE0, CMD=0x30

2. Sondear STATUS mediante CMD52 hasta que DRQ (bit 3) esté activo
   (STATUS 0xD8 = BSY+DRQ tratado como DRQ listo, según traza N91)

3. Cambiar PIO al programa de escritura DAT
4. Enviar CMD53: block_mode=1, fn=1, addr=0x0000, block_count=16

5. Escritura DAT PIO: para cada uno de los 16 bloques:
   a. Precalcular CRC16-CCITT por línea DAT (4 CRC independientes)
   b. Construir flujo de nibbles: inicio(0x0) + datos(1024 nibbles) + CRC(16) + fin(0xF)
   c. DMA del flujo de nibbles al FIFO TX de PIO
   d. PIO saca todos los nibbles, luego:
      - Cambia DAT a entrada
      - Genera 16 ciclos para el estado CRC desde la tarjeta
      - Sonda DAT0 hasta que la tarjeta libera el estado ocupado
      - Dispara IRQ 0 para señalar finalización del bloque

6. Cambiar PIO de nuevo al programa CMD

Intercambio de Programas PIO

El PIO del RP2040 tiene 32 ranuras de instrucción por bloque. Nuestros tres programas suman 55 instrucciones, por lo que no pueden coexistir. En su lugar, se usa una sola SM0 en PIO0, y los programas se intercambian escribiendo directamente en la memoria de instrucciones del PIO:

root@kitploit:~
static void load_program_raw(const pio_program_t *program) {
    for (uint i = 0; i < program->length; i++)
        pio->instr_mem[FIXED_OFFSET + i] = program->instructions[i];
}

Esto evita el asignador pio_add_program/pio_remove_program del SDK. El intercambio de programas toma ~1 µs. Cada intercambio va seguido de una reinicialización específica del programa que establece los mapeos de pines, la dirección de desplazamiento y el divisor de reloj.

Gestión de Energía

El análisis de las trazas lógicas del Nokia N91 revela una gestión de energía agresiva:

  • Modo inactivo: STANDBY IMMEDIATE (0xE0) cada ~7.5 segundos, incluso sin E/S. Cada standby desencadena una reinicialización completa de SDIO (CMD5 reintento → CMD3 → CMD7 → configuración CCCR). Se observaron 28 ciclos de standby en una sesión inactiva.
  • Modo activo: Standby emitido entre ráfagas de E/S (24 ciclos durante operaciones de archivos en unidad USB).
  • No se observaron otros comandos de energía (IDLE, SLEEP, CHECK POWER MODE) ni accesos al registro de energía CCCR.

El firmware replica este comportamiento con un tiempo de espera de inactividad configurable:

root@kitploit:~
#define IDLE_STANDBY_MS 5000  // en main.c

Dos rutas desencadenan el corte de energía del HDD:

  1. Tiempo de espera de inactividad (5 segundos) — el bucle principal detecta que no hay actividad de E/S
  2. Suspensión USB — el host suspende el puerto USB

Ambas rutas envían ATA STANDBY IMMEDIATE (0xE0) para vaciar la caché de escritura y estacionar las cabezas, luego cortan la energía mediante GP9.

Secuencia de activación (desencadenada por la primera READ/WRITE después del corte):

  1. Encender HDD, esperar 500ms para estabilización de alimentación
  2. Reinicialización SDIO basada en PIO: CMD5 (OCR) → 10ms de espera → CMD3 (RCA) → CMD7 (seleccionar)
  3. Cambiar a reloj PIO rápido, configurar CCCR mediante CMD52 (bus de 4 bits, bloques de 512B, habilitar fn1)
  4. Sondear fn1 listo (bit IO_READY del CCCR 1)
  5. Sondear estado DRDY estilo N91 durante 30ms hasta que la unidad esté lista para ATA

Manejo de Sectores Defectuosos

Cuando una transferencia multi-sector se encuentra con un sector defectuoso:

  1. Falla la lectura del fragmento → recuperación de errores (IO_ABORT + reinicio fn1, ~500ms)
  2. Recurre a E/S por sector para identificar el bloque fallido con precisión
  3. La capa ATA espera lo suficiente para capturar los bits finales de STATUS/ERROR en lugar de colapsar la falla en un DRQ timeout genérico
  4. Cualquier bloque no recuperado falla el comando SCSI inmediatamente con MEDIUM ERROR (lectura: 03/11/00, escritura: 03/0C/00)
  5. LBA del sector defectuoso en caché → las lecturas repetidas fallan rápidamente sin golpear nuevamente la unidad (protección anti-golpeteo contra tormentas de reintentos del host)
  6. Las escrituras siempre tocan el medio, según SBC — una escritura exitosa a un LBA defectuoso en caché lo elimina de la caché, exactamente como una unidad que limpia un sector pendiente

El punto 6 no es académico: esta unidad tenía un sector ilegible de larga data en LBA 1952 (READ: ST=0x51 ERR ERR=0x40 UNC). Una vez que el puente permitió que una escritura realmente llegara, la unidad reescribió el sector y se ha leído limpio desde entonces:

root@kitploit:~
[ATA] FAST-RD: ST=0x51 ERR ERR=0x40 UNC LBA=1952
[MSC] BAD SECTOR read LBA=1952
[MSC] Bad sector LBA=1952 repaired by write

Construcción

Prerrequisitos

  • Raspberry Pi Pico SDK — stock, sin modificar, fijado en 2.2.0
  • Cadena de herramientas ARM (arm-none-eabi-gcc)
  • CMake

La versión del SDK está fijada: si PICO_SDK_PATH está definido (variable de entorno o de CMake), se usa y su versión se verifica contra la fijación — una discrepancia falla la configuración con instrucciones (anular con -DMK4001_ALLOW_SDK_MISMATCH=ON). Sin PICO_SDK_PATH, la versión fijada del SDK se obtiene de GitHub automáticamente durante la configuración, por lo que un simple git clone && cmake && make es totalmente reproducible.

El firmware necesita un controlador de clase MSC de TinyUSB parcheado (datos de sentido de aplicación preservados en errores de lectura/escritura + una página de modo Caching con WCE=1). Ese archivo está incluido en este repositorio en lib/tinyusb_patched/msc_device.c — la compilación lo compila automáticamente en lugar de la copia del SDK, por lo que nunca se necesita cirugía del SDK. El diff contra el TinyUSB oficial (0.18.0, tal como se incluye con pico-sdk 2.2.0) está en lib/tinyusb_patched/; la fijación del SDK existe precisamente porque este archivo incluido debe seguir el TinyUSB del SDK.

Compilar y Grabar

root@kitploit:~
cd /home/pi/mk4001_bridge/build
cmake ..
make -j4

sudo openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg \
  -c "adapter speed 1000" -c "init" -c "reset halt" -c "sleep 200" \
  -c "program /home/pi/mk4001_bridge/build/mk4001_bridge.elf verify" \
  -c "reset run" -c "exit"

Cableado del Hardware

Nota: GP0 y GP1 están muertos en esta unidad Pico específica. Todas las asignaciones de pines SDIO están desplazadas +2.

Notas humanas: Claude se equivocó aquí porque no se dio cuenta de que GP0 y GP1 estaban siendo usados para la terminal UART en su configuración de compilación. Siguió olvidándolo, hasta el punto de que simplemente moví los GPIOs SDIO fuera de esa UART.

HDD_PWR no es necesario. No tienes que reiniciar la unidad para usarla; es más una conveniencia de desarrollo para reiniciar el HDD cuando muchas cosas están hardcodeadas. Dicho esto, si quieres ahorrar energía, puedes usar esa señal, pero puede manejar un reinicio en caliente sin problemas.

Verás mensajes de depuración a través de UART. No van a través de USB-CDC porque fue más fácil para Claude configurar un enlace de registro UART a USB separado que no se desconecte ni se vuelva inestable durante el desarrollo temprano.

El registro UART también informa la temperatura de la unidad cada 30 segundos mientras la unidad está activa ([TEMP] drive temperature: 29 C). El sensor se descubrió mediante ingeniería inversa del comando de proveedor Toshiba 0xC2 — el N91 lo lee al inicio de cada sesión de la unidad para hacer cumplir sus límites de temperatura de funcionamiento del HDD. Detalles en docs/N91_TRACE_ANALYSIS.md §4.

Aquí hay un ejemplo del registro:

root@kitploit:~
========================================
  MK4001MTD USB Bridge v0.11
  SDIO-ATA → USB Mass Storage (PIO)
========================================

[MAIN] Pre-delay 5000ms...
[PIO] Init OK: clkdiv=3.12 (~10.0 MHz), CMD@0
[MAIN] Power cycling HDD...
[SDIO] HDD power OFF
[SDIO] HDD power ON
[MAIN] SDIO init (PIO)...
[SDIO] CMD5 ready (OCR=0x901F8000)
[SDIO] RCA=0x0001
[SDIO] fn1 ready (attempt 0)
[MAIN] ATA IDENTIFY...
[ATA] IDENTIFY complete
Model:    [TOSHIBA MK4001MTD]
Serial:   [           763B004HA]
Firmware: [VH173A]
Sectors:  7862400 (3839 MB)
SMART:    not supported (supported=0, enabled=0)
IDENTIFY: W0=0040 W47=0000 W49=0000 W59=0000
  ATA W80=0000  Cmd W82=0000 W83=0000 W84=0000
  En  W85=0000 W86=0000 W87=0000  W89=0008 W128=0001

[DIAG] === Drive Diagnostics ===
[DIAG] Standard SMART: not supported (IDENTIFY W82 bit0 = 0)
[DIAG] Toshiba vendor CMD 0xC2:
  FEAT=0x01 unknown_01                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x02 unknown_02                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x03 unknown_03                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x04 unknown_04                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x10 diag_10 (LBA_LO varies)          → SC=00 LBA=00/00/00 ST=50
  FEAT=0x11 diag_11                          → SC=00 LBA=00/00/00 ST=50
  FEAT=0x12 diag_12 (LBA_LO varies)          → SC=00 LBA=01/00/00 ST=50
  FEAT=0x20 query_20 (N91: SC=0xFF always)   → SC=FE LBA=00/FF/00 ST=50
  FEAT=0x21 query_21 (N91: SC varies per boot) → SC=1B LBA=00/FF/00 ST=50

[MAIN] MBR: valid 0x55AA
[MAIN] Warming up...
[MAIN] PIO OK, STATUS=0x50
[MAIN] Drive: 7862400 sectors (3839 MB)
[MAIN] Ready.
[PWR] Idle 5000ms → STANDBY + power gate
[PWR] STANDBY IMMEDIATE → power gate
[SDIO] HDD power OFF

Finalmente, aquí está el cableado a la unidad real.
_DSC1176-2 Aquí hay un recorte del esquema del N91; también puedes mapear el número de pin. image

Nota al margen: esta es una unidad de 3V, pero creo que 3.3V está bien, principalmente es para ahorrar trabajo de cambio de nivel.

¡El HW diseñado específicamente para esta unidad está en /hardware! image

Archivos Fuente

Historial de Versiones

Pruebas

root@kitploit:~
# Verificar que el dispositivo apareció
lsblk -dno NAME,MODEL | grep MK4001

# Prueba del sistema de archivos — montar, copiar archivos, verificar
sudo mount /dev/sdX1 /mnt/mk4001
cp /tmp/testfile /mnt/mk4001/
sync
md5sum /tmp/testfile /mnt/mk4001/testfile    # deberían coincidir
sudo umount /mnt/mk4001

# Benchmarks de velocidad (dispositivo sin procesar, NO montar primero — dañará el sistema de archivos)
# Usar un offset seguro más allá del sistema de archivos o una unidad sin particionar
sudo dd if=/dev/sdX of=/dev/null bs=64k count=128 iflag=direct     # lectura
sudo dd if=/dev/zero of=/dev/sdX bs=64k count=64 oflag=direct seek=1024  # escritura (offset más allá del FS)

Notas humanas aquí, dato curioso: Cuando comenzó a hacer pruebas de velocidad, realmente hizo dd directamente a la unidad y dañó los sistemas de archivos... Afortunadamente, eso no importa mucho durante los desarrollos, pero ten siempre en cuenta cuando manejes tu configuración de OpenClaw.

Licencia

No me importa.

Descargar herramienta
MétricaValor
Velocidad de lectura~985 kB/s (limitado por USB full-speed)
Velocidad de escritura~920 kB/s (limitado por USB full-speed, caché de escritura anunciada)
Velocidad bruta lado SDIO~2.35 MB/s lectura / ~2.15 MB/s escritura (limitado por la unidad)
Capacidad3.75 GB (7,862,400 sectores)
Sistema de archivosFAT32 verificado (mount/unmount/fsck limpio)
Integridad de datosLectura+reescritura verificada; CRC16 por bloque en las 4 líneas DAT
Standby en reposo5 s inactivo o suspensión USB → STANDBY IMMEDIATE + corte de energía
Pin/Power
sdio_hw.c
DirecciónRegistroUso
0x00DATAObjetivo CMD53 para datos de sector
0x01ERR/FEATError (lectura) / Feature (escritura)
0x02SECCOUNTConteo de sectores
0x03LBA_LOLBA bits 0-7
0x04LBA_MIDLBA bits 8-15
0x05LBA_HILBA bits 16-23
0x06DEV/HEADDispositivo/Cabeza + LBA bits 24-27
0x07CMD/STATUSComando (escritura) / Estado (lectura)
GPIO del PicoFunciónNotas
GP2SDIO_CLKSalida de reloj del host
GP3SDIO_CMDLínea de comando bidireccional
GP4SDIO_DAT0Bit de datos 0
GP5SDIO_DAT1Bit de datos 1
GP6SDIO_DAT2Bit de datos 2
GP7SDIO_DAT3Bit de datos 3
GP9HDD_ENHabilitación de energía de la unidad (HIGH=encendido)
GP12UART TXSalida de depuración @ 115200
GP13UART RXEntrada de depuración
GP16LED: Energía HDDActivo bajo
GP17LED: HDD SaludableActivo bajo
GP18LED: LecturaActivo bajo
GP19LED: EscrituraActivo bajo
ArchivoLíneasPropósito
main.c210Inicialización, standby inactivo, suspensión/reanudación USB
msc_device.c400Callbacks USB MSC, activación por corte de energía, caché de sectores defectuosos
ata_sdio.c390Comandos ATA, recuperación de errores, diagnósticos de proveedor
sdio_pio.c635PIO SDIO: CMD52, CMD53 lectura/escritura, intercambio de programas, CRC16
sdio_hw.c45Inicialización de pines + control de energía del HDD
sdio.pio200Ensamblador PIO + ayudantes de inicialización del SDK C
led.h37Ayudantes de LED (GP16–GP19, activo bajo)
usb_descriptors.c77Descriptores de dispositivo/configuración/cadena USB
tusb_config.h20Configuración de TinyUSB (MSC, búfer EP de 32KB)
VersiónLecturaEscrituraCambio Clave
v0.1–v0.3105 kB/s93 kB/sSDIO bit-bang, CRC16, lógica de reintentos
v0.5374 kB/s—PIO de una sola SM, intercambio directo de memoria de instrucciones
v0.6583 kB/s93 kB/sLecturas CMD53 multi-bloque, corrección de drenaje de reloj CRC
v0.8588 kB/s274 kB/sEscrituras PIO, corrección de vaciado OSR
v0.9475 kB/s371 kB/sFragmentos de 64 sectores, verificación de lectura CRC16
v0.10453 kB/s329 kB/sReasignación de LED, pin HDD EN, UART en GP12/GP13
v0.11~450 kB/s~340 kB/sCorte de energía HDD, activación PIO, sentido de sector defectuoso, suspensión USB
v0.12~985 kB/s~920 kB/sSuperposición unidad/USB (pre-búsqueda de lectura + caché de escritura anunciada con escritura diferida), bloques PIO en pipeline, DMA bswap, bucles PIO de 4 ciclos, semántica de sector defectuoso estilo SBC (reparación por escritura), controlador TinyUSB MSC incluido