
RP2040-Firmware, die ein Toshiba MK4001MTD 0.85"-SDIO-Mikrolaufwerk als USB-Massenspeichergerät überbrückt und dabei den vollständigen SDIO-ATA-Protokollstapel von Grund auf implementiert, mit PIO-beschleunigten Lese-/Schreibvorgängen und Wiederherstellung fehlerhafter Sektoren.
RP2040 Pico-Firmware, die ein Toshiba MK4001MTD 0,85-Zoll-SDIO-Mikrolaufwerk als USB-Massenspeichergerät anbindet.

Das MK4001MTD ist ein 4-GB-Mikrolaufwerk, das ursprünglich im Nokia N91-Musiktelefon und in einigen anderen Geräten wie MP3-Playern oder USB-Laufwerken verwendet wurde, als Flash-Speicher noch recht teuer war.
Vielleicht haben Sie Einführungen gesehen, die behaupten, dieses Laufwerk verwende das MMC-Protokoll, aber das ist tatsächlich falsch. Ich habe dies eine Weile untersucht: Ich habe versucht, einen 8-Bit-MMCplus-Kartenleser zu bauen und verschiedene SD/MMC-Leser getestet, jedoch ohne Erfolg. Als letztes Mittel kaufte ich ein Nokia N91, um Logikspuren aufzuzeichnen und zu bestätigen, welches Protokoll es tatsächlich verwendet.
Hier ist das Foto, als ich versuchte, es mit meiner 8-Bit-MMCPlus-Leserplatine zu verwenden, und es stellte sich heraus, dass es kein MMC ist :(

Also besorgte ich mir schließlich ein N91, um Spuren aufzuzeichnen:

Im Gegensatz zu standardmäßigen ATA/CF-Mikrolaufwerken verwendet es eine SDIO-Schnittstelle mit ATA-Befehlen, die durch CMD52/CMD53 getunnelt werden. Kein vorhandener Treiber unterstützt dieses Protokoll, daher implementiert diese Firmware den gesamten Stack von Grund auf neu.
Das hat mich überrascht, da es einen SDIO-zu-ATA-Standard namens CE-ATA gibt. Aber wenn man sich die Veröffentlichungszeitleiste genau ansieht, kam CE-ATA später als dieses Laufwerk. Daher verlässt sich dieses Laufwerk vollständig auf SDIO-Befehle, und CE-ATA ist nicht verfügbar. CE-ATA hat zwei neue Befehle CMD60/CMD61 und verwendet CMD12/39, aber wie man an den Spuren sehen kann, verwendet es keinen davon.
Der zweite Hardware-Punkt, den es zu erwähnen gilt, ist, dass eine weitere Fehlinformation, die kursiert – dass es sich um eine 8-Bit-MMCPlus-Karte handele – nicht nur falsch ist, sondern dass die Pinbelegung auch nicht dem MMC-Standard folgt. Sie finden das Nokia N91 Service Manual mit einiger Dokumentation zur Pinbelegung: Während die Pinnummerierung dem MMCPlus-Standard folgt, tut dies die Pinzuordnung nicht. Dies ist ein wichtiges Detail, wenn Sie es selbst verdrahten: Es verwendet den gleichen MMC-Anschluss, aber die Pinzuordnung ist anders, mehr im Hardware-Abschnitt.
Abschließend sei angemerkt, dass dies gemeinsam mit Claude/OpenClaw entwickelt wurde. Ich habe die Logikspuren manuell gesammelt und einen Closed-Loop-Testaufbau für OpenClaw eingerichtet, um iterativ zu entwickeln – die Spuren zu analysieren und Funktionen zu implementieren. Die Dokumentation wird hauptsächlich von Claude verfasst; ich werde meine Notizen ebenfalls inline hinzufügen. Ich habe die Dokumentation auch selbst gelesen und überprüft, und sie sollte zuverlässig und leicht verständlich sein.
Einblicke in die Analyse der N91-Spuren finden Sie unter /docs/N91_TRACE_ANALYSIS.md; ich habe dort auch das N91-Service-Manual zusammen mit den rohen Logikspuren abgelegt.
Weitere Informationen im Blogbeitrag hier: https://www.willwhang.dev/Reading-MK4001MTD/
In Aktion sehen Sie es hier: https://youtu.be/GC4xil3_Bbc
Voll funktionsfähiger USB-Massenspeicher mit PIO-beschleunigtem Lesen/Schreiben und Leerlauf-Leistungsverwaltung.
| Metrik | Wert |
|---|---|
| Lesegeschwindigkeit | ~985 kB/s (USB Full-Speed begrenzt) |
| Schreibgeschwindigkeit | ~920 kB/s (USB Full-Speed begrenzt, beworbener Schreibcache) |
| Rohe SDIO-Seitengeschwindigkeit | ~2,35 MB/s Lesen / ~2,15 MB/s Schreiben (laufwerksbegrenzt) |
| Kapazität | 3,75 GB (7.862.400 Sektoren) |
| Dateisystem | FAT32 verifiziert (mount/unmount/fsck sauber) |
| Datenintegrität | Schreiben+Rücklesen verifiziert; CRC16 pro Block auf allen 4 DAT-Leitungen |
| Leerlauf-Standby | 5 s Leerlauf oder USB-Suspend → STANDBY SOFORT + Stromabschaltung |
USB Host ←→ USB MSC (TinyUSB) ←→ ATA Layer ←→ SDIO Layer (PIO) ←→ MK4001MTD
Die Firmware besteht aus vier Schichten:
USB MSC (msc_device.c) — TinyUSB Massenspeicherklasse. Übersetzt SCSI READ(10)/WRITE(10) in ATA-Sektoroperationen. 32 KB EP-Puffer, Batching von bis zu 64 Sektoren pro USB-Übertragung. Festplatten-I/O wird in beide Richtungen mit USB überlappt, wie bei einer echten ATA-USB-Brücke mit Caching-Laufwerk: Ein sequentieller Leseprefetcher holt das nächste Stück, während das vorherige zum Host streamt, und Schreibvorgänge werden gestapelt und geleert, während USB das nächste Stück empfängt. Das Gerät bewirbt seinen Schreibcache (Caching-Modusseite, WCE=1 – Hosts melden "Write cache: enabled" und geben SYNCHRONIZE CACHE bei fsync/unmount/suspend aus, was die Firmware respektiert). Ein fehlgeschlagenes Hintergrund-Flush wird als MEDIUM ERROR beim nächsten WRITE oder SYNCHRONIZE CACHE gemeldet; Schreibvorgänge auf bekanntermaßen fehlerhafte Sektoren nehmen einen strengen synchronen Pfad.
ATA-over-SDIO (ata_sdio.c) — Implementiert ATA-Befehle (IDENTIFY, READ SECTORS, WRITE SECTORS) durch Schreiben in ATA-Register, die in den Adressraum von SDIO-Funktion 1 über CMD52 abgebildet sind, und Überträgt Sektordaten über CMD53. 3-stufige Wiederholungslogik auf CMD-, Daten- und ATA-Ebene.
PIO SDIO (sdio_pio.c, sdio.pio) — Hardwarebeschleunigtes SDIO mithilfe des RP2040-PIO-Peripheriegeräts (4-Bit-Bus bei 10 MHz, 4 PIO-Zyklen pro Bit mit umgangenen Eingangssynchronisierern). Drei PIO-Programme teilen sich eine einzige Zustandsmaschine durch dynamischen Programmwechsel:
Pin/Power (sdio_hw.c) — GPIO-Initialisierung und HDD-Stromsteuerung. Die gesamte SDIO-Kommunikation verwendet PIO.
Menschliche Notizen: Interessanterweise zögerte Claude wirklich, SDIO in PIO zu implementieren, und es wurden viele Entwicklungszyklen damit verschwendet, zwischen PIO und Bit-Banging hin und her zu wechseln.
Das MK4001MTD präsentiert sich als SDIO-Karte mit einer I/O-Funktion. Die standardmäßige SDIO-Karteninitialisierung (CMD5/CMD3/CMD7) richtet den Bus ein, dann werden ATA-Register über SDIO-Befehle angesprochen:
Registerzugriff (CMD52): Jedes ATA-Register ist auf eine Funktion-1-Adresse abgebildet:
| Adresse | Register | Verwendung |
|---|---|---|
| 0x00 | DATA | CMD53-Ziel für Sektordaten |
| 0x01 | ERR/FEAT | Fehler (lesen) / Feature (schreiben) |
| 0x02 | SECCOUNT | Sektoranzahl |
| 0x03 | LBA_LO | LBA-Bits 0-7 |
| 0x04 | LBA_MID | LBA-Bits 8-15 |
| 0x05 | LBA_HI | LBA-Bits 16-23 |
| 0x06 | DEV/HEAD | Gerät/Kopf + LBA-Bits 24-27 |
| 0x07 | CMD/STATUS | Befehl (schreiben) / Status (lesen) |