Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
MK4001MTD-USB-Bridge — Firmware RP2040 faisant le pont entre un microdrive SDIO Toshiba MK4001MTD 0,85" et un périphérique de stockage de masse USB, implémentant la pile de protocole SDIO-ATA complète à partir de zéro avec des lectures/écritures accélérées par PIO et la récupération des secteurs défectueux. | Kitploit
Outils/GitHubGitHub/will127534/mk4001mtd-usb-bridge
Sécurité des Systèmes EmbarquésRétro-ingénierieRécupération de DonnéesHacking MatérielSécurité MatérielleSécurité Matériel et IoTAnalyse de Micrologiciel
GitHubwill127534/mk4001mtd-usb-bridge

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →

MK4001MTD-USB-Bridge

Voir le dépôt
4212il y a 1 moisVérifié par Kitploit

À propos

Firmware RP2040 faisant le pont entre un microdrive SDIO Toshiba MK4001MTD 0,85" et un périphérique de stockage de masse USB, implémentant la pile de protocole SDIO-ATA complète à partir de zéro avec des lectures/écritures accélérées par PIO et la récupération des secteurs défectueux.

Partager

Pont USB MK4001MTD

Micrologiciel pour RP2040 Pico qui fait le pont entre un microdrive Toshiba MK4001MTD 0,85" SDIO et un périphérique de stockage de masse USB. _DSC1170 _DSC1354

Le MK4001MTD est un microdrive de 4 Go initialement utilisé dans le Nokia N91 (téléphone musical) et certains autres appareils, comme des lecteurs MP3 ou des clés USB, à une époque où le stockage flash était encore assez cher.

Vous avez peut-être vu des présentations affirmant que ce disque utilise le protocole MMC, mais c'est en fait incorrect. J'ai enquêté là-dessus un moment : j'ai essayé de construire un lecteur de carte MMCplus 8 bits et testé différents lecteurs SD/MMC sans succès. En dernier recours, j'ai acheté un Nokia N91 pour capturer des traces logiques et confirmer quel protocole il utilise réellement.

Voici la photo de ma tentative d'utilisation avec ma carte lecteur 8-bit-MMCPlus, et il s'avère que ce n'est pas du MMC :( _DSC0484

J'ai donc fini par obtenir un N91 pour collecter des traces : _DSC1093 _DSC1131

Contrairement aux microdrives ATA/CF standard, il utilise une interface SDIO avec des commandes ATA tunnelisées via CMD52/CMD53. Aucun pilote existant ne prend en charge ce protocole, donc ce micrologiciel implémente la pile complète à partir de zéro.

Cela m'a surpris, car il existe une norme SDIO vers ATA appelée CE-ATA. Mais si l'on regarde attentivement la chronologie des versions, CE-ATA est arrivée après ce disque. Par conséquent, ce disque repose entièrement sur les commandes SDIO, et CE-ATA n'est pas disponible. CE-ATA a deux nouvelles commandes CMD60/CMD61 et utilise CMD12/39, mais on voit d'après les traces qu'il n'en utilise aucune.

Le second point matériel à mentionner est qu'une autre désinformation qui circule — affirmant qu'il s'agit d'une carte MMCPlus 8 bits — est non seulement fausse, mais en plus le brochage ne correspond pas non plus à la norme MMC. Vous pouvez trouver le manuel de service du Nokia N91 avec une documentation sur le brochage : bien que la numérotation des broches suive la norme MMCPlus, le mappage des broches ne la suit pas. C'est un détail important si vous câblez vous-même : il utilise le même connecteur MMC, mais le mappage des broches est différent, plus d'informations dans la section Matériel.

Enfin, notez que ce projet est co-développé avec Claude/OpenClaw. J'ai collecté les traces logiques manuellement et mis en place une station de test en boucle fermée pour qu'OpenClaw puisse itérer sur le développement — analyser les traces et implémenter les fonctionnalités. La documentation sera principalement rédigée par Claude ; j'ajouterai mes notes en ligne également. J'ai moi-même lu et vérifié la documentation, elle devrait être fiable et facile à suivre.

