Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Leitor / gravador de disquete Arduino Amiga (V2.2)

Componentes e suprimentos

Arduino UNO
× 1
SparkFun Arduino Pro Mini 328 - 5 V / 16 MHz
× 1
Resistor 1k ohm
× 1
Breadboard (genérico)
× 1
Fios de jumpers (genérico)
× 1
SparkFun FTDI Basic Breakout - 5V
× 1

Aplicativos e serviços online

Arduino IDE

Sobre este projeto


Este projeto continua o trabalho do meu projeto anterior de leitor de disco em https://create.arduino.cc/projecthub/projects/485582/

Para obter mais informações, visite http://amiga.robsmithdev.co.uk
  • Meu objetivo: Para criar uma forma simples, barata e de código aberto de recuperar e reescrever dados de e para os disquetes Amiga DD a partir do Windows 10.
  • Minha solução: Um esboço do Arduino + um aplicativo do Windows ( que pode ser transferido para outro O / S ) que realmente funciona!
  • Por quê: Para preservar os dados desses discos para o futuro. Além disso, um PC normal não pode ler / gravar discos Amiga devido à maneira como são gravados.





Gravando dados - Tentativa 1


Então, depois de conseguir ler os discos com sucesso, descobri que se você deseja manter a mídia física original, pode querer gravar os discos novamente. Achei que deveria resolver isso ao contrário, começando com o software (ou seja:convertendo os arquivos do disco ADF em dados MFM para a interface gravar de alguma forma )

Então comecei adicionando classes para ler um disco ADF e codificar todos os setores como uma trilha. Sabendo que poderia testar os dados que criei alimentando-os de volta na parte de decodificação, comecei a trabalhar nisso. Enquanto trabalhava nisso, decidi tentar descobrir o que havia de errado com meu Amiga. Afinal, não posso testar nenhum disco que criei se não tiver nada real para testá-los.

Desmontando meu A500 +, percebi que ele tinha um dos problemas mais comuns, a bateria do relógio vazava para todos os lados. Então, tirei a solda disso do quadro e comecei a limpá-lo. Enquanto isso, puxei a máquina inteira e comecei a limpar 20 anos de poeira e sujeira. Até desmontei a unidade de disquete para limpá-la.

Enquanto o limpava, decidi que era hora de me livrar do amarelecimento, então segui as informações sobre o Retr0brite e experimentei.

Em seguida, verifiquei todas as juntas da placa-mãe principal e encontrei uma conexão solta no conector de alimentação, alguns retoques com o ferro de solda e como novo. Esperei até estar satisfeito com o processo Retr0brite antes de remontar o computador.

Enquanto isso, continuei trabalhando no código para gravar discos. Eu queria ler o status da linha de proteção contra gravação, mas não importa o que eu configurei, ela não parecia mudar de voltagem. Então, separei o drive e segui os rastros dos pequenos interruptores que detectam o status de proteção contra gravação até um pequeno IC. Neste ponto, imaginei que a saída provavelmente só estará disponível quando você realmente quiser gravar dados.

Depois de muito de experimentação, descobri que você precisava puxar o / WRITE_GATE pin LOW antes de girar a unidade para permitir a gravação. Neste ponto, você pode obter o status de proteção contra gravação. Eu também notei que enquanto o / WRITE_GATE estava baixo, a unidade não desligou como antes até que o pino retornasse ao seu estado padrão HIGH.

O Amiga escreveria uma faixa inteira de uma vez. Uma faixa na memória tem 11 * 512 bytes (5638 bytes), no entanto, após a codificação MFM e colocando no formato AmigaDOS correto, a faixa funciona como 14848 bytes. Bem, não tem como caber nos 2k de memória do Arduino, nem nos seus 1k de EEPROM. Eu precisava de um método alternativo.

