Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Arduino Amiga Floppy Disk Reader / Writer (V2.2)

Componentes y suministros

Arduino UNO
× 1
SparkFun Arduino Pro Mini 328 - 5V / 16MHz
× 1
Resistencia 1k ohm
× 1
Breadboard (genérico)
× 1
Cables de puente (genéricos)
× 1
SparkFun FTDI Basic Breakout - 5V
× 1

Aplicaciones y servicios en línea

Arduino IDE

Acerca de este proyecto

Este proyecto continúa el trabajo de mi anterior proyecto de lector de disco en https://create.arduino.cc/projecthub/projects/485582/

Para obtener más información, visite http://amiga.robsmithdev.co.uk

  • Mi objetivo: Crear una forma simple, barata y de código abierto de recuperar y reescribir datos desde y hacia disquetes Amiga DD desde Windows 10.
  • Mi solución: Un boceto de Arduino + una aplicación de Windows ( que se puede portar a otros O / S ) que realmente funciona.
  • Por qué: Para preservar los datos de estos discos para el futuro. Además, una PC normal no puede leer / escribir discos Amiga debido a la forma en que están escritos.

Escritura de datos:intento 1

Entonces, después de poder leer discos con éxito, pensé que si desea mantener el medio físico original, es posible que desee volver a escribir los discos. Pensé que resolvería esto a la inversa, comenzando con el software (es decir, convirtiendo los archivos del disco ADF en datos MFM para que la interfaz escriba de alguna manera ).

Entonces comencé agregando clases para leer un disco ADF y codificar todos los sectores como una pista. Sabiendo que potencialmente podría probar los datos que creé al retroalimentarlos en la parte de decodificación, comencé a trabajar en esto. Mientras trabajaba en esto, decidí intentar averiguar qué le pasaba a mi Amiga. Después de todo, no puedo probar ningún disco que cree si no tengo nada real para probarlos.

Al desmontar mi A500 +, noté que había sufrido uno de los problemas más comunes, la batería del reloj se había filtrado por todas partes. Así que desolé esto del tablero y me puse a limpiar el tablero. Mientras lo hacía, saqué toda la máquina y me puse a limpiar 20 años de polvo y suciedad. Incluso desmonté la disquetera para limpiarla.

Mientras lo limpiaba, decidí que era hora de eliminar el color amarillento, así que seguí la información sobre Retr0brite y lo probé.

Luego revisé todas las juntas de la placa base principal y encontré una conexión suelta en el conector de alimentación, algunos retoques con el soldador y estaba como nueva. Esperé hasta que estuve satisfecho con el proceso de Retr0brite antes de volver a ensamblar la computadora.

Mientras tanto seguí trabajando en el código para escribir discos. Quería leer el estado de la línea de protección contra escritura, pero no importa lo que establezca, no parece que cambie el voltaje. Así que separé la unidad y seguí las huellas de los pequeños interruptores que detectan el estado de protección contra escritura hasta un pequeño IC. En este punto, supuse que la salida probablemente solo esté disponible cuando realmente desee escribir datos.

Después de mucho de experimentación, descubrí que necesitabas extraer el / WRITE_GATE pin LOW antes de girar la unidad para permitir la escritura. En este punto, puede obtener el estado de protección contra escritura. También noté que mientras / WRITE_GATE estaba bajo, la unidad no se apagó como solía hacerlo hasta que ese pin volvió a su estado ALTO predeterminado.

The Amiga escribiría una pista completa de una vez. Una pista en la memoria tiene 11 * 512 bytes (5638 bytes), sin embargo, después de codificar MFM y poner el formato AmigaDOS correcto, la pista funciona como 14848 bytes. Bueno, no hay forma de que pueda caber en los 2k de memoria de Arduino, ni en su 1k de EEPROM. Necesitaba un método alternativo.