Pour des informations sur l'analyse de la trace N91, consultez /docs/N91_TRACE_ANALYSIS.md. J'ai également mis le manuel de service N91 ainsi que les traces logiques brutes.

Voir plus dans l'article de blog ici : https://www.willwhang.dev/Reading-MK4001MTD/
Voir en action ici : https://youtu.be/GC4xil3_Bbc

Statut

Stockage de masse USB entièrement fonctionnel avec lectures/écritures accélérées par PIO et gestion de l'alimentation en veille.

Fonctionnement

Architecture

root@kitploit:~
Hôte USB ←→ USB MSC (TinyUSB) ←→ Couche ATA ←→ Couche SDIO (PIO) ←→ MK4001MTD

Le micrologiciel comporte quatre couches :

  1. USB MSC (msc_device.c) — Classe de stockage de masse TinyUSB. Traduit SCSI READ(10)/WRITE(10) en opérations de secteurs ATA. Tampon EP de 32 Ko, regroupement jusqu'à 64 secteurs par transfert USB. Les E/S du disque sont chevauchées avec l'USB dans les deux sens, comme un véritable pont ATA-USB avec un disque à cache : un préfetcheur de lecture séquentielle récupère le bloc suivant pendant que le précédent est envoyé à l'hôte, et les écritures sont mises en scène et vidées pendant que l'USB reçoit le morceau suivant. Le périphérique annonce son cache d'écriture (page de mode Caching, WCE=1 — les hôtes rapportent « Write cache: enabled » et émettent SYNCHRONIZE CACHE à fsync/démontage/suspension, ce que le micrologiciel respecte). Un vidage en arrière-plan qui échoue se manifeste par une MEDIUM ERROR sur le prochain WRITE ou SYNCHRONIZE CACHE ; les écritures sur des secteurs connus comme défectueux empruntent un chemin synchrone strict.

  2. ATA sur SDIO (ata_sdio.c) — Implémente les commandes ATA (IDENTIFY, READ SECTORS, WRITE SECTORS) en écrivant dans les registres ATA mappés dans l'espace d'adressage de la fonction SDIO 1 via CMD52, et en transférant les données de secteur via CMD53. Logique de nouvelle tentative à 3 niveaux (CMD, données et ATA).

  3. PIO SDIO (sdio_pio.c, sdio.pio) — SDIO accéléré par matériel utilisant le périphérique PIO du RP2040 (bus 4 bits à 10 MHz, 4 cycles PIO par bit avec synchroniseurs d'entrée contournés). Trois programmes PIO partagent une seule machine d'état via un échange dynamique de programmes :

    • Envoi/réception CMD (24 instructions) — envoie les commandes SDIO et reçoit les réponses
    • Lecture DAT (12 instructions) — lit les blocs de données du bus DAT 4 bits via un DMA d'inversion d'octets (pas de réorganisation par le CPU) ; le CRC du bloc N est vérifié pendant que le bloc N+1 défile
    • Écriture DAT (14 instructions) — écrit les blocs de données sur le bus DAT 4 bits via DMA, avec réception d'état CRC intégrée et attente d'occupé ; le flux de nibbles du bloc N+1 se construit pendant que le bloc N est transféré

Notes humaines : Fait intéressant, Claude était vraiment réticent à implémenter le SDIO en PIO, et de nombreux cycles de développement ont été perdus à faire des allers-retours entre PIO et bit-bang.

Le protocole SDIO-ATA

Le MK4001MTD se présente comme une carte SDIO avec une fonction d'E/S. L'initialisation standard de carte SDIO (CMD5/CMD3/CMD7) configure le bus, puis les registres ATA sont accédés via des commandes SDIO :

Accès aux registres (CMD52) : Chaque registre ATA est mappé à une adresse de la fonction 1 :

Transfert de données (CMD53) : Les données de secteur sont transférées en émettant CMD53 en mode bloc, ciblant le registre DATA (adresse 0x00). Pour des lectures multi-secteurs, un seul CMD53 avec block_count=N transfère N × 512 octets en une seule transaction multi-bloc SDIO.

Signalisation d'interruption : Le disque signale la disponibilité d'un secteur en activant une interruption SDIO (bit INT_PENDING 1 dans le registre CCCR 0x05). La lecture du registre ATA STATUS efface l'interruption.

Chemin de lecture (PIO multi-bloc)

Pour une lecture de 16 secteurs :

root@kitploit:~
1. Écrire les registres ATA via PIO CMD52 :
     SECCOUNT=16, LBA_LO/MID/HI, DEV/HEAD=0xE0, CMD=0x20

2. Interroger STATUS via CMD52 jusqu'à ce que DRQ (bit 3) soit mis à 1

3. Échanger PIO vers le programme de lecture DAT
4. Envoyer CMD53 : block_mode=1, fn=1, addr=0x0000, block_count=16

5. Lecture DAT PIO : pour chacun des 16 blocs :
   a. Attendre le bit de départ (toutes les lignes DAT à l'état bas)
   b. DMA de 1024 nibbles (512 octets) depuis la FIFO RX PIO vers le tampon
   c. Attendre que la SM ait fini d'horloger les nibbles CRC+fin (interroger PC de la SM)
   d. Réorganiser les nibbles → octets sur place

6. Échanger PIO vers le programme CMD

Chemin d'écriture (PIO multi-bloc)

Pour une écriture de 16 secteurs :

root@kitploit:~
1. Écrire les registres ATA via PIO CMD52 :
     SECCOUNT=16, LBA, DEV/HEAD=0xE0, CMD=0x30

2. Interroger STATUS via CMD52 jusqu'à ce que DRQ (bit 3) soit mis à 1
   (STATUS 0xD8 = BSY+DRQ traité comme DRQ prêt, d'après la trace N91)

3. Échanger PIO vers le programme d'écriture DAT
4. Envoyer CMD53 : block_mode=1, fn=1, addr=0x0000, block_count=16

5. Écriture DAT PIO : pour chacun des 16 blocs :
   a. Précalculer CRC16-CCITT par ligne DAT (4 CRC indépendants)
   b. Construire le flux de nibbles : start(0x0) + data(1024 nibbles) + CRC(16) + end(0xF)
   c. Envoyer par DMA le flux de nibbles vers la FIFO TX PIO
   d. Le PIO horloge tous les nibbles, puis :
      - Passe DAT en entrée
      - Horloge 16 cycles pour l'état CRC de la carte
      - Interroge DAT0 jusqu'à ce que la carte libère le signal d'occupé
      - Déclenche IRQ 0 pour signaler la fin du bloc

6. Échanger PIO vers le programme CMD

Échange de programmes PIO

Le PIO du RP2040 dispose de 32 emplacements d'instructions par bloc. Nos trois programmes totalisent 55 instructions, ils ne peuvent donc pas coexister. On utilise plutôt une seule SM0 sur PIO0, et les programmes sont échangés en écrivant directement dans la mémoire d'instructions 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];
}

Cela contourne l'allocateur pio_add_program/pio_remove_program du SDK. L'échange de programme prend environ 1 µs. Chaque échange est suivi d'une réinitialisation spécifique au programme qui définit les mappages de broches, la direction de décalage et le diviseur d'horloge.

Gestion de l'alimentation

L'analyse des traces logiques du Nokia N91 révèle une gestion agressive de l'alimentation :

  • Mode inactif : STANDBY IMMEDIATE (0xE0) toutes les ~7,5 secondes, même sans E/S. Chaque mise en veille déclenche une réinitialisation complète du SDIO (nouvelle tentative CMD5 → CMD3 → CMD7 → configuration CCCR). 28 cycles de veille observés dans une seule session inactive.
  • Mode actif : STANDBY émis entre les salves d'E/S (24 cycles lors d'opérations sur fichiers sur clé USB).
  • Aucune autre commande d'alimentation (IDLE, SLEEP, CHECK POWER MODE) ni accès au registre d'alimentation CCCR observée.