Decidi que tentaria enviar os dados 1 byte por vez em um thread de alta prioridade e aguardar um byte de resposta do Arduino antes de enviar o próximo. Mudei a taxa de transmissão para 2M para reduzir o atraso entre os personagens. Isso significava que demorava cerca de 5,5 uSec para enviar cada caractere e 5,5 uSec para recebê-lo de volta. O Arduino precisaria gravar 8 bits, a 500 kHz, portanto, precisaria de um novo byte a cada 16 uSeg. Portanto, deve haver tempo, supondo que o loop de código seja compacto o suficiente e o sistema operacional não atrase muito o envio e o recebimento.

Este foi um fracasso total e absoluto. Todo o ciclo de leitura / gravação demorou muito, muito além de uma revolução do disco. O lado do Arduino provavelmente era rápido o suficiente, mas o sistema operacional não respondia o suficiente. Ler discos funciona porque o sistema operacional (Windows no meu caso) armazenaria em buffer os dados que chegam, mas ao escrever, o Windows enviaria tudo de uma vez, mas como a taxa que estou enviando é muito mais rápida do que o Arduino precisa, dados seriam perdidos. Foi por isso que decidi por esse processo de reconhecimento bidirecional.





Gravando Dados - Tentativa 2


O controle de fluxo de software para este aplicativo simplesmente não era rápido o suficiente. Decidi investigar o controle de fluxo de hardware. Notei que na placa de breakout do FTDI existem pinos CTS e DTR. Significa Limpar para enviar e Data Terminal Ready . Percebi que enquanto a placa breakout estava conectada, a placa Arduino conectava o CTS ao GND.

Eu também não sabia em que direção esses pinos estavam realmente, mas depois de alguma experimentação, descobri que o pino CTS poderia ser sinalizado do Arduino e usado pelo PC para controlar o fluxo. Normalmente, isso é feito usando um buffer circular, mas no meu caso não poderia permitir isso, então eu simplesmente defini como '1' quando não quero dados e '0' enquanto faço.

Isso agora significava que eu poderia simplesmente pedir ao SO para enviar em massa os bytes como um pedaço e esperar que tudo fosse tratado no nível do kernel para que não fosse interrompido.

Eu tinha um loop interno que produzia cada bit dos 8 bits, mas decidi que provavelmente seria melhor dividir em 8 conjuntos de comandos.

Isso não funcionou. Se eu permitisse que o código fosse executado sem realmente executar a parte de gravação do disco, todos os bytes foram recebidos corretamente, mas com a execução do código, isso não aconteceu e os bytes recebidos estavam sendo perdidos.

Suspeitei que a alteração do status da linha CTX não interrompeu instantaneamente o fluxo de dados e o computador ainda pode enviar um ou dois caracteres. Possivelmente, no momento em que sinalizei a linha CTX, ela já estava enviando o próximo caractere.





Gravando dados - tentativa 3


Eu não queria ter uma interrupção em série, pois não queria que nenhum dos tempos de escrita fosse distorcido. Percebi que, entre a gravação de cada bit na unidade de disquete, haveria uma série de ciclos da CPU no próximo loop while. Decidi verificar entre cada gravação de bit se outro byte foi recebido desde que o CTX aumentou e armazená-lo.

Minha teoria era que quando você levantou CTX, o computador provavelmente já estava no meio da transmissão do próximo byte e como você não pode interrompê-lo no meio do fluxo, ele iria parar na metade deste. Isso significa que só preciso verificar um byte extra durante o loop e usá-lo se for encontrado, em vez de olhar para a porta serial novamente.

Portanto, pareceu funcionar, e o Arduino concluiu a gravação sem perder nenhum dado do computador. As únicas perguntas agora eram:ele realmente gravou algum dado e, em caso afirmativo, algum deles é válido?

Nesse ponto, eu tinha codificado apenas uma trilha, então decidi executar todo o algoritmo para codificar todas as 80 trilhas. Algo estranho estava acontecendo. O cabeçote não estava se movendo. Ainda o fazia durante a leitura, mas não durante a escrita.