Decidí que intentaría enviar los datos 1 byte a la vez en un hilo de alta prioridad y esperaría un byte de respuesta del Arduino antes de enviar el siguiente. Cambié la velocidad en baudios a 2M para reducir el retraso entre caracteres. Esto significaba que se necesitaron aproximadamente 5,5 uSec para enviar cada carácter y 5,5 uSec para recibir uno de vuelta. El Arduino necesitaría escribir 8 bits, a 500 kHz, por lo que necesitaría un nuevo byte cada 16 uSec. Por lo tanto, debería haber tiempo, asumiendo que el ciclo de código es lo suficientemente estrecho y que el sistema operativo no retrasa demasiado el envío y la recepción.

Este fue un completo y absoluto fracaso. El ciclo completo de lectura / escritura tomó demasiado tiempo, mucho más allá de una revolución del disco. El lado de Arduino probablemente fue lo suficientemente rápido, pero el sistema operativo no respondió lo suficiente. La lectura de discos funciona porque el sistema operativo (Windows en mi caso) almacenaría en búfer los datos que ingresan, pero al escribir, Windows simplemente los enviaría todos de una vez, pero debido a que la velocidad a la que estoy enviando es mucho más rápida de lo que Arduino lo necesita, los datos se perderían. Por eso me decidí por este proceso de reconocimiento bidireccional.

Escritura de datos:intento 2

El control de flujo de software para esta aplicación no fue lo suficientemente rápido. Decidí investigar el control de flujo de hardware. Noté que en la placa de ruptura FTDI hay clavijas CTS y DTR. Estos significan Limpiar para enviar y Terminal de datos listo . Noté que mientras la placa de ruptura estaba conectada, la placa Arduino conectó el CTS a GND.

Tampoco sabía en qué dirección estaban realmente estos pines, pero después de un poco de experimentación, descubrí que el pin CTS podía ser señalado desde el Arduino y utilizado por la PC para controlar el flujo. Normalmente, esto se hace usando un búfer circular, pero en mi caso no pude permitir esto, así que simplemente lo configuro en '1' cuando no quiero datos, y en '0' mientras lo hago.

Esto ahora significaba que podía pedirle al sistema operativo que enviara los bytes de forma masiva como un solo fragmento, y esperar que todo se manejara a nivel del kernel para que no se interrumpa.

Tenía un bucle interno que generaba cada bit de los 8 bits, pero decidí que probablemente era mejor en el tiempo desentrañarlo en 8 conjuntos de comandos.

Esto no funcionó. Si permitía que el código se ejecutara sin ejecutar realmente la parte de escritura del disco, entonces todos los bytes se recibían correctamente, pero al ejecutar el código, no era así y los bytes que se recibían se estaban perdiendo.

Sospeché que cambiar el estado de la línea CTX no detuvo instantáneamente el flujo de datos y la computadora aún puede enviar uno o dos caracteres. Posiblemente para cuando señalé la línea CTX, ya estaba en el proceso de enviar el siguiente carácter.

Escritura de datos:intento 3

No quería tener una interrupción en serie, ya que no quería que se distorsionara ninguno de los tiempos de escritura. Me di cuenta de que entre escribir cada bit en la unidad de disquete habría varios ciclos de CPU en el siguiente ciclo while. Decidí verificar entre cada escritura de bit si se había recibido otro byte desde que CTX subió y almacenarlo.

Mi teoría era que cuando subiste CTX, la computadora probablemente ya estaba en medio de transmitir el siguiente byte y, como no puedes detenerlo a mitad de la transmisión, lo haría la mitad después de este. Esto significa que solo necesito verificar un byte adicional durante el ciclo y usarlo si lo encuentro en lugar de mirar el puerto serie nuevamente.

Así que esto pareció funcionar, y Arduino completó la escritura sin perder ningún dato de la computadora. Las únicas preguntas ahora eran:¿realmente ha escrito algún dato y, de ser así, alguno de ellos es válido?

En este punto, solo había codificado una pista, así que decidí ejecutar todo el algoritmo para codificar las 80 pistas. Algo extraño estaba sucediendo. El cabezal impulsor no se movía en absoluto. Todavía lo hacía al leer, pero no al escribir.

