Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Arduino Amiga Floppy Disk Reader (V1)

Componenten en benodigdheden

Weerstand 1k ohm
× 1
Broodplank (algemeen)
× 1
Jumperdraden (algemeen)
× 1
SparkFun Breadboard-voeding 5V/3,3V
× 1
Arduino UNO
Of Pro Mini
× 1

Apps en online services

Arduino IDE

Over dit project

  • Mijn doel: Om een ​​eenvoudige, goedkope en open source manier te creëren om gegevens van Amiga DD diskettes te herstellen vanuit Windows 10 en andere besturingssystemen.
  • Mijn oplossing: Een Arduino + een Windows-applicatie
  • Waarom: Om gegevens van deze schijven voor de toekomst te bewaren. Ook kan een normale pc geen Amiga-schijven lezen vanwege de manier waarop ze zijn geschreven.

Projectwebsite:http://amiga.robsmithdev.co.uk/

Dit is V1 van het project. V2 bevat verbeterd lezen en schrijven!

Amiga-ervaringen

Ik heb mijn carrière te danken aan de Amiga, met name de A500+ die mijn ouders op 10-jarige leeftijd voor kerst voor me kochten. In het begin speelde ik de games, maar na een tijdje begon ik nieuwsgierig te worden naar wat het nog meer kon doen. Ik speelde met de Deluxe Paint III en leerde over Workbench.

De Amiga 500 Plus:

Elke maand kocht ik het populaire tijdschrift Amiga Format. Een maand had een gratis exemplaar van AMOS. Ik heb het Amiga-formaat ingevoerd Write A Game In AMOS wedstrijd toen AMOS Professional later op een coverdisk werd gezet en een van de 12 (denk ik) winnaars was met In The Pipe Line . Je moest ze echter echt achterna zitten voor prijzen!

AMOS - De Schepper:

Achtergrond

Verderop gebruikte ik het als onderdeel van mijn GCSE's en A-Level-projecten (dankzij Highspeed Pascal, dat compatibel was met Turbo Pascal op de pc)

Hoe dan ook, dat was lang geleden, en ik heb dozen met schijven en een A500+ die het niet meer doet, dus ik dacht erover om die schijven op mijn computer te back-uppen, zowel voor behoud als voor nostalgie.

De Amiga Forever-website heeft een uitstekende lijst met opties, waaronder hardware en misbruik van twee diskettestations in een pc. Helaas was geen van deze opties een optie met moderne hardware, en de KryoFlux/Catweasel-controllers zijn te duur. Ik was echt verrast dat het meeste closed source was.

Massaal in elektronica en gespeeld met Atmel-apparaten (AT89C4051 ) toen ik aan de universiteit zat, besloot ik de Arduino te bekijken (met dank aan GreatScott voor de inspiratie die laat zien hoe gemakkelijk het is om te beginnen) vroeg ik me af of dit mogelijk was.

Dus ik googelde voor Arduino diskettestation lezen code, en na het overslaan van alle projecten die misbruikt de drive om muziek te spelen, vond ik niet echt oplossingen. Ik vond een paar discussies in een paar groepen die suggereerden dat het niet mogelijk zou zijn. Ik vond wel een project rond een FPGA dat erg interessant was om te lezen, maar niet de richting die ik op wilde, dus de enige optie was om zelf een oplossing te bouwen.

Onderzoek

Toen ik aan dit project begon, had ik geen idee hoe de diskettedrive werkte, en nog minder hoe de gegevens erop waren gecodeerd. De volgende websites waren van onschatbare waarde voor mijn begrip van wat er gebeurt en hoe ze werken:

  • techtravels.org (en deze pagina)
  • Veelgestelde vragen over de .ADF-indeling (Amiga Disk File) door Laurent Clévy
  • Amiga Forever
  • Wikipedia - Amiga-schijfbestand
  • Engels Amiga-bord
  • QEEWiki - Tellers op de ATmega168/328
  • Pinout diskettestation
  • Lijst met disketteformaten

Aannames

Op basis van het onderzoek wist ik nu theoretisch hoe de gegevens naar de schijf werden geschreven en hoe de schijf draaide.