Descobri que, para mover o cabeçote da unidade para frente e para trás, primeiro você precisava levantar o pino / WRITE GATE, suspeitei que isso também fosse necessário para alterar a superfície. Depois de adicionar o código para fazer isso, o cabeçote da unidade se moveu conforme o esperado. Isso fazia sentido e evitaria a escrita acidental de faixas enquanto movia a cabeça.

Então, neste ponto, escrevi uma imagem de disco que havia criado anteriormente e tentei lê-la de volta. Nada foi detectado! Os dados que escrevi eram inválidos ou a forma como os escrevi estava errada.

Decidi alimentar os dados de setor MFM codificados que estava criando em meu algoritmo de decodificação de setor usado pelo leitor para validar se o que estava gerando era correto e válido, e estava. Obviamente, algo estava errado com a maneira como eu estava gravando os dados no disco.





Gravando dados - tentativa 4


Como nenhum dado estava sendo lido corretamente, decidi tentar algumas abordagens diferentes. Eu não tinha certeza se o pino / WRITE DATA deveria ser pulsado (e se sim, por quanto tempo), alternado ou apenas definido para o valor de dados brutos. Minha implementação atual pulsou o pino. Não consegui encontrar nenhuma informação online sobre como o pino de escrita deveria ser fisicamente manipulado durante a escrita.

O cabeçote de leitura nos enviaria um pulso cada vez que houvesse uma reversão de fluxo. Decidi alterar a implementação para que WRITE DATA fosse apenas definido com o valor do bit. Isso também não funcionou. Portanto, mudei o código para alternar o estado atual do pino. Ainda sem sorte.

É claro que uma dessas abordagens deve ter sido a correta. Então, decidi pegar o osciloscópio confiável novamente para dar uma olhada no que estava acontecendo. Decidi escrever o padrão MFM 0xAA para cada byte em uma trilha continuamente. 0xAA em binário é B10101010, então isso me daria uma onda quadrada perfeita que eu poderia monitorar para a frequência necessária.

Se ele não visse uma onda quadrada perfeita na frequência desejada, eu sabia que devia haver algum tipo de problema de tempo.

Eu conectei o osciloscópio, mas fiquei surpreso ao ver que os tempos eram perfeito. No entanto, por ser um telescópio antigo, não consegui ver mais do que alguns pulsos. O osciloscópio tinha esse maravilhoso modo "mag" x10. Quando pressionado, aumentava a base de tempo em 10, mas, mais importante, permitia que você percorresse todos os dados de maneira muito semelhante a um osciloscópio digital moderno.

Algo não estava correto aqui. Parecia que a cada 12 bits mais ou menos eu acabava com um período de apenas "alto" .

Os dados que eu estava enviando eram de alguma forma inválidos ou algo estava causando uma pausa no processo de gravação a cada 12 bits ou mais. 12 sendo um número estranho considerando que há apenas 8 bits em um byte.

Depois de pensar sobre isso, me perguntei se eu estava de volta com um problema de controle de fluxo. A maneira como eu projetei o loop era coletar quaisquer bytes extras perdidos que foram recebidos após termos esperado por um. Mas não era inteligente o suficiente para evitar a espera a cada dois bytes. Eu tinha duas opções, mover alguma coisa em uma interrupção ou patch do loop.

Decidi tentar primeiro corrigir a forma como o loop funcionava. O problema era resultado de um atraso causado pela espera do próximo byte do computador. Se abaixássemos CTX e esperássemos por um byte, quando levantássemos CTX novamente, outro byte já estava a caminho.

Eu mudo o loop para que, quando o segundo byte recebido tiver sido usado, o Arduino momentaneamente diminua o CTS e depois volte a aumentar para permitir que outro caractere seja enviado. Isso significava que no próximo loop já teríamos recebido o próximo byte, portanto, não era necessário esperar.

Testar isso produziu uma onda quadrada perfeita:

Isso significava que todo o tempo para escrever uma faixa foi perfeito, apenas para o real dados que estavam sendo gravados. Decidi deixar isso rodar por algumas faixas e lados, e então reli para ver se estava escrito corretamente. Eu estava configurando o pino / WRITE_DATA para o valor de bit correspondente dos dados recebidos.