Descubrí que para mover el cabezal de transmisión hacia adelante y hacia atrás, primero tenía que levantar el pin / WRITE GATE, sospeché que esto también era necesario para cambiar la superficie. Una vez que agregué el código para hacer esto, el cabezal de la unidad se movió como se esperaba. Esto tenía sentido y evitaría la escritura accidental de pistas mientras se mueve la cabeza.

Entonces, en este punto, escribí una imagen de disco que había creado anteriormente y luego intenté leerla. ¡No se pudo detectar nada! O los datos que había escrito no eran válidos o la forma en que los estaba escribiendo era incorrecta.

Decidí alimentar los datos codificados del sector MFM que estaba creando en mi algoritmo de decodificación de sector utilizado por el lector para validar que lo que estaba generando era correcto y válido, y lo era. Obviamente, algo andaba mal con la forma en que estaba escribiendo los datos en el disco.

Escritura de datos:intento 4

Como no se leían datos correctamente, decidí probar algunos enfoques diferentes. No estaba seguro de si el pin / WRITE DATA debería pulsarse (y si es así, por cuánto tiempo), alternar o simplemente establecer el valor de datos sin procesar. Mi implementación actual pulsó el pin. No había podido encontrar ninguna información en línea sobre cómo se suponía que se manipulaba físicamente el pin de escritura al escribir.

El cabezal de lectura nos enviaría un pulso cada vez que haya una inversión de flujo. Decidí cambiar la implementación para que WRITE DATA se estableciera en el valor del bit. Eso tampoco funcionó. Así que cambié el código para alternar el estado actual del pin. Sigo sin suerte.

Claramente, uno de estos enfoques debe haber sido el correcto. Así que decidí volver a sacar el confiable osciloscopio para ver lo que estaba pasando. Decidí escribir el patrón MFM 0xAA en cada byte de una pista de forma continua. 0xAA en binario es B10101010, por lo que esto me daría una onda cuadrada perfecta que podría monitorear para la frecuencia requerida.

Si no veía una onda cuadrada perfecta en la frecuencia deseada, entonces sabía que debía haber algún tipo de problema de sincronización.

Conecté el osciloscopio, pero me sorprendió ver que los tiempos eran Perfecto. Sin embargo, al ser un visor antiguo, no pude ver más que unos pocos pulsos. El visor tenía este maravilloso modo "mag" x10. Cuando se presiona, aumenta la base de tiempo en 10, pero lo que es más importante, le permite desplazarse por todos los datos como en un osciloscopio digital moderno.

Algo no estaba bien aquí. Parecía que cada 12 bits o así terminaba con un período de solo "alto" .

O los datos que estaba enviando no eran válidos de alguna manera, o había algo que causaba una pausa en el proceso de escritura cada 12 bits aproximadamente. 12 es un número extraño considerando que solo hay 8 bits en un byte.

Después de pensar en esto, me pregunté si había vuelto con un problema de control de flujo. La forma en que había diseñado el bucle era recoger los bytes extra extraviados que se recibieron después de haber esperado uno. Pero no era lo suficientemente inteligente como para evitar la espera cada dos bytes. Tenía dos opciones, mover algo en una interrupción, o parche el bucle.

Decidí intentar corregir la forma en que funcionaba el bucle primero. El problema se debió a un retraso causado por esperar el siguiente byte de la computadora. Si bajamos CTX y esperamos un byte, cuando subimos CTX nuevamente, otro byte ya estaba en camino.

Cambio el bucle para que cuando se haya usado el segundo byte recibido, Arduino baje momentáneamente el CTS y luego vuelva a subirlo para permitir que se envíe otro carácter. Esto significaba que en el siguiente ciclo ya habríamos recibido el siguiente byte, por lo que no fue necesario esperar.

Probar esto produjo una onda cuadrada perfecta:

Esto significó que todo el tiempo para escribir una pista fue perfecto, solo se redujo al real datos que se estaban escribiendo. Decidí dejar que esto se ejecutara por algunas pistas y lados, y luego volver a leerlo para ver si se había escrito correctamente. Estaba configurando el pin / WRITE_DATA al valor de bit correspondiente de los datos recibidos.

