
برنامج ثابت لـ RP2040 يربط مشغل Toshiba MK4001MTD 0.85" SDIO microdrive كجهاز تخزين كبير عبر USB، مع تنفيذ كامل لمكدس بروتوكول SDIO-ATA من الصفر باستخدام عمليات قراءة/كتابة مسرّعة بـ PIO واسترداد القطاعات التالفة.
برنامج ثابت لـ RP2040 Pico يوصل محرك Toshiba MK4001MTD 0.85" SDIO كجهاز تخزين كتلي USB.

محرك MK4001MTD هو محرك صغير سعة 4 جيجابايت كان يُستخدم أصلاً في هاتف Nokia N91 الموسيقي وبعض الأجهزة الأخرى، مثل مشغلات MP3 أو محركات USB، في وقت كانت فيه ذاكرة الفلاش لا تزال باهظة الثمن.
ربما تكون قد رأيت مقدمات تدّعي أن هذا المحرك يستخدم بروتوكول MMC، لكن هذا غير صحيح في الواقع. لقد كنت أبحث في هذا الأمر لبعض الوقت: حاولت بناء قارئ بطاقة MMCplus ذات 8 بت واختبرت عدة قُرّاء SD/MMC دون جدوى. كملاذ أخير، اشتريت هاتف Nokia N91 لالتقاط تتبعات منطقية وتأكيد البروتوكول الذي يستخدمه فعلياً.
هذه صورة عندما كنت أحاول استخدامه مع لوحة القارئ 8bit-MMCPlus الخاصة بي، واتضح أنه ليس MMC :(

لذا انتهى بي الأمر بشراء N91 لجمع التتبعات:

على عكس محركات ATA/CF الصغيرة القياسية، فهو يستخدم واجهة SDIO مع أوامر ATA مُمررة عبر CMD52/CMD53. لا يوجد مشغل موجود يدعم هذا البروتوكول، لذلك هذا البرنامج الثابت ينفذ المجموعة الكاملة من الصفر.
هذا الأمر فاجأني، لأن هناك معيار SDIO-to-ATA يسمى CE-ATA. لكن إذا نظرت عن كثب إلى الجدول الزمني للإصدارات، فإن CE-ATA جاء بعد هذا المحرك. ونتيجة لذلك، يعتمد هذا المحرك كلياً على أوامر SDIO، و CE-ATA غير متوفرة. CE-ATA لديها أمران جديدان CMD60/CMD61 وتستخدم CMD12/39، لكن يمكنك رؤية من التتبعات أنها لا تستخدم أيًا منها.
النقطة الثانية المتعلقة بالأجهزة هي أن معلومة خاطئة أخرى منتشرة – تدّعي أنها بطاقة MMCPlus ذات 8 بت – ليست غير صحيحة فحسب، بل إن ترتيب الأطراف لا يتبع معيار MMC أيضًا. يمكنك العثور على دليل خدمة Nokia N91 مع بعض التوثيق لترتيب الأطراف: بينما يتبع ترقيم الأطراف معيار MMCPlus، فإن تعيين الأطراف لا يتبعه. هذه تفاصيل مهمة إذا كنت تقوم بالتوصيل بنفسك: فهو يستخدم نفس موصل MMC، لكن تعيين الأطراف مختلف، مزيد من التفاصيل في قسم الأجهزة.
أخيرًا، لاحظ أن هذا تم تطويره بالاشتراك مع Claude/OpenClaw. قمت أنا بجمع التتبعات المنطقية يدويًا وإعداد محطة اختبار مغلقة الحلقة لـ OpenClaw لتكرار التطوير – تحليل التتبعات وتنفيذ الميزات. سيتم كتابة التوثيق بشكل أساسي بواسطة Claude؛ وسأضيف ملاحظاتي الخاصة في نفس السياق. لقد قرأت أيضًا التوثيق بنفسي وتأكدت منه، ويجب أن يكون موثوقًا وسهل المتابعة.
للحصول على رؤى حول التحليلات على تتبع N91، هي موجودة في /docs/N91_TRACE_ANALYSIS.md، وقد وضعت أيضًا دليل خدمة N91 هناك مع التتبعات المنطقية الأولية.
شاهد المزيد في منشور المدونة هنا: https://www.willwhang.dev/Reading-MK4001MTD/
شاهده وهو يعمل هنا: https://youtu.be/GC4xil3_Bbc
تخزين كتلي USB يعمل بكامل وظائفه مع قراءة/كتابة مُسرّعة عبر PIO وإدارة استهلاك الطاقة في وضع الخمول.
| المقياس | القيمة |
|---|---|
| سرعة القراءة | ~985 كيلوبايت/ثانية (محدودة بسرعة USB الكاملة) |
| سرعة الكتابة | ~920 كيلوبايت/ثانية (محدودة بسرعة USB الكاملة، ذاكرة تخزين مؤقت للكتابة مُعلن عنها) |
| سرعة جانب SDIO الخام | ~2.35 ميجابايت/ثانية قراءة / ~2.15 ميجابايت/ثانية كتابة (محدودة بالمحرك) |
| السعة | 3.75 جيجابايت (7,862,400 قطاع) |
| نظام الملفات | FAT32 مُتحقق منه (تركيب/فك/fsck نظيف) |
| سلامة البيانات | تم التحقق من الكتابة + إعادة القراءة؛ CRC16 لكل كتلة على جميع خطوط DAT الأربعة |
| وضع الاستعداد الخامل | 5 ثوانٍ خامل أو تعليق USB → STANDBY IMMEDIATE + قطع الطاقة |
مضيف USB ←→ USB MSC (TinyUSB) ←→ طبقة ATA ←→ طبقة SDIO (PIO) ←→ MK4001MTD
يتكون البرنامج الثابت من أربع طبقات:
USB MSC (msc_device.c) — فئة التخزين الكتلي TinyUSB. يترجم أوامر SCSI READ(10)/WRITE(10) إلى عمليات قطاع ATA. مخزن مؤقت لنقطة النهاية 32 كيلوبايت، تجميع يصل إلى 64 قطاعًا لكل نقل USB. يتم تداخل إدخال/إخراج المحرك مع USB في كلا الاتجاهين، مثل جسر ATA-USB حقيقي مع قرص تخزين مؤقت: جالب مسبق للقراءة المتسلسلة يجلب الجزء التالي بينما يتم دفق الجزء السابق إلى المضيف، ويتم تخزين الكتابات مؤقتًا وتفريغها أثناء استقبال USB للجزء التالي. يعلن الجهاز عن ذاكرة التخزين المؤقت للكتابة (صفحة وضع التخزين المؤقت، WCE=1 — تقارير المضيفين "ذاكرة تخزين مؤقت للكتابة: ممكّنة" ويصدرون SYNCHRONIZE CACHE عند fsync/فك التركيب/التعليق، وهو ما يلتزم به البرنامج الثابت). يؤدي فشل التفريغ الخلفي إلى ظهور MEDIUM ERROR في عملية WRITE أو SYNCHRONIZE CACHE التالية؛ تأخذ الكتابات إلى القطاعات المعروفة بأنها تالفة مسارًا تزامنيًا صارمًا.
ATA-over-SDIO (ata_sdio.c) — ينفذ أوامر ATA (IDENTIFY، READ SECTORS، WRITE SECTORS) عن طريق الكتابة إلى سجلات ATA المُخطط لها في مساحة عنوان وظيفة SDIO 1 عبر CMD52، ونقل بيانات القطاع عبر CMD53. منطق إعادة محاولة من 3 مستويات على مستويات CMD والبيانات وATA.
PIO SDIO (sdio_pio.c, sdio.pio) — SDIO مُسرّع بالأجهزة باستخدام الطرفية PIO لـ RP2040 (ناقل 4 بت بسرعة 10 ميجاهرتز، 4 دورات PIO لكل بت مع تخطي مزامنات الإدخال). ثلاثة برامج PIO تشترك في آلة حالة واحدة عبر التبديل الديناميكي للبرنامج:
الطرفية/الطاقة (sdio_hw.c) — تهيئة GPIO والتحكم في طاقة القرص الصلب. جميع اتصالات SDIO تستخدم PIO.
ملاحظات بشرية: من المثير للاهتمام، أن Claude كان مترددًا حقًا في تنفيذ SDIO في PIO، وتم إهدار الكثير من دورات التطوير في التبديل ذهابًا وإيابًا بين PIO والتلاعب بالبتات.
يقدم MK4001MTD نفسه كبطاقة SDIO مع وظيفة إدخال/إخراج واحدة. تهيئة بطاقة SDIO القياسية (CMD5/CMD3/CMD7) تقوم بإعداد الناقل، ثم يتم الوصول إلى سجلات ATA من خلال أوامر SDIO:
الوصول إلى السجل (CMD52): يتم تعيين كل سجل ATA إلى عنوان وظيفة 1:
| العنوان | السجل | الاستخدام |
|---|---|---|
| 0x00 | DATA | هدف CMD53 لبيانات القطاع |
| 0x01 | ERR/FEAT | خطأ (قراءة) / ميزة (كتابة) |
| 0x02 | SECCOUNT | عدد القطاعات |
| 0x03 | LBA_LO | LBA بت 0-7 |
| 0x04 | LBA_MID | LBA بت 8-15 |
| 0x05 | LBA_HI | LBA بت 16-23 |
| 0x06 | DEV/HEAD | الجهاز/الرأس + LBA بت 24-27 |
| 0x07 | CMD/STATUS | أمر (كتابة) / حالة (قراءة) |
نقل البيانات (CMD53): يتم نقل بيانات القطاع عن طريق إصدار CMD53 في وضع الكتلة مستهدفًا سجل DATA (العنوان 0x00). للقراءات متعددة القطاعات، يقوم CMD53 واحد مع block_count=N بنقل N × 512 بايت في معاملة واحدة متعددة الكتل SDIO.
إشارات المقاطعة: يشير المحرك إلى جاهزية القطاع عن طريق تأكيد مقاطعة SDIO (بت INT_PENDING 1 في سجل CCCR 0x05). قراءة سجل STATUS ATA تمسح المقاطعة.
لقراءة 16 قطاعًا:
1. كتابة سجلات ATA عبر PIO CMD52:
SECCOUNT=16, LBA_LO/MID/HI, DEV/HEAD=0xE0, CMD=0x20
2. استقصاء STATUS عبر CMD52 حتى يتم تعيين DRQ (بت 3)
3. تبديل PIO إلى برنامج قراءة DAT
4. إرسال CMD53: block_mode=1, fn=1, addr=0x0000, block_count=16
5. PIO قراءة DAT: لكل من الكتل الـ 16:
أ. انتظار بت البداية (جميع خطوط DAT منخفضة)
ب. DMA 1024 nibble (512 بايت) من PIO RX FIFO إلى المخزن المؤقت
ج. انتظار انتهاء SM من ساعة nibbles CRC+النهاية (استقصاء SM PC)
د. إعادة تجميع nibbles → بايتات في المكان
6. تبديل PIO مرة أخرى إلى برنامج CMD
لكتابة 16 قطاعًا:
1. كتابة سجلات ATA عبر PIO CMD52:
SECCOUNT=16, LBA, DEV/HEAD=0xE0, CMD=0x30
2. استقصاء STATUS عبر CMD52 حتى يتم تعيين DRQ (بت 3)
(STATUS 0xD8 = BSY+DRQ يُعامل كجاهز DRQ، حسب تتبع N91)