Ik begon wat cijfers uit te werken. Gebaseerd op de snelheid waarmee de schijf met dubbele dichtheid ronddraaide (300 tpm) en de manier waarop de gegevens zijn opgeslagen (80 tracks, 11 sectoren per track en 512 bytes per sector, gecodeerd met MFM), om de gegevens nauwkeurig te lezen die ik nodig had om te kunnen bemonster de gegevens op 500 Khz; dat is best snel als je bedenkt dat de Arduino maar op 16Mhz draait.

In de volgende pogingen heb ik het alleen over de Arduino-kant. Ga naar decoderen.

Poging 1:

Eerst moest ik de hardware en de interface naar de diskettedrive verzamelen. De diskettedrive die ik op mijn werk van een oude pc heb gehaald en tegelijkertijd de IDE-kabel heb gepakt.

Hieronder staat een foto van bevrijd diskettestation van een oude pc:

Toen ik de pin-out van de drive bestudeerde, realiseerde ik me dat ik maar een paar draden nodig had, en nadat ik naar de drive had gekeken, realiseerde ik me dat deze ook geen 12v-ingang gebruikte.

De aandrijving laten draaien werd bereikt door de aandrijving te selecteren en de motor in te schakelen. Het hoofd verplaatsen was eenvoudig. U stelt de /DIR pin hoog of laag en pulseerde vervolgens de /STEP pin. Je kon zien of het hoofd track 0 (de eerste track) had bereikt door de /TRK00 in de gaten te houden pin.

Ik was benieuwd naar de /INDEX pin. Deze pulseert één keer per omwenteling. Omdat de Amiga dit niet gebruikt om het begin van de track te vinden, had ik het niet nodig en kon het negeren. Hierna is het gewoon een kwestie van kiezen welke kant van de schijf moet worden gelezen (/SIDE1 ) en verbinding maken met /RDATA .

Met de hoge gegevenssnelheidsvereiste was mijn eerste gedachte om een ​​manier te vinden om dit minder een probleem te maken door te proberen de vereisten voor deze snelheid te verlagen.

Het plan was om twee 8-bit schuifregisters te gebruiken (SN74HC594N ) om de vereiste bemonsteringsfrequentie met een factor 8 te verminderen. Ik gebruikte wat Ebay noemde Pro Mini atmega328 Board 5V 16M Arduino Compatible Nano (dus ik weet niet wat dat officieel is, maar dit werkt wel op de Uno!) om dit parallel te bufferen gegevens en stuur deze naar de pc met behulp van de seriële/USART-interface. Ik wist dat dit sneller moest zijn dan 500 Kbaud (met alle seriële overhead erbij).

sn74hc594.pdf

Na het dumpen van de standaard Arduino seriële bibliotheek, was ik erg blij te ontdekken dat ik de USART op de Arduino kon configureren met uptp 2M baud, en met een van die F2DI break-out boards (eBay noemde het Basic Breakout Board For FTDI FT232RL USB naar serieel IC voor Arduino - zie hieronder) Ik kon met plezier gegevens verzenden en ontvangen met deze snelheid (62,5 Khz), maar ik moest dit nauwkeurig doen.

Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf

Het FTDI breakout board dat perfect past bij de interface op het Arduino board:

Eerst gebruikte ik de Arduino om van de 8-bits schuifregisters slechts één van de 8 bits hoog te klokken. De andere ontving een feed rechtstreeks van de floppydrive (waardoor serie-naar-parallel conversie mogelijk werd).

Het volgende is een gekke foto van het breadboard waarop ik dit destijds heb gebouwd:

Ik heb een van de Arduino-timers gebruikt om een ​​500Khz-signaal op een van de uitgangspinnen te genereren en omdat de hardware dit beheert, is het zeer nauwkeurig! - Nou, mijn multimeter mat het toch als precies 500khz.

De code werkte, ik klokte een volledige 8-bits aan gegevens in op 62,5 kHz, waardoor de Arduino-CPU nauwelijks werd gebruikt. Ik heb echter niets zinnigs ontvangen. Op dat moment realiseerde ik me dat ik de feitelijke gegevens die uit de floppydrive komen, nader moest bekijken. Dus kocht ik een goedkope oude oscilloscoop van eBay (Gould OS300 20Mhz Oscilloscope) om te kijken wat er aan de hand was.