Cuando volví a leer los datos, parecía que no se había codificado nada, pero luego pasé al otro lado del disco. Efectivamente, ahí estaba mi patrón. No sabía por qué solo había escrito en un lado del disco.

Después de pensarlo un poco, comencé a preguntarme si el pin / WRITE GATE en realidad no funcionaba como pensaba. Ocurrió que al tirar del pasador hacia abajo, puede estar habilitando el cabezal de borrado en la unidad. Si este fuera el caso, solo debería hacer esto cuando en realidad esté escribiendo o podría terminar con ruido en el disco mientras gira y se borra.

Cambié todo el código para que / WRITE GATE solo se usara al iniciar la unidad por primera vez, y luego solo literalmente durante el ciclo de escritura. ¡Eso funciono! ¡Ahora estaba escribiendo datos en ambos lados del disco!

Así que lo intenté de nuevo con una imagen de disco ADF real y dejé que se completara. Luego utilicé la parte del lector para ver si podía volver a leerlo. ¡Funcionó! Pero por alguna razón, tomó bastante tiempo volver a leer este disco. No recibía ningún error de MFM, pero me costaba encontrar todos los sectores.

Había dos posibilidades para que yo mirara ahora:en primer lugar, si los datos realmente se escribieron lo suficientemente oportunamente; y en segundo lugar, ¿funcionaría realmente el disco en un Amiga real?

Demasiado emocionado con la idea de que podría haber escrito un disco. Arranqué el ahora funciona A500 + y coloque el disco. Momentos después, el disco comenzó a arrancar y luego mostró el famoso mensaje de error de suma de comprobación. Entonces estaba escribiendo algo válido, pero no consistente.

Decidí que, a menos que pudiera leer los datos a un ritmo mucho más preciso, escribir un disco no tenía sentido.

Leyendo datos (nuevamente)

Quería mejorar la calidad de lectura porque no estaba satisfecho con la implementación actual. La implementación actual no permitía la suficiente flexibilidad para que los pulsos llegaran en momentos ligeramente impares. Necesitaba un nuevo enfoque.

En primer lugar, decidí sincronizar la lectura con el pulso / INDEX. Amiga no lo requiere, pero puede ser útil más adelante para probar, escribir y leer.

Varias personas en los comentarios de la primera mitad de este proyecto sugirieron que debería registrar el tiempo entre pulsos en lugar del método que había implementado. El único problema con esto era hacer llegar estos datos a la PC lo suficientemente rápido. Si tuviera que enviar un byte por cada bit, fácilmente podría superar el máximo de 2 M baudios.

Decidí que lo mejor que podía hacer era intentar darle un poco de sentido a los datos. Así que decidí dejar que el contador que estaba usando originalmente funcionara libremente, hasta 255. Luego puse el código en un bucle esperando un pulso y ese punto vio cuánto tiempo había pasado.

En una situación ideal, el valor mínimo más bajo posible sería 32 (correspondiente a 2 uSec). Con MFM solo podía tener un máximo de tres ceros seguidos, por lo que el máximo que debería alcanzar este valor era 128. Esto significaba que había un máximo de 4 combinaciones posibles seguidas.

Probé varios discos para ver dónde se encuentran la mayoría de estas frecuencias, y los resultados se pueden ver a continuación:

Mirando esto, encuentro la mayoría de los puntos alrededor de un contador de 52, 89 y 120. Sin embargo, estos eran algo específicos de mi unidad y, por lo tanto, no eran una buena guía. Después de un poco de experimentación, utilicé la siguiente fórmula: value =(COUNTER - 16) / 32 . Cuando se recortó entre 0 y 3, esto me dio la salida que necesitaba. Cada 4 de estos y podría escribir un byte.