Le micrologiciel reproduit ce comportement avec un délai d'inactivité configurable :

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

Deux chemins déclenchent la coupure d'alimentation du disque dur :

  1. Délai d'inactivité (5 secondes) — la boucle principale détecte l'absence d'activité d'E/S
  2. Suspension USB — l'hôte suspend le port USB

Les deux chemins envoient ATA STANDBY IMMEDIATE (0xE0) pour vider le cache d'écriture et garer les têtes, puis coupent l'alimentation via GP9.

Séquence de réveil (déclenchée par la première lecture/écriture après coupure) :

  1. Mettre sous tension le disque dur, attendre 500 ms pour la stabilisation de l'alimentation
  2. Réinitialisation SDIO basée sur PIO : CMD5 (OCR) → 10 ms de stabilisation → CMD3 (RCA) → CMD7 (sélection)
  3. Passer à l'horloge PIO rapide, configurer CCCR via CMD52 (bus 4 bits, blocs de 512 octets, activation fn1)
  4. Interroger la disponibilité de fn1 (bit IO_READY du CCCR)
  5. Interrogation du statut DRDY pendant 30 ms (style N91) jusqu'à ce que le disque soit prêt pour ATA

Gestion des secteurs défectueux

Lorsqu'un transfert multi-secteurs rencontre un secteur défectueux :

  1. La lecture du bloc échoue → récupération d'erreur (IO_ABORT + réinitialisation fn1, ~500 ms)
  2. Repli vers des E/S secteur par secteur pour identifier précisément le bloc défaillant
  3. La couche ATA attend suffisamment longtemps pour capturer les bits finaux STATUS/ERROR au lieu de réduire l'échec à un DRQ timeout générique
  4. Tout bloc non récupéré fait échouer la commande SCSI immédiatement avec MEDIUM ERROR (lecture : 03/11/00, écriture : 03/0C/00)
  5. Le LBA du secteur défectueux est mis en cache → les lectures répétées échouent rapidement sans ré-interroger le disque (protection anti-marteau contre les tempêtes de nouvelles tentatives de l'hôte)
  6. Les écritures touchent toujours le support, selon SBC — une écriture réussie sur un LBA connu comme défectueux le supprime du cache, exactement comme un disque qui efface un secteur en attente

Le point 6 n'est pas théorique : ce disque avait un secteur illisible de longue date au LBA 1952 (READ: ST=0x51 ERR ERR=0x40 UNC). Une fois que le pont a permis à une écriture de l'atteindre, le disque a réécrit le secteur et il est relu proprement depuis :

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

Construction

Prérequis

  • SDK Raspberry Pi Pico — standard, non modifié, épinglé à la version 2.2.0
  • Chaîne d'outils ARM (arm-none-eabi-gcc)
  • CMake

La version du SDK est verrouillée : si PICO_SDK_PATH est défini (variable d'environnement ou CMake), il est utilisé et sa version est vérifiée par rapport à l'épingle — une incompatibilité fait échouer la configuration avec des instructions (remplacer par -DMK4001_ALLOW_SDK_MISMATCH=ON). Sans PICO_SDK_PATH du tout, la version épinglée du SDK est téléchargée automatiquement depuis GitHub au moment de la configuration, donc un simple git clone && cmake && make est parfaitement reproductible.

Le micrologiciel a besoin d'un pilote de classe MSC TinyUSB patché (données de sense d'application préservées en cas d'erreurs de lecture/écriture + une page de mode Caching avec WCE=1). Ce fichier est fourni dans ce dépôt à lib/tinyusb_patched/msc_device.c — la compilation l'utilise automatiquement à la place de la copie du SDK, donc aucune modification du SDK n'est jamais nécessaire. Le diff par rapport à TinyUSB amont (0.18.0, tel qu'inclus dans pico-sdk 2.2.0) se trouve dans lib/tinyusb_patched/ ; l'épingle du SDK existe précisément parce que ce fichier fourni doit suivre le TinyUSB du SDK.

Construction et flash

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"

Câblage matériel

Remarque : GP0 et GP1 sont morts sur cette unité Pico spécifique. Toutes les affectations des GPIO SDIO sont décalées de +2.

Notes humaines : Claude s'est trompé ici car il n'a pas réalisé que GP0 et GP1 étaient utilisés pour le terminal UART dans sa configuration de construction. Il n'arrêtait pas de l'oublier, au point que j'ai simplement déplacé les GPIO SDIO hors de cet UART.

HDD_PWR n'est pas nécessaire. Vous n'avez pas besoin de couper l'alimentation du disque pour l'utiliser ; c'est surtout une commodité de développement pour réinitialiser le disque dur quand beaucoup de choses sont codées en dur. Cela dit, si vous souhaitez économiser de l'énergie, vous pouvez utiliser ce signal, mais il supporte la réinitialisation à chaud sans problème.

Vous verrez des messages de débogage sur l'UART. Ils ne passent pas par USB-CDC car il était plus facile pour Claude de mettre en place une liaison de journalisation UART-vers-USB séparée qui ne se déconnecte pas ou ne devient pas instable pendant le développement précoce.

Le journal UART rapporte également la température du disque toutes les 30 secondes lorsque le disque est actif ([TEMP] drive temperature: 29 C). Le capteur a été découvert par rétro-ingénierie de la commande constructeur Toshiba 0xC2 — le N91 la lit au début de chaque session disque pour imposer ses limites de température de fonctionnement du disque dur. Détails dans docs/N91_TRACE_ANALYSIS.md §4.

Voici un exemple du journal :

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

Enfin, voici le câblage vers le disque réel.
_DSC1176-2 Voici un extrait du schéma N91, vous pouvez également mapper le numéro de broche. image

Note secondaire : ce disque est en 3 V mais je pense que 3,3 V convient, surtout pour éviter du travail de décalage de niveau.

Un matériel spécifiquement conçu pour ce disque se trouve dans /hardware ! image

Fichiers source

Historique des versions

Test

root@kitploit:~
# Vérifier que le périphérique est apparu
lsblk -dno NAME,MODEL | grep MK4001

# Test du système de fichiers — monter, copier des fichiers, vérifier
sudo mount /dev/sdX1 /mnt/mk4001
cp /tmp/testfile /mnt/mk4001/
sync
md5sum /tmp/testfile /mnt/mk4001/testfile    # doit correspondre
sudo umount /mnt/mk4001

# Tests de vitesse (périphérique brut, NE PAS monter d'abord — cela corromprait le système de fichiers)
# Utiliser un décalage sûr après le système de fichiers ou un disque non partitionné
sudo dd if=/dev/sdX of=/dev/null bs=64k count=128 iflag=direct     # lecture
sudo dd if=/dev/zero of=/dev/sdX bs=64k count=64 oflag=direct seek=1024  # écriture (décalage après le système de fichiers)

Notes humaines ici, anecdote amusante : Quand il a commencé les tests de vitesse, il a en fait utilisé dd directement sur le disque et endommagé les systèmes de fichiers... Heureusement, cela n'a pas eu d'importance majeure pendant le développement, mais gardez toujours cela à l'esprit lorsque vous manipulez OpenClaw et votre configuration.

Licence

Je m'en fiche.

Télécharger l’outil
MétriqueValeur
Vitesse de lecture~985 ko/s (limité par la pleine vitesse USB)
Vitesse d'écriture~920 ko/s (limité par la pleine vitesse USB, cache d'écriture annoncé)
Vitesse côté SDIO brute~2,35 Mo/s en lecture / ~2,15 Mo/s en écriture (limité par le disque)
Capacité3,75 Go (7 862 400 secteurs)
Système de fichiersFAT32 vérifié (montage/démontage/fsck propre)
Intégrité des donnéesÉcriture+relecture vérifiée ; CRC16 par bloc sur les 4 lignes DAT
Veille inactif5 s d'inactivité ou suspension USB → STANDBY IMMEDIATE + coupure d'alimentation
  • Broches/Alimentation (sdio_hw.c) — Initialisation des GPIO et commande d'alimentation du disque dur. Toute la communication SDIO utilise le PIO.

  • AdresseRegistreUsage
    0x00DATACible CMD53 pour les données de secteur
    0x01ERR/FEATErreur (lecture) / Feature (écriture)
    0x02SECCOUNTNombre de secteurs
    0x03LBA_LOLBA bits 0-7
    0x04LBA_MIDLBA bits 8-15
    0x05LBA_HILBA bits 16-23
    0x06DEV/HEADDevice/Head + LBA bits 24-27
    0x07CMD/STATUSCommande (écriture) / Statut (lecture)
    GPIO PicoFonctionRemarques
    GP2SDIO_CLKSortie d'horloge hôte
    GP3SDIO_CMDLigne de commande bidirectionnelle
    GP4SDIO_DAT0Bit de données 0
    GP5SDIO_DAT1Bit de données 1
    GP6SDIO_DAT2Bit de données 2
    GP7SDIO_DAT3Bit de données 3
    GP9HDD_ENActivation de l'alimentation du disque (HIGH=marche)
    GP12UART TXSortie de débogage à 115200 bauds
    GP13UART RXEntrée de débogage
    GP16LED : Alimentation disqueActive basse
    GP17LED : Disque sainActive basse
    GP18LED : LectureActive basse
    GP19LED : ÉcritureActive basse
    FichierLignesObjectif
    main.c210Initialisation, veille inactive, suspension/reprise USB
    msc_device.c400Callbacks USB MSC, réveil par coupure d'alimentation, cache de secteurs défectueux
    ata_sdio.c390Commandes ATA, récupération d'erreur, diagnostics constructeur
    sdio_pio.c635SDIO PIO : CMD52, CMD53 lecture/écriture, échange de programme, CRC16
    sdio_hw.c45Initialisation des broches + contrôle d'alimentation du disque dur
    sdio.pio200Assembleur PIO + helpers d'initialisation du SDK C
    led.h37Helpers pour LED (GP16–GP19, actif bas)
    usb_descriptors.c77Descripteurs USB de périphérique/configuration/chaîne
    tusb_config.h20Configuration TinyUSB (MSC, tampon EP de 32 Ko)
    VersionLectureÉcritureChangement clé
    v0.1–v0.3105 ko/s93 ko/sSDIO en bit-bang, CRC16, logique de nouvelle tentative
    v0.5374 ko/s—PIO mono-SM, échange direct de mémoire d'instructions
    v0.6583 ko/s93 ko/sLectures CMD53 multi-blocs, correction du drain d'horloge CRC
    v0.8588 ko/s274 ko/sÉcritures PIO, correction du vidage OSR
    v0.9475 ko/s371 ko/sBlocs de 64 secteurs, vérification de lecture CRC16
    v0.10453 ko/s329 ko/sRéaffectation LED, broche HDD EN, UART sur GP12/GP13
    v0.11~450 ko/s~340 ko/sCoupure d'alimentation disque dur, réveil PIO, sense de secteur défectueux, suspension USB
    v0.12~985 ko/s~920 ko/sChevauchement disque/USB (préfetcheur de lecture + cache d'écriture annoncé avec écriture en différé), blocs PIO pipeline, DMA d'inversion d'octets, boucles PIO 4 cycles, sémantique de secteur défectueux style SBC (réparation par écriture), pilote MSC TinyUSB fourni