Ao ler os dados de volta, parecia que nada havia sido codificado, mas então pulei para o outro lado do disco. Com certeza, esse era o meu padrão. Eu não sabia por que havia escrito apenas em um lado do disco.

Depois de pensar um pouco, comecei a me perguntar se o pino / WRITE GATE não funcionava da maneira que pensei. Aconteceu que puxar o pino para baixo pode estar habilitando a cabeça de apagamento na unidade. Se for esse o caso, eu só devo fazer isso quando estiver realmente escrevendo, ou posso acabar com ruído no disco enquanto ele gira e apaga.

Mudei todo o código para que o / WRITE GATE fosse usado apenas ao iniciar a unidade pela primeira vez e, posteriormente, apenas literalmente durante o loop de gravação. Isso funcionou! Agora eu estava gravando dados em ambos os lados do disco!

Então, tentei novamente com uma imagem de disco ADF real e deixei terminar. Usei então a parte do leitor para ver se conseguia ler de volta. Funcionou! Mas, por alguma razão, demorou algum tempo para ler este disco de volta. Eu não estava recebendo nenhum erro de MFM, mas estava lutando para encontrar todos os setores.

Havia duas possibilidades para eu examinar agora:em primeiro lugar, os dados realmente foram escritos em tempo hábil; e em segundo lugar, o disco realmente funcionaria em um Amiga real?

Muito animado com a ideia de que posso ter realmente escrito um disco, inicializei o agora funcionando A500 + e coloque o disco. Momentos depois, o disco inicializa e exibe a famosa mensagem de erro de checksum. Então, eu estava escrevendo algo válido, mas não era consistente.

Decidi que, a menos que pudesse ler os dados em uma taxa muito mais precisa, seria inútil gravar um disco.





Lendo dados (novamente)


Eu queria melhorar a qualidade de leitura, pois não estava feliz com a implementação atual. A implementação atual não permitiu flexibilidade suficiente para os pulsos chegarem em momentos um pouco estranhos. Eu precisava de uma nova abordagem.

Em primeiro lugar, decidi que sincronizaria a leitura com o pulso / INDEX. Não é exigido pelo Amiga, mas pode ser útil mais tarde para testar, escrever e ler.

Várias pessoas nos comentários da primeira metade deste projeto sugeriram que eu deveria registrar o tempo entre os pulsos, em vez do método que implementei. O único problema com isso era levar esses dados para o PC com rapidez suficiente. Se eu fosse enviar um byte para cada bit, poderia facilmente exceder o máximo de 2M de baud.

Decidi que a melhor coisa a fazer seria tentar entender um pouco os dados. Então eu decidi deixar o contador que eu estava usando originalmente rodar livremente, até 255. Eu então coloquei o código em um loop esperando por um pulso e este ponto viu quanto tempo havia passado.

Em uma situação ideal, o menor valor mínimo possível seria 32 (correspondendo a 2 uSeg). Com o MFM, você só poderia ter um máximo de três zeros em uma linha, então o máximo que esse valor deveria atingir era 128. Isso significava que havia no máximo 4 combinações possíveis em uma linha.

Eu testei vários discos para ver onde fica a maioria dessas frequências, e os resultados podem ser vistos abaixo:

Olhando para isso, encontro a maioria dos pontos em torno de um contador de 52, 89 e 120. No entanto, eles eram um tanto específicos para minha unidade e, portanto, não eram uma boa orientação. Após algumas experiências, usei a seguinte fórmula: value =(COUNTER - 16) / 32 . Quando cortado entre 0 e 3, isso me deu a saída que eu precisava. Cada 4 deles e eu poderíamos escrever um byte.