Se me ocurrió que debido a que no podía tener dos '1 juntos en un flujo de bits codificado en MFM, podía asumir con seguridad que cualquier cosa para el primer valor no era válido y podría tratarse como otra secuencia' 01 '. La siguiente parte fue descomprimir estos datos una vez recibidos por la PC y convertirlos nuevamente en datos MFM. Esto fue simple, ya que 00 no podía suceder, un 01 significaba escribir '01', un 10 significaba escribir '001' y un 11 significaba escribir '0001'. Probé esto y, para mi sorpresa, mis resultados fueron 100% exitosos. También probé con algunos discos más, ¡100%! Ahora tenía un lector de disco muy confiable.

Dado que este nuevo enfoque es mucho más tolerante con los datos del disco, ya no necesitaba ningún análisis de fase ni tantos reintentos. La mayoría de mis discos ahora se leen perfectamente. Algunos requirieron algunos reintentos, pero al final llegaron allí. La última parte fue analizar estadísticamente los datos y ver si podían repararse; sin embargo, el 99% de las veces que ingresaban datos incorrectos eran completamente irreconocibles y, por lo tanto, eran de poca ayuda.

Escritura de datos:intento 5

Ahora que pude verificar lo que había escrito con alta precisión, significaba que probar el escritor sería mucho más fácil.

Me puse a analizar el código para ver qué andaba mal. Escribí una secuencia 0x55 en una pista completa y luego la volví a leer. De vez en cuando, un poco había cambiado en los datos que regresaban, lo que significa que había algún tipo de problema de sincronización al escribir.

Resultó que esto se debía en parte a la forma en que manejaba el puerto serie y en parte al uso del temporizador. Estaba esperando que el temporizador alcanzara el valor 32, escribiendo el bit y luego restableciéndolo. Lo cambié para no tener que modificar el valor del contador del temporizador.

Escribiría el primer bit cuando el contador llegara a 16, luego el siguiente cuando llegara a 48 (16 + 32), y el siguiente cuando llegara a 80 (16 + 32 + 32) y así sucesivamente. El temporizador 2, que es de solo 8 bits, vuelve a cero después del octavo bit, exactamente cuando lo necesitábamos. Esto significaba que mientras escribiéramos el bit en el valor del temporizador requerido, estaríamos exactamente a 500 kbps.

También miré cómo estaba leyendo los datos del puerto serie. Esto se estaba leyendo entre cada bit, pero también tenía que ser lo más breve posible. Después de un poco de experimentación logré el bloque de trabajo más corto.

Después de modificar el código de Windows para admitir la verificación, estaba listo para volver a intentarlo. Esta vez supe que si el disco se verificaba correctamente, entonces debería funcionar correctamente en el Amiga.

Así que intenté escribir otro disco. Con verificar, tomó más tiempo. Con el nuevo algoritmo, alrededor del 95% de las pistas pasaron la verificación en el primer intento, y solo el 5% restante tuvo que ser reescrito una vez más. Estaba feliz con esto y metí el disco en el Amiga. ¡Funcionó perfectamente!

Escritura de datos:intento 6

Después de algunos comentarios de algunas personas que han estado usando esto, quedó claro que incluso con la verificación en la unidad no siempre se producían discos completamente legibles. El software podría leerlos perfectamente, pero las computadoras Amiga reportarían algunos errores de suma de verificación aquí y allá.

Eché otro vistazo al código, me pregunté si era un problema de tiempo y miré para ver si se podía hacer que fuera impulsado por interrupciones, pero lamentablemente con la pequeña cantidad de tiempo entre cada bit, simplemente no hay suficiente tiempo con interrupciones para consiga esto conservando los registros que modifique, etc.

Luego volví a mirar el código de escritura. Existe una pequeña posibilidad de que después de que se haya escrito un byte completo, el código se haya vuelto a realizar en bucle para comenzar a escribir el siguiente byte antes de que el temporizador se haya desbordado de nuevo a 0, lo que permite que el primer bit se escriba antes.

Agregué un pequeño bucle para asegurarme de que esto no pudiera suceder, lo que con suerte solucionará esto para cualquiera que tenga este problema.

Escritura de datos:intento 7

Después de recibir muchos informes de errores de suma de comprobación para discos escritos, comencé a investigar. Al principio pensé que tendría que ponerme a mirar los datos MFM del disco, pero el problema era mucho más simple