Terwijl ik wachtte tot de oscilloscoop arriveerde, besloot ik iets anders te proberen.

Een codefragment dat wordt gebruikt om de gegevens uit de schuifregisters te lezen:

void readTrackData() { byte op; for (int a=0; a<5632; a++) {// We wachten op de "byte" startmarkering while (digitalRead(PIN_BYTE_READ_SIGNAL)==LOW) {}; // Lees de 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); // Wacht tot high weer daalt terwijl (digitalRead(PIN_BYTE_READ_SIGNAL)==HIGH) {}; }} 

Poging 2:

Ik besloot dat de ploegenregisters, terwijl een leuk idee waarschijnlijk niet hielp. Ik kon gemakkelijk 8 bits in één keer lezen, maar het kwam bij me op dat ik er niet zeker van kon zijn dat alle bits in de eerste plaats correct waren ingeklokt. Bij het lezen van de documentatie suggereerde het dat de gegevens meer uit korte pulsen bestonden dan uit pieken en dalen.

Ik verwijderde de schuifregisters en vroeg me af wat er zou gebeuren als ik probeerde te controleren op een puls van de schijf in een Interrupt (ISR) met behulp van het eerder ingestelde 500Khz-signaal. Ik heb de Arduino opnieuw geconfigureerd om de ISR te genereren, en nadat ik de problemen van de Arduino-bibliotheken die in de weg zaten (met behulp van de ISR die ik wilde) voorbij was, ging ik naar Timer 2.

Ik schreef een korte ISR die een globale enkele byte met één bit naar links zou verschuiven en als de pin die op de datalijn van de diskettedrive was aangesloten LAAG was (de pulsen zijn laag) Ik zou er OF een 1 op zetten. Elke 8 keer dat ik dit deed, schreef ik de ingevulde byte naar de USART.

Dit ging niet zoals verwacht! De Arduino begon zich zeer grillig en vreemd te gedragen. Ik realiseerde me al snel dat de ISR meer tijd kostte om uit te voeren dan de tijd tussen de oproepen ernaar. Ik zou elke 2 µSec een puls kunnen ontvangen op basis van de snelheid van de Arduino, en een wilde veronderstelling maken dat elke C-instructie vertaald naar 1 klokmachinecodecyclus, Ik realiseerde me dat ik maximaal 32 instructies kon hebben. Helaas zouden de meeste meer dan één instructie zijn, en na Googlen realiseerde ik me dat de overhead bij het starten van een ISR sowieso enorm was; om nog maar te zwijgen van het feit dat de digitalRead-functies erg traag zijn.

Ik heb de digitalRead . gedumpt functie in het voordeel van directe toegang tot de poortpinnen! Dit hielp nog steeds niet en was niet snel genoeg. Omdat ik niet bereid was op te geven, stopte ik deze aanpak en besloot ik verder te gaan en iets anders te proberen.

Op dit punt arriveerde de oscilloscoop die ik had gekocht, en het werkte! Een knapperige oude oscilloscoop die waarschijnlijk ouder was dan ik! Maar deed het werk nog steeds perfect. (Als je niet weet wat een oscilloscoop is, kijk dan eens op EEVblog #926 - Introduction To The Oscilloscope, en als je van elektronica houdt, raad ik je aan er nog een paar te bekijken en rond te snuffelen op de EEVBlog-website.

Mijn nieuw aangeschafte knapperige oude oscilloscoop (Gould OS300 20Mhz):

Nadat het 500Khz-signaal op het ene kanaal was aangesloten en de uitvoer van de floppydrive op het andere, was het duidelijk dat er iets niet klopte. Het 500Khz-signaal was een perfecte blokgolf die het als een trigger gebruikte, de floppy-gegevens waren overal. Ik kon de pulsen zien, maar het was meer een waas. Als ik het signaal van de floppydrive activeerde, was het blokgolfsignaal van het 500Khz-signaal overal en niet synchroon ermee.

Foto's van de sporen op de oscilloscoop die van de twee kanalen uitgaan. Je kunt het niet helemaal zien, maar op het kanaal niet die worden geactiveerd, zijn duizenden vage spookachtige lijnen:

Individueel kon ik pulsen meten van beide signalen op 500 Khz, wat niet logisch was, alsof ze allebei op dezelfde snelheid liepen maar niet zouden worden geactiveerd, zodat je beide signalen goed kunt zien, dan moet er iets mis zijn.

Na veel spelen met de triggerlevels lukte het me om erachter te komen wat er aan de hand was. Mijn signaal was een perfecte 500Khz, maar als ik naar het signaal van de floppydrive kijk, dan waren ze correct verdeeld, maar niet altijd. Tussen groepen pulsen was er een foutafwijking, en ook hiaten in de gegevens waardoor het signaal totaal niet synchroon liep.

Als ik me het vorige onderzoek herinner, moest de schijf met 300 tpm draaien, maar het zou eigenlijk niet precies 300 tpm kunnen zijn, plus de schijf die de gegevens schreef, zou ook niet precies 300 tpm kunnen zijn. Dan is er nog de afstand tussen sectoren en sectorhiaten. Er was duidelijk een synchronisatieprobleem en het synchroniseren van het 500Khz-signaal naar de diskettedrive aan het begin van het lezen zou niet werken.

Ik ontdekte ook dat de puls van de diskettedrive extreem kort was, hoewel je dit zou kunnen wijzigen door de pullup-weerstand te veranderen, en als de timing niet precies goed was, zou de Arduino een puls kunnen missen.

Toen ik op de universiteit (University of Leicester) zat, volgde ik een module met de naam embedded system. We hebben de Atmel 8051-microcontrollers bestudeerd. Een van de projecten betrof het tellen van pulsen van een gesimuleerd weerstation (roterende encoder). Destijds proefde ik de pin met regelmatige tussenpozen, maar dit was niet erg nauwkeurig.

De moduledocent, Prof Pont suggereerde dat ik de hardwareteller had moeten gebruiken kenmerken van het apparaat (ik wist niet eens dat het er ooit een had.)

Ik controleerde de datasheet voor de ATMega328 en ja hoor, elk van de drie timers kon worden geconfigureerd om pulsen te tellen die door een externe ingang werden geactiveerd. Hierdoor was snelheid geen issue meer. Het enige dat ik eigenlijk moest weten, was of er een puls was opgetreden binnen een tijdvenster van 2 µSec.

Poging 3:

Ik heb de Arduino-schets aangepast om de 500khz-timer opnieuw in te stellen wanneer de eerste puls werd gedetecteerd en elke keer dat de 500khz-timer overstroomde, controleerde ik de tellerwaarde om te zien of er een puls was gedetecteerd. Ik voerde vervolgens dezelfde bit-shifting-reeks uit en elke 8 bits schreef een byte naar de USART.

Er kwamen gegevens binnen en ik begon het op de pc te analyseren. In de gegevens begon ik te zien wat leek op geldige gegevens. Het vreemde synchronisatiewoord zou verschijnen, of groepen van 0xAAAA-reeksen, maar niets betrouwbaars. Ik wist dat ik iets op het spoor was, maar miste nog steeds iets.

Poging 4:

Ik realiseerde me dat terwijl de gegevens werden gelezen, de gegevens van de schijf waarschijnlijk niet synchroon liepen met mijn 500 kHz-signaal. Ik heb dit bevestigd door elke keer dat ik begon met lezen 20 bytes te lezen.

Toen ik las over hoe ik met dit synchronisatieprobleem moest omgaan, kwam ik de zin Phase Locked Loop of PLL tegen. In zeer eenvoudige bewoordingen, voor wat we doen, zou de fasevergrendelde lus de klokfrequentie (de 500 kHz) dynamisch aanpassen om frequentieafwijking en variantie in het signaal te compenseren.

De resolutie op de timer was niet hoog genoeg om het met kleine hoeveelheden te variëren (bijv. 444khz, 470khz, 500khz, 533khz, 571khz enz.) en om dit goed uit te voeren, zou ik de code waarschijnlijk een heel stuk sneller moeten laten lopen.

De Arduino-timers werken door te tellen tot een vooraf bepaald aantal (in dit geval 16 voor 500khz ) dan stellen ze een overloopregister in en beginnen ze opnieuw vanaf 0. De actuele tellerwaarde kan op elk moment worden gelezen en beschreven.

Ik heb de schets aangepast om in een lus te wachten tot de timer overliep, en toen hij overliep, controleerde ik of er een puls was zoals voorheen. Het verschil deze keer was dat wanneer een puls werd gedetecteerd in de lus, ik reset de timertellerwaarde naar een vooraf gedefinieerde fase positie, waardoor de timer effectief opnieuw wordt gesynchroniseerd met elke puls.

Ik koos de waarde die ik naar de timerteller schreef, zodanig dat deze op 1 µsec van de detectiepuls (halverwege) zou overlopen, zodat de volgende keer dat de timer overstroomde, de puls 2 µsec uit elkaar zou zijn geweest.

Dit werkte! Ik las nu bijna perfecte gegevens van de schijf. Ik kreeg nog steeds veel checksum-fouten, wat vervelend was. Ik loste de meeste hiervan op door steeds hetzelfde nummer op de schijf opnieuw te lezen totdat ik alle 11 sectoren had met geldige header- en gegevenscontrolesommen.

Ik was op dit punt nieuwsgierig, dus ik haakte het allemaal weer aan de oscilloscoop om te zien wat er nu aan de hand was, en zoals ik al vermoedde, kon ik nu beide sporen zien omdat ze allebei synchroon met elkaar bleven:

Ik zou dit graag wat duidelijker zien, als iemand mij een mooie digitale oscilloscoop van topkwaliteit wil schenken (bijvoorbeeld een van die Keysight-oscilloscopen!) zou ik het zeer op prijs stellen!

Poging 5:

Ik vroeg me af of ik hierin verbetering zou kunnen brengen. Kijkend naar de code, met name de binnenste leeslus (zie hieronder), had ik een while-lus die wachtte op de overloop en vervolgens een innerlijke if op zoek naar een hartslag om mee te synchroniseren.

Een codefragment dat wordt gebruikt om de gegevens te lezen en ermee te synchroniseren:

register bool done =false;// Wacht op 500khz overflow terwijl (!(TIFR2&_BV(TOV2))) { // dalende flank gedetecteerd tijdens het wachten op de 500khz puls. if ((TCNT0) &&(!done)) { // puls gedetecteerd, reset de timerteller om te synchroniseren met de puls TCNT2=fase; // Wacht tot de hartslag weer hoog wordt terwijl (!(PIN_RAW_FLOPPYDATA_PORT &PIN_RAW_FLOPPYDATA_MASK)) {}; gedaan =waar; }}// Reset de overloopvlagTIFR2|=_BV(TOV2); // Hebben we een puls van de drive gedetecteerd?if (TCNT0) {DataOutputByte|=1; TCNT0=0;} 

Ik realiseerde me dat, afhankelijk van welke instructie werd uitgevoerd in de bovenstaande lussen, de tijd tussen pulsdetectie en het schrijven van TCNT2=phase; kan veranderen tegen de tijd die nodig is om een ​​paar instructies uit te voeren.

Omdat ik me realiseerde dat dit enkele fouten/jitter in de gegevens kan veroorzaken en ook met de bovenstaande lus is het mogelijk dat ik de puls van de schijf mis (waardoor ik een re-sync bit mis). Ik besloot om een ​​van mijn eerdere pogingen, de ISR (onderbreken).

Ik heb de datapuls aangesloten op een tweede pin op de Arduino. De data was nu verbonden met de COUNTER0 trigger en nu ook de INT0 pin. INT0 is een van de hoogste interrupt-prioriteiten, dus het zou de vertragingen tussen de trigger en de ISR die wordt aangeroepen moeten minimaliseren, en aangezien dit de enige interrupt is, ben ik geïnteresseerd in het feit dat alle andere zijn uitgeschakeld.

Het enige dat nodig was om te onderbreken, was de bovenstaande hersynchronisatiecode uit te voeren, waardoor de code er als volgt uitzag:

// Wacht op 500khz overloop terwijl (!(TIFR2&_BV(TOV2))) {} // Reset de overloopvlagTIFR2|=_BV(TOV2); // Hebben we een puls van de drive gedetecteerd?if (TCNT0) {DataOutputByte|=1; TCNT0=0;} 

De ISR zag er als volgt uit:(merk op dat ik attachInterrupt niet heb gebruikt, omdat dit ook overhead aan de oproep toevoegt).

vluchtige byte targetPhase;ISR (INT0_vect) { TCNT2=targetPhase;} 

Het compileren hiervan produceerde veel te veel code om snel genoeg uit te voeren. In feite het demonteren van het bovenstaande geproduceerd:

push r1push r0in r0, 0x3f; 63push r0eor r1, r1push r24 lds r24, 0x0102; 0x800102 steken 0x00B2, r24; 0x8000b2 pop r24pop r0out 0x3f, r0; 63pop r0pop r1reti 

Door de code te analyseren realiseerde ik me dat er maar een paar instructies waren die ik echt nodig had. Ik merkte op dat de compiler alle registers die ik bashen zou bijhouden, veranderde ik de ISR als volgt:

 vluchtige byte targetPhase asm ("targetPhase");ISR (INT0_vect) { asm vluchtige ("lds __tmp_reg__, targetPhase"); asm vluchtige("sts %0, __tmp_reg__" ::"M" (_SFR_MEM_ADDR(TCNT2)));} 

Die gedemonteerd, produceerde de volgende instructies:

push r1push r0in r0, 0x3f; 63duw r0eor r1, r1lds r0, 0x0102; 0x800102 steken 0x00B2, r0; 0x8000b2 pop r0out 0x3f, r0; 63pop r0pop r1reti 

Nog te veel instructies. Ik merkte dat de compiler veel extra instructies toevoegde, die voor mijn toepassing er eigenlijk niet hoefden te zijn. Dus ik zocht de ISR() . op en stuitte op een tweede parameter ISR_NAKED. Door dit toe te voegen, zou de compiler geen speciale code kunnen toevoegen, maar dan zou ik verantwoordelijk zijn voor het onderhouden van registers, de stapel en het correct terugkeren van de interrupt. Ik zou ook het SREG-register moeten bijhouden, maar omdat geen van de commando's die ik moest bellen het heeft gewijzigd, hoefde ik me er geen zorgen over te maken.

Dit veranderde de ISR-code in:

ISR (INT0_vect, ISR_NAKED) { asm vluchtig("push __tmp_reg__"); // Bewaar de tmp_register asm vluchtige ("lds __tmp_reg__, targetPhase"); // Kopieer de fasewaarde naar het tmp_register asm vluchtige("sts %0, __tmp_reg__" ::"M" (_SFR_MEM_ADDR(TCNT2))); // Kopieer het tmp_register naar de geheugenlocatie waar TCNT2 asm vluchtig is ("pop __tmp_reg__"); // Herstel de tmp_register asm vluchtige ("reti"); // En verlaat de ISR} 

Waar de compiler naar heeft geconverteerd:

druk op r0lds r0, 0x0102; 0x800102 steken 0x00B2, r0; 0x8000b2 pop r0reti 

Vijf instructies! Perfect, of in ieder geval zo snel als het zou zijn, theoretisch gezien 0,3125 µSec nodig om uit te voeren! Dit zou nu moeten betekenen dat de hersynchronisatie moet plaatsvinden in tijdconsistente perioden na de puls. Hieronder is een timingdiagram van wat er aan de hand is. Zo herstel je data van een seriële datafeed die geen kloksignaal heeft:

Dit verbeterde de resultaten een beetje. Het is nog steeds niet perfect. Sommige schijven lezen elke keer perfect, sommige schijven duurt eeuwen en moet het steeds opnieuw proberen. Ik weet niet zeker of dit komt omdat sommige schijven daar al zo lang hebben gezeten dat het magnetisme zo laag is geworden dat de versterkers van de aandrijving het niet aankunnen. Ik vroeg me af of dit iets te maken had met de diskettedrive van de pc, dus ik verbond deze met een externe Amiga diskettedrive die ik had, maar de resultaten waren identiek.

Poging 6:

Ik vroeg me af of er nog iets aan te doen was. Misschien was het signaal van de drive luidruchtiger dan ik dacht. Na het lezen van meer informatie ontdekte ik dat een pullup-weerstand van 1 KOhm de norm was, ingevoerd in een Schmitt-trigger.

Na het installeren van een SN74HCT14N Hex Schmitt-trigger en het opnieuw configureren van de schets om te triggeren op stijgende randen in plaats van dalende randen, probeerde ik het, maar het maakte niet echt een merkbaar verschil. Ik denk dat, aangezien ik elke keer naar een of meer pulsen zocht, dit waarschijnlijk geabsorbeerd toch enig geluid. Dus we houden het bij methode Attempt 5!

sn74hct14.pdf

Mijn uiteindelijke breadboard-oplossing zag er zo uit:

Merk op dat de bedrading op het bovenstaande enigszins verschilt van de live-schets. Ik heb een aantal Arduino-pinnen opnieuw besteld om het schakelschema gemakkelijker te maken.

Poging 7:

Ik was een beetje ontevreden over sommige schijven die ik niet had gelezen. Soms zaten de schijven gewoon niet goed in de diskettedrive. Ik denk dat de veer op de sluiter niet hielp.

Ik begon te kijken of er fouten waren in de daadwerkelijk ontvangen MFM-gegevens van de schijf.

Uit de regels van hoe MFM-codering werkt, realiseerde ik me dat een paar eenvoudige regels als volgt kunnen worden toegepast:

  • Er mogen geen twee '1'-bits naast elkaar staan
  • Er mogen niet meer dan drie '0'-bits naast elkaar staan

Ten eerste keek ik bij het decoderen van MFM-gegevens of er twee '1's op een rij waren. Als dat zo was, nam ik aan dat de gegevens in de loop van de tijd een beetje wazig waren geworden en negeerde ik de tweede '1'.

Met deze regel toegepast, zijn er letterlijk drie situaties van 5 bits waar fouten blijven optreden. Dit zou een nieuw gebied zijn waar ik zou kunnen kijken om de gegevens te verbeteren.

Maar ik was vooral verrast dat er niet zoveel MFM-fouten werden gedetecteerd. Ik ben een beetje in de war waarom sommige schijven niet kunnen lezen als er geen fouten worden gevonden.

Dit is een gebied voor verder onderzoek.

Decodering

Nadat ik had gelezen hoe MFM werkte, wist ik niet helemaal zeker hoe het correct was uitgelijnd.

In eerste instantie dacht ik dat de drive 1s en 0s uitvoerde voor de aan en uit bits. Dit was niet het geval. De omvormer geeft een puls af voor elke faseovergang, dwz:elke keer dat de data van 0 naar 1 of van 1 naar 0 gingen.

Nadat ik dit had gelezen, vroeg ik me af of ik dit terug moest converteren naar enen en nullen door het in een flip-flop-toggle te voeren, of de gegevens te lezen, naar sectoren te zoeken en als er geen werden gevonden, de gegevens omkeren en het opnieuw proberen!

Het blijkt dat dit niet het geval is en dat het veel eenvoudiger is. De pulsen zijn eigenlijk de RAW MFM-gegevens en kunnen rechtstreeks in de decoderingsalgoritmen worden ingevoerd. Nu ik dit begreep, begon ik code te schrijven om een ​​buffer van de schijf te scannen en te zoeken naar het synchronisatiewoord 0x4489. Verrassend genoeg vond ik het!

Uit het onderzoek dat ik had uitgevoerd, realiseerde ik me dat ik echt moest zoeken naar 0xAAAAAAA44894489 (een aantekening van het onderzoek suggereerde ook dat er enkele bugs waren in de vroege Amiga-code die betekenden dat de bovenstaande reeks niet werd gevonden. Dus in plaats daarvan zocht ik naar 0x2AAAAAAA44894489 na het ANDen van de gegevens met 0x7FFFFFFFFFFFFFF ).

Zoals verwacht vond ik er tot 11 van deze op elke baan die overeenkomt met de daadwerkelijke start van de 11 Amiga-sectoren. Ik begon toen de bytes te lezen die volgden om te zien of ik de sectorinformatie kon decoderen.

Ik heb een stukje code uit een van de bovenstaande referenties genomen om te helpen bij het decoderen van MFM. Het heeft geen zin om het wiel opnieuw uit te vinden, toch?

Na het lezen van de koptekst en gegevens, probeerde ik het naar schijf te schrijven als een ADF-bestand. Het standaard ADF-bestandsformaat is heel eenvoudig. Het zijn letterlijk gewoon de 512 bytes van elke sector (van beide kanten van de schijf) die in volgorde worden geschreven. Na het te hebben geschreven en geprobeerd te openen met ADFOpus en kreeg gemengde resultaten, soms opende het het bestand, soms mislukte het. Er zaten duidelijk fouten in de gegevens. Ik begon naar de checksum-velden in de header te kijken, sectoren met ongeldige checksums af te wijzen en het lezen te herhalen totdat ik 11 geldige had.

Voor sommige schijven waren dit alle 11 bij de eerste lezing, sommige namen verschillende pogingen en ook verschillende fasewaarden.

Eindelijk is het me gelukt om geldige ADF-bestanden te schrijven. Sommige schijven zouden eeuwen duren, sommige letterlijk de snelheid die de Amiga ze zou hebben gelezen. Omdat ik geen werkende Amiga meer heb, kon ik niet echt controleren of deze schijven normaal lezen, ze hebben jaren in een doos op zolder gestaan, dus het kan zijn dat ze aangetast zijn.

Dus wat nu?

Het volgende is al gebeurd - V2 is hier beschikbaar en heeft verbeterde lees- en schrijfondersteuning!

Ten eerste heb ik het hele project gratis en open source gemaakt onder GNU General Public License V3. Als we enige hoop willen hebben op het behoud van de Amiga, dan moeten we elkaar niet beroven voor het voorrecht, en bovendien wil ik teruggeven aan het beste platform waar ik ooit aan heb gewerkt. Ik hoop ook dat mensen dit zullen ontwikkelen en verder zullen ontwikkelen en blijven delen.

Ik wil nu naar andere formaten kijken. ADF-bestanden zijn goed, maar ze werken alleen voor AmigaDOS-geformatteerde schijven. Er zijn veel titels met aangepaste kopieerbeveiliging en niet-standaard sectorindelingen die eenvoudigweg niet door deze indeling kunnen worden ondersteund.

Volgens Wikipedia is er nog een ander schijfbestandsformaat, het FDI-formaat. Een universeel formaat dat goed gedocumenteerd is. Het voordeel van dit formaat is dat het probeert de trackgegevens zo dicht mogelijk bij het origineel op te slaan, dus hopelijk worden de bovenstaande problemen opgelost!

Ik kwam ook de Software Preservation Society tegen, met name CAPS (formeel de Classic Amiga Preservation Society ) en hun IPF-formaat. Na een beetje lezen was ik erg teleurgesteld, het was allemaal gesloten en het voelde alsof ze dit formaat gewoon gebruikten om hun schijfleeshardware te verkopen.

Dus mijn focus zal op de FDI liggen! formaat. Mijn enige zorg hier is met gegevensintegriteit. Er zijn geen checksums voor mij om te controleren of de read geldig was, maar ik heb een paar ideeën om dat op te lossen!

En tot slot zal ik er ook naar kijken door een schrijfschijfoptie toe te voegen (mogelijk met ondersteuning voor zowel FDI als ADF), omdat het echt niet zo moeilijk zou moeten zijn om toe te voegen.

Code

GitHub-opslagplaats
Arduino-schets en Windows-broncodehttps://github.com/RobSmithDev/ArduinoFloppyDiskReader

Schema's


Productieproces

  1. Animatie
  2. Diskette
  3. Arduino Spybot
  4. FlickMote
  5. Zelfgemaakte tv B-Gone
  6. Hoofdklok
  7. Vind mij
  8. Arduino Power
  9. Tech-TicTacToe
  10. Arduino Quadruped
  11. Arduino Amiga Floppy Disk Reader (V1)