Ocorreu-me que, como você não poderia ter dois '1's juntos em um fluxo de bits codificado MFM, eu poderia assumir com segurança que qualquer coisa para o primeiro valor era inválido e poderia ser tratado como outra sequência' 01 '. A próxima parte foi descompactar esses dados uma vez recebidos pelo PC e transformá-los novamente em dados MFM. Isso era simples, já que 00 não poderia acontecer, um 01 significava escrever '01', um 10 significava escrever '001' e um 11 significava escrever '0001'. Eu tentei isso e, para minha surpresa, meus resultados foram 100% bem-sucedidos. Também tentei com mais alguns discos, 100%! Agora eu tinha um leitor de disco muito confiável.

Com essa nova abordagem sendo muito mais tolerante com os dados do disco, não precisei mais de nenhuma análise de fase ou de tantas tentativas. A maioria dos meus discos agora lê perfeitamente. Alguns exigiram algumas tentativas, mas acabaram chegando lá. A última parte foi analisar estatisticamente os dados e ver se eles poderiam ser reparados; no entanto, 99% das vezes, os dados ruins que chegavam eram completamente irreconhecíveis e, portanto, de pouca ajuda.





Gravando dados - tentativa 5


Agora que eu podia verificar o que havia escrito com alta precisão, seria muito mais fácil testar o redator.

Comecei a analisar o código para ver o que estava errado. Escrevi uma sequência 0x55 para uma faixa inteira e, em seguida, li de volta. De vez em quando, um pouco mudou na volta dos dados, o que significa que havia algum tipo de problema de tempo na escrita.

Acontece que isso se deveu em parte à maneira como eu estava lidando com a porta serial e em parte ao uso do temporizador. Eu estava esperando o cronômetro atingir o valor 32, escrevendo o bit e, em seguida, reiniciando-o. Eu mudei para não ter que modificar o valor do contador do cronômetro.

Eu escreveria o primeiro bit quando o contador atingisse 16, depois o próximo quando atingisse 48 (16 + 32) e o próximo quando atingisse 80 (16 + 32 + 32) e assim por diante. Sendo o Timer2 de apenas 8 bits, volta para zero após o 8º bit, exatamente quando precisamos. Isso significava que, enquanto escrevêssemos o bit no valor do temporizador necessário, estaríamos exatamente a 500 kbps.

Também observei como estava lendo os dados da porta serial. Isso estava sendo lido entre cada bit, mas também precisava ser o mais curto possível. Depois de um pouco de experimentação, alcancei o bloco de trabalho mais curto.

Depois de modificar o código do Windows para suportar a verificação, agora eu estava pronto para tentar novamente. Desta vez eu sabia que se o disco fosse verificado corretamente, ele deveria funcionar corretamente no Amiga.

Então, tentei gravar outro disco. Com a verificação demorou mais. Com o novo algoritmo, cerca de 95% das faixas passaram na verificação na primeira tentativa, com apenas os 5% restantes tendo que ser reescritos mais uma vez. Fiquei feliz com isso e coloquei o disco no Amiga. Funcionou perfeitamente!





Gravando dados - tentativa 6


Depois de alguns comentários de algumas pessoas que têm usado isso, ficou claro que mesmo com o Verify na unidade nem sempre estava produzindo discos totalmente legíveis. O software poderia lê-los perfeitamente, mas os computadores Amiga relatariam alguns erros de checksum aqui e ali.

Dei outra olhada no código, me perguntei se era um problema de tempo e verifiquei se poderia ser feito para ser controlado por interrupções, mas, infelizmente, com a pequena quantidade de tempo entre cada bit, simplesmente não há tempo suficiente com interrupções para consiga isso preservando os registros que você modificar etc.

Eu então olhei de volta para o código de escrita. Há uma pequena chance de que, após a gravação de um byte completo, o código possa ter feito um loop de volta para começar a escrever o próximo byte antes que o cronômetro tenha estourado de volta para 0, permitindo que o primeiro bit seja escrito mais cedo.

Eu adicionei um pequeno loop para garantir que isso não acontecesse, o que esperançosamente corrigirá isso para qualquer pessoa com esse problema.





Gravando dados - tentativa 7