Al mirar XCopy Pro para ver los errores de suma de verificación, informó los códigos 4 y 6, lo que significa errores de suma de verificación en los encabezados de sector y áreas de datos. Si solo hubiera sido el área de datos, habría asumido que era simplemente algo que ver con escribir los últimos bits de la pista, pero no lo fue.

Comencé a mirar el código de escritura y el relleno que tenía alrededor de cada pista, preguntándome si estaba sobrescribiendo el inicio de una pista de vez en cuando, así que reduje enormemente el relleno posterior a la pista de 256 bytes a 8. Para mi sorpresa, mi verificación luego eliminó una tonelada de errores.

Esto me hizo preguntarme si el problema real es que no estoy escribiendo suficientes datos. Me dispuse a agregar un comando Track Erase al Arduino que escribiría el patrón 0xAA en toda la pista y luego escribiría mi pista. Para mi sorpresa, XCopy le dio un 100% de aprobación. Espero que eso haya solucionado ese problema.

Diagnóstico

He recibido muchos comentarios de personas que han realizado con éxito este proyecto, tanto funcionando como no. Decidí que crearía un módulo de diagnóstico en el código para ayudar a cualquiera que no pueda hacer que el suyo funcione.

La opción de diagnóstico consta de algunos comandos adicionales para que Arduino los procese, así como una serie completa de eventos que se ejecutan para garantizar que todo esté cableado correctamente.

Entonces, ¿qué sigue?

Todo el proyecto es gratuito y de código abierto bajo la Licencia Pública General GNU V3. Si queremos tener alguna esperanza de preservar el Amiga, entonces no deberíamos estafarnos unos a otros por el privilegio. Y además, quiero retribuir a la mejor plataforma en la que he trabajado. También espero que la gente desarrolle esto, lo lleve más allá y siga compartiendo.

La solución de escritura actual no es una opción en Arduino UNO a menos que use una placa de ruptura serial / FTDI separada, por lo que mis próximas tareas son hacer que funcione en eso (posiblemente usando el IC 23K256 para almacenar la pista antes de escribirla en el disco).

Todavía quiero mirar otros formatos. Los archivos ADF son buenos, pero solo funcionan para discos formateados con AmigaDOS. Hay muchos títulos con protección de copia personalizada y formatos de sector no estándar que simplemente no pueden ser compatibles con este formato. He recibido información muy útil sobre esto, pero actualmente no tengo muchos discos para probar.

Según Wikipedia, hay otro formato de archivo de disco, el formato FDI. Un formato universal que está bien documentado. La ventaja de este formato es que intenta almacenar los datos de la pista lo más cerca posible del original, ¡así que con suerte solucionará los problemas anteriores!

También me encontré con la Sociedad de Preservación de Software, específicamente CAPS (formalmente la Sociedad de Preservación de Amiga Clásica ) y su formato IPF. Después de leer un poco, me decepcionó mucho; está todo cerrado y se siente como si solo estuvieran usando este formato para vender su hardware de lectura de disco.

Por tanto, mi atención se centrará en el formato de IED. Mi única preocupación aquí es la integridad de los datos. No habrá ninguna suma de comprobación para comprobar si la lectura fue válida, ¡pero tengo algunas ideas para resolver eso!

Código

Sketch y fuente de la aplicación de Windows
Arduino Sketch y código fuente de la aplicación de Windows de ejemplo https://github.com/RobSmithDev/ArduinoFloppyDiskReader

Esquemas

Circuito para Arduino Pro Mini Circuito para Arduino UNO

Proceso de manufactura

  1. Animación
  2. Disquete
  3. Diversión con giroscopio con NeoPixel Ring
  4. Arduino Spybot
  5. FlickMote
  6. Televisión casera B-Gone
  7. Controlador de juego Arduino
  8. Traje de nube
  9. Reloj maestro
  10. Pixie:un reloj de pulsera NeoPixel basado en Arduino
  11. Lector de disquetes Arduino Amiga (V1)