Pembaca Floppy Disk Amiga Berbasis Arduino: Pemulihan Data Open-Source Hemat Biaya
Komponen dan Perlengkapan
Resistor 1k ohm — 1 unit
Breadboard (generic) — 1 unit
Kabel jumper (generic) — 1 set
SparkFun Breadboard Power Supply 5V/3.3V — 1 unit
Arduino UNO atau Pro Mini — 1 unit
Aplikasi dan Layanan Online
Arduino IDE
Tentang Proyek
Tujuan saya: Menciptakan cara sederhana, murah, dan open-source untuk memulihkan data dari floppy disk Amiga DD dari dalam Windows 10 dan sistem operasi lainnya.
Solusi saya: Arduino ditambah aplikasi Windows.
Mengapa: Untuk melestarikan data dari disk ini untuk masa depan. Selain itu, komputer normal tidak bisa membaca disk Amiga karena cara data ditulis.
Situs web proyek: https://amiga.robsmithdev.co.uk/
Ini adalah versi 1 dari proyek. Versi 2 membaca dan menulis yang ditingkatkan!
Pengalaman Amiga
Saya hutang karir saya pada Amiga, khususnya A500+ yang orang tua saya beli untuk saya pada Natal ketika berusia 10 tahun. Awalnya saya bermain game, tetapi setelah beberapa saat saya mulai penasaran dengan apa lagi yang bisa dilakukan. Saya bermain dengan Deluxe Paint III dan mempelajari Workbench.
Amiga 500 Plus:
Setiap bulan saya membeli majalah Amiga Format yang populer. Satu bulan ada salinan gratis AMOS. Saya mengikuti kompetensi Write A Game In AMOS Amiga Format ketika AMOS Professional dimasukkan ke coverdisk nanti, dan menjadi salah satu 12 pemenang (menurut saya) dengan In The Pipe Line. Anda benar-benar harus mengejar mereka untuk hadiahnya!
AMOS – Pencipta:
Latar Belakang
Selanjutnya, saya menggunakannya sebagai bagian dari proyek GCSE dan A-Level saya (berkat Highspeed Pascal, yang kompatibel dengan Turbo Pascal di PC).
Itu adalah waktu yang lama, dan saya punya kotak-kotak disk, serta A500+ yang tidak berfungsi lagi, jadi saya memikirkan untuk mencadangkan disk tersebut ke komputer saya, baik untuk pelestarian maupun nostalgia.
Situs web Amiga Forever memiliki daftar opsi yang bagus yang mencakup hardware, dan menyalahgunakan dua drive floppy di PC - Sayangnya tidak ada salah satu yang merupakan opsi dengan hardware modern, dan pengontrol KryoFlux/Catweasel terlalu mahal. Saya sangat terkejut bahwa sebagian besarnya adalah closed source.
Sangat tertarik pada elektronika dan telah bermain dengan perangkat Atmel (AT89C4051) saat di universitas, saya memutuskan untuk melihat Arduino (kredit kepada GreatScott untuk inspirasi yang menunjukkan betapa mudahnya memulai) Saya bertanya apakah ini mungkin.
Jadi saya mencari Google untuk kode Arduino floppy drive reading, dan setelah melewati semua proyek yang menyalahgunakan drive untuk memutar musik, saya tidak benar-benar menemukan solusi apa pun. Saya menemukan beberapa diskusi dalam beberapa grup yang menunjukkan tidak akan mungkin. Saya menemukan proyek yang berpusat pada FPGA yang sangat menarik untuk dibaca, tetapi bukan arah yang saya inginkan, jadi satu-satunya opsi adalah membangun solusi sendiri.
Penelitian
Saat memulai proyek ini saya tidak memiliki ide bagaimana drive floppy bekerja, dan bahkan kurang bagaimana data dikodekan padanya. Situs web berikut sangat berharga dalam pemahaman saya tentang apa yang terjadi dan bagaimana mereka bekerja:
techtravels.org (dan halaman ini)
The .ADF (Amiga Disk File) format FAQ by Laurent Clévy
Amiga Forever
Wikipedia - Amiga Disk File
English Amiga Board
QEEWiki - Counters on the ATmega168/328
Floppy drive pinout
List of floppy disk formats
Asumsi
Berdasarkan penelitian saya sekarang tahu secara teoretis bagaimana data ditulis ke disk, dan bagaimana disk berputar.
Saya mulai menghitung beberapa angka. Berdasarkan kecepatan disk double density berputar (300rpm) dan cara data disimpan (80 track, 11 sektor per track dan 512 byte per sektor, dienkode menggunakan MFM), untuk membaca data secara akurat saya perlu dapat mengambil sampel data pada 500Khz; itu cukup cepat ketika Anda mempertimbangkan Arduino hanya berjalan pada 16Mhz.
Dalam upaya yang berikut saya hanya berbicara tentang sisi Arduino. Lompat ke decoding.
Upaya 1
Pertama saya perlu mengumpulkan hardware dan antarmuka ke drive floppy. Drive floppy yang saya ambil dari komputer lama di kantor, dan mengambil kabel IDE-nya pada saat yang sama.
Di bawah ini adalah foto liberated drive floppy dari komputer lama:
Studi pinout drive saya menyadari saya hanya membutuhkan beberapa kabel darinya, dan setelah melihat drive saya menyadari drive tidak menggunakan masukan 12v juga.
Menggerakkan drive dicapai dengan memilih drive dan mengaktifkan motor. Memindahkan kepala sederhana. Anda mengatur pin /DIR tinggi atau rendah, dan kemudian memulsa pin /STEP. Anda bisa tahu apakah kepala telah mencapai track 0 (track pertama) dengan memantau pin /TRK00.
Saya penasaran tentang pin /INDEX. Ini memulsa sekali setiap putaran. Karena Amiga tidak menggunakan ini untuk menemukan awal track saya tidak membutuhkannya dan dapat mengabaikannya. Setelah ini ini hanya masalah memilih sisi mana dari disk yang akan dibaca (/SIDE1) dan menghubungkan /RDATA.
Dengan kebutuhan kecepatan data yang tinggi, pemikiran pertama saya adalah menemukan cara untuk membuat ini kurang menjadi masalah dengan mencoba mengurangi persyaratan pada kecepatan ini.
Rencana adalah menggunakan dua register geser 8-bit (SN74HC594N) untuk mengurangi frekuensi pemindaian yang diperlukan dengan faktor 8. Saya menggunakan yang disebut Ebay Pro Mini atmega328 Board 5V 16M Arduino Compatible Nano (jadi saya tidak tahu apa itu secara resmi, tetapi ini berfungsi pada Uno!) untuk menyimpan data parallel ini dan mengirimkannya ke PC menggunakan antarmuka serial/USART-nya. Saya tahu ini perlu berjalan lebih cepat dari 500Kbaud (dengan semua overhead serial yang terlibat juga).
sn74hc594.pdf
Setelah meninggalkan perpustakaan serial Arduino standar, saya sangat senang menemukan saya dapat mengonfigurasi USART pada Arduino hingga 2M baud, dan dengan salah satu papan breakout F2DI (Ebay menyebutnya Basic Breakout Board For FTDI FT232RL USB to Serial IC For Arduino - lihat di bawah) saya dapat dengan senang hati mengirim dan menerima data pada kecepatan ini (62.5Khz) tetapi saya perlu melakukan ini dengan akurat.
Papan breakout FTDI yang cocok dengan antarmuka pada papan Arduino:
Pertama, saya menggunakan Arduino untuk mengatur salah satu register geser 8-bit hanya salah satu dari 8 bit yang diclock tinggi. Yang lain menerima masukan langsung dari drive floppy (jadi memberikan konversi serial ke parallel).
Di bawah ini adalah gambar gila dari breadboard yang saya bangun ini pada saat itu:
Saya menggunakan salah satu timer Arduino untuk menghasilkan sinyal 500Khz pada salah satu pin output-nya dan karena hardware mengelola ini itu sangat akurat! - Setidaknya multimeter saya mengukurnya tepat 500khz.
Kodenya berfungsi, saya menclock seluruh 8-bit data pada 62.5khz, sehingga CPU Arduino hampir tidak terpakai. Namun saya tidak menerima apa yang bermakna. Pada titik ini saya menyadari saya perlu melihat lebih dekat data sebenarnya yang keluar dari drive floppy. Jadi saya membeli osiloskop murah lama dari eBay (Gould OS300 20Mhz Oscilloscope) untuk memeriksa apa yang terjadi.
Sementara menunggu osiloskop tiba saya memutuskan untuk mencoba sesuatu yang lain.
Potongan kode yang digunakan untuk membaca data dari register geser:
void readTrackData() { byte op; for (int a=0; a<5632; a++) { // We'll wait for the "byte" start marker while (digitalRead(PIN_BYTE_READ_SIGNAL)==LOW) {}; // Read the byte op=0; if (digitalRead(DATA_LOWER_NIBBLE_PB0)==HIGH) op|=1; if (digitalRead(DATA_LOWER_NIBBLE_PB1)==HIGH) op|=2; if (digitalRead(DATA_LOWER_NIBBLE_PB2)==HIGH) op|=4; if (digitalRead(DATA_LOWER_NIBBLE_PB3)==HIGH) op|=8; if (digitalRead(DATA_UPPER_NIBBLE_A0)==HIGH) op|=16; if (digitalRead(DATA_UPPER_NIBBLE_A1)==HIGH) op|=32; if (digitalRead(DATA_UPPER_NIBBLE_A2)==HIGH) op|=64; if (digitalRead(DATA_UPPER_NIBBLE_A3)==HIGH) op|=128; writeByteToUART(op); // Wait for high to drop again while (digitalRead(PIN_BYTE_READ_SIGNAL)==HIGH) {}; } }
Upaya 2
Saya memutuskan bahwa register geser, sementara ide yang bagus, mungkin tidak membantu. Saya dapat dengan mudah membaca 8 bit sekaligus, tetapi itu muncul kepada saya bahwa saya tidak bisa yakin bahwa semua bit diclock dengan benar pada awalnya. Membaca dokumentasi itu menunjukkan bahwa data lebih banyak pulsa pendek daripada tinggi dan rendah.
Saya menghapus register geser dan bertanya apa yang akan terjadi jika saya mencoba memeriksa pulsa dari drive dalam Interrupt (ISR) menggunakan sinyal 500Khz yang telah diatur sebelumnya. Saya mengonfigurasi ulang Arduino untuk menghasilkan ISR, dan setelah saya melewati masalah perpustakaan Arduino yang menghalangi (menggunakan ISR yang saya inginkan) saya pindah ke Timer 2.
Saya menulis ISR singkat yang akan menggeser byte global satu bit ke kiri dan kemudian jika pin yang terhubung ke garis data drive floppy adalah LOW (pulsa low-going) saya akan OR 1 padanya. Setiap 8 kali saya melakukan ini saya menulis byte yang selesai ke USART.
Ini tidak berjalan seperti yang diharapkan! Arduino mulai berperilaku sangat tidak stabil dan aneh. Segera saya menyadari ISR membutuhkan lebih banyak waktu untuk dieksekusi daripada waktu antara pemanggilannya. Saya dapat menerima pulsa setiap 2µSec dan berdasarkan kecepatan Arduino, dan membuat asumsi liar bahwa setiap instruksi C diterjemahkan menjadi 1 siklus kode mesin, saya menyadari saya paling banyak dapat memiliki 32 instruksi. Sayangnya sebagian besar akan lebih dari satu instruksi, dan setelah mencari Google saya menyadari overhead memulai ISR sangat besar; tidak pernah disebutkan fungsi digitalRead yang sangat lambat.
Saya meninggalkan fungsi digitalRead untuk mengakses pin port secara langsung! Ini masih tidak membantu dan tidak cukup cepat. Tidak siap menyerah, saya menyelubungkan pendekatan ini dan memutuskan untuk melanjutkan dan mencoba sesuatu yang lain.
Pada titik ini osiloskop yang saya beli tiba, dan itu berfungsi! Osiloskop tua yang berkarat yang mungkin lebih tua dari saya! Tapi masih melakukan pekerjaan dengan sempurna. (Jika Anda tidak tahu apa itu osiloskop lihat EEVblog #926 - Introduction To The Oscilloscope, dan jika Anda tertarik pada elektronika saya menonton beberapa lagi dan menelusuri situs web EEVBlog.
Osiloskop tua yang berkarat baru saya beli (Gould OS300 20Mhz):
Setelah menghubungkan sinyal 500Khz ke satu channel dan output dari drive floppy ke channel lain itu jelas ada sesuatu yang tidak beres. Sinyal 500Khz adalah gelombang persegi sempurna menggunakan sebagai trigger, data floppy ada di mana-mana. Saya bisa melihat pulsa, tapi itu lebih banyak kabur. Demikian pula jika saya trigger dari sinyal drive floppy, gelombang persegi sinyal 500Khz ada di mana-mana dan tidak sinkron dengannya.
Foto jejak pada osiloskop trigger dari dua channel. Anda tidak bisa melihatnya dengan jelas, tapi pada channel bukan yang di-trigger ada ribuan garis hantu samar-samar:
Secara individual saya dapat mengukur pulsa dari kedua sinyal pada 500Khz, yang tidak masuk akal, karena jika keduanya berjalan pada kecepatan yang sama tetapi tidak akan trigger sehingga Anda dapat melihat kedua sinyal dengan baik maka pasti ada sesuatu yang salah.
Setelah banyak bermain dengan level trigger saya berhasil mengetahui apa yang terjadi. Sinyal saya adalah 500Khz sempurna, tetapi melihat sinyal drive floppy, well mereka berjarak dengan benar, tetapi tidak selalu. Antara kelompok pulsa ada error drift, dan juga celah dalam data yang membuat sinyal total tidak sinkron.
Ingat penelitian sebelumnya, drive seharusnya berputar pada 300rpm, tetapi mungkin tidak tepat 300rpm, dan drive yang menulis data mungkin juga tidak tepat 300rpm. Lalu ada jarak antara sektor dan celah sektor. Jelas ada masalah sinkronisasi, dan menyinkronkan sinyal 500Khz ke drive floppy pada awal baca tidak akan berhasil.
Saya juga menemukan bahwa pulsa dari drive floppy sangat pendek, meskipun Anda dapat memodifikasi ini dengan mengubah resistor pullup, dan jika waktu tidak tepat maka Arduino mungkin melewatkan pulsa sama sekali.
Saat saya di universitas (University of Leicester) saya mengambil modul yang disebut embedded system. Kami mempelajari mikrokontroler Atmel 8051. Salah satu proyek melibatkan menghitung pulsa dari stasiun cuaca simulasi (rotary encoder). Waktu itu saya mengambil sampel pin pada interval teratur, tetapi ini tidak sangat akurat.
Pengajar modul, Prof Pont menyarankan saya seharusnya menggunakan fitur hardware counter perangkat (saya tidak tahu itu memiliki satu pada waktu itu.)
Saya memeriksa datasheet ATMega328 dan memang masing-masing dari tiga timer dapat dikonfigurasi untuk menghitung pulsa yang dipicu dari masukan eksternal. Ini berarti kecepatan tidak lagi menjadi masalah. Yang sebenarnya perlu saya ketahui adalah apakah pulsa telah terjadi dalam jendela waktu 2µSec.
Upaya 3
Saya menyesuaikan sketsa Arduino untuk mereset timer 500khz ketika pulsa pertama terdeteksi dan setiap kali timer 500khz overflow saya memeriksa nilai counter untuk melihat apakah pulsa telah terdeteksi. Saya kemudian melakukan urutan bit-shifting yang sama dan setiap 8 bit menulis byte ke USART.
Data masuk dan saya mulai menganalisisnya di PC. Dalam data saya mulai melihat sesuatu yang terlihat seperti data yang valid. Kata sinkronisasi aneh akan muncul, atau kelompok urutan 0xAAAA, tapi tidak ada yang terpercaya. Saya tahu saya berada pada sesuatu, tetapi masih kehilangan sesuatu.
Upaya 4
Saya menyadari bahwa saat data dibaca, data dari drive mungkin keluar sinkron/fase dengan sinyal 500khz saya. Saya mengonfirmasi ini dengan hanya membaca 20 byte setiap kali saya mulai membaca.
Membaca tentang cara menangani masalah sinkron ini saya menemukan frasa Phase Locked Loop atau PLL. Dalam istilah yang sangat sederhana, untuk apa yang kita lakukan, phase locked loop akan menyesuaikan frekuensi clock (500khz) secara dinamis untuk mengkompensasi drift frekuensi dan variasi dalam sinyal.
Resolusi timer tidak cukup tinggi untuk mengubahnya dengan jumlah yang cukup kecil (misalnya 444khz, 470khz, 500khz, 533khz, 571khz dll.) dan untuk melakukan ini dengan benar, saya mungkin memerlukan kode untuk berjalan jauh lebih cepat.
Timer Arduino bekerja dengan menghitung hingga angka yang telah ditentukan (dalam kasus ini 16 untuk 500khz) lalu mengatur register overflow dan mulai lagi dari 0. Nilai counter sebenarnya dapat dibaca dan ditulis pada setiap titik.
Saya menyesuaikan sketsa untuk menunggu dalam loop hingga timer overflow, dan saat overflow saya memeriksa pulsa seperti sebelumnya. Perbedaannya kali ini adalah saat pulsa terdeteksi di dalam loop, saya mereset nilai counter timer ke posisi fase yang telah ditentukan, secara efektif menyinkronkan ulang timer dengan setiap pulsa.
Saya memilih nilai yang saya tulis ke counter timer sehingga akan overflow pada 1µSec dari pulsa deteksi (setengah jalan) sehingga saat timer overflow berikutnya pulsa akan berjarak 2µSec.
Ini berhasil! Saya sekarang membaca hampir data yang sempurna dari disk. Saya masih mendapatkan banyak kesalahan checksum yang mengganggu. Saya menyelesaikan sebagian besar dengan terus-menerus membaca ulang track yang sama pada drive hingga saya memiliki semua 11 sektor dengan header dan checksum data yang valid.
Saya penasaran pada titik ini, jadi saya menghubungkannya kembali ke osiloskop lagi untuk melihat apa yang terjadi sekarang, dan seperti yang saya duga, saya sekarang dapat melihat kedua jejak karena keduanya tetap sinkron satu sama lain:
Saya akan senang melihat ini sedikit lebih jelas, jika ada yang ingin menumbangkan osiloskop digital kelas atas yang cantik (misalnya salah satu Keysight!) saya akan sangat mengapresiasi!
Upaya 5
Saya bertanya apakah saya dapat meningkatkan ini. Melihat kode, khususnya loop baca internal (lihat di bawah) saya memiliki loop while menunggu overflow dan kemudian if internal yang mencari pulsa untuk sinkronisasi.
Potongan kode yang digunakan untuk membaca data dan sinkronkan padanya:
register bool done = false; // Wait for 500khz overflow while (!(TIFR2&_BV(TOV2))) { // falling edge detected while waiting for the 500khz pulse. if ((TCNT0) && (!done)) { // pulse detected, reset the timer counter to sync with the pulse TCNT2=phase; // Wait for the pulse to go high again while (!(PIN_RAW_FLOPPYDATA_PORT & PIN_RAW_FLOPPYDATA_MASK)) {}; done = true; } } // Reset the overflow flag TIFR2|=_BV(TOV2); // Did we detect a pulse from the drive? if (TCNT0) { DataOutputByte|=1; TCNT0=0; }
Saya menyadari bahwa tergantung pada instruksi mana yang dieksekusi dalam loop di atas, waktu antara deteksi pulsa dan penulisan TCNT2=phase; dapat berubah berdasarkan waktu yang dibutuhkan untuk mengeksekusi beberapa instruksi.
Menyadari bahwa ini mungkin menyebabkan beberapa kesalahan/jitter dalam data dan juga dengan loop di atas mungkin saya sebenarnya akan melewatkan pulsa dari drive (jadi melewatkan bit re-sync) saya memutuskan untuk mengambil trik dari salah satu upaya sebelumnya saya, ISR (interrupt).
Saya menghubungkan pulsa data ke pin kedua pada Arduino. Data sekarang terhubung ke trigger COUNTER0 dan sekarang juga pin INT0. INT0 adalah salah satu prioritas interrupt tertinggi sehingga seharusnya meminimalkan keterlambatan antara trigger dan pemanggilan ISR, dan karena ini adalah satu-satunya interrupt yang saya minati semua yang lainnya dinonaktifkan.
Semua yang perlu dilakukan interrupt adalah melakukan kode re-sync di atas, ini mengubah kode menjadi seperti ini:
// Wait for 500khz overflow while (!(TIFR2&_BV(TOV2))) {} // Reset the overflow flag TIFR2|=_BV(TOV2); // Did we detect a pulse from the drive? if (TCNT0) { DataOutputByte|=1; TCNT0=0; }
ISR terlihat seperti ini: (catatan saya tidak menggunakan attachInterrupt karena ini juga menambahkan overhead pada pemanggilan).
Mengkompilasi ini menghasilkan terlalu banyak kode untuk dieksekusi cukup cepat. Faktanya mendisasemblikan di atas menghasilkan:
push r1 push r0 in r0, 0x3f ; 63 push r0 eor r1, r1 push r24 lds r24, 0x0102 ; 0x800102 sts 0x00B2, r24 ; 0x8000b2 pop r24 pop r0 out 0x3f, r0 ; 63 pop r0 pop r1 reti
Dengan menganalisis kode saya menyadari ada hanya beberapa instruksi yang sebenarnya saya butuhkan. Memperhatikan bahwa compiler akan melacak register apa pun yang saya hancurkan, saya mengubah ISR sebagai berikut:
Yang saat didisasemblikan menghasilkan instruksi berikut:
push r1 push r0 in r0, 0x3f ; 63 push r0 eor r1, r1 lds r0, 0x0102 ; 0x800102 sts 0x00B2, r0 ; 0x8000b2 pop r0 out 0x3f, r0 ; 63 pop r0 pop r1 reti
Masih terlalu banyak instruksi. Saya menyadari bahwa compiler menambahkan banyak instruksi tambahan, yang untuk aplikasi saya sebenarnya tidak perlu ada. Jadi saya mencari ISR() dan menemukan parameter kedua ISR_NAKED. Menambahkan ini akan mencegah compiler menambahkan kode khusus, tetapi kemudian saya akan bertanggung jawab untuk memelihara register, stack dan kembali dari interrupt dengan benar. Saya juga akan perlu memelihara register SREG, tetapi karena tidak ada perintah yang saya butuhkan yang memodifikasinya saya tidak perlu khawatir tentang itu.
Ini mengubah kode ISR menjadi:
ISR (INT0_vect, ISR_NAKED) { asm volatile("push __tmp_reg__"); // Preserve the tmp_register asm volatile("lds __tmp_reg__, targetPhase"); // Copy the phase value into the tmp_register asm volatile("sts %0, __tmp_reg__" : : "M" (_SFR_MEM_ADDR(TCNT2))); // Copy the tmp_register into the memory location where TCNT2 is asm volatile("pop __tmp_reg__"); // Restore the tmp_register asm volatile("reti"); // And exit the ISR }
Yang dikonversi compiler menjadi:
push r0 lds r0, 0x0102 ; 0x800102 sts 0x00B2, r0 ; 0x8000b2 pop r0 reti
Lima instruksi! Sempurna, atau setidaknya sempat cepat yang mungkin, secara teoretis memakan waktu 0.3125µSec untuk dieksekusi! Ini sekarang berarti re-sync harus terjadi pada interval waktu yang konsisten setelah pulsa. Di bawah ini adalah diagram waktu dari apa yang terjadi. Ini adalah cara Anda memulihkan data dari umpan data serial yang tidak memiliki sinyal clock:
Ini meningkatkan hasil sedikit. Ini masih tidak sempurna. Beberapa disk selalu dibaca dengan sempurna, beberapa disk membutuhkan waktu lama dan harus terus mencoba ulang. Saya tidak yakin apakah ini karena beberapa disk telah tersimpan selama waktu yang lama sehingga magnetisme telah menurun ke tingkat yang sangat rendah sehingga penguat drive tidak dapat mengatasi. Saya bertanya apakah ini terkait dengan drive floppy PC, jadi saya menghubungkannya ke drive floppy Amiga eksternal yang saya miliki, tetapi hasilnya identik.
Upaya 6
Saya bertanya apakah ada yang lain yang dapat dilakukan. Mungkin sinyal dari drive lebih berisik dari yang saya pikir. Setelah membaca informasi lebih lanjut saya menemukan bahwa resistor pullup 1KOhm adalah standar, diarahkan ke Schmitt trigger.
Setelah menginstal SN74HCT14N Hex Schmitt Trigger dan mengonfigurasi ulang sketsa untuk trigger pada tepi naik daripada tepi turun saya mencoba, tapi itu tidak membuat perbedaan yang terlihat. Saya menebak karena saya mencari satu atau lebih pulsa setiap kali ini mungkin menyerap noise apa pun. Jadi kita akan tetap dengan metode Upaya 5!
sn74hct14.pdf
Solusi breadboard akhir saya terlihat seperti ini:
Perhatikan kabel di atas sedikit berbeda dari sketsa langsung. Saya mengurut ulang beberapa pin Arduino untuk membuat diagram rangkaian lebih mudah.
Upaya 7
Saya sedikit tidak puas dengan beberapa disk yang tidak saya baca. Terkadang disk tidak duduk dengan benar di drive floppy. Saya menebak pegas pada tutup shutter tidak membantu.
Saya mulai mencari deteksi apakah ada kesalahan dalam data MFM yang sebenarnya yang diterima dari disk.
Dari aturan cara kerja pengkodean MFM, saya menyadari bahwa beberapa aturan sederhana dapat diterapkan sebagai berikut:
Tidak boleh ada dua bit '1' berdampingan
Tidak boleh ada lebih dari tiga bit '0' berdampingan
Pertama kali saat mendekode data MFM saya mencari apakah ada dua '1' berturut-turut. Jika ada saya asumsi data sedikit kabur seiring waktu dan mengabaikan '1' kedua.
Dengan aturan ini diterapkan, ada secara harfiah tiga situasi 5 bit di mana kesalahan dapat terjadi. Ini akan menjadi area baru di mana saya dapat mencoba untuk meningkatkan data.
Sebagian besar, saya terkejut sebenarnya tidak ada banyak kesalahan MFM yang terdeteksi. Saya sedikit bingung mengapa beberapa disk tidak akan dibaca ketika tidak ada kesalahan yang ditemukan.
Ini adalah area untuk penelitian lebih lanjut.
Decoding
Setelah membaca cara kerja MFM, saya tidak sepenuhnya yakin bagaimana itu menyelaraskan dengan benar.
Pertama saya pikir drive mengeluarkan 1 dan 0 untuk bit on dan off. Ini bukan kasusnya. Drive mengeluarkan pulsa untuk setiap transisi fase, yaitu: setiap kali data berubah dari 0 ke 1, atau 1 ke 0.
Setelah membaca ini saya bertanya apakah saya perlu mengubahnya kembali menjadi 1 dan 0 dengan memberikannya ke flip-flop toggle, atau membaca data, mencari sektor, dan jika tidak ada yang ditemukan maka membalikkan data dan mencoba lagi!
Turns out ini bukan kasusnya dan itu jauh lebih sederhana. Pulsa sebenarnya adalah data MFM mentah dan dapat langsung diarahkan ke algoritma dekode. Sekarang saya memahami ini saya mulai menulis kode untuk memindai buffer dari drive dan mencari kata sinkron 0x4489. Dengan kejutannya saya menemukannya!
Dari penelitian yang telah saya lakukan, saya menyadari saya perlu sebenarnya mencari 0xAAAAAAAA44894489 (catatan dari penelitian juga menyarankan bahwa ada beberapa bug dalam kode Amiga awal yang berarti urutan di atas tidak ditemukan. Jadi sebagai gantinya saya mencari 0x2AAAAAAA44894489 setelah ANDing data dengan 0x7FFFFFFFFFFFFFFF).
Seperti yang diharapkan saya menemukan hingga 11 dari ini pada setiap track yang sesuai dengan awal aktual dari 11 sektor Amiga. Saya kemudian mulai membaca byte yang diikuti untuk melihat apakah saya dapat mendekode informasi sektor.
Saya mengambil potongan kode dari salah satu referensi di atas untuk membantu dengan dekode MFM. Tidak ada gunanya menciptakan roda lagi, kan?
Setelah membaca header dan data, saya mencoba menulisnya ke disk sebagai file ADF. Format file ADF standar sangat sederhana. Ini secara harfiah hanya 512 byte dari setiap sektor (dari kedua sisi disk) ditulis secara berurutan. Setelah menulis dan mencoba membukanya dengan ADFOpus dan mendapat hasil bervariasi, terkadang itu membuka file, terkadang gagal. Tentu ada kesalahan dalam data. Saya mulai melihat bidang checksum dalam header, menolak sektor dengan checksum tidak valid dan mengulangi membaca hingga saya memiliki 11 yang valid.
Untuk beberapa disk ini semua 11 pada baca pertama, beberapa membutuhkan beberapa percobaan dan nilai fase yang berbeda juga.
Akhirnya saya berhasil menulis file ADF yang valid. Beberapa disk akan membutuhkan waktu lama, beberapa secara harfiah secepat Amiga akan membacanya. Tidak memiliki Amiga yang berfungsi lagi saya tidak dapat memeriksa apakah disk ini dibaca dengan benar secara normal, mereka telah disimpan dalam kotak di atap selama bertahun-tahun jadi mungkin telah rusak.
Jadi Apa Selanjutnya?
Selanjutnya sudah terjadi - V2 tersedia di sini dan memiliki dukungan baca tulis yang ditingkatkan!
Nah, pertama, saya telah membuat seluruh proyek gratis dan open source di bawah GNU General Public Licence V3. Jika kita ingin memiliki harapan apa pun untuk melestarikan Amiga maka kita tidak boleh menjerat satu sama lain untuk hak istimewa itu, dan selain itu, saya ingin memberikan kembali ke platform terbaik yang pernah saya kerjakan. Saya juga berharap orang akan mengembangkan ini dan membawa lebih jauh dan terus berbagi.
Saya selanjutnya ingin melihat format lain. File ADF bagus, tetapi mereka hanya berfungsi untuk disk yang diformat AmigaDOS. Ada banyak judul dengan perlindungan salinan khusus dan format sektor non-standar yang sebenarnya tidak dapat didukung oleh format ini.
Menurut Wikipedia ada format file disk lain, format FDI. Format universal yang terdokumentasi dengan baik. Keuntungan dari format ini adalah ia mencoba menyimpan data track sejauh mungkin dari aslinya jadi semoga akan memperbaiki masalah di atas!
Saya juga menemukan Software Preservation Society, khususnya CAPS (sebelumnya Classic Amiga Preservation Society) dan format IPF mereka. Setelah sedikit membaca saya sangat kecewa, semuanya tertutup, dan terasa seperti mereka hanya menggunakan format ini untuk menjual hardware pembaca disk mereka.
Jadi fokus saya akan pada format FDI! Keunggulan saya di sini adalah dengan integritas data. Tidak akan ada checksum bagi saya untuk diperiksa untuk melihat apakah baca valid, tetapi saya memiliki beberapa ide untuk menyelesaikan itu!
Dan akhirnya saya juga akan melihat untuk menambahkan opsi tulis disk (mungkin mendukung FDI serta ADF), karena seharusnya tidak sulit untuk ditambahkan.
Code
GitHub Repo
Sketsa Arduino dan kode sumber Windows: https://github.com/RobSmithDev/ArduinoFloppyDiskReader