Depois de obter muitos relatórios de erros de soma de verificação em discos gravados, comecei a investigar. A princípio pensei que teria que olhar para os dados MFM do disco, mas o problema era na verdade muito mais simples

Olhando para o XCopy Pro para ver os erros de checksum, ele relatou os códigos 4 e 6, significando erros de checksum nos cabeçalhos de setor e áreas de dados. Se fosse apenas a área de dados, eu teria assumido que era puramente algo a ver com a gravação dos últimos bits da faixa, mas não foi.

Comecei a olhar para o código de escrita e o preenchimento que tinha em torno de cada faixa, me perguntando se estava substituindo o início de uma faixa de vez em quando, então reduzi enormemente o preenchimento pós-faixa de 256 bytes para 8. Para minha surpresa, minha verificação então chutou uma tonelada de erros.

Isso me fez pensar se o problema real é que não estou gravando dados suficientes. Comecei a adicionar um comando Track Erase ao Arduino, que gravaria o padrão 0xAA em toda a trilha e, em seguida, escreveria minha trilha. Para minha surpresa, o XCopy deu 100% de aprovação. Então, espero que isso tenha resolvido o problema.





Diagnóstico


Recebi muitos comentários de pessoas que realizaram este projeto com sucesso, trabalhando ou não. Decidi que iria construir um módulo de diagnóstico no código para ajudar qualquer pessoa que não consegue fazer o seu funcionar.

A opção de diagnóstico consiste em alguns comandos extras para o Arduino processar, bem como em toda uma série de eventos que são executados para garantir que tudo esteja conectado corretamente.





Então, o que vem a seguir?


Todo o projeto é gratuito e de código aberto sob a GNU General Public License V3. Se quisermos ter alguma esperança de preservar o Amiga, não devemos roubar uns aos outros por causa do privilégio. Além disso, quero retribuir a melhor plataforma em que já trabalhei. Também espero que as pessoas desenvolvam isso, levem adiante e continuem compartilhando.

A solução de gravação atual não é uma opção no Arduino UNO, a menos que você use uma placa de breakout FTDI / serial separada, então minhas próximas tarefas são fazê-la funcionar (possivelmente usando o IC 23K256 para armazenar a trilha antes de gravá-la no disco).

Ainda quero olhar para outros formatos. Os arquivos ADF são bons, mas funcionam apenas com discos formatados com AmigaDOS. Existem muitos títulos com proteção de cópia personalizada e formatos de setor não padrão que simplesmente não podem ser suportados por este formato. Recebi algumas informações muito úteis sobre isso, mas atualmente não tenho muitos discos para testar.

De acordo com a Wikipedia, existe outro formato de arquivo em disco, o formato FDI. Um formato universal bem documentado. A vantagem desse formato é que ele tenta armazenar os dados da faixa o mais próximo possível do original, portanto, esperamos corrigir os problemas acima!

Também descobri a Software Preservation Society, especificamente CAPS (formalmente a Classic Amiga Preservation Society ) e seu formato IPF. Depois de ler um pouco, fiquei muito desapontado; está tudo fechado e parecia que eles estavam apenas usando esse formato para vender seu hardware de leitura de disco.

Portanto, meu foco será no formato de IDE. Minha única preocupação aqui é com a integridade dos dados. Não haverá nenhuma soma de verificação para eu verificar se a leitura foi válida, mas tenho algumas ideias para resolver isso!

Código

Sketch e fonte de aplicativos do Windows
Arduino Sketch e um exemplo de código-fonte do aplicativo Windowshttps://github.com/RobSmithDev/ArduinoFloppyDiskReader

Esquemas

Circuito para Arduino Pro Mini Circuito para Arduino UNO

Processo de manufatura

  1. Animação
  2. Disquete
  3. Diversão do giroscópio com anel NeoPixel
  4. Arduino Spybot
  5. FlickMote
  6. TV B-Gone caseiro
  7. Controlador de jogo Arduino
  8. Traje da nuvem
  9. Relógio mestre
  10. Leitor de disquete Arduino Amiga (V1)